/* 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; // last selected part var part_id = 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=' + 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'); 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 span = document.getElementById('url_' + field); span.innerHTML = span.innerText; } // 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) { part_id = parseInt(results.options[results.selectedIndex].value); for (const part of parts) { if (part.id == part_id) { //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); } } // add distributors, properties and components for (const table of tables) { const tbody = document.getElementById(table); tbody.innerHTML = null; part[table].push({name: "", value: ""}); // empty field to add for (const row of part[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 = row.name; td.appendChild(input); tr.appendChild(td); if (null != row.value) { td = document.createElement('td'); input = document.createElement('input'); input.type = "text"; input.value = row.value; input.style.width = "95%"; td.appendChild(input); tr.appendChild(td); } if (row.sku) { td = document.createElement('td'); input = document.createElement('input'); input.type = "text"; input.value = row.sku; input.style.width = "95%"; td.appendChild(input); tr.appendChild(td); } if (null != row.quantity) { td = document.createElement('td'); input = document.createElement('input'); input.type = "number"; input.min = "0"; input.step = "1"; input.value = row.quantity; input.style.width = "95%"; td.appendChild(input); tr.appendChild(td); } if (row.url) { td = document.createElement('td'); td.innerHTML = "link"; tr.appendChild(td); } tbody.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.push({name: distributor.cells[0].firstChild.value, sku: distributor.cells[1].firstChild.value}); } // get properties part.properties = []; const properties = document.getElementById('properties'); for (const prop of properties.rows) { part.properties.push({name: prop.cells[0].firstChild.value, value: prop.cells[1].firstChild.value}); } // get components part.components = []; const components = document.getElementById('components'); for (const component of components.rows) { const nam = component.cells[0].firstChild.value; const q = component.cells[1].firstChild.value; if (nam && nam.length > 0) { part.components.push({name: nam, quantity: parseInt(q)}); } } 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)); }