From 01b1fd581e62213a38bcf429f72a82e4df105438 Mon Sep 17 00:00:00 2001 From: nps-jashton Date: Mon, 3 Aug 2026 20:21:13 +0000 Subject: [PATCH] Upload files to "Pricer Extension" --- Pricer Extension/content.js | 128 +++++++++++++++++++++++++++++++++ Pricer Extension/manifest.json | 23 ++++++ Pricer Extension/popup.html | 16 +++++ Pricer Extension/popup.js | 14 ++++ 4 files changed, 181 insertions(+) create mode 100644 Pricer Extension/content.js create mode 100644 Pricer Extension/manifest.json create mode 100644 Pricer Extension/popup.html create mode 100644 Pricer Extension/popup.js diff --git a/Pricer Extension/content.js b/Pricer Extension/content.js new file mode 100644 index 0000000..66eb3d7 --- /dev/null +++ b/Pricer Extension/content.js @@ -0,0 +1,128 @@ +// 1. Create the 'catcher' element (invisible to the user) +const catcher = document.createElement('input'); +catcher.style.cssText = 'position:fixed; opacity:0; pointer-events:none; top:0;'; +document.body.appendChild(catcher); + +const ext = typeof browser !== "undefined" ? browser : chrome; + +ext.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === "ARM_SCANNER") { + catcher.focus(); + sendResponse({status: "ready"}); + } +}); + +// 3. Handle the Scanner Input +catcher.addEventListener('keydown', async (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + // Decode the Base64 string back into a JSON string + const decodedData = atob(catcher.value); + const data = JSON.parse(decodedData); + + await processHardwareData(data); + catcher.value = ''; + + } +}); + +async function fillMatSelect(selectId, targetText) { + const selectEl = document.getElementById(selectId); + if (!selectEl) return; + + selectEl.focus(); + // 1. Open dropdown using mousedown (more reliable than click) + selectEl.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); + + // 2. Wait for overlay panel to appear + let panel; + for (let i = 0; i < 10; i++) { + panel = document.querySelector('.cdk-overlay-pane'); + if (panel) break; + await new Promise(r => setTimeout(r, 50)); + } + if (!panel) return; + + // 3. Find options inside overlay + const options = panel.querySelectorAll('mat-option, .mdc-list-item'); + + for (let option of options) { + const text = option.textContent.trim(); + if (text.includes(targetText)) { + option.click(); + return; + } + } +} + +function triggerEnter(input) { + const enterDown = new KeyboardEvent('keydown', { + bubbles: true, + cancelable: true, + key: 'Enter', + code: 'Enter', + keyCode: 13 + }); + + const enterUp = new KeyboardEvent('keyup', { + bubbles: true, + cancelable: true, + key: 'Enter', + code: 'Enter', + keyCode: 13 + }); + + input.dispatchEvent(enterDown); + input.dispatchEvent(enterUp); +} + +// 4. Fill the actual Angular/jQuery form +async function processHardwareData(data) { + + const group = 'input-product-group'; + const sub = 'input-sub-group'; + const cat = 'input-product-category'; + + const groupEl = document.getElementById(group); + groupEl.focus(); + groupEl.value = "ELECTRONICS"; + groupEl.dispatchEvent(new Event('input', { bubbles: true })); + triggerEnter(groupEl); + + const subEl = document.getElementById(sub); + subEl.focus(); + subEl.value = "COMPUTERS"; + subEl.dispatchEvent(new Event('input', { bubbles: true })); + triggerEnter(subEl); + + const catEl = document.getElementById(cat); + catEl.focus(); + catEl.value = "MISC (COMPUTERS)"; + catEl.dispatchEvent(new Event('input', { bubbles: true })); + triggerEnter(catEl); + + const map = { + 'b': 'input-brand', + 'd': 'input-prodDescrip', + 'n': 'text-condition-notes', + 's': 'input-style', + 'e': 'serial-tags' + }; + + for (const [key, id] of Object.entries(map)) { + const input = document.getElementById(id); + if (input && data[key]) { + input.value = data[key]; + + // Trigger events so the webpage 'wakes up' to the new data + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + } + } + + // Handle the special Angular Material dropdown + if (data['c']) { + await fillMatSelect('mat-select-10', data['c']); + } + +} \ No newline at end of file diff --git a/Pricer Extension/manifest.json b/Pricer Extension/manifest.json new file mode 100644 index 0000000..1e7ecdb --- /dev/null +++ b/Pricer Extension/manifest.json @@ -0,0 +1,23 @@ +{ + "manifest_version": 3, + "name": "Hardware Pricing Bridge", + "version": "0.1.0", + "permissions": ["activeTab", "scripting", "tabs"], + "action": { + "default_popup": "popup.html" + }, + "content_scripts": [ + { + "matches": ["https://pricer.thenpsenterprise.com/*"], + "js": ["content.js"] + } + ], + "host_permissions": [ + "https://pricer.thenpsenterprise.com/*" + ], + "browser_specific_settings": { + "gecko": { + "id": "hardware-pricing-bridge@npsstore.com" + } + } +} \ No newline at end of file diff --git a/Pricer Extension/popup.html b/Pricer Extension/popup.html new file mode 100644 index 0000000..ba9079a --- /dev/null +++ b/Pricer Extension/popup.html @@ -0,0 +1,16 @@ + + + + + + +

Scanner Bridge

+ + + + + \ No newline at end of file diff --git a/Pricer Extension/popup.js b/Pricer Extension/popup.js new file mode 100644 index 0000000..0df642f --- /dev/null +++ b/Pricer Extension/popup.js @@ -0,0 +1,14 @@ +const ext = typeof browser !== "undefined" ? browser : chrome; + +document.getElementById('arm-scanner').addEventListener('click', async () => { + try { + const tabs = await ext.tabs.query({ active: true, currentWindow: true }); + const tab = tabs[0]; + + await ext.tabs.sendMessage(tab.id, { action: "ARM_SCANNER" }); + + window.close(); + } catch (err) { + console.error("Error sending message:", err); + } +}); \ No newline at end of file