/* frontend for the part database * Copyright (C) 2023 King Kévin * SPDX-License-Identifier: GPL-3.0-or-later */ "use strict"; // the last search query var last_search = null; // the collection of parts var parts = null; // part field to populate const fields = ["name", "description", "details", "package", "manufacturer", "mpn", "family", "datasheet", "page", "location", "stock"]; // URLs to set const urls = ["page", "datasheet"]; // tables with key value information const tables = ["distributors", "properties", "components"]; function search() { const terms = document.getElementById('terms'); if (terms && terms.value && terms.value.length >= 3) { } else { return; } last_search = '/search/' + terms.value; let xhr = new XMLHttpRequest(); xhr.open('GET', last_search, true); xhr.onload = function() { if (decodeURI(this.responseURL).endsWith(last_search)) { parts = JSON.parse(this.response); results(); } }; xhr.onerror = function() { console.log("search call failed"); }; xhr.send(); } function results() { const results = document.getElementById('results'); let part_id = -1; if (results.selectedIndex >= 0) { part_id = parseInt(results.options[results.selectedIndex].value); } results.innerHTML = null; for (const part of parts) { const option = document.createElement('option'); option.setAttribute('value', part.id); option.innerHTML = part.name; if (part.description) { option.innerHTML += " (" + part.description + ")"; if (part_id == part.id) { option.selected = "selected"; } } results.appendChild(option); } select_part(); // in case we reselected } function clear() { // clear part fields for (const field of fields) { const input = document.getElementById('part_' + field); input.value = ""; } // clear URLs for (const field of urls) { const a = document.getElementById('url_' + field); a.href = null; } // clear tables for (const table of tables) { const body = document.getElementById(table); body.innerHTML = null; } } function select_part() { const results = document.getElementById('results'); if (results.selectedIndex >= 0) { let part_selected = parseInt(results.options[results.selectedIndex].value); for (const part of parts) { if (part.id == part_selected) { //console.log(part); // populate part fields for (const field of fields) { const input = document.getElementById('part_' + field); if (undefined === part[field]) { input.value = ""; } else { input.value = part[field]; } } // set URLs for (const field of urls) { const span = document.getElementById('url_' + field); const text = span.innerText; span.innerHTML = null; if (undefined === part[field] || null == part[field]) { span.innerHTML = text; } else { const a = document.createElement('a'); a.href = part[field]; a.innerText = text; span.appendChild(a); } } // set distributors const distributors = document.getElementById('distributors'); distributors.innerHTML = null; for (const distributor of part["distributors"]) { const tr = document.createElement('tr'); const td_name = document.createElement('td'); td_name.innerText = distributor.name; tr.appendChild(td_name); const td_sku = document.createElement('td'); const input = document.createElement('input'); input.type = "text"; input.style.width = "95%"; if (distributor.sku) { input.value = distributor.sku; } td_sku.appendChild(input); tr.appendChild(td_sku); const td_url = document.createElement('td'); if (distributor.url) { td_url.innerHTML = "link"; } tr.appendChild(td_url); distributors.appendChild(tr); } // add properties and components const kv_tables = ['properties', 'components']; for (const kv_table of kv_tables) { const table = document.getElementById(kv_table); table.innerHTML = null; part[kv_table][""] = ""; // empty field to add for (const key in part[kv_table]) { const tr = document.createElement('tr'); let td = document.createElement('td'); let input = document.createElement('input'); input.type = "text"; input.style.width = "95%"; input.value = key; td.appendChild(input); tr.appendChild(td); td = document.createElement('td'); input = document.createElement('input'); if ('components' == kv_table) { input.type = "number"; input.min = "0"; input.step = "1"; input.value = part[kv_table][key] } else { input.type = "text"; if ("object" == typeof part[kv_table][key]) { input.value = part[kv_table][key].join(","); } else { input.value = part[kv_table][key]; } } input.style.width = "95%"; td.appendChild(input); tr.appendChild(td); table.appendChild(tr); } } // add attachments const attachments = document.getElementById('attachments'); attachments.innerHTML = null; for (const attachment of part["attachments"]) { const a = document.createElement('a'); a.href = attachment; const img = document.createElement('img'); img.alt = attachment.split("/").slice(-1); img.src = attachment; a.appendChild(img); attachments.appendChild(a); } } } } } function delete_part() { if (null == parts) { return; } const results = document.getElementById('results'); if (results.selectedIndex < 0) { return; } const part_selected = parseInt(results.options[results.selectedIndex].value); const xhr = new XMLHttpRequest(); xhr.open('GET', '/delete/' + part_selected, true); xhr.onload = function() { clear(); search(); // refresh search }; xhr.onerror = function() { console.log("delete part failed"); }; xhr.send(); } function update_part() { // the part to update let part = {}; // its id const results = document.getElementById('results'); if (results.selectedIndex >= 0) { part.id = parseInt(results.options[results.selectedIndex].value); } // the fields for (const field of fields) { const input = document.getElementById('part_' + field); part[field] = input.value; } if (part["name"].length == 0) { return; } // get distributors part.distributors = {}; const distributors = document.getElementById('distributors'); for (const distributor of distributors.rows) { part.distributors[distributor.cells[0].innerText] = distributor.cells[1].firstChild.value; } // get properties part.properties = {}; const properties = document.getElementById('properties'); for (const prop of properties.rows) { const name = prop.cells[0].firstChild.value; const value = prop.cells[1].firstChild.value; if (name && name.length > 0 && value && value.length > 0) { part.properties[name] = value.split(","); } } // get components part.components = {}; const components = document.getElementById('components'); for (const component of components.rows) { const name = component.cells[0].firstChild.value; const quantity = component.cells[1].firstChild.value; if (name && name.length > 0) { part.components[name] = parseInt(quantity); } } //console.log(part); var post = new XMLHttpRequest(); post.open("POST", "part"); post.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); post.onload = function() { clear(); search(); // refresh search }; post.onerror = function() { console.log("update part failed"); }; post.send(JSON.stringify(part)); }