import { generateTable } from "../../../utils/template/functions/common.js";
import { UiElement } from "../../../ui/UiElement.js";
import { roundNumber } from "../../../utils/utils.js";
import { Window } from "../../../ui/Window.js";
import { DWS_DEFAULT_URL } from "../../../data/DwsLoader.js";
import "./DwsInput.css";
export { DwsInput }
/**
* HTML input for searching URNs in the DWS
*
* events
* - select_urn: fired when a URN is selected from the List
*
* @memberof vef.map.importer.ui
*
*/
class DwsInput extends UiElement {
static dropdowns = [];
/**
* options = {
* dwsUrl: string,
* closeable: boolean,
* staticQuery: string
* }
*
* @param {HTMLElement | string} target target element
* @param {object} options
*/
constructor(target, options = {}) {
super(target, {
"select_urn": []
});
this.options = Object.assign({
dwsUrl: null,
staticQuery: "",
closeable: true
}, options || {});
this.cache_ = null;
this.activeDevice = null;
this.staticQuery = this.options.staticQuery;
this.initHTMLElement_(this.options.closeable);
DwsInput.dropdowns.push(this);
}
/**
* Initialize the HTML structure of the Ui
*
* @private
*/
initHTMLElement_(closeable = true) {
const element = this.getElement();
element.classList.add("dws-input");
if (!closeable) element.classList.add("not-closeable");
element.innerHTML = `
<i class="fas fa-times"><!--
--></i><input spellcheck="false" placeholder="Search for Sensor URNs" class="query" type="text"/><!--
--><div class="search-results"></div>
`;
element.querySelector(".fa-times").addEventListener("click", () => this.hide());
element.addEventListener("click", (e) => e.stopPropagation());
const input = element.querySelector(".query");
input.addEventListener("focus", () => this.showSearchResults_());
// init search events
let searchTimeout = null;
input.addEventListener("input", () => {
// abort any running fetches
if (this.abortController_) this.abortController_.abort();
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
this.search_();
searchTimeout = null;
}, 750);
});
input.addEventListener("keydown", (e) => {
if (e.key == "Enter") {
if (this.abortController_) this.abortController_.abort();
clearTimeout(searchTimeout);
this.search_();
}
});
this.infoWindow = new Window(this.getElement(), { open: false });
this.infoWindow.getElement().classList.add("pointer-left");
// close info window when leaving
element.querySelector(".search-results").addEventListener("mouseleave", () => this.infoWindow.close());
}
dispose() {
DwsInput.dropdowns = DwsInput.dropdowns.filter(dropdown => dropdown != this);
super.dispose();
}
/**
* Display the search result list.
*
* @private
*/
showSearchResults_() {
const element = this.getElement();
element.classList.add("active");
const callback = () => {
document.removeEventListener("click", callback);
this.hideSearchResults_();
}
document.addEventListener("click", callback);
this.search_();
// close other dropdowns
DwsInput.dropdowns.forEach(dropdown => {
if (dropdown != this) dropdown.hideSearchResults_();
});
}
/**
* Hide the search result list
*
* @private
*/
hideSearchResults_() {
const element = this.getElement();
element.classList.remove("active");
}
/**
* Execute the search. takes the
* search query from the text input
*
* @private
*/
search_() {
const q = this.getInputValue_();
this.abortController_ = new AbortController();
const url = this.options.dwsUrl || DWS_DEFAULT_URL;
fetch(url + "/search", {
signal: this.abortController_.signal,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
hits: 20,
query: ((q) ? ("(id:/.*" + q + ".*/^20 )") : "*:*") + " AND (metadata.source:NRT)" + this.staticQuery,
sorts: ["metadata.code:asc"],
indices: [],
offset: 0,
queryFacets: {},
types: []
})
})
.then(respone => {
this.abortController_ = null;
return respone.json()
})
.then(json => {
this.cache_ = json.records;
})
.catch(error => {
this.cache_ = [];
})
.finally(() => {
this.populateList_(this.cache_);
})
}
/**
* Populate the search result list with content.
* Gets called by this.search_()
*
* @param {object[]} devices
*
* @private
*/
populateList_(devices) {
const element = this.getElement();
const results = element.querySelector(".search-results");
while (results.firstChild) {
results.removeChild(results.lastChild);
}
for (let i = 0; i < devices.length; ++i) {
let device = devices[i];
const result = document.createElement("div");
result.classList.add("search-result");
result.innerHTML = `
<i class="layer-type fas fa-database"></i>
<span class="layer-title">${device.metadata.code}</span>
<i id="result-icon" class="add-layer fas fa-plus-circle"></i>
`;
result.addEventListener("click", (e) => {
this.selectUrn_(device, e);
});
result.addEventListener("mouseover", () => this.showInfoBox_(device, result, results));
results.appendChild(result);
}
}
/**
* Creates an infoBox for the DWS layers
*
* @param {object} device
* @param {HTMLElement} result
* @param {HTMLElement} results
*
* @private
*/
showInfoBox_(device, result, results) {
let rect = result.getBoundingClientRect();
let outerRect = results.getBoundingClientRect();
const lastDate = new Date(device.metadata.lastDate);
const difference = new Date().getTime() - lastDate.getTime();
const days = roundNumber(difference / 86400000, 1);
const properties = {
"Last Active": days + " days ago",
"Model": device.metadata.model,
"Parameter": device.parameters[0].united
};
this.infoWindow.setOptions({
top: rect.top + "px",
left: outerRect.left + outerRect.width + 15 + "px",
width: "300px",
height: "unset",
open: true,
title: device.metadata.code,
content: generateTable(properties)
});
}
getInputValue_() {
return this.getElement().querySelector(".query").value.trim();
}
setInputValue_(value) {
this.getElement().querySelector(".query").value = value;
}
/**
* Create an instance of the Layer class
* and fire the event "select_urn"
*
* @param {object} device
* @param {object} pointerEvent
*/
selectUrn_(device, pointerEvent) {
this.setInputValue_(device.metadata.code);
this.activeDevice = device;
this.hideSearchResults_();
this.fire("select_urn", { device: device, pointerEvent: pointerEvent });
}
deselect_() {
this.setInputValue_("");
this.activeDevice = null;
}
/**
* Show the DwsInput
*/
show() {
const element = this.getElement();
element.style.display = "flex";
element.querySelector(".query").value = "";
element.querySelector(".query").focus();
}
/**
* Hide the DwsInput
*/
hide() {
this.getElement().style.display = "none";
}
}