├── docs
├── .nojekyll
├── favicon.ico
├── img
│ ├── autoComplete.js.png
│ ├── icons
│ │ ├── apple-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-96x96.png
│ │ ├── ms-icon-70x70.png
│ │ ├── ms-icon-144x144.png
│ │ ├── ms-icon-150x150.png
│ │ ├── ms-icon-310x310.png
│ │ ├── android-icon-36x36.png
│ │ ├── android-icon-48x48.png
│ │ ├── android-icon-72x72.png
│ │ ├── android-icon-96x96.png
│ │ ├── apple-icon-114x114.png
│ │ ├── apple-icon-120x120.png
│ │ ├── apple-icon-144x144.png
│ │ ├── apple-icon-152x152.png
│ │ ├── apple-icon-180x180.png
│ │ ├── apple-icon-57x57.png
│ │ ├── apple-icon-60x60.png
│ │ ├── apple-icon-72x72.png
│ │ ├── apple-icon-76x76.png
│ │ ├── android-icon-144x144.png
│ │ ├── android-icon-192x192.png
│ │ └── apple-icon-precomposed.png
│ ├── logos
│ │ ├── cdnjs_logo.png
│ │ ├── html_logo.png
│ │ ├── unpkg_logo.png
│ │ ├── yarn_logo.png
│ │ ├── codepen_logo.png
│ │ ├── jsdelivr_logo.png
│ │ ├── nodejs_logo.png
│ │ └── javascript_logo.png
│ ├── autoComplete.init.png
│ ├── autoComplete.js_Preview.png
│ ├── autoComplete.js_WidePreview.png
│ └── autoComplete.js.svg
├── browserconfig.xml
├── _coverpage.md
├── manifest.json
├── demo
│ ├── css
│ │ └── main.css
│ ├── js
│ │ └── index.js
│ └── index.html
├── index.html
└── releases.md
├── dist
├── js
│ ├── autoComplete.js.gz
│ ├── autoComplete.min.js.gz
│ ├── index.js
│ ├── autoComplete.min.js
│ └── autoComplete.js
├── css
│ ├── images
│ │ ├── magnifier.svg
│ │ └── search.svg
│ ├── autoComplete.02.css
│ ├── autoComplete.01.css
│ ├── main.css
│ └── autoComplete.css
├── index.html
└── db
│ └── test.json
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── feature-request.md
│ └── bug-report.md
├── .editorconfig
├── .vscode
└── settings.json
├── src
├── utils
│ ├── debouncer.js
│ └── eventEmitter.js
├── components
│ ├── Input.js
│ ├── Item.js
│ └── List.js
├── services
│ └── search.js
├── controllers
│ ├── listController.js
│ ├── dataController.js
│ └── navigationController.js
└── autoComplete.js
├── .gitignore
├── package.json
├── rollup.config.js
├── README.md
└── LICENSE
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/favicon.ico
--------------------------------------------------------------------------------
/dist/js/autoComplete.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/dist/js/autoComplete.js.gz
--------------------------------------------------------------------------------
/docs/img/autoComplete.js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/autoComplete.js.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon.png
--------------------------------------------------------------------------------
/docs/img/logos/cdnjs_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/cdnjs_logo.png
--------------------------------------------------------------------------------
/docs/img/logos/html_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/html_logo.png
--------------------------------------------------------------------------------
/docs/img/logos/unpkg_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/unpkg_logo.png
--------------------------------------------------------------------------------
/docs/img/logos/yarn_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/yarn_logo.png
--------------------------------------------------------------------------------
/dist/js/autoComplete.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/dist/js/autoComplete.min.js.gz
--------------------------------------------------------------------------------
/docs/img/autoComplete.init.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/autoComplete.init.png
--------------------------------------------------------------------------------
/docs/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/img/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/docs/img/icons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/docs/img/logos/codepen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/codepen_logo.png
--------------------------------------------------------------------------------
/docs/img/logos/jsdelivr_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/jsdelivr_logo.png
--------------------------------------------------------------------------------
/docs/img/logos/nodejs_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/nodejs_logo.png
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | liberapay: TarekRaafat
4 | patreon: TarekRaafat
5 |
--------------------------------------------------------------------------------
/docs/img/icons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/docs/img/icons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/docs/img/icons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/docs/img/logos/javascript_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/logos/javascript_logo.png
--------------------------------------------------------------------------------
/docs/img/autoComplete.js_Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/autoComplete.js_Preview.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-36x36.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-48x48.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-72x72.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-96x96.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-144x144.png
--------------------------------------------------------------------------------
/docs/img/icons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/android-icon-192x192.png
--------------------------------------------------------------------------------
/docs/img/autoComplete.js_WidePreview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/autoComplete.js_WidePreview.png
--------------------------------------------------------------------------------
/docs/img/icons/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wikia/autoComplete.js/master/docs/img/icons/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/docs/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | charset = utf-8
7 | tab_width = 2
8 | indent_size = 2
9 | indent_style = space
10 | insert_final_newline = true
11 |
12 | # Indentation override for all JS under lib directory
13 | [*.js]
14 | max_line_length = 120
15 | trim_trailing_whitespace = true
16 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Raafat",
4 | "Tarek",
5 | "activedescendant",
6 | "afterend",
7 | "autocapitalize",
8 | "autocorrect",
9 | "combobox",
10 | "debouncer",
11 | "haspopup",
12 | "labelledby",
13 | "listbox",
14 | "nodent",
15 | "sourcemap",
16 | "tabindex",
17 | "tarekraafat",
18 | "textbox",
19 | "toplevel",
20 | "uninit"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/src/utils/debouncer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Debouncer
3 | *
4 | * @param {Function} callback - The callback function
5 | * @param {Number} delay - The delay number value
6 | *
7 | * @returns {Function} - The callback function wrapped in `setTimeout` function
8 | */
9 | export default (callback, delay) => {
10 | let inDebounce;
11 | return function () {
12 | const context = this;
13 | const args = arguments;
14 | clearTimeout(inDebounce);
15 | inDebounce = setTimeout(() => callback.apply(context, args), delay);
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/src/utils/eventEmitter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Event emitter/dispatcher `Function`
3 | *
4 | * @param {Element} target - The target element to listen for
5 | * @param {Object} detail - The detail object containing relevant information or null
6 | * @param {String} name - The name of the event fired
7 | *
8 | */
9 | export default (target, detail, name) => {
10 | // Dispatch event on input
11 | target.dispatchEvent(
12 | new CustomEvent(name, {
13 | bubbles: true,
14 | detail,
15 | cancelable: true,
16 | })
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/src/components/Input.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Input field element
3 | *
4 | * @param {Object} config - autoComplete configurations
5 | *
6 | */
7 | export default (config) => {
8 | // General attributes
9 | // ARIA attributes
10 | config.inputField.setAttribute("role", "combobox");
11 | config.inputField.setAttribute("aria-haspopup", true);
12 | config.inputField.setAttribute("aria-expanded", false);
13 | config.inputField.setAttribute("aria-controls", config.resultsList.idName);
14 | config.inputField.setAttribute("aria-autocomplete", "both");
15 | };
16 |
--------------------------------------------------------------------------------
/dist/css/images/magnifier.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Item.js:
--------------------------------------------------------------------------------
1 | /**
2 | * List Item element creator
3 | *
4 | * @param {String} itemValue - The item string value
5 | * @param {Number} resultIndex - The result item index
6 | * @param {Object} config - autoComplete configurations
7 | *
8 | * @returns {Element} - The created result item element
9 | */
10 | export default (item, index, config) => {
11 | // Create a DIV element for each matching result item
12 | const result = document.createElement(config.resultItem.element);
13 | result.setAttribute("id", `${config.resultItem.idName}_${index}`);
14 | result.setAttribute("class", config.resultItem.className);
15 | result.setAttribute("role", "option");
16 | result.innerHTML = item.match;
17 | if (config.resultItem.content) config.resultItem.content(item, result);
18 |
19 | return result;
20 | };
21 |
--------------------------------------------------------------------------------
/src/components/List.js:
--------------------------------------------------------------------------------
1 | /**
2 | * List element creator
3 | *
4 | * @param {Object} config - autoComplete configurations
5 | *
6 | * @returns {Element} - The created list element
7 | */
8 | export default (config) => {
9 | // Create a DIV element that will contain the results items
10 | const list = document.createElement(config.resultsList.element);
11 | list.setAttribute("id", config.resultsList.idName);
12 | list.setAttribute("aria-label", config.name);
13 | list.setAttribute("class", config.resultsList.className);
14 | list.setAttribute("role", "listbox");
15 | list.setAttribute("tabindex", "-1");
16 | if (config.resultsList.container) config.resultsList.container(list);
17 | const destination =
18 | "string" === typeof config.resultsList.destination
19 | ? document.querySelector(config.resultsList.destination)
20 | : config.resultsList.destination();
21 | // Append the DIV element as a child of autoComplete container
22 | destination.insertAdjacentElement(config.resultsList.position, list);
23 |
24 | return list;
25 | };
26 |
--------------------------------------------------------------------------------
/dist/css/images/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest an idea (or improvement for an existing feature)
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
17 |
18 | **Is your feature request related to a problem? Please describe.**
19 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
20 |
21 | **Thoroughly Describe the solution you'd like**
22 | A clear and concise description of what you want to happen.
23 |
24 | **Please provide a few use cases for this feature**
25 | 1. ...
26 | 2. ...
27 |
28 | **Please Describe alternatives you've considered**
29 | A clear and concise description of any alternative solutions or features you've considered.
30 |
31 | **Additional context**
32 | Add any other context or screenshots about the feature request here.
33 |
--------------------------------------------------------------------------------
/docs/_coverpage.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | > Simple autocomplete pure vanilla Javascript library. Live Demo **v8.3**
6 |
7 | autoComplete.js is a simple pure vanilla Javascript library that's progressively designed for speed,
high versatility and seamless integration with a wide range of projects & systems.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | [GitHub](https://github.com/TarekRaafat/autoComplete.js)
20 | [Get Started](#introduction)
21 |
22 | 
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Something broken or is not functioning as expected.
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
14 |
15 | - [ ] **System Information**
16 | - [ ] Browser type and version
17 | - [ ] OS type and version
18 | - [ ] WINDOWS: be sure to indicate which terminal you're using -- (i.e., cmd.exe, powershell, git- bash, cygwin, Ubuntu via windows subsystem for linux, etc...)
19 | - [ ] Node version (IF applicable)
20 | - [ ] Any error messages that may be in the console where you ran npm start
21 | - [ ] Any error messages in the JS console
22 |
23 | - [ ] **Describe the bug**
24 |
25 |
26 | - [ ] **To Reproduce**
27 | Steps to reproduce the behavior:
79 |
80 | ## Documentation:
81 |
82 | - For more details check out **autoComplete.js** **docs** :notebook_with_decorative_cover:
83 |
84 |
85 |
86 | ## Third-Party Plugins:
87 |
88 | - [Contao autoComplete.js Bundle](https://github.com/heimrichhannot/contao-autocompletejs-bundle) by [@heimrichhannot](https://github.com/heimrichhannot)
89 |
90 | * * *
91 |
92 | ## Support
93 |
94 | For general questions about autoComplete.js, tweet at [@TarekRaafat].
95 |
96 | For technical questions, you should post a question on [Stack Overflow] and tag
97 | it with [autoComplete.js][so tag].
98 |
99 |
100 |
101 | [stack overflow]: https://stackoverflow.com/
102 |
103 | [@tarekraafat]: https://twitter.com/TarekRaafat
104 |
105 | [so tag]: https://stackoverflow.com/questions/tagged/autoComplete.js
106 |
107 | * * *
108 |
109 | ## Author
110 |
111 | **Tarek Raafat**
112 |
113 | - Email: tarek.m.raafat@gmail.com
114 | - Website:
115 | - Github:
116 |
117 | Distributed under the Apache 2.0 license. See `Apache 2.0` for more information.
118 |
119 | * * *
120 |
121 | ## License
122 |
123 | Apache 2.0 © [Tarek Raafat](http://www.tarekraafat.com)
124 |
--------------------------------------------------------------------------------
/src/controllers/navigationController.js:
--------------------------------------------------------------------------------
1 | import { closeAllLists } from "./listController";
2 | import eventEmitter from "../utils/eventEmitter";
3 |
4 | /**
5 | * List navigation function initializer
6 | *
7 | * @param {Object} config - autoComplete configurations
8 | * @param {Object} dataFeedback - The available data object
9 | *
10 | */
11 | const navigate = (config, dataFeedback) => {
12 | // Reset focus state
13 | let currentFocus = -1;
14 |
15 | /**
16 | * Update list item state
17 | *
18 | * @param {Object} event - The `keydown` event Object
19 | * @param {Array } list - The array of list items
20 | * @param {Boolean} state - Of the arrow Down/Up
21 | * @param {Object} config - autoComplete configurations
22 | *
23 | */
24 | const update = (event, list, state, config) => {
25 | event.preventDefault();
26 | if (state) {
27 | // If the arrow DOWN or TAB key is pressed
28 | // increase the currentFocus
29 | currentFocus++;
30 | } else {
31 | // If the arrow UP or TAB key is pressed
32 | // decrease the currentFocus
33 | currentFocus--;
34 | }
35 | // and add "active" class to the list item
36 | addActive(list);
37 | config.inputField.setAttribute("aria-activedescendant", list[currentFocus].id);
38 | /**
39 | * @emits {navigation} Emits Event on results list navigation
40 | **/
41 | eventEmitter(
42 | event.srcElement,
43 | { event, ...dataFeedback, selection: dataFeedback.results[currentFocus] },
44 | "navigation"
45 | );
46 | };
47 |
48 | /**
49 | * Remove list item active state
50 | *
51 | * @param {Array } list - The array of list items
52 | *
53 | */
54 | const removeActive = (list) => {
55 | // Remove "active" class from all list items
56 | for (let index = 0; index < list.length; index++) {
57 | // Remove "active" class from the item
58 | list[index].removeAttribute("aria-selected");
59 | // list[index].setAttribute("aria-selected", "false");
60 | if (config.selection.className !== "") {
61 | list[index].classList.remove(config.selection.className);
62 | }
63 | }
64 | };
65 |
66 | /**
67 | * Add active state to list item
68 | *
69 | * @param {Array } list - The array of list items
70 | *
71 | */
72 | const addActive = (list) => {
73 | // Add "active" class to a list item
74 | if (!list) return false;
75 | // Remove "active" class from all list items
76 | removeActive(list);
77 | if (currentFocus >= list.length) currentFocus = 0;
78 | if (currentFocus < 0) currentFocus = list.length - 1;
79 | // Add "active" class to the item
80 | list[currentFocus].setAttribute("aria-selected", "true");
81 | if (config.selection.className !== "") {
82 | list[currentFocus].classList.add(config.selection.className);
83 | }
84 | };
85 |
86 | /**
87 | * List Navigation Function
88 | *
89 | * @param {Object} event - The `keydown` event Object
90 | *
91 | */
92 | const navigation = (event) => {
93 | let list = document.getElementById(config.resultsList.idName);
94 |
95 | if (!list) return config.inputField.removeEventListener("keydown", navigate);
96 |
97 | list = list.getElementsByTagName(config.resultItem.element);
98 |
99 | if (event.keyCode === 27) {
100 | // If the ESC key is pressed
101 | // Clear Input value
102 | config.inputField.value = "";
103 | // Closes open lists
104 | closeAllLists(config);
105 | } else if (event.keyCode === 40 || event.keyCode === 9) {
106 | // Update list items state
107 | update(event, list, true, config);
108 | } else if (event.keyCode === 38 || event.keyCode === 9) {
109 | // Update list items state
110 | update(event, list, false, config);
111 | } else if (event.keyCode === 13) {
112 | // If the ENTER key is pressed
113 | // prevent the form from its default behaviour "being submitted"
114 | event.preventDefault();
115 | if (currentFocus > -1) {
116 | // and simulate a click on the selected "active" item
117 | if (list) list[currentFocus].click();
118 | }
119 | }
120 | };
121 |
122 | const navigate = config.resultsList.navigation || navigation;
123 |
124 | // Remove previous keydown listener
125 | if (config.inputField.autoCompleteNavigate)
126 | config.inputField.removeEventListener("keydown", config.inputField.autoCompleteNavigate);
127 | config.inputField.autoCompleteNavigate = navigate;
128 |
129 | /**
130 | * @listens {keydown} Listens to all `keydown` events on the input field
131 | **/
132 | config.inputField.addEventListener("keydown", navigate);
133 | };
134 |
135 | export { navigate };
136 |
--------------------------------------------------------------------------------
/docs/demo/js/index.js:
--------------------------------------------------------------------------------
1 | // The autoComplete.js Engine instance creator
2 | const autoCompleteJS = new autoComplete({
3 | name: "food & drinks",
4 | data: {
5 | src: async function () {
6 | // Loading placeholder text
7 | document.querySelector("#autoComplete").setAttribute("placeholder", "Loading...");
8 | // Fetch External Data Source
9 | const source = await fetch("../demo/db/generic.json");
10 | const data = await source.json();
11 | // Post Loading placeholder text
12 | document.querySelector("#autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder);
13 | // Returns Fetched data
14 | return data;
15 | },
16 | key: ["food", "cities", "animals"],
17 | results: (list) => {
18 | // Filter duplicates
19 | const filteredResults = Array.from(new Set(list.map((value) => value.match))).map((food) => {
20 | return list.find((value) => value.match === food);
21 | });
22 |
23 | return filteredResults;
24 | },
25 | },
26 | trigger: {
27 | event: ["input", "focus"],
28 | },
29 | placeHolder: "Search for Food & Drinks!",
30 | searchEngine: "strict",
31 | highlight: true,
32 | maxResults: 5,
33 | resultItem: {
34 | content: (data, element) => {
35 | // Modify Results Item Style
36 | element.style = "display: flex; justify-content: space-between;";
37 | // Modify Results Item Content
38 | element.innerHTML = `
39 |
40 | ${data.match}
41 |
42 |
43 | ${data.key}
44 | `;
45 | },
46 | },
47 | noResults: (dataFeedback, generateList) => {
48 | // Generate autoComplete List
49 | generateList(autoCompleteJS, dataFeedback, dataFeedback.results);
50 | // No Results List Item
51 | const result = document.createElement("li");
52 | result.setAttribute("class", "no_result");
53 | result.setAttribute("tabindex", "1");
54 | result.innerHTML = `Found No Results for "${dataFeedback.query}"`;
55 | document.querySelector(`#${autoCompleteJS.resultsList.idName}`).appendChild(result);
56 | },
57 | onSelection: (feedback) => {
58 | document.querySelector("#autoComplete").blur();
59 | // Prepare User's Selected Value
60 | const selection = feedback.selection.value[feedback.selection.key];
61 | // Render selected choice to selection div
62 | document.querySelector(".selection").innerHTML = selection;
63 | // Replace Input value with the selected value
64 | document.querySelector("#autoComplete").value = selection;
65 | // Console log autoComplete data feedback
66 | console.log(feedback);
67 | },
68 | });
69 |
70 | // Toggle Search Engine Type/Mode
71 | document.querySelector(".toggler").addEventListener("click", function () {
72 | // Holds the toggle button alignment
73 | const toggle = document.querySelector(".toggle").style.justifyContent;
74 |
75 | if (toggle === "flex-start" || toggle === "") {
76 | // Set Search Engine mode to Loose
77 | document.querySelector(".toggle").style.justifyContent = "flex-end";
78 | document.querySelector(".toggler").innerHTML = "Loose";
79 | autoCompleteJS.searchEngine = "loose";
80 | } else {
81 | // Set Search Engine mode to Strict
82 | document.querySelector(".toggle").style.justifyContent = "flex-start";
83 | document.querySelector(".toggler").innerHTML = "Strict";
84 | autoCompleteJS.searchEngine = "strict";
85 | }
86 | });
87 |
88 | // Toggle results list and other elements
89 | const action = function (action) {
90 | const github = document.querySelector(".github-corner");
91 | const title = document.querySelector("h1");
92 | const mode = document.querySelector(".mode");
93 | const selection = document.querySelector(".selection");
94 | const footer = document.querySelector(".footer");
95 |
96 | if (action === "dim") {
97 | github.style.opacity = 1;
98 | title.style.opacity = 1;
99 | mode.style.opacity = 1;
100 | selection.style.opacity = 1;
101 | footer.style.opacity = 1;
102 | } else {
103 | github.style.opacity = 0.1;
104 | title.style.opacity = 0.3;
105 | mode.style.opacity = 0.2;
106 | selection.style.opacity = 0.1;
107 | footer.style.opacity = 0.1;
108 | }
109 | };
110 |
111 | // Toggle event for search input
112 | // showing & hiding results list onfocus/blur
113 | ["focus", "blur"].forEach(function (eventType) {
114 | document.querySelector("#autoComplete").addEventListener(eventType, function () {
115 | // Hide results list & show other elements
116 | if (eventType === "blur") {
117 | action("dim");
118 | } else if (eventType === "focus") {
119 | // Show results list & hide other elements
120 | action("light");
121 | }
122 | });
123 | });
124 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | autoComplete.js - Vanilla Javascript library
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/dist/js/index.js:
--------------------------------------------------------------------------------
1 | // // autoComplete.js input eventListener on connect event
2 | // document.querySelector("#autoComplete").addEventListener("connect", function (event) {
3 | // console.log(event);
4 | // });
5 | // autoComplete.js input eventListener on initialization event
6 | document.querySelector("#autoComplete").addEventListener("init", function (event) {
7 | console.log(event);
8 | });
9 | // // autoComplete.js input eventListener on input event
10 | // document.querySelector("#autoComplete").addEventListener("input", function (event) {
11 | // console.log(event);
12 | // });
13 | // // autoComplete.js input eventListener on data response event
14 | // document.querySelector("#autoComplete").addEventListener("fetch", function (event) {
15 | // console.log(event.detail);
16 | // });
17 | // // autoComplete.js input eventListener on search results event
18 | // document.querySelector("#autoComplete").addEventListener("results", function (event) {
19 | // console.log(event.detail);
20 | // });
21 | // // autoComplete.js input eventListener on post results list rendering event
22 | // document.querySelector("#autoComplete").addEventListener("rendered", function (event) {
23 | // console.log(event.detail);
24 | // });
25 | // // autoComplete.js input eventListener on results list navigation
26 | // document.querySelector("#autoComplete").addEventListener("navigation", function (event) {
27 | // console.log(event.detail);
28 | // });
29 | // // autoComplete.js input eventListener on post un-initialization event
30 | // document.querySelector("#autoComplete").addEventListener("unInit", function (event) {
31 | // console.log(event);
32 | // });
33 |
34 | // The autoComplete.js Engine instance creator
35 | const autoCompleteJS = new autoComplete({
36 | name: "food & drinks",
37 | selector: "#autoComplete",
38 | observer: false,
39 | data: {
40 | src: async () => {
41 | // Loading placeholder text
42 | document.querySelector("#autoComplete").setAttribute("placeholder", "Loading...");
43 |
44 | if (!JSON.parse(localStorage.getItem("acData"))) {
45 | // Fetch External Data Source
46 | const source = await fetch("./db/generic.json");
47 | const data = await source.json();
48 | // Saves the fetched data into local storage
49 | localStorage.setItem("acData", JSON.stringify(data));
50 | // Retrieve the cached data from local storage
51 | const localData = JSON.parse(localStorage.getItem("acData"));
52 | // Post Loading placeholder text
53 | document.querySelector("#autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder);
54 | // Returns Fetched data
55 | return localData;
56 | }
57 |
58 | // Post Loading placeholder text
59 | document.querySelector("#autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder);
60 |
61 | return JSON.parse(localStorage.getItem("acData"));
62 | },
63 | key: ["food", "cities", "animals"],
64 | cache: true,
65 | results: (list) => {
66 | // Filter duplicates
67 | const filteredResults = Array.from(new Set(list.map((value) => value.match))).map((food) => {
68 | return list.find((value) => value.match === food);
69 | });
70 |
71 | return filteredResults;
72 | },
73 | },
74 | searchEngine: "strict",
75 | placeHolder: "Search for Food & Drinks!",
76 | maxResults: 5,
77 | sort: (a, b) => {
78 | if (a.match < b.match) return -1;
79 | if (a.match > b.match) return 1;
80 | return 0;
81 | },
82 | highlight: true,
83 | debounce: 100,
84 | threshold: 1,
85 | trigger: {
86 | event: ["input", "focus"],
87 | },
88 | resultItem: {
89 | content: (data, element) => {
90 | // Modify Results Item Style
91 | element.style = "display: flex; justify-content: space-between;";
92 | // Modify Results Item Content
93 | element.innerHTML = `
94 |
95 | ${data.match}
96 |
97 |
98 | ${data.key}
99 | `;
100 | },
101 | },
102 | noResults: (dataFeedback, generateList) => {
103 | // Generate autoComplete List
104 | generateList(autoCompleteJS, dataFeedback, dataFeedback.results);
105 | // No Results List Item
106 | const result = document.createElement("li");
107 | result.setAttribute("class", "no_result");
108 | result.setAttribute("tabindex", "1");
109 | result.innerHTML = `Found No Results for "${dataFeedback.query}"`;
110 | document.querySelector(`#${autoCompleteJS.resultsList.idName}`).appendChild(result);
111 | },
112 | feedback: (data) => {
113 | console.log(data);
114 | },
115 | onSelection: (feedback) => {
116 | document.querySelector("#autoComplete").blur();
117 | // Prepare User's Selected Value
118 | const selection = feedback.selection.value[feedback.selection.key];
119 | // Render selected choice to selection div
120 | document.querySelector(".selection").innerHTML = selection;
121 | // Replace Input value with the selected value
122 | document.querySelector("#autoComplete").value = selection;
123 | // Console log autoComplete data feedback
124 | console.log(feedback);
125 | },
126 | });
127 |
128 | // autoComplete.unInit();
129 |
130 | // Toggle Search Engine Type/Mode
131 | document.querySelector(".toggler").addEventListener("click", function () {
132 | // Holds the toggle button alignment
133 | const toggle = document.querySelector(".toggle").style.justifyContent;
134 |
135 | if (toggle === "flex-start" || toggle === "") {
136 | // Set Search Engine mode to Loose
137 | document.querySelector(".toggle").style.justifyContent = "flex-end";
138 | document.querySelector(".toggler").innerHTML = "Loose";
139 | autoCompleteJS.searchEngine = "loose";
140 | } else {
141 | // Set Search Engine mode to Strict
142 | document.querySelector(".toggle").style.justifyContent = "flex-start";
143 | document.querySelector(".toggler").innerHTML = "Strict";
144 | autoCompleteJS.searchEngine = "strict";
145 | }
146 | });
147 |
148 | // Toggle results list and other elements
149 | const action = function (action) {
150 | const github = document.querySelector(".github-corner");
151 | const title = document.querySelector("h1");
152 | const mode = document.querySelector(".mode");
153 | const selection = document.querySelector(".selection");
154 | const footer = document.querySelector(".footer");
155 |
156 | if (action === "dim") {
157 | github.style.opacity = 1;
158 | title.style.opacity = 1;
159 | mode.style.opacity = 1;
160 | selection.style.opacity = 1;
161 | footer.style.opacity = 1;
162 | } else {
163 | github.style.opacity = 0.1;
164 | title.style.opacity = 0.3;
165 | mode.style.opacity = 0.2;
166 | selection.style.opacity = 0.1;
167 | footer.style.opacity = 0.1;
168 | }
169 | };
170 |
171 | // Toggle event for search input
172 | // showing & hiding results list onfocus/blur
173 | ["focus", "blur"].forEach(function (eventType) {
174 | document.querySelector("#autoComplete").addEventListener(eventType, function () {
175 | // Hide results list & show other elements
176 | if (eventType === "blur") {
177 | action("dim");
178 | } else if (eventType === "focus") {
179 | // Show results list & hide other elements
180 | action("light");
181 | }
182 | });
183 | });
184 |
--------------------------------------------------------------------------------
/docs/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
18 | autoComplete.js - Vanilla Javascript library
19 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
71 |
72 |
73 |
74 |
76 |
77 |
78 |
79 |
80 |
81 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/dist/js/autoComplete.min.js:
--------------------------------------------------------------------------------
1 | var a,b;a=this,b=function(){"use strict";function e(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,i=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,s=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return o=e.done,e},e:function(e){s=!0,r=e},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw r}}}}function u(e,t){for(var n=document.getElementsByClassName(e.resultsList.className),i=0;i=e.length?0:o)<0?e.length-1:o].setAttribute("aria-selected","true"),e[o].classList.add("autoComplete_selected")},a=n.resultsList.navigation||function(e){var t=document.getElementById(n.resultsList.idName);if(!t)return n.inputField.removeEventListener("keydown",a);t=t.getElementsByTagName(n.resultItem.element),27===e.keyCode?(n.inputField.value="",u(n)):40===e.keyCode||9===e.keyCode?i(e,t,!0,n):38===e.keyCode||9===e.keyCode?i(e,t,!1,n):13===e.keyCode&&(e.preventDefault(),-1'.concat(a,""):a,o++),r.push(a)}if(o===e.length)return r.join("")}else if(i.includes(e))return e=new RegExp("".concat(e),"i").exec(t),n.highlight?t.replace(e,''.concat(e,"")):t}(s,t,o))&&e?a.push({key:e,index:n,match:t,value:i}):t&&!e&&a.push({index:n,match:t,value:i}))}var i=o.data.store[n];if(o.data.key){var t,r=l(o.data.key);try{for(r.s();!(t=r.n()).done;)e(t.value)}catch(e){r.e(e)}finally{r.f()}}else e()},t=0;t=r.threshold&&o.replace(/ /g,"").length)?a.dataStore().then(function(e){try{return u(a),a.start(n,i),s.call(a)}catch(e){return t(e)}},t):(u(a),s.call(a));function s(){return e()}})}},{key:"init",value:function(){var e,n,i,r,t=this;(e=this).inputField.setAttribute("role","combobox"),e.inputField.setAttribute("aria-haspopup",!0),e.inputField.setAttribute("aria-expanded",!1),e.inputField.setAttribute("aria-controls",e.resultsList.idName),e.inputField.setAttribute("aria-autocomplete","both"),this.placeHolder&&this.inputField.setAttribute("placeholder",this.placeHolder),this.hook=(n=function(){t.compose()},i=this.debounce,function(){var e=this,t=arguments;clearTimeout(r),r=setTimeout(function(){return n.apply(e,t)},i)}),this.trigger.event.forEach(function(e){t.inputField.removeEventListener(e,t.hook),t.inputField.addEventListener(e,t.hook)}),d(this.inputField,null,"init")}},{key:"preInit",value:function(){var r=this;new MutationObserver(function(e,t){var n,i=l(e);try{for(i.s();!(n=i.n()).done;){n.value;r.inputField&&(t.disconnect(),d(r.inputField,null,"connect"),r.init())}}catch(e){i.e(e)}finally{i.f()}}).observe(document,{childList:!0,subtree:!0})}},{key:"unInit",value:function(){this.inputField.removeEventListener("input",this.hook),d(this.inputField,null,"unInit")}}])&&e(n.prototype,i),h&&e(n,h),T},"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):(a="undefined"!=typeof globalThis?globalThis:a||self).autoComplete=b();
2 |
--------------------------------------------------------------------------------
/src/autoComplete.js:
--------------------------------------------------------------------------------
1 | import inputComponent from "./components/Input";
2 | import { generateList, closeAllLists } from "./controllers/listController";
3 | import { navigate } from "./controllers/navigationController";
4 | import {
5 | getInputValue,
6 | prepareQueryValue,
7 | checkTriggerCondition,
8 | listMatchingResults,
9 | } from "./controllers/dataController";
10 | import debouncer from "./utils/debouncer";
11 | import eventEmitter from "./utils/eventEmitter";
12 |
13 | /**
14 | * @desc This is autoComplete.js
15 | * @version 8.3.2
16 | * @example let autoCompleteJS = new autoComplete({config});
17 | */
18 | export default class autoComplete {
19 | constructor(config) {
20 | // Deconstructing config values
21 | const {
22 | name = "Search",
23 | selector = "#autoComplete", // User input selector
24 | observer = false, // Input field Observer
25 | data: {
26 | src, // Data src selection
27 | key, // Data src key selection
28 | cache = false, // Flag to cache data src
29 | store, // Data feedback store
30 | results, // Data feedback matching results
31 | },
32 | query, // Query interceptor function
33 | trigger: {
34 | event = ["input"], // autoComplete event
35 | condition = false, // condition trigger
36 | } = {},
37 | searchEngine = "strict", // Search engine type
38 | diacritics = false, // Diacritics to be ignored
39 | threshold = 1, // Minimum characters length before engine starts rendering
40 | debounce = 0, // Minimum duration for API calls debounce
41 | resultsList: {
42 | render: resultsListRender = true,
43 | container = false,
44 | destination, // Results list selector
45 | position = "afterend", // Results list position
46 | element: resultsListElement = "ul", // Results list element tag
47 | idName: resultsListId = "autoComplete_list",
48 | className: resultsListClass = "autoComplete_list",
49 | navigation = false, // Results list navigation
50 | } = {},
51 | sort = false, // Sorting results list
52 | placeHolder, // Placeholder text
53 | maxResults = 5, // Maximum number of results to show
54 | resultItem: {
55 | content = false, // Result item function
56 | element: resultItemElement = "li", // Result item element tag
57 | idName: resultItemId = "autoComplete_result",
58 | className: resultItemClass = "autoComplete_result",
59 | } = {},
60 | noResults, // No results action
61 | selection: {
62 | className: selectionClass = "autoComplete_selected",
63 | } = {},
64 | highlight: {
65 | render: highlightRender = false,
66 | className: highlightClass = "autoComplete_highlighted",
67 | } = {},
68 | feedback, // Data feedback
69 | onSelection, // Action function on result selection
70 | } = config;
71 |
72 | // Assigning config values to properties
73 | this.name = name;
74 | this.selector = selector;
75 | this.observer = observer;
76 | this.data = {
77 | src,
78 | key,
79 | cache,
80 | store,
81 | results,
82 | };
83 | this.query = query;
84 | this.trigger = {
85 | event,
86 | condition,
87 | };
88 | this.searchEngine = searchEngine;
89 | this.diacritics = diacritics;
90 | this.threshold = threshold;
91 | this.debounce = debounce;
92 | this.resultsList = {
93 | render: resultsListRender,
94 | container,
95 | destination: destination || this.selector,
96 | position,
97 | element: resultsListElement,
98 | idName: resultsListId,
99 | className: resultsListClass,
100 | navigation,
101 | };
102 | this.sort = sort;
103 | this.placeHolder = placeHolder;
104 | this.maxResults = maxResults;
105 | this.resultItem = {
106 | content,
107 | element: resultItemElement,
108 | idName: resultItemId,
109 | className: resultItemClass,
110 | };
111 | this.noResults = noResults;
112 | this.selection = {
113 | className: selectionClass,
114 | };
115 | this.highlight = {
116 | render: highlightRender,
117 | className: highlightClass,
118 | }
119 | this.feedback = feedback;
120 | this.onSelection = onSelection;
121 | // Assign the input field selector
122 | this.inputField = typeof this.selector === "string" ? document.querySelector(this.selector) : this.selector();
123 | // Invoke preInit if enabled
124 | // or initiate autoComplete instance directly
125 | this.observer ? this.preInit() : this.init();
126 | }
127 |
128 | // Run autoComplete processes
129 | start(input, query) {
130 | // - Match query with existing value
131 | // Returns matching results list
132 | const results = this.data.results
133 | ? this.data.results(listMatchingResults(this, query))
134 | : listMatchingResults(this, query);
135 | // - Prepare data feedback object
136 | const dataFeedback = { input, query, matches: results, results: results.slice(0, this.maxResults) };
137 | /**
138 | * @emits {response} Emits Event on search response
139 | **/
140 | eventEmitter(this.inputField, dataFeedback, "results");
141 | // - Checks if there are NO results
142 | // Runs noResults action function
143 | if (!results.length) return this.noResults ? this.noResults(dataFeedback, generateList) : null;
144 | // - If resultsList set not to render
145 | if (!this.resultsList.render) return this.feedback(dataFeedback);
146 | // - Generate & Render results list
147 | const list = results.length ? generateList(this, dataFeedback, results) : null;
148 | /**
149 | * @emits {rendered} Emits Event after results list rendering
150 | **/
151 | eventEmitter(this.inputField, dataFeedback, "rendered");
152 | // - Initialize navigation
153 | navigate(this, dataFeedback);
154 | /**
155 | * @desc
156 | * Listens for all `click` events in the document
157 | * and closes this menu if clicked outside the list and input field
158 | * @listens {click} Listens to all `click` events on the document
159 | **/
160 | document.addEventListener("click", (event) => closeAllLists(this, event.target));
161 | }
162 |
163 | async dataStore() {
164 | // Check if cache is NOT true
165 | // and store is empty
166 | if (this.data.cache && this.data.store) return null;
167 | // Fetch new data from source and store it
168 | this.data.store = typeof this.data.src === "function" ? await this.data.src() : this.data.src;
169 | /**
170 | * @emits {request} Emits Event on data response
171 | **/
172 | eventEmitter(this.inputField, this.data.store, "fetch");
173 | }
174 |
175 | // Run autoComplete composer
176 | async compose() {
177 | // 0- Prepare raw input value
178 | const input = getInputValue(this.inputField);
179 | // 1- Prepare manipulated query input value
180 | const query = prepareQueryValue(input, this);
181 | // 2- Get trigger condition
182 | const triggerCondition = checkTriggerCondition(this, query);
183 | // 3- Check triggering condition
184 | if (triggerCondition) {
185 | // 4- Prepare the data
186 | await this.dataStore();
187 | // 5- Close all open lists
188 | closeAllLists(this);
189 | // 6- Start autoComplete engine
190 | this.start(input, query);
191 | } else {
192 | // 4- Close all open lists
193 | closeAllLists(this);
194 | }
195 | }
196 |
197 | // Initialization stage
198 | init() {
199 | // Set input field attributes
200 | inputComponent(this);
201 | // Set placeholder attribute value
202 | if (this.placeHolder) this.inputField.setAttribute("placeholder", this.placeHolder);
203 | // Run executer
204 | this.hook = debouncer(() => {
205 | // - Prepare autoComplete processes
206 | this.compose();
207 | }, this.debounce);
208 | /**
209 | * @listens {input} Listens to all `input` events on the input field
210 | **/
211 | this.trigger.event.forEach((eventType) => {
212 | this.inputField.removeEventListener(eventType, this.hook);
213 | this.inputField.addEventListener(eventType, this.hook);
214 | });
215 | /**
216 | * @emits {init} Emits Event on Initialization
217 | **/
218 | eventEmitter(this.inputField, null, "init");
219 | }
220 |
221 | // Pre-Initialization stage
222 | preInit() {
223 | // Observe DOM changes
224 | // Options for the observer (which mutations to observe)
225 | const config = { childList: true, subtree: true };
226 | // Callback function to execute when mutations are observed
227 | const callback = (mutationsList, observer) => {
228 | // Traditional 'for loops' for IE 11
229 | for (let mutation of mutationsList) {
230 | // Check if this is the selected input field
231 | if (this.inputField) {
232 | // If yes disconnect the observer
233 | observer.disconnect();
234 | /**
235 | * @emits {connect} Emits Event on connection
236 | **/
237 | eventEmitter(this.inputField, null, "connect");
238 | // Initialize autoComplete
239 | this.init();
240 | }
241 | }
242 | };
243 | // Create an observer instance linked to the callback function
244 | const observer = new MutationObserver(callback);
245 | // Start observing the target node for configured mutations
246 | // The entire document will be observed for mutations
247 | observer.observe(document, config);
248 | }
249 |
250 | // Un-initialize autoComplete
251 | unInit() {
252 | this.inputField.removeEventListener("input", this.hook);
253 | /**
254 | * @emits {detached} Emits Event on input eventListener detachment
255 | **/
256 | eventEmitter(this.inputField, null, "unInit");
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/docs/img/autoComplete.js.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/docs/releases.md:
--------------------------------------------------------------------------------
1 | ## Versioning
2 |
3 | * * *
4 |
5 | For transparency and insight into the release cycle, releases will be numbered
6 | with the following format:
7 |
8 | `..`
9 |
10 | And constructed with the following guidelines:
11 |
12 | - Breaking backwards compatibility bumps the major
13 | - New additions without breaking backwards compatibility bumps the minor
14 | - Bug fixes and misc changes bump the patch
15 |
16 | For more information on semantic versioning, please visit .
17 |
18 | Release flags:
19 |
20 | - `[Experimental]`: Under testing and might be deprecated at any point
21 | - `[Deprecated]`: Not developed / supported anymore, might be removed at any point
22 | - `[Removed]`: Completely gone, no longer exists
23 | - `[Changed]`: A change in the API
24 |
25 | * * *
26 |
27 | ## Release Notes
28 |
29 | - v8.3.2 ✨
30 | - 🔧 Fix: `selector` as a function breaks when `observer` is true (Thanks 👍 @brunobg) #179
31 |
32 | - v8.3.1
33 | - 🔧 Fix: Keyboard navigation selection reset (Thanks 👍 @marsimeau) #177
34 |
35 | - v8.3.0
36 | - ➕ Added: `event` object to the `onSelection` data `feedback` (Thanks 👍 @Liano) #176
37 |
38 | - v8.2.3
39 | - 🔧 Fix: `resultItem` ID `setAttribute` to be `idName` instead of `className` (Thanks 👍 @marsimeau) #173
40 |
41 | - v8.2.2
42 | - 🔧 Fix: `diacritics` composite characters do not match (Thanks 👍 @ikemo3 @Michin0suke @bravik) #169 #171
43 |
44 | - v8.2.1
45 | - 🔝 Updated: `package.json` node engine version from `12` to `>=12` (Thanks 👍 @mynameisbogdan) #164
46 | - 🔝 Updated: `package.json` npm engine version from `6` to `>=6`
47 |
48 | - v8.2.0
49 | - ➕ Added: `data.results` API to access and manipulate data feedback matching results
50 | - 🔧 Fixed: `resultItem.content` API `data` params to pass the entire item data (Thanks 👍 @jwendel) #163
51 |
52 | - v8.1.1
53 | - 🔧 Fixed: `selector` API to accept function (Thanks 👍 @goaround) #160 #161
54 | - 🔧 Fixed: `resultsList` destination API to accept function (Thanks 👍 @goaround) #160 #162
55 |
56 | - v8.1.0
57 | - ➕ Added: `observer` Controller API [Turned off by default] #149
58 | - ➕ Added: New Light Style [autoComplete.02.css]
59 | - 🔧 Fixed: Main build `live reload` issue (Thanks 👍 @lougroshek) #155
60 |
61 | - v8.0.4
62 | - Fixed: Remove prior event listeners before adding new one in `init` (Thanks 👍 @RobinLawinsky) #153
63 |
64 | - v8.0.3
65 | - Fixed: Custom results list rendering destination (Thanks 👍 @RobinLawinsky) #150
66 |
67 | - v8.0.2
68 | - Enhanced: Input Field Assignment Order
69 | - Fixed: Trigger Event API
70 |
71 | - v8.0.1
72 | - Build Update
73 |
74 | - v8.0.0
75 | - Whole New More Modern Architecture Design
76 | - Added: High Quality Accessibility ([WAI-ARIA 1.2](https://www.w3.org/TR/wai-aria-practices-1.2/examples/combobox/combobox-autocomplete-both.html)) Support
77 | - Added: Life Cycle Events (Thanks 👍 @zippy84) #89
78 | - Added: `init/unInit` methods (Thanks 👍 @Keagel) #115
79 | - Added: Input Field Observing Functionality
80 | - Added: `Diacritics` 2 way Support (Thanks 👍 @batcaverna, @svkmedia) #77 #93
81 | - Added: API for Controlling `Classes` & `IDs` (Thanks 👍 @xtellurian, @Lirux) #73
82 | - Added: New neutral/non-opinionated Style (Thanks 👍 @luizbills) #92
83 | - Enhanced: `autoComplete.js` Internal Flow
84 | - Enhanced: `data` Fetching
85 | - Enhanced: `data` Storing
86 | - Enhanced: `resultsList` Navigation
87 | - Enhanced: `resultsList` Rendering (Thanks 👍 @eballeste) #105 #139 #126
88 | - Fixed: `resultsList` element visibility in idle state (Thanks 👍 @digiiitalmb) #100
89 | - Fixed: `query` threshold length accuracy #142
90 | - Fixed: Calling `dataSrc` on each trigger (Thanks 👍 @thomasphilibert) #106
91 | - Fixed: Right-click behavior on `resultsList` (Thanks 👍 @drankje) #94
92 | - Fixed: Cursor relocation on keyboard `keyUp` or `keyDown` (Thanks 👍 @cadday) #117
93 | - Fixed: `data` as a `Number` parsing issue (Thanks 👍 @andresfdel17) #132
94 | - Fixed: `autoComplete.js` interference with native keyboard events (Thanks 👍 @eballeste) #104
95 | - Fixed: Keyboard events stops working when `onSelection` not defined (Thanks 👍 @AustinGrey) #130
96 |
97 | - v7.2.0
98 | - Added support to `textarea` input field (Thanks 👍 @EmilStenstrom)
99 |
100 |
101 | - v7.1.3
102 | - Enhanced mouse selection (Thanks 👍 @adan-ferguson)
103 |
104 |
105 | - v7.1.2
106 | - Fixed error behavior occurs when searching (Empty, False, Null) record
107 |
108 |
109 | - v7.1.1
110 | - `resList` now is fully created in `DocumentFragment` before rendering for better performance (Thanks 👍 @asafwat)
111 | - `config` parameters restructure (Thanks 👍 @asafwat)
112 | - Reduced `autoComplete.js` weight
113 |
114 | - v7.1.0
115 | - New improved Navigation logic (Thanks 👍 @mtomov)
116 | - `shadowRoot` API support `[Removed]`
117 | - Enhanced `resList.navigation` API data feedback
118 | - Styling `[Changed]`
119 | - Major code Refactor & Optimizations
120 | - Faster performance
121 | - Reduced `autoComplete.js` weight
122 |
123 | - v7.0.3
124 | - Duplicate values selection bug fix (Thanks 👍 @plungerman)
125 |
126 | - v7.0.2
127 | - Data Promise bug fix (Thanks 👍 @braco)
128 | - Remote API duplicate calls fix (Thanks 👍 @srinivas025, @argebynogame)
129 | - `trigger.condition` enhancement (Thanks 👍 @sakuraineed)
130 | - Code Refactor for faster performance and lighter weight
131 |
132 | - v7.0.1
133 | - `api multiple calls` issue fix (Thanks 👍 @srinivas025)
134 |
135 | - v7.0.0
136 | - New API for results list navigation `resultsList.navigation` (Thanks 👍 @fredluetkemeier)
137 | - New API for autoComplete.js engine `trigger.event` (Thanks 👍 @fredluetkemeier)
138 | - New API for autoComplete.js engine `trigger.condition`
139 | - Added Support to `Shadow DOM` expanding customizability (Thanks 👍 @MSDevs)
140 | - Node Element Support for Input Selector (Thanks 👍 @jkhaui)
141 | - Empty record issue fix (Thanks 👍 @Platon)
142 | - `customEngine` API `[Removed]`
143 | - `customEngine` merged with `searchEngine` API key for more convenience `[Changed]`
144 | - Code Optimizations
145 |
146 | - v6.1.0
147 | - Use Custom Search Algorithm via `customEngine` method (Thanks @hwangm)
148 |
149 | - v6.0.0
150 | - `CustomEvent` & `Closest` method IE compatibility (Thanks @g-viet)
151 | - Query interception (Thanks @barns101)
152 | - Simplified `resultsList` & `resultItem`
153 | - `EventEmitter` fires on clearing input field
154 | - `EventEmitter` now has `input` method for row user’s input
155 | - `EventEmitter` now has `query` method for intercepted user’s input
156 |
157 | - v5.3.0
158 | - Get results from `eventEmitter` without rendering list through `resultsList.render` API
159 | - EventEmitter name `type` changed to `autoComplete` `[Changed]`
160 |
161 | - v5.2.0
162 | - Added Event Emitter on `noResults` event
163 |
164 | - v5.1.2
165 | - `noResults` API unset error bug fix
166 |
167 | - v5.1.1
168 | - `UpperCase` query bug fix
169 |
170 | - v5.1.0
171 | - Added `noResults` open API for No Results (Thanks @chabri)
172 | - HTML elements `ContentEditable` Input Support (Thanks @philippejadin)
173 |
174 | - v5.0.0
175 | - Large datasets handeling (Thanks @Johann-S)
176 | - API Data fetching & Dynamic Data reloading (Thanks @Brostafa)
177 | - Debouncing API Calls
178 | - Custom `resultsList` & `resultItem` Elements (Thanks @Johann-S)
179 | - Bug fixes
180 | - Code Clean Up
181 |
182 | - v4.0.0
183 | - Multiple searchable `keys` for data `src` (Thanks @Johann-S)
184 | - Rendered `results` in original case (Thanks @nickbp12)
185 | - Improved Development Environment (Thanks @ziishaned)
186 | - IE 11 fix (Thanks @maciekgrzybek)
187 | - Improved returned data object `onSelection`
188 | - Index of result data value
189 | - Total number of matching results
190 | - Key of result data value (If multiple keys)
191 | - HTML element of selected result
192 | - Sort rendered `results` API
193 | - Enhanced `results` navigation adding `ArrowRight` key for selection
194 | - Added `event` emitter on input field type name `type` returns
195 | - Query
196 | - Number of matching results
197 | - Rendered results
198 | - Keyboard event
199 | - Code Clean Up
200 |
201 | - v3.2.2
202 | - Fixed bug with `hightlight` API default value during `strict` engine mode
203 | - Fixed bug with `resultsList` API default value when not configured
204 |
205 | - v3.2.1
206 | - Isolated `resultsList` value for multiple instances **(Thanks @albu77)**
207 |
208 | - v3.2.0
209 | - API Enhancements over rendered results list container `resultsList > container` function **(Thanks @albu77)**
210 |
211 | - v3.1.0
212 | - Added API for rendered results list container `resultsList > container` function **(Thanks @albu77)**
213 | - API Enhancements
214 |
215 | - v3.0.0
216 | - Added API for rendered result item `resultItem` function
217 | - `renderResults` API name changed to `resultsList` `[Changed]`
218 |
219 | - v2.1.0
220 | - Added support for Keyboard `(Arrow)` & `(Tab)` Navigation
221 | - Selection event object returns in data feedback **(Thanks @alvaaz)**
222 | - Added `Function` support to `selector` for detached DOM rendering **(Thanks @mikob)**
223 | - Added `Function` support to `renderResults` for detached DOM rendering
224 | - Fixed Placeholder if not set doesn't overwrite external assigned values **(Thanks @mikob)**
225 | - Replaced `id` with `data-attribute` **(Thanks @mikob)**
226 | - Input doesn't clear automatically `onSelection` event **(Thanks @mikob)**
227 | - Place Holder doesn't assign selected value `onSelection` event automatically
228 | - Error message rendered on Engine failure in the body for End-User `[Removed]` **(Thanks @mikob)**
229 | - API `data-attribute` setting `[Removed]`
230 | - Optimizations
231 | - Style Enhancements
232 |
233 | - v2.0.1
234 | - Fixed multiple space input issue **(Thanks @DevOsamaMohamed)**
235 | - Fixed remote data source excessive requests **(Thanks @DevOsamaMohamed)**
236 | - Optimizations for performance enhancements
237 | - Reduced Weight
238 |
239 | - v2.0.0
240 | - Added support for array of `Objects` & `JSON` as data source with `Key` selection
241 | - Added support for external data source via `Promises` & `Async/Await` function
242 | - Added more comprehensive and usable data feedback on user selection `(User Input, Results List, User Selection)` Object
243 | - `dataSrc` method `CHANGED` to object method `data` with two new methods `src` & `key` ([Check API Configurations](/?id=api-configurations))
244 | - Highlighted Results class name `CHANGED` from `.autoComplete_highlighted_result` to `autoComplete_highlighted`
245 | - Many Optimizations for better performance
246 | - Scroll Infinite results style in [Demo](https://tarekraafat.github.io/autoComplete.js/demo/)
247 |
248 | - v1.5.4
249 | - Gzipped options for both builds are ready `(2KB) non-minified` & `(1KB) minified`
250 | - Fixed styling issue with selections last selection child on mobile devices
251 |
252 | - v1.5.3
253 | - Added `threshold` for minimum characters length before Engine starts rendering suggestions
254 | - Optimizations for better performance
255 | - Reduced Weight to `(3KB)` minified
256 |
257 | - v1.5.2
258 | - Fixed `onSelection` null action issue
259 | - Placeholder keeps value of last selection `[Removed]`
260 | - Fully isolated UI from Logic
261 | - Some code cleanup & optimizations
262 | - Reduced Weight
263 |
264 | - v1.5.1
265 | - Bug fixes
266 |
267 | - v1.5.0
268 | - Ability to change results destination & position `renderResults`
269 | - Optimizations for faster performance & lighter weight
270 | - Enhanced error handling capabilities
271 | - Styles fixes for better cross browser compatibility
272 | - Added detailed documentation
273 |
274 | - v1.4.1
275 | - Bug Fixes
276 |
277 | - v1.4.0
278 | - Added new type/mode of Search Engine `strict`
279 | - Detached the results list style behavior from code
280 | - `Placeholder max. length` option `[Removed]`
281 | - Optimizations for higher performance & lighter weight
282 |
283 | - v1.3.1
284 | - Refactored for higher speed & smaller footprint
285 | - Bug fixes & Optimizations
286 |
287 | - v1.3.0
288 | - Added new `datasrc` a function that returns `Array`
289 |
290 | - v1.2.1
291 | - Added Placeholder text maximum length option `[Experimental]`
292 | - Added new style sheet variation
293 |
294 | - v1.2.0
295 | - Redesigned the entire search engine for better results & experience
296 | - Added support for Multi-keyword search
297 | - Fixed issue with Capital letters reflects in results
298 |
299 | - v1.1.0
300 | - Reduced the library size 97% `(101KB -> 4KB)`
301 | - Introducing 2 different versions of the library `(pure, minified)`
302 | - Replaced webpack with Rollup for better bundling
303 | - Fixed some bugs caused problems with node apps
304 |
305 | - v1.0.3
306 | - Refactored & Optimized to reduce size and enhance performance
307 |
308 | - v1.0.2
309 | - Fixed the library name in the webpack.config.js file
310 |
311 | - v1.0.1
312 | - Optimizations Reduced the library weight by 1KB
313 |
314 | - v1.0.0
315 | - Add customized data attribute tag for generated results
316 | - Highlight matching results from the results list
317 | - Set maximum number for shown results
318 | - Add placeholder text to the input field
319 | - Placeholder keeps the last selection value saved
320 |
--------------------------------------------------------------------------------
/dist/js/autoComplete.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.autoComplete = factory());
5 | }(this, (function () { 'use strict';
6 |
7 | function _classCallCheck(instance, Constructor) {
8 | if (!(instance instanceof Constructor)) {
9 | throw new TypeError("Cannot call a class as a function");
10 | }
11 | }
12 |
13 | function _defineProperties(target, props) {
14 | for (var i = 0; i < props.length; i++) {
15 | var descriptor = props[i];
16 | descriptor.enumerable = descriptor.enumerable || false;
17 | descriptor.configurable = true;
18 | if ("value" in descriptor) descriptor.writable = true;
19 | Object.defineProperty(target, descriptor.key, descriptor);
20 | }
21 | }
22 |
23 | function _createClass(Constructor, protoProps, staticProps) {
24 | if (protoProps) _defineProperties(Constructor.prototype, protoProps);
25 | if (staticProps) _defineProperties(Constructor, staticProps);
26 | return Constructor;
27 | }
28 |
29 | function _defineProperty(obj, key, value) {
30 | if (key in obj) {
31 | Object.defineProperty(obj, key, {
32 | value: value,
33 | enumerable: true,
34 | configurable: true,
35 | writable: true
36 | });
37 | } else {
38 | obj[key] = value;
39 | }
40 |
41 | return obj;
42 | }
43 |
44 | function ownKeys(object, enumerableOnly) {
45 | var keys = Object.keys(object);
46 |
47 | if (Object.getOwnPropertySymbols) {
48 | var symbols = Object.getOwnPropertySymbols(object);
49 | if (enumerableOnly) symbols = symbols.filter(function (sym) {
50 | return Object.getOwnPropertyDescriptor(object, sym).enumerable;
51 | });
52 | keys.push.apply(keys, symbols);
53 | }
54 |
55 | return keys;
56 | }
57 |
58 | function _objectSpread2(target) {
59 | for (var i = 1; i < arguments.length; i++) {
60 | var source = arguments[i] != null ? arguments[i] : {};
61 |
62 | if (i % 2) {
63 | ownKeys(Object(source), true).forEach(function (key) {
64 | _defineProperty(target, key, source[key]);
65 | });
66 | } else if (Object.getOwnPropertyDescriptors) {
67 | Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
68 | } else {
69 | ownKeys(Object(source)).forEach(function (key) {
70 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
71 | });
72 | }
73 | }
74 |
75 | return target;
76 | }
77 |
78 | function _unsupportedIterableToArray(o, minLen) {
79 | if (!o) return;
80 | if (typeof o === "string") return _arrayLikeToArray(o, minLen);
81 | var n = Object.prototype.toString.call(o).slice(8, -1);
82 | if (n === "Object" && o.constructor) n = o.constructor.name;
83 | if (n === "Map" || n === "Set") return Array.from(o);
84 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
85 | }
86 |
87 | function _arrayLikeToArray(arr, len) {
88 | if (len == null || len > arr.length) len = arr.length;
89 |
90 | for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
91 |
92 | return arr2;
93 | }
94 |
95 | function _createForOfIteratorHelper(o, allowArrayLike) {
96 | var it;
97 |
98 | if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
99 | if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
100 | if (it) o = it;
101 | var i = 0;
102 |
103 | var F = function () {};
104 |
105 | return {
106 | s: F,
107 | n: function () {
108 | if (i >= o.length) return {
109 | done: true
110 | };
111 | return {
112 | done: false,
113 | value: o[i++]
114 | };
115 | },
116 | e: function (e) {
117 | throw e;
118 | },
119 | f: F
120 | };
121 | }
122 |
123 | throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
124 | }
125 |
126 | var normalCompletion = true,
127 | didErr = false,
128 | err;
129 | return {
130 | s: function () {
131 | it = o[Symbol.iterator]();
132 | },
133 | n: function () {
134 | var step = it.next();
135 | normalCompletion = step.done;
136 | return step;
137 | },
138 | e: function (e) {
139 | didErr = true;
140 | err = e;
141 | },
142 | f: function () {
143 | try {
144 | if (!normalCompletion && it.return != null) it.return();
145 | } finally {
146 | if (didErr) throw err;
147 | }
148 | }
149 | };
150 | }
151 |
152 | var inputComponent = (function (config) {
153 | config.inputField.setAttribute("role", "combobox");
154 | config.inputField.setAttribute("aria-haspopup", true);
155 | config.inputField.setAttribute("aria-expanded", false);
156 | config.inputField.setAttribute("aria-controls", config.resultsList.idName);
157 | config.inputField.setAttribute("aria-autocomplete", "both");
158 | });
159 |
160 | var createList = (function (config) {
161 | var list = document.createElement(config.resultsList.element);
162 | list.setAttribute("id", config.resultsList.idName);
163 | list.setAttribute("aria-label", config.name);
164 | list.setAttribute("class", config.resultsList.className);
165 | list.setAttribute("role", "listbox");
166 | list.setAttribute("tabindex", "-1");
167 | if (config.resultsList.container) config.resultsList.container(list);
168 | var destination = "string" === typeof config.resultsList.destination ? document.querySelector(config.resultsList.destination) : config.resultsList.destination();
169 | destination.insertAdjacentElement(config.resultsList.position, list);
170 | return list;
171 | });
172 |
173 | var createItem = (function (item, index, config) {
174 | var result = document.createElement(config.resultItem.element);
175 | result.setAttribute("id", "".concat(config.resultItem.idName, "_").concat(index));
176 | result.setAttribute("class", config.resultItem.className);
177 | result.setAttribute("role", "option");
178 | result.innerHTML = item.match;
179 | if (config.resultItem.content) config.resultItem.content(item, result);
180 | return result;
181 | });
182 |
183 | var closeAllLists = function closeAllLists(config, element) {
184 | var list = document.getElementsByClassName(config.resultsList.className);
185 | for (var index = 0; index < list.length; index++) {
186 | if (element !== list[index] && element !== config.inputField) list[index].parentNode.removeChild(list[index]);
187 | }
188 | config.inputField.removeAttribute("aria-activedescendant");
189 | config.inputField.setAttribute("aria-expanded", false);
190 | };
191 | var generateList = function generateList(config, data, matches) {
192 | var list = createList(config);
193 | config.inputField.setAttribute("aria-expanded", true);
194 | var _loop = function _loop(index) {
195 | var item = data.results[index];
196 | var resultItem = createItem(item, index, config);
197 | resultItem.addEventListener("click", function (event) {
198 | var dataFeedback = {
199 | event: event,
200 | matches: matches,
201 | input: data.input,
202 | query: data.query,
203 | results: data.results,
204 | selection: _objectSpread2(_objectSpread2({}, item), {}, {
205 | index: index
206 | })
207 | };
208 | if (config.onSelection) config.onSelection(dataFeedback);
209 | });
210 | list.appendChild(resultItem);
211 | };
212 | for (var index = 0; index < data.results.length; index++) {
213 | _loop(index);
214 | }
215 | return list;
216 | };
217 |
218 | var eventEmitter = (function (target, detail, name) {
219 | target.dispatchEvent(new CustomEvent(name, {
220 | bubbles: true,
221 | detail: detail,
222 | cancelable: true
223 | }));
224 | });
225 |
226 | var navigate = function navigate(config, dataFeedback) {
227 | var currentFocus = -1;
228 | var update = function update(event, list, state, config) {
229 | event.preventDefault();
230 | if (state) {
231 | currentFocus++;
232 | } else {
233 | currentFocus--;
234 | }
235 | addActive(list);
236 | config.inputField.setAttribute("aria-activedescendant", list[currentFocus].id);
237 | eventEmitter(event.srcElement, _objectSpread2(_objectSpread2({
238 | event: event
239 | }, dataFeedback), {}, {
240 | selection: dataFeedback.results[currentFocus]
241 | }), "navigation");
242 | };
243 | var removeActive = function removeActive(list) {
244 | for (var index = 0; index < list.length; index++) {
245 | list[index].removeAttribute("aria-selected");
246 | list[index].classList.remove("autoComplete_selected");
247 | }
248 | };
249 | var addActive = function addActive(list) {
250 | if (!list) return false;
251 | removeActive(list);
252 | if (currentFocus >= list.length) currentFocus = 0;
253 | if (currentFocus < 0) currentFocus = list.length - 1;
254 | list[currentFocus].setAttribute("aria-selected", "true");
255 | list[currentFocus].classList.add("autoComplete_selected");
256 | };
257 | var navigation = function navigation(event) {
258 | var list = document.getElementById(config.resultsList.idName);
259 | if (!list) return config.inputField.removeEventListener("keydown", navigate);
260 | list = list.getElementsByTagName(config.resultItem.element);
261 | if (event.keyCode === 27) {
262 | config.inputField.value = "";
263 | closeAllLists(config);
264 | } else if (event.keyCode === 40 || event.keyCode === 9) {
265 | update(event, list, true, config);
266 | } else if (event.keyCode === 38 || event.keyCode === 9) {
267 | update(event, list, false, config);
268 | } else if (event.keyCode === 13) {
269 | event.preventDefault();
270 | if (currentFocus > -1) {
271 | if (list) list[currentFocus].click();
272 | }
273 | }
274 | };
275 | var navigate = config.resultsList.navigation || navigation;
276 | if (config.inputField.autoCompleteNavigate) config.inputField.removeEventListener("keydown", config.inputField.autoCompleteNavigate);
277 | config.inputField.autoCompleteNavigate = navigate;
278 | config.inputField.addEventListener("keydown", navigate);
279 | };
280 |
281 | var searchEngine = (function (query, record, config) {
282 | var recordLowerCase = config.diacritics ? record.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC") : record.toLowerCase();
283 | if (config.searchEngine === "loose") {
284 | query = query.replace(/ /g, "");
285 | var match = [];
286 | var searchPosition = 0;
287 | for (var number = 0; number < recordLowerCase.length; number++) {
288 | var recordChar = record[number];
289 | if (searchPosition < query.length && recordLowerCase[number] === query[searchPosition]) {
290 | recordChar = config.highlight ? "".concat(recordChar, "") : recordChar;
291 | searchPosition++;
292 | }
293 | match.push(recordChar);
294 | }
295 | if (searchPosition === query.length) {
296 | return match.join("");
297 | }
298 | } else {
299 | if (recordLowerCase.includes(query)) {
300 | var pattern = new RegExp("".concat(query), "i");
301 | query = pattern.exec(record);
302 | var _match = config.highlight ? record.replace(query, "".concat(query, "")) : record;
303 | return _match;
304 | }
305 | }
306 | });
307 |
308 | var getInputValue = function getInputValue(inputField) {
309 | return inputField instanceof HTMLInputElement || inputField instanceof HTMLTextAreaElement ? inputField.value.toLowerCase() : inputField.innerHTML.toLowerCase();
310 | };
311 | var prepareQueryValue = function prepareQueryValue(inputValue, config) {
312 | return config.query && config.query.manipulate ? config.query.manipulate(inputValue) : config.diacritics ? inputValue.normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC") : inputValue;
313 | };
314 | var checkTriggerCondition = function checkTriggerCondition(config, queryValue) {
315 | return config.trigger.condition ? config.trigger.condition(queryValue) : queryValue.length >= config.threshold && queryValue.replace(/ /g, "").length;
316 | };
317 | var listMatchingResults = function listMatchingResults(config, query) {
318 | var resList = [];
319 | var _loop = function _loop(index) {
320 | var record = config.data.store[index];
321 | var search = function search(key) {
322 | var recordValue = (key ? record[key] : record).toString();
323 | if (recordValue) {
324 | var match = typeof config.searchEngine === "function" ? config.searchEngine(query, recordValue) : searchEngine(query, recordValue, config);
325 | if (match && key) {
326 | resList.push({
327 | key: key,
328 | index: index,
329 | match: match,
330 | value: record
331 | });
332 | } else if (match && !key) {
333 | resList.push({
334 | index: index,
335 | match: match,
336 | value: record
337 | });
338 | }
339 | }
340 | };
341 | if (config.data.key) {
342 | var _iterator = _createForOfIteratorHelper(config.data.key),
343 | _step;
344 | try {
345 | for (_iterator.s(); !(_step = _iterator.n()).done;) {
346 | var key = _step.value;
347 | search(key);
348 | }
349 | } catch (err) {
350 | _iterator.e(err);
351 | } finally {
352 | _iterator.f();
353 | }
354 | } else {
355 | search();
356 | }
357 | };
358 | for (var index = 0; index < config.data.store.length; index++) {
359 | _loop(index);
360 | }
361 | var list = config.sort ? resList.sort(config.sort) : resList;
362 | return list;
363 | };
364 |
365 | var debouncer = (function (callback, delay) {
366 | var inDebounce;
367 | return function () {
368 | var context = this;
369 | var args = arguments;
370 | clearTimeout(inDebounce);
371 | inDebounce = setTimeout(function () {
372 | return callback.apply(context, args);
373 | }, delay);
374 | };
375 | });
376 |
377 | var autoComplete = function () {
378 | function autoComplete(config) {
379 | _classCallCheck(this, autoComplete);
380 | var _config$name = config.name,
381 | name = _config$name === void 0 ? "Search" : _config$name,
382 | _config$selector = config.selector,
383 | selector = _config$selector === void 0 ? "#autoComplete" : _config$selector,
384 | _config$observer = config.observer,
385 | observer = _config$observer === void 0 ? false : _config$observer,
386 | _config$data = config.data,
387 | src = _config$data.src,
388 | key = _config$data.key,
389 | _config$data$cache = _config$data.cache,
390 | cache = _config$data$cache === void 0 ? false : _config$data$cache,
391 | store = _config$data.store,
392 | results = _config$data.results,
393 | query = config.query,
394 | _config$trigger = config.trigger;
395 | _config$trigger = _config$trigger === void 0 ? {} : _config$trigger;
396 | var _config$trigger$event = _config$trigger.event,
397 | event = _config$trigger$event === void 0 ? ["input"] : _config$trigger$event,
398 | _config$trigger$condi = _config$trigger.condition,
399 | condition = _config$trigger$condi === void 0 ? false : _config$trigger$condi,
400 | _config$searchEngine = config.searchEngine,
401 | searchEngine = _config$searchEngine === void 0 ? "strict" : _config$searchEngine,
402 | _config$diacritics = config.diacritics,
403 | diacritics = _config$diacritics === void 0 ? false : _config$diacritics,
404 | _config$threshold = config.threshold,
405 | threshold = _config$threshold === void 0 ? 1 : _config$threshold,
406 | _config$debounce = config.debounce,
407 | debounce = _config$debounce === void 0 ? 0 : _config$debounce,
408 | _config$resultsList = config.resultsList;
409 | _config$resultsList = _config$resultsList === void 0 ? {} : _config$resultsList;
410 | var _config$resultsList$r = _config$resultsList.render,
411 | render = _config$resultsList$r === void 0 ? true : _config$resultsList$r,
412 | _config$resultsList$c = _config$resultsList.container,
413 | container = _config$resultsList$c === void 0 ? false : _config$resultsList$c,
414 | destination = _config$resultsList.destination,
415 | _config$resultsList$p = _config$resultsList.position,
416 | position = _config$resultsList$p === void 0 ? "afterend" : _config$resultsList$p,
417 | _config$resultsList$e = _config$resultsList.element,
418 | resultsListElement = _config$resultsList$e === void 0 ? "ul" : _config$resultsList$e,
419 | _config$resultsList$i = _config$resultsList.idName,
420 | resultsListId = _config$resultsList$i === void 0 ? "autoComplete_list" : _config$resultsList$i,
421 | _config$resultsList$c2 = _config$resultsList.className,
422 | resultsListClass = _config$resultsList$c2 === void 0 ? "autoComplete_list" : _config$resultsList$c2,
423 | _config$resultsList$n = _config$resultsList.navigation,
424 | navigation = _config$resultsList$n === void 0 ? false : _config$resultsList$n,
425 | _config$sort = config.sort,
426 | sort = _config$sort === void 0 ? false : _config$sort,
427 | placeHolder = config.placeHolder,
428 | _config$maxResults = config.maxResults,
429 | maxResults = _config$maxResults === void 0 ? 5 : _config$maxResults,
430 | _config$resultItem = config.resultItem;
431 | _config$resultItem = _config$resultItem === void 0 ? {} : _config$resultItem;
432 | var _config$resultItem$co = _config$resultItem.content,
433 | content = _config$resultItem$co === void 0 ? false : _config$resultItem$co,
434 | _config$resultItem$el = _config$resultItem.element,
435 | resultItemElement = _config$resultItem$el === void 0 ? "li" : _config$resultItem$el,
436 | _config$resultItem$id = _config$resultItem.idName,
437 | resultItemId = _config$resultItem$id === void 0 ? "autoComplete_result" : _config$resultItem$id,
438 | _config$resultItem$cl = _config$resultItem.className,
439 | resultItemClass = _config$resultItem$cl === void 0 ? "autoComplete_result" : _config$resultItem$cl,
440 | noResults = config.noResults,
441 | _config$highlight = config.highlight,
442 | highlight = _config$highlight === void 0 ? false : _config$highlight,
443 | feedback = config.feedback,
444 | onSelection = config.onSelection;
445 | this.name = name;
446 | this.selector = selector;
447 | this.observer = observer;
448 | this.data = {
449 | src: src,
450 | key: key,
451 | cache: cache,
452 | store: store,
453 | results: results
454 | };
455 | this.query = query;
456 | this.trigger = {
457 | event: event,
458 | condition: condition
459 | };
460 | this.searchEngine = searchEngine;
461 | this.diacritics = diacritics;
462 | this.threshold = threshold;
463 | this.debounce = debounce;
464 | this.resultsList = {
465 | render: render,
466 | container: container,
467 | destination: destination || this.selector,
468 | position: position,
469 | element: resultsListElement,
470 | idName: resultsListId,
471 | className: resultsListClass,
472 | navigation: navigation
473 | };
474 | this.sort = sort;
475 | this.placeHolder = placeHolder;
476 | this.maxResults = maxResults;
477 | this.resultItem = {
478 | content: content,
479 | element: resultItemElement,
480 | idName: resultItemId,
481 | className: resultItemClass
482 | };
483 | this.noResults = noResults;
484 | this.highlight = highlight;
485 | this.feedback = feedback;
486 | this.onSelection = onSelection;
487 | this.inputField = typeof this.selector === "string" ? document.querySelector(this.selector) : this.selector();
488 | this.observer ? this.preInit() : this.init();
489 | }
490 | _createClass(autoComplete, [{
491 | key: "start",
492 | value: function start(input, query) {
493 | var _this = this;
494 | var results = this.data.results ? this.data.results(listMatchingResults(this, query)) : listMatchingResults(this, query);
495 | var dataFeedback = {
496 | input: input,
497 | query: query,
498 | matches: results,
499 | results: results.slice(0, this.maxResults)
500 | };
501 | eventEmitter(this.inputField, dataFeedback, "results");
502 | if (!results.length) return this.noResults ? this.noResults(dataFeedback, generateList) : null;
503 | if (!this.resultsList.render) return this.feedback(dataFeedback);
504 | results.length ? generateList(this, dataFeedback, results) : null;
505 | eventEmitter(this.inputField, dataFeedback, "rendered");
506 | navigate(this, dataFeedback);
507 | document.addEventListener("click", function (event) {
508 | return closeAllLists(_this, event.target);
509 | });
510 | }
511 | }, {
512 | key: "dataStore",
513 | value: function dataStore() {
514 | var _this2 = this;
515 | return new Promise(function ($return, $error) {
516 | if (_this2.data.cache && _this2.data.store) return $return(null);
517 | return new Promise(function ($return, $error) {
518 | if (typeof _this2.data.src === "function") {
519 | return _this2.data.src().then($return, $error);
520 | }
521 | return $return(_this2.data.src);
522 | }).then(function ($await_5) {
523 | try {
524 | _this2.data.store = $await_5;
525 | eventEmitter(_this2.inputField, _this2.data.store, "fetch");
526 | return $return();
527 | } catch ($boundEx) {
528 | return $error($boundEx);
529 | }
530 | }, $error);
531 | });
532 | }
533 | }, {
534 | key: "compose",
535 | value: function compose() {
536 | var _this3 = this;
537 | return new Promise(function ($return, $error) {
538 | var input, query, triggerCondition;
539 | input = getInputValue(_this3.inputField);
540 | query = prepareQueryValue(input, _this3);
541 | triggerCondition = checkTriggerCondition(_this3, query);
542 | if (triggerCondition) {
543 | return _this3.dataStore().then(function ($await_6) {
544 | try {
545 | closeAllLists(_this3);
546 | _this3.start(input, query);
547 | return $If_3.call(_this3);
548 | } catch ($boundEx) {
549 | return $error($boundEx);
550 | }
551 | }, $error);
552 | } else {
553 | closeAllLists(_this3);
554 | return $If_3.call(_this3);
555 | }
556 | function $If_3() {
557 | return $return();
558 | }
559 | });
560 | }
561 | }, {
562 | key: "init",
563 | value: function init() {
564 | var _this4 = this;
565 | inputComponent(this);
566 | if (this.placeHolder) this.inputField.setAttribute("placeholder", this.placeHolder);
567 | this.hook = debouncer(function () {
568 | _this4.compose();
569 | }, this.debounce);
570 | this.trigger.event.forEach(function (eventType) {
571 | _this4.inputField.removeEventListener(eventType, _this4.hook);
572 | _this4.inputField.addEventListener(eventType, _this4.hook);
573 | });
574 | eventEmitter(this.inputField, null, "init");
575 | }
576 | }, {
577 | key: "preInit",
578 | value: function preInit() {
579 | var _this5 = this;
580 | var config = {
581 | childList: true,
582 | subtree: true
583 | };
584 | var callback = function callback(mutationsList, observer) {
585 | var _iterator = _createForOfIteratorHelper(mutationsList),
586 | _step;
587 | try {
588 | for (_iterator.s(); !(_step = _iterator.n()).done;) {
589 | var mutation = _step.value;
590 | if (_this5.inputField) {
591 | observer.disconnect();
592 | eventEmitter(_this5.inputField, null, "connect");
593 | _this5.init();
594 | }
595 | }
596 | } catch (err) {
597 | _iterator.e(err);
598 | } finally {
599 | _iterator.f();
600 | }
601 | };
602 | var observer = new MutationObserver(callback);
603 | observer.observe(document, config);
604 | }
605 | }, {
606 | key: "unInit",
607 | value: function unInit() {
608 | this.inputField.removeEventListener("input", this.hook);
609 | eventEmitter(this.inputField, null, "unInit");
610 | }
611 | }]);
612 | return autoComplete;
613 | }();
614 |
615 | return autoComplete;
616 |
617 | })));
618 |
--------------------------------------------------------------------------------
/dist/db/test.json:
--------------------------------------------------------------------------------
1 | [
2 | "Sauce - Thousand Island",
3 | "Wild Boar - Tenderloin",
4 | "Goat - Whole Cut",
5 | "Cherries - Bing, Canned",
6 | "Table Cloth 62x120 Colour",
7 | "Bag - Clear 7 Lb",
8 | "Kippers - Smoked",
9 | "Pasta - Ravioli",
10 | "Capers - Pickled",
11 | "Ice Cream Bar - Oreo Sandwich",
12 | "Worcestershire Sauce",
13 | "Chicken - Whole",
14 | "Cabbage - Red",
15 | "Crab - Meat",
16 | "Star Anise, Whole",
17 | "Wine - Cave Springs Dry Riesling",
18 | "Sobe - Orange Carrot",
19 | "Longos - Chicken Cordon Bleu",
20 | "Soup - Campbells Chicken",
21 | "Vermouth - Sweet, Cinzano",
22 | "V8 - Tropical Blend",
23 | "Wine - Casillero Deldiablo",
24 | "Remy Red Berry Infusion",
25 | "Danishes - Mini Raspberry",
26 | "Pork - Suckling Pig",
27 | "Flour - Masa De Harina Mexican",
28 | "Puree - Raspberry",
29 | "Hot Chocolate - Individual",
30 | "Wine - Magnotta - Pinot Gris Sr",
31 | "Chicken - Whole Fryers",
32 | "Lobster - Base",
33 | "Foil - 4oz Custard Cup",
34 | "Pie Filling - Apple",
35 | "Vermouth - Sweet, Cinzano",
36 | "Bread - Corn Muffaletta",
37 | "Jam - Blackberry, 20 Ml Jar",
38 | "Pie Pecan",
39 | "Soup - Tomato Mush. Florentine",
40 | "Beer - True North Strong Ale",
41 | "Lemonade - Island Tea, 591 Ml",
42 | "Grenadine",
43 | "Bonito Flakes - Toku Katsuo",
44 | "Coconut Milk - Unsweetened",
45 | "Red Snapper - Fillet, Skin On",
46 | "Potatoes - Idaho 80 Count",
47 | "Table Cloth - 53x69 Colour",
48 | "Cloves - Ground",
49 | "Lychee - Canned",
50 | "Appetizer - Assorted Box",
51 | "Bread - Petit Baguette",
52 | "Sproutsmustard Cress",
53 | "Squid Ink",
54 | "Puree - Kiwi",
55 | "Coffee - Beans, Whole",
56 | "Sea Urchin",
57 | "Placemat - Scallop, White",
58 | "Coriander - Seed",
59 | "Bread - Crusty Italian Poly",
60 | "Veal - Round, Eye Of",
61 | "Cheese - Grana Padano",
62 | "Lighter - Bbq",
63 | "Pastry - Carrot Muffin - Mini",
64 | "Crab - Soft Shell",
65 | "Lettuce - Romaine, Heart",
66 | "Roe - Lump Fish, Red",
67 | "Soup - Campbells, Creamy",
68 | "Schnappes Peppermint - Walker",
69 | "Sunflower Seed Raw",
70 | "Longos - Lasagna Beef",
71 | "Oil - Shortening,liqud, Fry",
72 | "Cake - Cake Sheet Macaroon",
73 | "Rabbit - Saddles",
74 | "Pasta - Cheese / Spinach Bauletti",
75 | "Container - Foam Dixie 12 Oz",
76 | "Wine - Alsace Gewurztraminer",
77 | "Mcguinness - Blue Curacao",
78 | "Smoked Paprika",
79 | "Kellogs Cereal In A Cup",
80 | "Jolt Cola - Red Eye",
81 | "Lobster - Canned Premium",
82 | "Cheese - Taleggio D.o.p.",
83 | "Gingerale - Schweppes, 355 Ml",
84 | "Calypso - Pineapple Passion",
85 | "Bread - Roll, Calabrese",
86 | "Anchovy Paste - 56 G Tube",
87 | "Bread - 10 Grain Parisian",
88 | "Wine - White, Riesling, Semi - Dry",
89 | "Ecolab - Ster Bac",
90 | "Napkin - Beverage 1 Ply",
91 | "Wine - Taylors Reserve",
92 | "Pork - Butt, Boneless",
93 | "Melon - Honey Dew",
94 | "Curry Powder Madras",
95 | "Leeks - Large",
96 | "Pastry - Trippleberry Muffin - Mini",
97 | "Appetizer - Smoked Salmon / Dill",
98 | "Soup - Cream Of Broccoli",
99 | "Pepper - White, Ground",
100 | "Lemon Tarts",
101 | "Beer - Paulaner Hefeweisse",
102 | "Mountain Dew",
103 | "Paper Towel Touchless",
104 | "Pizza Pizza Dough",
105 | "Cinnamon Rolls",
106 | "Bread - Raisin Walnut Oval",
107 | "Lid Coffee Cup 8oz Blk",
108 | "Pancetta",
109 | "Cookies - Englishbay Oatmeal",
110 | "Cinnamon - Ground",
111 | "Tea - Herbal - 6 Asst",
112 | "Clams - Littleneck, Whole",
113 | "Chinese Foods - Thick Noodles",
114 | "Icecream Bar - Del Monte",
115 | "Beef - Eye Of Round",
116 | "Soup - Base Broth Beef",
117 | "Cheese - Parmigiano Reggiano",
118 | "Dikon",
119 | "Carbonated Water - Raspberry",
120 | "Wine - Chateau Aqueria Tavel",
121 | "Apple - Granny Smith",
122 | "Madeira",
123 | "Sauce - Plum",
124 | "Cake - Dulce De Leche",
125 | "Jam - Apricot",
126 | "Milk - 2%",
127 | "Pie Shells 10",
128 | "Tea - Herbal - 6 Asst",
129 | "Flower - Dish Garden",
130 | "Wine - Red, Mosaic Zweigelt",
131 | "Carbonated Water - Blackberry",
132 | "Almonds Ground Blanched",
133 | "Cheese - Swiss",
134 | "Paper - Brown Paper Mini Cups",
135 | "Soup Campbells",
136 | "Wine - Winzer Krems Gruner",
137 | "Wine - Segura Viudas Aria Brut",
138 | "Sugar - Brown, Individual",
139 | "Wine - Alsace Riesling Reserve",
140 | "Bread - Pumpernickel",
141 | "Lamb - Bones",
142 | "Beef - Roasted, Cooked",
143 | "Crackers - Graham",
144 | "Vodka - Smirnoff",
145 | "Bay Leaf Ground",
146 | "Berry Brulee",
147 | "Table Cloth 91x91 Colour",
148 | "Oil - Canola",
149 | "Sauce - Oyster",
150 | "Sausage - Breakfast",
151 | "Cookies - Assorted",
152 | "Wine - Barossa Valley Estate",
153 | "Capon - Breast, Wing On",
154 | "Cabbage - Savoy",
155 | "Cheese - Cheddar With Claret",
156 | "Lamb - Whole, Fresh",
157 | "Icecream - Dstk Cml And Fdg",
158 | "Initation Crab Meat",
159 | "Cake - Night And Day Choclate",
160 | "Cranberry Foccacia",
161 | "Beef - Tenderloin Tails",
162 | "Creme De Menth - White",
163 | "Olives - Green, Pitted",
164 | "Crab - Back Fin Meat, Canned",
165 | "Knife Plastic - White",
166 | "Dc - Sakura Fu",
167 | "Grapes - Green",
168 | "Ice Cream - Chocolate",
169 | "Mangoes",
170 | "Doilies - 12, Paper",
171 | "Broom - Push",
172 | "Pasta - Detalini, White, Fresh",
173 | "Guava",
174 | "Corn Syrup",
175 | "Lotus Rootlets - Canned",
176 | "Longos - Grilled Chicken With",
177 | "Pepsi - Diet, 355 Ml",
178 | "Swiss Chard",
179 | "Red Snapper - Fillet, Skin On",
180 | "Soupcontfoam16oz 116con",
181 | "Pastry - Butterscotch Baked",
182 | "Cocoa Butter",
183 | "Squash - Butternut",
184 | "Steam Pan Full Lid",
185 | "Lemons",
186 | "Beans - Yellow",
187 | "Lettuce - Iceberg",
188 | "Beef - Top Butt",
189 | "Lemons",
190 | "Soup - Verve - Chipotle Chicken",
191 | "Soup - Knorr, Chicken Gumbo",
192 | "Blackberries",
193 | "Tumeric",
194 | "Yokaline",
195 | "Prunes - Pitted",
196 | "Pastry - Chocolate Chip Muffin",
197 | "Garlic Powder",
198 | "Chicken - Bones",
199 | "Soup - Campbells, Beef Barley",
200 | "Quail - Jumbo Boneless",
201 | "Crawfish",
202 | "Allspice - Jamaican",
203 | "Muffin Mix - Blueberry",
204 | "Magnotta Bel Paese Red",
205 | "Coconut - Shredded, Unsweet",
206 | "Appetizer - Shrimp Puff",
207 | "Squid - Breaded",
208 | "Lobster - Tail 6 Oz",
209 | "Doilies - 12, Paper",
210 | "Pur Value",
211 | "Lettuce - Boston Bib - Organic",
212 | "Sesame Seed",
213 | "Seabream Whole Farmed",
214 | "Potatoes - Idaho 100 Count",
215 | "Kiwi Gold Zespri",
216 | "Nantucket Pine Orangebanana",
217 | "Napkin - Dinner, White",
218 | "Lemonade - Kiwi, 591 Ml",
219 | "Five Alive Citrus",
220 | "Beef Dry Aged Tenderloin Aaa",
221 | "Tea - Green",
222 | "Coffee Guatemala Dark",
223 | "Whmis Spray Bottle Graduated",
224 | "Mushroom - Portebello",
225 | "Cookies Cereal Nut",
226 | "Tea - Honey Green Tea",
227 | "Sauce - Chili",
228 | "Juice - Pineapple, 48 Oz",
229 | "Sprouts - Bean",
230 | "Pork Casing",
231 | "Soap - Pine Sol Floor Cleaner",
232 | "Gelatine Powder",
233 | "Sauce - Apple, Unsweetened",
234 | "Sauce - Roasted Red Pepper",
235 | "Sauce - Fish 25 Ozf Bottle",
236 | "Beans - Black Bean, Canned",
237 | "Pate Pans Yellow",
238 | "Bread - Roll, Soft White Round",
239 | "Tomato - Plum With Basil",
240 | "Pork - Bacon,back Peameal",
241 | "Port - 74 Brights",
242 | "Mustard - Individual Pkg",
243 | "Cheese - Grana Padano",
244 | "Wine - Casablanca Valley",
245 | "Rhubarb",
246 | "Shallots",
247 | "Crackers - Graham",
248 | "Sugar - Fine",
249 | "Ice Cream Bar - Drumstick",
250 | "Muffin - Mix - Bran And Maple 15l",
251 | "Cauliflower",
252 | "Truffle Shells - Semi - Sweet",
253 | "Leeks - Baby, White",
254 | "Wine - Chateau Aqueria Tavel",
255 | "Cumin - Whole",
256 | "Clementine",
257 | "Oil - Safflower",
258 | "Pepper - Gypsy Pepper",
259 | "Island Oasis - Lemonade",
260 | "Champagne - Brights, Dry",
261 | "Wasabi Paste",
262 | "Chilli Paste, Ginger Garlic",
263 | "Tea - Herbal - 6 Asst",
264 | "Veal - Shank, Pieces",
265 | "Olives - Morracan Dired",
266 | "Cabbage Roll",
267 | "Cheese - St. Paulin",
268 | "Flower - Potmums",
269 | "Potatoes - Mini White 3 Oz",
270 | "Wine - Blue Nun Qualitatswein",
271 | "Parsnip",
272 | "Soup Campbells Split Pea And Ham",
273 | "Garlic Powder",
274 | "Bread - Multigrain Oval",
275 | "Pork - Chop, Frenched",
276 | "Appetizer - Mango Chevre",
277 | "Oil - Shortening - All - Purpose",
278 | "Cheese - Brick With Pepper",
279 | "Chick Peas - Dried",
280 | "Yoghurt Tubes",
281 | "Longos - Lasagna Veg",
282 | "Sobe - Orange Carrot",
283 | "Lemon Balm - Fresh",
284 | "Wine - Clavet Saint Emilion",
285 | "Chinese Foods - Chicken Wing",
286 | "Sobe - Green Tea",
287 | "Pepper - Scotch Bonnet",
288 | "Clams - Bay",
289 | "Tabasco Sauce, 2 Oz",
290 | "Soup - Campbells, Spinach Crm",
291 | "Chicken - Ground",
292 | "Pork - Side Ribs",
293 | "Sauce - Sesame Thai Dressing",
294 | "Onions - White",
295 | "Pork - Sausage Casing",
296 | "Wine - Red, Gamay Noir",
297 | "Beef - Ground Lean Fresh",
298 | "Ginger - Fresh",
299 | "Soup - Campbells Broccoli",
300 | "Bread - White Epi Baguette",
301 | "Sobe - Berry Energy",
302 | "Cheese - Brie Roitelet",
303 | "Wine - Delicato Merlot",
304 | "Mushroom - Chanterelle, Dry",
305 | "Laundry - Bag Cloth",
306 | "Wasabi Powder",
307 | "Cake - Mini Cheesecake",
308 | "Cheese - Goat With Herbs",
309 | "Bay Leaf",
310 | "Madeira",
311 | "Steamers White",
312 | "Apple - Royal Gala",
313 | "Bread Roll Foccacia",
314 | "Bread Crumbs - Panko",
315 | "Soup - Tomato Mush. Florentine",
316 | "Pail For Lid 1537",
317 | "Sour Cream",
318 | "Dr. Pepper - 355ml",
319 | "Yogurt - Cherry, 175 Gr",
320 | "Crackers - Soda / Saltins",
321 | "Soup - French Onion, Dry",
322 | "Trueblue - Blueberry 12x473ml",
323 | "Beef - Short Loin",
324 | "Wine - Savigny - Les - Beaune",
325 | "Onions - Pearl",
326 | "Water - Spring Water 500ml",
327 | "Radish - Pickled",
328 | "Crab - Meat",
329 | "Fennel - Seeds",
330 | "Cheese - St. Andre",
331 | "Doilies - 5, Paper",
332 | "Sambuca Cream",
333 | "Scallops - Live In Shell",
334 | "Veal - Eye Of Round",
335 | "Gatorade - Xfactor Berry",
336 | "Glucose",
337 | "Bread - Bistro White",
338 | "Pear - Prickly",
339 | "Chocolate - Semi Sweet",
340 | "Chicken - Leg / Back Attach",
341 | "Spice - Onion Powder Granulated",
342 | "Shrimp - Black Tiger 26/30",
343 | "Creme De Cacao Mcguines",
344 | "Melon - Watermelon Yellow",
345 | "Wine - Marlbourough Sauv Blanc",
346 | "Flour - Chickpea",
347 | "Jam - Raspberry,jar",
348 | "Bay Leaf",
349 | "Wine - Chardonnay South",
350 | "Juice - Lime",
351 | "Syrup - Monin - Granny Smith",
352 | "Olives - Black, Pitted",
353 | "Bread Foccacia Whole",
354 | "Lentils - Green Le Puy",
355 | "Coriander - Ground",
356 | "Beef - Diced",
357 | "Steel Wool S.o.s",
358 | "Flour - Teff",
359 | "Towel Dispenser",
360 | "Currants",
361 | "Olives - Nicoise",
362 | "Pepper - Chili Powder",
363 | "Sproutsmustard Cress",
364 | "Campari",
365 | "Sauce - Mint",
366 | "Squid U5 - Thailand",
367 | "Pork Casing",
368 | "Cut Wakame - Hanawakaba",
369 | "Yucca",
370 | "Smoked Tongue",
371 | "Magnotta Bel Paese Red",
372 | "Chicken - Whole",
373 | "Rum - Coconut, Malibu",
374 | "Sauce - Hoisin",
375 | "Extract - Raspberry",
376 | "Ginsing - Fresh",
377 | "Table Cloth 81x81 Colour",
378 | "Sprite, Diet - 355ml",
379 | "Pepper - Chilli Seeds Mild",
380 | "Lid Coffee Cup 8oz Blk",
381 | "Syrup - Monin - Granny Smith",
382 | "Beef - Tenderloin - Aa",
383 | "Chinese Foods - Cantonese",
384 | "Juice - Apple, 341 Ml",
385 | "Grapefruit - Pink",
386 | "Tart Shells - Barquettes, Savory",
387 | "Shrimp - Baby, Warm Water",
388 | "Chocolate Bar - Coffee Crisp",
389 | "Sambuca - Opal Nera",
390 | "Tea - Apple Green Tea",
391 | "Sauce - Caesar Dressing",
392 | "Food Colouring - Orange",
393 | "Wine - Chenin Blanc K.w.v.",
394 | "Olives - Stuffed",
395 | "Flour - Fast / Rapid",
396 | "Sauce - Caesar Dressing",
397 | "Shark - Loin",
398 | "Filling - Mince Meat",
399 | "Pimento - Canned",
400 | "Beef - Bones, Marrow",
401 | "Tarts Assorted",
402 | "Muffin Mix - Oatmeal",
403 | "Muffin Batt - Blueberry Passion",
404 | "Creme De Cacao White",
405 | "Beer - Labatt Blue",
406 | "Cheese - Mozzarella, Shredded",
407 | "Wine - Saint Emilion Calvet",
408 | "Fish - Base, Bouillion",
409 | "Cookie Choc",
410 | "Pepper - Roasted Red",
411 | "Mushroom - Morels, Dry",
412 | "Soup - Campbells Pasta Fagioli",
413 | "Wine - Saint - Bris 2002, Sauv",
414 | "Cabbage - Red",
415 | "Melon - Honey Dew",
416 | "Wine - Chardonnay Mondavi",
417 | "Pasta - Gnocchi, Potato",
418 | "Oven Mitts 17 Inch",
419 | "Schnappes - Peach, Walkers",
420 | "Truffle Cups - White Paper",
421 | "Wine - Red, Colio Cabernet",
422 | "Mushroom - Porcini Frozen",
423 | "Cheese - Montery Jack",
424 | "Foil - Round Foil",
425 | "Potatoes - Pei 10 Oz",
426 | "Longos - Burritos",
427 | "Wine - Masi Valpolocell",
428 | "Juice - Propel Sport",
429 | "Cheese Cheddar Processed",
430 | "Food Colouring - Orange",
431 | "Longos - Grilled Veg Sandwiches",
432 | "Macaroons - Homestyle Two Bit",
433 | "Juice - Apple 284ml",
434 | "Yogurt - Banana, 175 Gr",
435 | "Sea Bass - Fillets",
436 | "Lamb Rack - Ontario",
437 | "Eggroll",
438 | "Fiddlehead - Frozen",
439 | "Salt - Rock, Course",
440 | "Pork - Sausage Casing",
441 | "Compound - Orange",
442 | "Beans - Navy, Dry",
443 | "Pastry - Trippleberry Muffin - Mini",
444 | "Juice - V8 Splash",
445 | "Chocolate Liqueur - Godet White",
446 | "Pork - Belly Fresh",
447 | "Potatoes - Fingerling 4 Oz",
448 | "Longan",
449 | "Capers - Pickled",
450 | "Turnip - Mini",
451 | "Egg - Salad Premix",
452 | "Towel Dispenser",
453 | "Wine - Taylors Reserve",
454 | "Halibut - Whole, Fresh",
455 | "Longos - Grilled Salmon With Bbq",
456 | "Oregano - Dry, Rubbed",
457 | "Pepper - Scotch Bonnet",
458 | "Jolt Cola - Red Eye",
459 | "Sugar - Monocystal / Rock",
460 | "Wooden Mop Handle",
461 | "Sausage - Meat",
462 | "Juice - Cranberry 284ml",
463 | "Cake Circle, Foil, Scallop",
464 | "Ecolab - Orange Frc, Cleaner",
465 | "Seedlings - Buckwheat, Organic",
466 | "Vinegar - Balsamic, White",
467 | "Iced Tea - Lemon, 460 Ml",
468 | "Lettuce - Red Leaf",
469 | "Cookie Dough - Chocolate Chip",
470 | "Sausage - Meat",
471 | "Garam Masala Powder",
472 | "Squid - Breaded",
473 | "Spring Roll Veg Mini",
474 | "Chocolate Eclairs",
475 | "Lamb - Shoulder, Boneless",
476 | "Lighter - Bbq",
477 | "Stock - Beef, White",
478 | "Wine - Kwv Chenin Blanc South",
479 | "Pepper - White, Ground",
480 | "Plate Foam Laminated 9in Blk",
481 | "Pasta - Fettuccine, Egg, Fresh",
482 | "Pork - Butt, Boneless",
483 | "Apple - Custard",
484 | "Sauce - Demi Glace",
485 | "Napkin - Beverage 1 Ply",
486 | "Wine - Masi Valpolocell",
487 | "Bread - Mini Hamburger Bun",
488 | "Extract - Lemon",
489 | "Compound - Orange",
490 | "Soap - Hand Soap",
491 | "Longos - Grilled Chicken With",
492 | "Lettuce - Treviso",
493 | "Wine - Cotes Du Rhone Parallele",
494 | "Grapes - Black",
495 | "Ezy Change Mophandle",
496 | "Peas - Frozen",
497 | "Apricots Fresh",
498 | "Venison - Denver Leg Boneless",
499 | "Wine - Fat Bastard Merlot",
500 | "Ice Cream Bar - Drumstick",
501 | "Dome Lid Clear P92008h",
502 | "Pepper - Yellow Bell",
503 | "Yogurt - Peach, 175 Gr",
504 | "Squash - Butternut",
505 | "Squash - Butternut",
506 | "Chinese Foods - Plain Fried Rice",
507 | "Foil Wrap",
508 | "Vector Energy Bar",
509 | "Milk Powder",
510 | "Danishes - Mini Cheese",
511 | "Lamb - Bones",
512 | "Lamb - Leg, Boneless",
513 | "Towels - Paper / Kraft",
514 | "Appetizer - Sausage Rolls",
515 | "Banana Turning",
516 | "Pastry - Lemon Danish - Mini",
517 | "Turkey - Oven Roast Breast",
518 | "Emulsifier",
519 | "Table Cloth - 53x69 Colour",
520 | "Cheese - Asiago",
521 | "Fennel - Seeds",
522 | "Plums - Red",
523 | "Soup - Campbells Chili Veg",
524 | "Halibut - Steaks",
525 | "Wine - Magnotta, Merlot Sr Vqa",
526 | "Cornish Hen",
527 | "Cocoa Butter",
528 | "Dikon",
529 | "Tuna - Fresh",
530 | "Pastry - Baked Scones - Mini",
531 | "Clam Nectar",
532 | "Apple - Royal Gala",
533 | "Crawfish",
534 | "Truffle Cups - Brown",
535 | "Wine - Red, Pinot Noir, Chateau",
536 | "Scotch - Queen Anne",
537 | "Browning Caramel Glace",
538 | "Gelatine Leaves - Bulk",
539 | "Chips - Potato Jalapeno",
540 | "Soho Lychee Liqueur",
541 | "Momiji Oroshi Chili Sauce",
542 | "Tart Shells - Sweet, 2",
543 | "Pears - Fiorelle",
544 | "Flour - All Purpose",
545 | "Soup - Campbellschix Stew",
546 | "Oregano - Fresh",
547 | "Daves Island Stinger",
548 | "Scallop - St. Jaques",
549 | "Sauce - Cranberry",
550 | "Wasabi Paste",
551 | "Tamarind Paste",
552 | "Foil - Round Foil",
553 | "Vinegar - White",
554 | "Lambcasing",
555 | "Swiss Chard - Red",
556 | "Country Roll",
557 | "Kahlua",
558 | "Mushroom - Chanterelle Frozen",
559 | "Cheese - Provolone",
560 | "Wine - Red, Pinot Noir, Chateau",
561 | "Table Cloth 81x81 Colour",
562 | "Cognac - Courvaisier",
563 | "Towel Multifold",
564 | "Bread - Crusty Italian Poly",
565 | "Eggwhite Frozen",
566 | "Dried Peach",
567 | "Steampan Lid",
568 | "Cheese - Brie,danish",
569 | "Tart Shells - Savory, 3",
570 | "Hog / Sausage Casing - Pork",
571 | "Sachet",
572 | "Puree - Strawberry",
573 | "Food Colouring - Red",
574 | "Yogurt - Banana, 175 Gr",
575 | "Blue Curacao - Marie Brizard",
576 | "Relish",
577 | "Goat - Whole Cut",
578 | "Potatoes - Idaho 80 Count",
579 | "Milk - Chocolate 250 Ml",
580 | "Tea - Apple Green Tea",
581 | "Bacardi Raspberry",
582 | "Food Colouring - Green",
583 | "Pate Pans Yellow",
584 | "Ice Cream - Turtles Stick Bar",
585 | "Bread - Bagels, Mini",
586 | "Carbonated Water - Blackberry",
587 | "Pastry - Baked Scones - Mini",
588 | "Pork - Back, Short Cut, Boneless",
589 | "Chicken - Diced, Cooked",
590 | "Muffin Batt - Ban Dream Zero",
591 | "Wine - Shiraz Wolf Blass Premium",
592 | "Yucca",
593 | "Soup - Campbells, Classic Chix",
594 | "Chocolate Bar - Coffee Crisp",
595 | "Dr. Pepper - 355ml",
596 | "Shrimp - 31/40",
597 | "Brocolinni - Gaylan, Chinese",
598 | "Beans - Kidney, Canned",
599 | "Mix - Cocktail Ice Cream",
600 | "Longos - Grilled Veg Sandwiches",
601 | "Tomatoes - Yellow Hot House",
602 | "Bread - Raisin Walnut Pull",
603 | "Cut Wakame - Hanawakaba",
604 | "Turnip - White",
605 | "Icecream - Dstk Cml And Fdg",
606 | "Turkey - Breast, Double",
607 | "Bread - Dark Rye, Loaf",
608 | "Beans - Fava Fresh",
609 | "Cherries - Fresh",
610 | "Appetizer - Escargot Puff",
611 | "Soap - Hand Soap",
612 | "Cotton Wet Mop 16 Oz",
613 | "Wine - Rioja Campo Viejo",
614 | "Eggs - Extra Large",
615 | "Veal Inside - Provimi",
616 | "Turnip - Wax",
617 | "Swiss Chard - Red",
618 | "Salmon - Atlantic, Fresh, Whole",
619 | "Gatorade - Xfactor Berry",
620 | "Juice - Clam, 46 Oz",
621 | "Pepper - Scotch Bonnet",
622 | "Chicken - Ground",
623 | "Ecolab - Ster Bac",
624 | "Salmon - Whole, 4 - 6 Pounds",
625 | "Rice - 7 Grain Blend",
626 | "Wanton Wrap",
627 | "Wine - Cotes Du Rhone",
628 | "Pepper - Green, Chili",
629 | "Beef - Bresaola",
630 | "Wine - Prosecco Valdobiaddene",
631 | "Crackers - Trio",
632 | "Oil - Safflower",
633 | "Bread - Rolls, Rye",
634 | "Brownies - Two Bite, Chocolate",
635 | "Potatoes - Pei 10 Oz",
636 | "Wine - Gato Negro Cabernet",
637 | "Bagel - Everything",
638 | "Wine - Riesling Dr. Pauly",
639 | "Pepper - Orange",
640 | "Croissant, Raw - Mini",
641 | "Turkey - Oven Roast Breast",
642 | "Salt - Table",
643 | "Beer - Mill St Organic",
644 | "Bagel - Everything Presliced",
645 | "Chivas Regal - 12 Year Old",
646 | "Dc - Sakura Fu",
647 | "Longos - Penne With Pesto",
648 | "Wine - Saint - Bris 2002, Sauv",
649 | "Galliano",
650 | "Seedlings - Buckwheat, Organic",
651 | "Mustard Prepared",
652 | "Beef - Inside Round",
653 | "Mayonnaise",
654 | "Oranges",
655 | "Soho Lychee Liqueur",
656 | "Truffle Paste",
657 | "Pork - Bones",
658 | "Spice - Pepper Portions",
659 | "Soup - Cream Of Potato / Leek",
660 | "Foam Espresso Cup Plain White",
661 | "Spice - Onion Powder Granulated",
662 | "Beef - Tenderloin",
663 | "Pickles - Gherkins",
664 | "Sponge Cake Mix - Vanilla",
665 | "Turkey Tenderloin Frozen",
666 | "Cheese - Le Cru Du Clocher",
667 | "Pears - Anjou",
668 | "Blackberries",
669 | "Truffle - Whole Black Peeled",
670 | "Wine - Placido Pinot Grigo",
671 | "Soup Campbells Turkey Veg.",
672 | "Coconut - Whole",
673 | "Kellogs Special K Cereal",
674 | "Cookie - Oatmeal",
675 | "Potatoes - Pei 10 Oz",
676 | "Wanton Wrap",
677 | "Beef - Montreal Smoked Brisket",
678 | "Snapple - Iced Tea Peach",
679 | "Muffins - Assorted",
680 | "Bread - Olive Dinner Roll",
681 | "Chervil - Fresh",
682 | "Dill - Primerba, Paste",
683 | "Lamb - Ground",
684 | "Soup - Campbells Mac N Cheese",
685 | "Bamboo Shoots - Sliced",
686 | "Pate Pans Yellow",
687 | "Sherbet - Raspberry",
688 | "Calypso - Lemonade",
689 | "Cranberries - Fresh",
690 | "Danishes - Mini Raspberry",
691 | "Wine - Redchard Merritt",
692 | "Melon - Cantaloupe",
693 | "Tea - Camomele",
694 | "Zucchini - Mini, Green",
695 | "Creme De Cacao White",
696 | "Sausage - Meat",
697 | "Silicone Paper 16.5x24",
698 | "Chinese Foods - Cantonese",
699 | "Barramundi",
700 | "Sugar - Splenda Sweetener",
701 | "Edible Flower - Mixed",
702 | "Nut - Pine Nuts, Whole",
703 | "Chestnuts - Whole,canned",
704 | "Juice Peach Nectar",
705 | "Roe - Lump Fish, Black",
706 | "Lobster - Tail, 3 - 4 Oz",
707 | "Dikon",
708 | "Snapple Raspberry Tea",
709 | "Chips - Miss Vickies",
710 | "Wine - Prem Select Charddonany",
711 | "Gelatine Leaves - Envelopes",
712 | "Soup Campbells - Tomato Bisque",
713 | "Pail With Metal Handle 16l White",
714 | "Coconut - Creamed, Pure",
715 | "Beer - Sleemans Honey Brown",
716 | "Filo Dough",
717 | "Appetizer - Smoked Salmon / Dill",
718 | "External Supplier",
719 | "Table Cloth 120 Round White",
720 | "Cinnamon Buns Sticky",
721 | "Lettuce - Lambs Mash",
722 | "Wine - Masi Valpolocell",
723 | "Bread - Multigrain, Loaf",
724 | "Laundry - Bag Cloth",
725 | "Muffin - Carrot Individual Wrap",
726 | "Foam Espresso Cup Plain White",
727 | "Corn - Cream, Canned",
728 | "Salt - Kosher",
729 | "Flour - Semolina",
730 | "Cheese - Roquefort Pappillon",
731 | "Milk - Buttermilk",
732 | "Curry Powder",
733 | "Squash - Butternut",
734 | "Chicken Breast Halal",
735 | "Cookie Trail Mix",
736 | "Tequila Rose Cream Liquor",
737 | "Wine - Rubyport",
738 | "Cheese - Boursin, Garlic / Herbs",
739 | "Wine - Rhine Riesling Wolf Blass",
740 | "Fond - Chocolate",
741 | "Sage Derby",
742 | "Pastry - Banana Tea Loaf",
743 | "Tarragon - Primerba, Paste",
744 | "Tarts Assorted",
745 | "Flower - Daisies",
746 | "Pepper - Black, Whole",
747 | "Croissant, Raw - Mini",
748 | "Vinegar - Sherry",
749 | "Juice - Tomato, 48 Oz",
750 | "Lettuce - Sea / Sea Asparagus",
751 | "Pate - Liver",
752 | "Chips - Miss Vickies",
753 | "Tabasco Sauce, 2 Oz",
754 | "Tortillas - Flour, 12",
755 | "Wine - Cave Springs Dry Riesling",
756 | "Muffin Batt - Blueberry Passion",
757 | "Lamb Tenderloin Nz Fr",
758 | "Jerusalem Artichoke",
759 | "Lobster - Live",
760 | "Yoghurt Tubes",
761 | "Sauce - Black Current, Dry Mix",
762 | "Soup - Campbells Broccoli",
763 | "Latex Rubber Gloves Size 9",
764 | "Tuna - Yellowfin",
765 | "Turkey - Breast, Bone - In",
766 | "Pasta - Fettuccine, Egg, Fresh",
767 | "Pork - Back, Long Cut, Boneless",
768 | "Rice Pilaf, Dry,package",
769 | "Bread - Corn Muffaleta Onion",
770 | "Fish - Soup Base, Bouillon",
771 | "Chocolate Bar - Reese Pieces",
772 | "Sesame Seed Black",
773 | "Muffin Mix - Lemon Cranberry",
774 | "Extract - Vanilla,artificial",
775 | "Island Oasis - Banana Daiquiri",
776 | "Sage Derby",
777 | "Carbonated Water - White Grape",
778 | "Macaroons - Homestyle Two Bit",
779 | "Grenadillo",
780 | "Sauce - Ranch Dressing",
781 | "Pepper - Cayenne",
782 | "Table Cloth 90x90 Colour",
783 | "Water - Aquafina Vitamin",
784 | "Chips - Doritos",
785 | "Wine - Shiraz South Eastern",
786 | "Beef - Rib Roast, Cap On",
787 | "Pasta - Tortellini, Fresh",
788 | "Noodles - Cellophane, Thin",
789 | "Asparagus - Frozen",
790 | "Cheese - Cheddar, Medium",
791 | "Beef - Cow Feet Split",
792 | "Milk - Condensed",
793 | "Figs",
794 | "Trout Rainbow Whole",
795 | "Vodka - Hot, Lnferno",
796 | "Cognac - Courvaisier",
797 | "Wine - Soave Folonari",
798 | "Mcgillicuddy Vanilla Schnap",
799 | "Honey - Lavender",
800 | "Coconut Milk - Unsweetened",
801 | "Coke - Classic, 355 Ml",
802 | "Salt - Seasoned",
803 | "Soup - Campbells Mac N Cheese",
804 | "Longos - Cheese Tortellini",
805 | "Beer - Guiness",
806 | "Pate Pans Yellow",
807 | "Carrots - Purple, Organic",
808 | "Squash - Pattypan, Yellow",
809 | "Maple Syrup",
810 | "Langers - Mango Nectar",
811 | "French Pastry - Mini Chocolate",
812 | "Cheese - Perron Cheddar",
813 | "Beans - Black Bean, Preserved",
814 | "Wine - Chianti Classica Docg",
815 | "Appetizer - Tarragon Chicken",
816 | "Beef Cheek Fresh",
817 | "Pasta - Rotini, Dry",
818 | "Oil - Truffle, White",
819 | "Asparagus - Green, Fresh",
820 | "Cheese - Gouda Smoked",
821 | "Nori Sea Weed - Gold Label",
822 | "Wine - Chardonnay South",
823 | "Wine - Bourgogne 2002, La",
824 | "Avocado",
825 | "Yoplait Drink",
826 | "Galliano",
827 | "Apple - Delicious, Red",
828 | "Bagel - Everything Presliced",
829 | "Mop Head - Cotton, 24 Oz",
830 | "Chicken - Base, Ultimate",
831 | "Pastry - Chocolate Chip Muffin",
832 | "Nantucket Orange Juice",
833 | "Fond - Neutral",
834 | "Ham - Procutinni",
835 | "Wine - Sake",
836 | "Longos - Lasagna Veg",
837 | "Juice - Cranberry, 341 Ml",
838 | "Foie Gras",
839 | "Bread - Calabrese Baguette",
840 | "Orange Roughy 6/8 Oz",
841 | "Cheese - Victor Et Berthold",
842 | "Tomato - Plum With Basil",
843 | "Tuna - Loin",
844 | "Flour - Cake",
845 | "Chocolate - Chips Compound",
846 | "Sobe - Liz Blizz",
847 | "Cabbage - Nappa",
848 | "Pork - Back Ribs",
849 | "Corn Shoots",
850 | "Wine - Winzer Krems Gruner",
851 | "Cheese - Romano, Grated",
852 | "Beans - Navy, Dry",
853 | "Wine - Charddonnay Errazuriz",
854 | "Garam Marsala",
855 | "Muffin Hinge - 211n",
856 | "Wine - Charddonnay Errazuriz",
857 | "Milk - Skim",
858 | "Lobster - Base",
859 | "Toothpick Frilled",
860 | "Nestea - Iced Tea",
861 | "White Baguette",
862 | "Veal - Striploin",
863 | "Placemat - Scallop, White",
864 | "Gelatine Leaves - Bulk",
865 | "Ice Cream - Strawberry",
866 | "Beef - Roasted, Cooked",
867 | "Pepper - Cubanelle",
868 | "Wine - Prosecco Valdobiaddene",
869 | "Muffin Hinge 117n",
870 | "Tortillas - Flour, 8",
871 | "Chicken Breast Halal",
872 | "Juice - Apple Cider",
873 | "Anchovy Fillets",
874 | "Tuna - Sushi Grade",
875 | "Rice - Sushi",
876 | "Veal - Brisket, Provimi, Bone - In",
877 | "Icecream - Dibs",
878 | "Scallops - 20/30",
879 | "Scallops - In Shell",
880 | "Mushroom - Porcini Frozen",
881 | "Alize Red Passion",
882 | "Muffin - Mix - Strawberry Rhubarb",
883 | "Puree - Raspberry",
884 | "Coffee - Espresso",
885 | "Onion - Dried",
886 | "Wine - Dubouef Macon - Villages",
887 | "Scallops - In Shell",
888 | "Steampan - Foil",
889 | "Sauce - Sesame Thai Dressing",
890 | "Rappini - Andy Boy",
891 | "Steam Pan Full Lid",
892 | "Cup - 8oz Coffee Perforated",
893 | "Pepper - Red Thai",
894 | "Lobak",
895 | "Juice - Mango",
896 | "Parsley Italian - Fresh",
897 | "Shrimp - Black Tiger 6 - 8",
898 | "Juice - Cranberry, 341 Ml",
899 | "Pork - Belly Fresh",
900 | "Yeast Dry - Fermipan",
901 | "Rice - 7 Grain Blend",
902 | "Fireball Whisky",
903 | "Ice Cream - Chocolate",
904 | "Oil - Truffle, Black",
905 | "Puff Pastry - Slab",
906 | "Salmon Atl.whole 8 - 10 Lb",
907 | "Truffle Shells - White Chocolate",
908 | "Tea - Mint",
909 | "Bread - 10 Grain",
910 | "Wine - Red Oakridge Merlot",
911 | "Appetizer - Escargot Puff",
912 | "Wine - Barbera Alba Doc 2001",
913 | "Pears - Bosc",
914 | "Mushroom - White Button",
915 | "Chocolate - Sugar Free Semi Choc",
916 | "Scampi Tail",
917 | "Aspic - Clear",
918 | "Silicone Parch. 16.3x24.3",
919 | "Ice Cream - Strawberry",
920 | "Chicken - Livers",
921 | "Scotch - Queen Anne",
922 | "Wine - Remy Pannier Rose",
923 | "Beef - Texas Style Burger",
924 | "Wine - Cotes Du Rhone Parallele",
925 | "Veal - Liver",
926 | "Grapefruit - Pink",
927 | "Juice - Clamato, 341 Ml",
928 | "Puree - Strawberry",
929 | "Temperature Recording Station",
930 | "Fireball Whisky",
931 | "Garbage Bags - Clear",
932 | "Cake - French Pear Tart",
933 | "Tomato Paste",
934 | "Initation Crab Meat",
935 | "Cut Wakame - Hanawakaba",
936 | "Wine - Gato Negro Cabernet",
937 | "Cheese - Goat",
938 | "Mushroom - Chanterelle, Dry",
939 | "Chip - Potato Dill Pickle",
940 | "Tart Shells - Sweet, 2",
941 | "Shrimp - 16/20, Iqf, Shell On",
942 | "Yogurt - Cherry, 175 Gr",
943 | "Sobe - Berry Energy",
944 | "Vermouth - White, Cinzano",
945 | "Fennel - Seeds",
946 | "Potatoes - Pei 10 Oz",
947 | "Orange - Tangerine",
948 | "Juice - Grapefruit, 341 Ml",
949 | "Oyster - In Shell",
950 | "Pepper - Julienne, Frozen",
951 | "Cake - Cheese Cake 9 Inch",
952 | "Salmon - Smoked, Sliced",
953 | "Beer - Corona",
954 | "Sardines",
955 | "Spaghetti Squash",
956 | "Allspice - Jamaican",
957 | "Ranchero - Primerba, Paste",
958 | "Peas - Frozen",
959 | "Turkey - Breast, Double",
960 | "Wine - Rosso Del Veronese Igt",
961 | "Flower - Commercial Bronze",
962 | "Swiss Chard - Red",
963 | "Pork - Smoked Kassler",
964 | "Wine - Acient Coast Caberne",
965 | "Beef - Tenderlion, Center Cut",
966 | "Capon - Whole",
967 | "Pernod",
968 | "Mint - Fresh",
969 | "Shrimp - Black Tiger 26/30",
970 | "Sugar Thermometer",
971 | "Quinoa",
972 | "Bread - Multigrain, Loaf",
973 | "Wild Boar - Tenderloin",
974 | "Juice - Cranberry, 341 Ml",
975 | "Salt - Table",
976 | "Soup - Campbells Chili Veg",
977 | "Beef - Ox Tongue",
978 | "Coke - Diet, 355 Ml",
979 | "Ecolab - Hobart Washarm End Cap",
980 | "Chestnuts - Whole,canned",
981 | "Tart Shells - Savory, 4",
982 | "Brandy - Bar",
983 | "Carbonated Water - Orange",
984 | "Beer - Labatt Blue",
985 | "Clams - Littleneck, Whole",
986 | "Extract - Vanilla,artificial",
987 | "Veal - Kidney",
988 | "Doilies - 8, Paper",
989 | "Juice - Lemon",
990 | "Dry Ice",
991 | "Flour - So Mix Cake White",
992 | "Wine - Tribal Sauvignon",
993 | "Wine - Casillero Deldiablo",
994 | "Veal - Loin",
995 | "Oil - Margarine",
996 | "Lemon Pepper",
997 | "Jagermeister",
998 | "Chocolate Bar - Oh Henry",
999 | "Trueblue - Blueberry Cranberry",
1000 | "Wine - Red, Pelee Island Merlot",
1001 | "Wine - White, Ej"
1002 | ]
1003 |
--------------------------------------------------------------------------------