blob: 31ceeeafd5a06079dd781adb1de8ca0d722c8b7a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {DomUtils} from "./tobago-utils";
class Suggest extends HTMLElement {
static asyncResults: (data: string[]) => void;
hiddenInput: HTMLInputElement;
static loadFromServer = function (input: HTMLInputElement): (query, syncResults, asyncResults) => void {
let timeout;
return function findMatches(query, syncResults, asyncResults): void {
const root = input.getRootNode() as ShadowRoot | Document;
let suggest = root.getElementById(input.dataset.tobagoSuggestFor) as Suggest;
// todo: suggest.hiddenInput.value should contain the last query value
if (suggest.hiddenInput.value !== query) {
if (timeout) {
clearTimeout(timeout);
}
const delay = suggest.delay;
timeout = setTimeout(function (): void {
suggest.hiddenInput.value = query;
Suggest.asyncResults = asyncResults;
delete suggest.dataset.tobagoSuggestData;
console.info("query: '" + query + "'");
jsf.ajax.request(
suggest.id,
null, // todo: event?
{
"javax.faces.behavior.event": "suggest",
execute: suggest.id,
render: suggest.id
});
}, delay);
}
};
};
static fromClient = function (data): (query, syncResults) => void {
return (query, syncResults): void => {
const result = [];
for (let i = 0; i < data.length; i++) {
if (data[i].indexOf(query) >= 0) {
result.push(data[i]);
}
}
syncResults(result);
};
};
constructor() {
super();
this.hiddenInput = document.createElement("input");
this.hiddenInput.setAttribute("type", "hidden");
this.hiddenInput.setAttribute("name", this.id);
this.appendChild(this.hiddenInput);
}
get for(): string {
return this.getAttribute("for");
}
set for(forValue: string) {
this.setAttribute("for", forValue);
}
get minChars(): number {
return parseInt(this.getAttribute("min-chars"));
}
set minChars(minChars: number) {
this.setAttribute("min-chars", String(minChars));
}
get delay(): number {
return parseInt(this.getAttribute("delay"));
}
set delay(delay: number) {
this.setAttribute("delay", String(delay));
}
get maxItems(): number {
return parseInt(this.getAttribute("max-items"));
}
set maxItems(maxItems: number) {
this.setAttribute("max-items", String(maxItems));
}
get update(): boolean {
return this.hasAttribute("update");
}
set update(update: boolean) {
if (update) {
this.setAttribute("update", "");
} else {
this.removeAttribute("update");
}
}
get totalCount(): number {
return parseInt(this.getAttribute("total-count"));
}
set totalCount(totalCount: number) {
this.setAttribute("total-count", String(totalCount));
}
get data(): string[] {
return JSON.parse(this.getAttribute("data"));
}
set data(data: string[]) {
this.setAttribute("data", JSON.stringify(data));
}
get localMenu(): boolean {
return this.hasAttribute("local-menu");
}
set localMenu(update: boolean) {
if (update) {
this.setAttribute("local-menu", "");
} else {
this.removeAttribute("local-menu");
}
}
connectedCallback(): void {
const root = this.getRootNode() as ShadowRoot | Document;
const input = root.getElementById(this.for) as HTMLInputElement;
const $input = jQuery(input);
if (this.update && input.classList.contains("tt-input")) { // already initialized: so only update data
if (Suggest.asyncResults) {
Suggest.asyncResults(this.data);
Suggest.asyncResults = null;
}
} else { // new
input.dataset.tobagoSuggestFor = this.id;
input.autocomplete = "off";
let source;
if (this.update) {
source = Suggest.loadFromServer(input);
} else {
source = Suggest.fromClient(this.data);
}
let suggestPopup = root.getElementById(this.id + "::popup");
if (suggestPopup) {
suggestPopup.parentElement.removeChild(suggestPopup);
}
suggestPopup = document.createElement("div");
suggestPopup.id = this.id + "::popup";
suggestPopup.classList.add("tt-menu", "tt-empty");
root.querySelector(".tobago-page-menuStore").appendChild(suggestPopup);
const menu = this.localMenu ? null : suggestPopup;
$input.typeahead({
menu: menu,
minLength: this.minChars,
hint: true,// todo
highlight: true // todo
}, {
//name: 'test',// todo
limit: this.maxItems,
source: source
});
// old with jQuery:
$input.on("typeahead:change", function (event: JQuery.Event): void {
const input = this;
input.dispatchEvent(new Event("change"));
});
// new without jQuery:
// input.addEventListener("typeahead:change", (event: Event) => {
// const input = event.currentTarget as HTMLInputElement;
// input.dispatchEvent(new Event("change"));
// });
// old with jQuery:
$input.on("typeahead:open", function (event: JQuery.Event): void {
const input = this;
const suggestPopup = root.getElementById(input.dataset.tobagoSuggestFor + "::popup");
suggestPopup.style.top = DomUtils.offset(input).top + input.offsetHeight + "px";
suggestPopup.style.left = DomUtils.offset(input).left + "px";
suggestPopup.style.minWidth = input.offsetWidth + "px";
});
// new without jQuery:
// input.addEventListener("typeahead:open", (event: Event) => {
// const input = event.currentTarget as HTMLInputElement;
// const suggestPopup = document.getElementById(input.dataset.tobagoSuggestFor + "::popup");
// suggestPopup.style.top = DomUtils.offset(input).top + input.offsetHeight + "px";
// suggestPopup.style.left = DomUtils.offset(input).left + "px";
// suggestPopup.style.minWidth = input.offsetWidth + "px";
// });
}
}
}
document.addEventListener("DOMContentLoaded", function (event: Event): void {
window.customElements.define("tobago-suggest", Suggest);
});