/* Define a web component providing a settable and selectable list
$("symList").setData(r, append = false);
where r is array of objects with properties name,detail,kind
https://stackoverflow.com/questions/50404970/web-components-pass-data-to-and-from
https://www.w3schools.com/howto/howto_js_treeview.asp
*/
class ListComponent extends HTMLElement {
#shadow;
#data;
#iconKinds; //array from kind integer to codicon name
constructor() {
super();
this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true });
this.#data = [];
// codicons kind
this.#iconKinds = [
'symbol-file',
'symbol-class',
'symbol-namespace',
'symbol-structure',
'symbol-class',
'symbol-method',
'symbol-property',
'symbol-field',
'symbol-method-arrow',
'symbol-enum',
'symbol-interface',
'symbol-method',
'symbol-variable',
'symbol-constant',
'symbol-string',
'symbol-numeric',
'symbol-boolean',
'symbol-array',
'symbol-structure',
'symbol-key',
'dash',
'symbol-enum-member',
'symbol-misc',
'symbol-event',
'symbol-operator',
'symbol-parameter'
];
this.render();
}
setData(newData, append = false) {
if (!Array.isArray(newData)) {
console.warn("Invalid format, expected an array.");
return;
}
this.#data = append ? this.#data.concat(newData) : structuredClone(newData);
this.render();
}
set data(value) {
this.setData(value, false);
}
get data() {
return this.#data;
}
/* Render the list items #data */
render() {
// eventhandler for click and keyboard, updates usage of selected class and raises event
const select = e => {
if(e.type ==="keyup" && !(e.key==="Enter" )) return;
this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; });
e.currentTarget.className = 'selected';
const i=e.currentTarget.getAttribute("data-index")
console.log('Item index clicked:', i,this.#data[i]);
// You can dispatch a custom event here if needed.
this.dispatchEvent(new CustomEvent('itemSelected', {
detail: this.#data[i],
bubbles: true,
composed: true
}));
};
// create list and items
const list = document.createElement('ul');
list.style = "overflow: auto;";
this.#data.forEach((item, index) => {
const listItem = document.createElement('li');
const icon=this.#iconKinds[item.kind];
//listItem.setAttribute("tabindex", "0")
listItem.setAttribute("data-index", index)
listItem.innerHTML = `
Error loading data: ${error.message}
`; } } /* Define the new custom element */ customElements.define('qd-list', ListComponent); class PanelComponent extends HTMLElement { #shadow; #data; #iconKinds; //array from kind integer to codicon name constructor() { super(); this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true }); this.#data = []; this.#iconKinds = []; this.render(); } setData(newData, append = false) { if (!Array.isArray(newData)) { console.warn("Invalid format, expected an array."); return; } this.#data = append ? this.#data.concat(newData) : structuredClone(newData); this.render(); } set data(value) { this.setData(value, false); } get data() { return this.#data; } /* Render the list items #data */ render() { const list = document.createElement('ul'); list.style = "overflow: auto;"; const select = e => { if(e.type ==="keyup" && !(e.key==="Enter" )) return; this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; }); e.currentTarget.className = 'selected'; const i=e.currentTarget.getAttribute("data-index") console.log('Item index clicked:', i,this.#data[i]); // You can dispatch a custom event here if needed. this.dispatchEvent(new CustomEvent('itemSelected', { detail: this.#data[i], bubbles: true, composed: true })); }; this.#data.forEach((item, index) => { const listItem = document.createElement('li'); const icon=this.#iconKinds[item.kind]; listItem.setAttribute("tabindex", "0") listItem.setAttribute("data-index", index) listItem.innerHTML = `XX* ${item.name} - ${item.detail}`; listItem.addEventListener('click', select); listItem.addEventListener('keyup', select); list.appendChild(listItem); }); this.#shadow.innerHTML = ''; const style = document.createElement('style'); style.textContent = ` background-color: #e3e4e4ff;font-size: 80%; scrollbar-color: #000077 #bada55;} .selected { background-color: #0d6efd;color: #ffff;} `; this.#shadow.appendChild(style); this.#shadow.appendChild(list); } /* Render an error message if JSON fetching fails */ renderError(error) { this.#shadow.innerHTML = `Error loading data: ${error.message}
`; } } /* Define the new custom element */ customElements.define('qd-panel', PanelComponent);