/* 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 = ` ${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 = ` @import url("../codicon@0.0.40/codicon.css"); ul { list-style-type: none; padding:0;margin:0;overflow: auto; background-color: #f8f9fa;font-size: 80%;} li { padding: 0 0 0 2px; cursor: pointer; width:100%; } li:not(.selected) :hover { background-color: #ccc; } .selected { background-color: #0d6efd;color: #ffff;} i {vertical-align: middle;} `; 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-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 = ` @import url("../codicon@0.0.40/codicon.css"); ul { list-style-type: none; padding:0;margin:0; background-color: #e3e4e4ff;font-size: 80%;} li { padding: 0 0 0 2px; border-bottom: 1px solid #ccc; cursor: pointer; width:100%; } li:not(.selected) :hover { background-color: #ccc; } .selected { background-color: #0d6efd;color: #ffff;} i {vertical-align: middle;} `; 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);