// @ts-check /** * Reads extension data from localStorage or fetches from data.json if not present. * Then displays the extensions in the DOM using a template. * * Expects the following HTML structure: * *
*/ (async function () { 'use strict'; /** @type {HTMLTemplateElement|null} */ const template = /** @type {HTMLTemplateElement|null} */ (document.getElementById('extension-template')); /** @type {HTMLElement|null} */ const extensionTable = document.querySelector('.extensions'); if (!template || !(template instanceof HTMLTemplateElement)) { console.error("template is not good."); return; } /** * @typedef {Object} Extension * @property {number} id - Unique identifier for the extension * @property {string} logo - URL or path to the extension's logo image * @property {string} name - Name of the extension * @property {string} description - Description of the extension * @property {boolean} isActive - Whether the extension is active */ /** * Saves extension records to localStorage. * @param {Extension[]} extensions * @returns {void} */ const saveRecords = (extensions) => { localStorage.setItem('extensionData', JSON.stringify(extensions)); }; /** * Adds a unique id to each extension record. * @param {Extension[]} extensions * @returns {Extension[]} */ const giveIdToRecords = (extensions) => { let id = 1; for (const extension of extensions) { extension.id = id; ++id; } return extensions; }; /** * Gets the list of extensions from localStorage or fetches from data.json. * @returns {Promise} */ const getExtensions = async () => { let extensions = localStorage.getItem("extensionData"); if (!extensions || extensions === "null") { // read from file try { const response = await fetch('data.json'); // Fetch JSON file const json = await response.json(); // Parse JSON const records = giveIdToRecords(Array.isArray(json) ? json : []); saveRecords(records); extensions = JSON.stringify(records); } catch (error) { console.error('Error fetching JSON:', error); extensions = ""; } } else { try { extensions = JSON.parse(extensions); } catch (e) { console.error('Error parsing extension data from localStorage:', e); extensions = ""; } } return Array.isArray(extensions) ? extensions : []; }; /** * Displays the list of extensions in the DOM. * @param {Extension[]} data - Array of extension objects to display * @returns {void} */ const displayExtensions = (data) => { if (!data) { console.error("No data to display or data is not an array."); return; } let id = 0; for (const extension of data) { // Clone the new row and insert it into the table const clone = template.content.cloneNode(true); if (!(clone instanceof DocumentFragment)) { console.error("Clone is not a DocumentFragment."); return; } const card = clone.querySelector('.extension'); if (!card) { console.error("Card element not found in the template."); return; } id++; card.setAttribute('data-id', id.toString()); /** @type {HTMLImageElement|null} */ let image = clone.querySelector("img"); if (!image) { console.error("Image element not found in the template."); return; } image.src = extension.logo; /** @type {HTMLHeadingElement|null} */ let h2 = clone.querySelector("h2"); if (!h2) { console.error("Heading element not found in the template."); return; } h2.textContent = extension.name; /** @type {HTMLParagraphElement|null} */ let p = clone.querySelector("p"); if (!p) { console.error("Paragraph element not found in the template."); return; } p.textContent = extension.description; /** @type {HTMLInputElement|null} */ let active = clone.querySelector("input[type='checkbox'][role='switch']"); if (!active || !(active instanceof HTMLInputElement)) { console.error("Checkbox element not found in the template."); return; } active.checked = extension.isActive; if (!extensionTable) { console.error("Extension table element not found in the document."); return; } extensionTable.appendChild(clone); } }; const enableEventhandlersRemoveButtons = () => { // find removeButton let removeButtons = document.querySelectorAll('.remove-button'); // add Eventlisteners removeButtons.forEach(element => { element.addEventListener("click", async (e) => { const button = e.target; if (!button || !(button instanceof Element)) { console.error("Button is null or not an Element."); return; } const cardElement = button.closest('.extension'); if (!cardElement) { console.error("Could not find closest .extension element."); return; } const card_id = cardElement.getAttribute('data-id'); if (!card_id) { console.error("data-id attribute not found on .extension element."); return; } // read the data from localStorage let extensions = localStorage.getItem("extensionData"); if (!extensions || extensions === "null") { console.error("No extension data found in localStorage."); return; } //filter out the extension with the given id const extensions_array = JSON.parse(extensions); if (Array.isArray(extensions_array)) { const filteredExtensions = extensions_array.filter(extension => extension.id !== parseInt(card_id)); // save the new data to localStorage saveRecords(filteredExtensions); // remove the card from the DOM document.querySelector(`.extension[data-id='${card_id}']`)?.remove(); } else { console.error("Parsed extensions is not an array."); } const extensions_new = await getExtensions(); displayExtensions(extensions_new) }) }); }; const enableEventhandlersSwitch = () => { // find all switches let switches = document.querySelectorAll('.extension input[type="checkbox"][role="switch"]'); // add Eventlisteners switches.forEach(element => { element.addEventListener("change", async (e) => { const checkbox = e.target; if (!checkbox || !(checkbox instanceof HTMLInputElement)) { console.error("Checkbox is null or not an HTMLInputElement."); return; } const cardElement = checkbox.closest('.extension'); if (!cardElement) { console.error("Could not find closest .extension element."); return; } const card_id = cardElement.getAttribute('data-id'); if (!card_id) { console.error("data-id attribute not found on .extension element."); return; } // read the data from localStorage let extensions = localStorage.getItem("extensionData"); if (!extensions || extensions === "null") { console.error("No extension data found in localStorage."); return; } // parse the data and update the isActive property const extensions_array = JSON.parse(extensions); if (Array.isArray(extensions_array)) { const extensionToUpdate = extensions_array.find(extension => extension.id === parseInt(card_id)); if (extensionToUpdate) { extensionToUpdate.isActive = checkbox.checked; // Update isActive property saveRecords(extensions_array); // Save updated records } else { console.error(`Extension with id ${card_id} not found.`); } } else { console.error("Parsed extensions is not an array."); } }); }); }; // Fetch and display extensions const extensions = await getExtensions(); displayExtensions(extensions); enableEventhandlersRemoveButtons(); enableEventhandlersSwitch(); })();