import { Pagination } from "../../../search/Pagination.js";
import { UiElement } from "../../../ui/UiElement.js";
import { registerDataTransfer } from "../../../ui/dnd/util.js";
import { IndexBinder } from "../binder/IndexBinder.js";
import { createVEFLayerConfig } from "../../../utils/universal/ogc/createVEFLayerConfig.js";
import "./CatalogUi.css";
import { loadLayer } from "../../utils/loadLayer.js";
export { CatalogUi };
/**
* Ui class for importing NRT layers from DWS
*
* @memberof vef.map.importer.ui
*/
class CatalogUi extends UiElement {
title = "Catalog";
classes = ["catalog-ui", "importer-ui"];
html = `
<div class="catalog-input-wrapper">
<input class="catalog-input" type="text" spellcheck="false" placeholder="Search for layers..."></input>
<button class="catalog-search-button" title="search"><i class="fas fa-search"></i></button>
<button title="filter" class="btn-filter"><i class="fas fa-filter"></i></button>
</div>
<div class="catalog-filters">
<div class="catalog-filter">
<h4>Layer Type</h4>
<label>Show WMS</label> <input class="show-wms" type="checkbox" checked/> -
<label>Show WFS</label> <input class="show-wfs" type="checkbox"/>
</div>
</div>
<div class="catalog-results"></div>
<div class="results-pagination"></div>
`;
constructor(target, options) {
super(target, {
"add_layers": [],
"show_info": []
});
this.page_ = 0;
this.limit_ = 6;
this.pagination_ = null;
this.url_ = (options && ("url" in options)) ? options.url : null;
this.indices_ = (options && ("indices" in options)) ? options.indices : null;
this.indexBinder_ = new IndexBinder(this.url_, this.indices_);
this.setHtml(this.html);
this.setClass(this.classes);
this.initPagination_();
this.initEvents_();
this.applySearch_();
}
initPagination_() {
this.pagination_ = new Pagination(this.query(".results-pagination"));
this.pagination_.on("changed", page => {
this.applySearch_(page);
})
}
initEvents_() {
let searchTimeout = null;
this.query(".catalog-search-button").addEventListener("click", () => this.applySearch_());
this.query(".catalog-input").addEventListener("keydown", e => {
if (e.which == 13) { // "enter" key
clearTimeout(searchTimeout);
searchTimeout = null;
this.applySearch_();
} else {
if (searchTimeout) clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
searchTimeout = null;
this.applySearch_();
}, 1000);
}
});
this.query(".btn-filter").addEventListener("click", e => {
const element = this.getElement();
if (element.classList.contains("filters-active")) {
element.classList.remove("filters-active");
this.applySearch_();
} else {
element.classList.add("filters-active");
}
});
}
async showResults_(response) {
const results = this.query(".catalog-results");
results.style.height = "auto";
if (response.hits == 0) {
results.innerHTML = "<b style='color: var(--primary-color);'>No layers found.</b>";
return;
}
results.innerHTML = "";
for (let i = 0; i < response.records.length; ++i) {
const record = response.records[i];
const cache = await createVEFLayerConfig(record);
if (!cache) return;
const layer = loadLayer({}, cache);
const result = document.createElement("div");
result.classList.add("result");
result.innerHTML = `
<div class="result-drag">
<i class="fas fa-arrows-alt"></i>
</div>
<div class="result-content">
<a href="#" class="layer-title"></a>
<div class="layer-type"></div>
<div class="layer-abstract"></div>
<a class="service-url" target="_blank"></a>
<a title="layer info" href="#" class="info-button fas fa-info"></a>
</div>
`;
const title = result.querySelector(".layer-title");
title.innerText = record.title;
title.title = record.title;
title.addEventListener("click", e => {
e.preventDefault();
const layers = {};
layers[layer.uniqueId] = layer;
this.fire("add_layers", {
structure: { "#": [layer.uniqueId] },
layers: layers
});
});
const btnInfo = result.querySelector(".info-button");
btnInfo.addEventListener("click", e => {
e.preventDefault();
this.fire("show_info", layer);
});
// remove html from abstract
const abstractDiv = document.createElement("div");
abstractDiv.innerHTML = record.description;
const abstract = result.querySelector(".layer-abstract");
abstract.innerText = abstractDiv.innerText.replace(/(\r\n|\n|\r)/gm, " ");
abstract.title = abstractDiv.innerText;
const type = result.querySelector(".layer-type");
switch (layer.type.toLowerCase()) {
case "wms":
type.innerHTML = "<i class='vef vef-raster'></i> WMS"
break;
case "wfs":
type.innerHTML = "<i class='fas fa-draw-polygon'></i> WFS"
break;
}
// find url
for (let i = 0; i < record.resources.length; ++i) {
const resource = record.resources[i];
if (resource.type == "link") {
const a = result.querySelector(".service-url");
a.href = resource.uri;
a.title = resource.uri;
a.innerText = resource.uri;
break;
}
}
this.initDragDrop_(result, layer);
results.appendChild(result);
}
}
initDragDrop_(result, layer) {
result.draggable = true;
result.addEventListener('dragstart', (e) => {
e.stopPropagation();
e.dataTransfer.setData("layer_transfer_id", registerDataTransfer(layer));
});
}
emptyResults_() {
this.pagination_.show(0, 0);
const results = this.query(".catalog-results");
results.style.height = results.clientHeight + "px";
results.innerHTML = `
<div style="text-align: center; margin: 20px 0">
<i style="color:var(--primary-color); font-size: 18px;" class="fas fa-spinner fa-spin fa-fw"></i>'
</div>
`;
}
request_(params) {
let query = "";
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
const response = JSON.parse(xhr.responseText);
const page = Math.ceil(response.offset / this.limit_) + 1;
const pages = Math.ceil(response.totalHits / this.limit_);
this.pagination_.show(page, pages);
this.showResults_(response);
}
};
xhr.open("GET", query, true);
xhr.setRequestHeader('Accept', 'application/json;charset=UTF-8');
xhr.send();
}
applySearch_(page) {
this.emptyResults_();
this.page_ = (Number.isFinite(page) && (page >= 0)) ? page : 1;
const params = {
hits: this.limit_,
offset: Math.floor((this.page_ - 1) * this.limit_),
queryFacets: {},
operator: "AND",
query: ""
}
let query = this.query(".catalog-input").value.trim();
if (query.length > 0) {
if (!(query.includes('"') || query.includes("'"))) query = "*" + query + "*";
params.query = `(title:(${query})^3 OR (${query}))`;
} else {
params.sorts = ["_random"]
}
const showWms = this.query(".show-wms").checked;
const showWfs = this.query(".show-wfs").checked;
let typeQuery = "";
if (showWms) typeQuery += '"wms"';
if (showWfs) {
if (typeQuery.length > 0) typeQuery += " OR ";
typeQuery += '"wfs"';
}
if (typeQuery) {
params.query += ` resources.metadata.type:(${typeQuery})`;
}
this.indexBinder_.fetch(params)
.then(response => {
const page = Math.ceil(response.offset / this.limit_) + 1;
const pages = Math.ceil(response.totalHits / this.limit_);
this.showResults_(response);
this.pagination_.show(page, pages);
})
.catch(e => {
console.error(e);
})
}
}