From 938f83fa06ffd458eb5f0db9dbb52b762dfe4df6 Mon Sep 17 00:00:00 2001 From: Benedikt Seeger <benedikt.seeger@ptb.de> Date: Mon, 24 Feb 2025 11:26:20 +0100 Subject: [PATCH] new JS codebase --- .gitignore | 2 + README.md | 188 ----- dcc-viewer/.idea/workspace.xml | 34 +- dcc-viewer/package-lock.json | 33 - dcc-viewer/package.json | 10 - dcc-viewer/public/index.html | 17 - dcc-viewer/public/styles.css | 32 - dcc-viewer/src/components/BaseViewer.js | 8 - dcc-viewer/src/components/JSONTreeViewer.js | 9 - .../src/components/accordionComponent.js | 20 - dcc-viewer/src/components/tabComponent.js | 29 - dcc-viewer/src/globalData.js | 3 - dcc-viewer/src/globalOptions.js | 1 - dcc-viewer/src/idRegistry.js | 1 - dcc-viewer/src/main.js | 23 - dcc-viewer/src/ui/adminRenderer.js | 72 -- dcc-viewer/src/ui/jsonTreeViewer.js | 11 - dcc-viewer/src/ui/languageSelector.js | 6 - dcc-viewer/src/ui/measurementRenderer.js | 63 -- dcc-viewer/src/ui/themeSwitcher.js | 4 - dcc-viewer/src/utils.js | 4 - dcc-viewer/src/viewerRegistry.js | 5 - dcc-viewer/src/xmlToJson.js | 6 - index.html | 12 + package-lock.json | 751 ++++++++++++++++++ package.json | 18 + project_snapshot.json | 4 +- project_structure.json | 35 +- src/app.js | 74 ++ src/main.js | 6 + src/renderers/AdminRenderer.js | 22 + src/renderers/MeasurementRenderer.js | 57 ++ src/renderers/SelectRenderer.js | 18 + src/styles.css | 20 + 34 files changed, 1016 insertions(+), 582 deletions(-) delete mode 100644 README.md delete mode 100644 dcc-viewer/package-lock.json delete mode 100644 dcc-viewer/package.json delete mode 100644 dcc-viewer/public/index.html delete mode 100644 dcc-viewer/public/styles.css delete mode 100644 dcc-viewer/src/components/BaseViewer.js delete mode 100644 dcc-viewer/src/components/JSONTreeViewer.js delete mode 100644 dcc-viewer/src/components/accordionComponent.js delete mode 100644 dcc-viewer/src/components/tabComponent.js delete mode 100644 dcc-viewer/src/globalData.js delete mode 100644 dcc-viewer/src/globalOptions.js delete mode 100644 dcc-viewer/src/idRegistry.js delete mode 100644 dcc-viewer/src/main.js delete mode 100644 dcc-viewer/src/ui/adminRenderer.js delete mode 100644 dcc-viewer/src/ui/jsonTreeViewer.js delete mode 100644 dcc-viewer/src/ui/languageSelector.js delete mode 100644 dcc-viewer/src/ui/measurementRenderer.js delete mode 100644 dcc-viewer/src/ui/themeSwitcher.js delete mode 100644 dcc-viewer/src/utils.js delete mode 100644 dcc-viewer/src/viewerRegistry.js delete mode 100644 dcc-viewer/src/xmlToJson.js create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/app.js create mode 100644 src/main.js create mode 100644 src/renderers/AdminRenderer.js create mode 100644 src/renderers/MeasurementRenderer.js create mode 100644 src/renderers/SelectRenderer.js create mode 100644 src/styles.css diff --git a/.gitignore b/.gitignore index 7880498..c4e2517 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ dcc-viewer/node_modules/ + +node_modules/ diff --git a/README.md b/README.md deleted file mode 100644 index 1ef7d7c..0000000 --- a/README.md +++ /dev/null @@ -1,188 +0,0 @@ -# **📜 Project Outline: Digital Calibration Certificate (DCC) Viewer** -🚀 **Goal:** Develop a fully **client-side** TypeScript application for visualizing, analyzing, and interacting with **Digital Calibration Certificates (DCC)**. - -✅ **Features:** -- **Load & Parse DCC XML** (`xml2js`) -- **Extract Key Data** (`administrativeData`, `measurementResults`, etc.) -- **Cross-Reference `id/refID`** (`idRegistry.ts`) -- **Multi-Language Support** (`lang="XX"`) -- **Interactive Plots & Tables** (`Plotly.js`, `DataTables.js`) - ---- - -## **📌 Features & Objectives** -### **1ï¸âƒ£ XML Parsing & Data Handling** -- 📂 **Load XML files** using `<input type="file">`. -- 🔄 **Convert XML → JSON** (`xml2js`). -- 🔗 **Store elements with `id` in `idRegistry.ts`** for easy lookup. -- ðŸ·ï¸ **Resolve `refID` references dynamically** across components. - -### **2ï¸âƒ£ UI Rendering & Components** -- 📊 **Data visualization with Plotly.js** (e.g., charge transfer coefficients, uncertainty). -- 📋 **Tabular representation with DataTables.js**. -- 📜 **Expandable/collapsible sections** for hierarchical data. -- 🌠**Localization support** (show only preferred language). -- 🎨 **Dark mode/light mode toggle**. - -### **3ï¸âƒ£ Interactive Features** -- 📠**Drag & Drop XML Upload**. -- 🔠**Search & Filter DCC elements**. -- ðŸ–±ï¸ **Click to view referenced elements (`refID`)**. -- 📤 **Export filtered tables to CSV/JSON**. - ---- - -## **📂 Folder Structure** -``` -dcc-viewer/ -│── src/ # Source code -│ ├── main.ts # Main entry point -│ ├── xmlToJson.ts # Converts XML → JSON -│ ├── idRegistry.ts # Stores global IDs for cross-referencing -│ ├── globalData.ts # Stores parsed XML data -│ ├── globalOptions.ts # User preferences (language, theme, etc.) -│ ├── viewerRegistry.ts # Maps XML elements to viewer components -│ ├── utils.ts # Helper functions (language filtering, ID lookup) -│ ├── components/ # UI Components -│ │ ├── BaseViewer.ts # Abstract class for all viewers -│ │ ├── AdministrativeDataViewer.ts # View DCC metadata -│ │ ├── MeasurementResultsViewer.ts # View measurement results -│ │ ├── TableViewer.ts # Displays tables for tabular data -│ │ ├── PlotViewer.ts # Uses Plotly.js for interactive plots -│ │ ├── IdentificationViewer.ts # Shows ID-based data -│ │ ├── EquipmentViewer.ts # Displays measuring equipment -│ │ ├── InfluenceConditionsViewer.ts # Shows environmental conditions -│ │ ├── StatementsViewer.ts # Displays decision rules & statements -│ │ ├── ReferenceViewer.ts # Displays cross-referenced elements -│ ├── ui/ # UI-related code -│ │ ├── languageSelector.ts # Dropdown to change language -│ │ ├── themeSwitcher.ts # Dark mode toggle -│ ├── plots/ # Plotly-based visualization components -│── public/ # Static assets -│ ├── index.html # Main UI -│ ├── styles.css # Styling -│── package.json # Dependencies -│── tsconfig.json # TypeScript config -│── README.md # Documentation -``` - ---- - -## **📜 `README.md` (Project Documentation)** -```md -# ðŸ—ï¸ Digital Calibration Certificate (DCC) Viewer -A fully client-side **TypeScript application** for visualizing and analyzing **Digital Calibration Certificates (DCC)**. - ---- - -## ✨ Features -- 📂 **Load DCC XML files** and parse into structured JSON. -- 🔗 **ID & refID-based cross-referencing** for linked elements. -- 🌠**Localization support** (Choose preferred language for display). -- 📊 **Interactive Plots** using [Plotly.js](https://plotly.com/javascript/). -- 📋 **Sortable, Filterable Tables** using [DataTables.js](https://datatables.net/). -- 🎨 **Dark Mode / Light Mode** UI. -- 🔠**Search & Filtering** for DCC elements. -- 📤 **Export Options** (Download tables as CSV/JSON). - ---- - -## 📦 Installation & Setup -### **1ï¸âƒ£ Install Dependencies** -```sh -npm install -``` -### **2ï¸âƒ£ Run Locally** -```sh -npx vite -``` -or serve via a local HTTP server: -```sh -npx http-server public -``` - ---- - -## 📚 Project Structure -``` -dcc-viewer/ -│── src/ -│ ├── main.ts # Main app logic -│ ├── xmlToJson.ts # Converts XML → JSON -│ ├── idRegistry.ts # Global storage for `id` elements -│ ├── globalOptions.ts # Stores localization & UI preferences -│ ├── viewerRegistry.ts # Registers custom viewers -│ ├── utils.ts # Helper functions (language filtering, ID lookup) -│ ├── components/ # UI Components for rendering DCC data -│ │ ├── BaseViewer.ts -│ │ ├── AdministrativeDataViewer.ts -│ │ ├── MeasurementResultsViewer.ts -│ │ ├── TableViewer.ts -│ │ ├── PlotViewer.ts -│ │ ├── IdentificationViewer.ts -│ │ ├── EquipmentViewer.ts -│ │ ├── InfluenceConditionsViewer.ts -│ │ ├── StatementsViewer.ts -│ │ ├── ReferenceViewer.ts -│── public/ -│ ├── index.html # UI entry point -│ ├── styles.css # Basic styles -│── package.json -│── tsconfig.json -``` - ---- - -## 🚀 Usage -1. Open **`index.html`** in a browser. -2. Click **"Upload XML"** to load a DCC file. -3. Explore **linked elements**, **localized texts**, and **visualizations**. - ---- - -## 🛠Technologies Used -- **TypeScript** (Type Safety) -- **xml2js** (XML → JSON Conversion) -- **Plotly.js** (Interactive Plots) -- **DataTables.js** (Filterable Tables) -- **Vite** (Development Server) -- **CSS/HTML** (Basic UI Styling) - ---- - -## 📊 Interactive Features -| Feature | Description | -|---------|------------| -| 📂 XML Parsing | Load DCC, store it in global state | -| 🌠Localization | Show only elements in preferred language | -| 🔗 ID Linking | Resolve `refID` dynamically | -| 📊 Plots | Render line charts, histograms using Plotly | -| 📋 Tables | Sort, filter, paginate data using DataTables | -| 🎨 Dark Mode | Switch between light/dark themes | - ---- - -## 🛠Future Improvements -- ✅ **Additional Graph Types** -- ✅ **Export Graphs as Images** -- ✅ **Drag & Drop XML Upload** -- ✅ **LocalStorage for Preferences** - ---- - -## 📜 License -MIT License -``` - ---- - -## **🚀 Next Steps** -1. **Implement File Upload UI** (`index.html`, `main.ts`). -2. **Integrate `xml2js` & Build `idRegistry.ts`**. -3. **Implement Measurement & Equipment Viewers** (`MeasurementResultsViewer.ts`, `EquipmentViewer.ts`). -4. **Add Table & Plot Components** (`TableViewer.ts`, `PlotViewer.ts`). -5. **Add Global Language Toggle & Theme Switcher**. - ---- - -### **💡 Does this refactored structure match your vision?** 😃 \ No newline at end of file diff --git a/dcc-viewer/.idea/workspace.xml b/dcc-viewer/.idea/workspace.xml index 85843e9..369cbba 100644 --- a/dcc-viewer/.idea/workspace.xml +++ b/dcc-viewer/.idea/workspace.xml @@ -5,17 +5,27 @@ </component> <component name="ChangeListManager"> <list default="true" id="c3d759c9-e9f8-41d4-b9b5-ef12db68e70c" name="Changes" comment=""> - <change afterPath="$PROJECT_DIR$/src/components/accordionComponent.js" afterDir="false" /> - <change afterPath="$PROJECT_DIR$/src/components/tabComponent.js" afterDir="false" /> - <change afterPath="$PROJECT_DIR$/src/ui/adminRenderer.js" afterDir="false" /> - <change afterPath="$PROJECT_DIR$/src/ui/jsonTreeViewer.js" afterDir="false" /> - <change afterPath="$PROJECT_DIR$/src/ui/measurementRenderer.js" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/public/styles.css" beforeDir="false" afterPath="$PROJECT_DIR$/public/styles.css" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/globalData.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/globalData.js" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/main.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.js" afterDir="false" /> - <change beforePath="$PROJECT_DIR$/src/xmlToJson.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/xmlToJson.js" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/public/styles.css" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/components/BaseViewer.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/components/JSONTreeViewer.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/components/accordionComponent.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/components/tabComponent.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/globalData.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/globalOptions.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/idRegistry.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/main.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/ui/adminRenderer.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/ui/jsonTreeViewer.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/ui/languageSelector.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/ui/measurementRenderer.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/ui/themeSwitcher.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/utils.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/viewerRegistry.js" beforeDir="false" /> + <change beforePath="$PROJECT_DIR$/src/xmlToJson.js" beforeDir="false" /> </list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> @@ -85,7 +95,7 @@ <workItem from="1740132146315" duration="24000" /> <workItem from="1740132175271" duration="89000" /> <workItem from="1740158794192" duration="1155000" /> - <workItem from="1740380748268" duration="2676000" /> + <workItem from="1740380748268" duration="5118000" /> </task> <servers /> </component> diff --git a/dcc-viewer/package-lock.json b/dcc-viewer/package-lock.json deleted file mode 100644 index dda2d33..0000000 --- a/dcc-viewer/package-lock.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "dcc-viewer", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dcc-viewer", - "version": "1.0.0", - "dependencies": { - "xml-js": "^1.6.11" - } - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" - }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "license": "MIT", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - } - } -} diff --git a/dcc-viewer/package.json b/dcc-viewer/package.json deleted file mode 100644 index 68a489d..0000000 --- a/dcc-viewer/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "dcc-viewer", - "version": "1.0.0", - "scripts": { - "dev": "vite" - }, - "dependencies": { - "xml-js": "^1.6.11" - } -} diff --git a/dcc-viewer/public/index.html b/dcc-viewer/public/index.html deleted file mode 100644 index 758d4ea..0000000 --- a/dcc-viewer/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <title>DCC Viewer</title> - <script type="module" src="/src/main.js"></script> - <link rel="stylesheet" href="/public/styles.css"> -</head> -<body> -<h1>DCC Viewer</h1> - -<input type="file" id="file-input" accept=".xml"> - -<div id="admin-data-container"></div> -<div id="measurement-data-container"></div> -</body> -</html> diff --git a/dcc-viewer/public/styles.css b/dcc-viewer/public/styles.css deleted file mode 100644 index 79e2888..0000000 --- a/dcc-viewer/public/styles.css +++ /dev/null @@ -1,32 +0,0 @@ -.accordion-header { - background-color: #f0f0f0; - border: none; - padding: 10px; - cursor: pointer; - width: 100%; - text-align: left; -} - -.accordion-content { - display: none; - padding: 10px; -} - -.accordion-content.open { - display: block; -} - -.tabs { - display: flex; - gap: 10px; -} - -.tabs button { - padding: 5px 10px; - cursor: pointer; -} - -.tab-content { - border: 1px solid #ddd; - padding: 10px; -} diff --git a/dcc-viewer/src/components/BaseViewer.js b/dcc-viewer/src/components/BaseViewer.js deleted file mode 100644 index 11d24a9..0000000 --- a/dcc-viewer/src/components/BaseViewer.js +++ /dev/null @@ -1,8 +0,0 @@ -export class BaseViewer { - constructor(sectionData) { - this.sectionData = sectionData; - } - render() { - throw new Error('render() must be implemented in subclasses'); - } -} \ No newline at end of file diff --git a/dcc-viewer/src/components/JSONTreeViewer.js b/dcc-viewer/src/components/JSONTreeViewer.js deleted file mode 100644 index 4fcd426..0000000 --- a/dcc-viewer/src/components/JSONTreeViewer.js +++ /dev/null @@ -1,9 +0,0 @@ -import { BaseViewer } from './BaseViewer.js'; - -export class JSONTreeViewer extends BaseViewer { - render() { - const container = document.createElement('pre'); - container.textContent = JSON.stringify(this.sectionData, null, 2); - return container; - } -} \ No newline at end of file diff --git a/dcc-viewer/src/components/accordionComponent.js b/dcc-viewer/src/components/accordionComponent.js deleted file mode 100644 index bc77325..0000000 --- a/dcc-viewer/src/components/accordionComponent.js +++ /dev/null @@ -1,20 +0,0 @@ -export function createAccordion(title, contentElement) { - const container = document.createElement('div'); - container.classList.add('accordion'); - - const header = document.createElement('button'); - header.textContent = title; - header.classList.add('accordion-header'); - - const content = document.createElement('div'); - content.classList.add('accordion-content'); - content.appendChild(contentElement); - - header.addEventListener('click', () => { - content.classList.toggle('open'); - }); - - container.appendChild(header); - container.appendChild(content); - return container; -} diff --git a/dcc-viewer/src/components/tabComponent.js b/dcc-viewer/src/components/tabComponent.js deleted file mode 100644 index 51b08be..0000000 --- a/dcc-viewer/src/components/tabComponent.js +++ /dev/null @@ -1,29 +0,0 @@ -export function createTabs(tabsData) { - const container = document.createElement('div'); - container.classList.add('tabs-container'); - - const tabs = document.createElement('div'); - tabs.classList.add('tabs'); - - const contentContainer = document.createElement('div'); - contentContainer.classList.add('tab-content'); - - tabsData.forEach((tab, index) => { - const button = document.createElement('button'); - button.textContent = tab.title; - button.addEventListener('click', () => { - contentContainer.innerHTML = ''; - contentContainer.appendChild(tab.content); - }); - - tabs.appendChild(button); - - if (index === 0) { - contentContainer.appendChild(tab.content); - } - }); - - container.appendChild(tabs); - container.appendChild(contentContainer); - return container; -} diff --git a/dcc-viewer/src/globalData.js b/dcc-viewer/src/globalData.js deleted file mode 100644 index d3b8d90..0000000 --- a/dcc-viewer/src/globalData.js +++ /dev/null @@ -1,3 +0,0 @@ -export const globalData = { - dcc: null // This will hold the parsed DCC JSON data -}; \ No newline at end of file diff --git a/dcc-viewer/src/globalOptions.js b/dcc-viewer/src/globalOptions.js deleted file mode 100644 index 09c0db1..0000000 --- a/dcc-viewer/src/globalOptions.js +++ /dev/null @@ -1 +0,0 @@ -export const globalOptions = { preferredLanguage: 'en' }; \ No newline at end of file diff --git a/dcc-viewer/src/idRegistry.js b/dcc-viewer/src/idRegistry.js deleted file mode 100644 index d61c792..0000000 --- a/dcc-viewer/src/idRegistry.js +++ /dev/null @@ -1 +0,0 @@ -export const idRegistry = {}; \ No newline at end of file diff --git a/dcc-viewer/src/main.js b/dcc-viewer/src/main.js deleted file mode 100644 index 29b595d..0000000 --- a/dcc-viewer/src/main.js +++ /dev/null @@ -1,23 +0,0 @@ -import { convertXMLToJSON } from './xmlToJson.js'; -import { globalData } from './globalData.js'; -import { renderAdministrativeData } from './ui/adminRenderer.js'; -import { renderMeasurementResults } from './ui/measurementRenderer.js'; - -const fileInput = document.getElementById('file-input'); - -fileInput.addEventListener('change', async (event) => { - const file = event.target.files?.[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = async () => { - const xmlString = reader.result; - globalData.dcc = await convertXMLToJSON(xmlString); // Store DCC globally - - console.log("DCC Data Loaded:", globalData.dcc); - - renderAdministrativeData(globalData.dcc.administrativeData); - renderMeasurementResults(globalData.dcc.measurementResults); - }; - reader.readAsText(file); -}); diff --git a/dcc-viewer/src/ui/adminRenderer.js b/dcc-viewer/src/ui/adminRenderer.js deleted file mode 100644 index 857d6a4..0000000 --- a/dcc-viewer/src/ui/adminRenderer.js +++ /dev/null @@ -1,72 +0,0 @@ -import { createAccordion } from '../components/accordionComponent.js'; -import { JSONTreeViewer } from './jsonTreeViewer.js'; -import { globalData } from '../globalData.js'; - -export function renderAdministrativeData() { - const container = document.getElementById('admin-data-container'); - container.innerHTML = ''; // Clear previous content - - const dccRoot = globalData.dcc?.['dcc:digitalCalibrationCertificate']; - if (!dccRoot) { - container.innerHTML = "<p>No Digital Calibration Certificate Found</p>"; - return; - } - - const adminData = dccRoot?.['dcc:administrativeData']; - if (!adminData) { - container.innerHTML = "<p>No Administrative Data Found</p>"; - return; - } - - // 🔹 SOFTWARE SECTION - const softwareContainer = document.createElement('div'); - const softwareList = (adminData?.['dcc:dccSoftware']?.['dcc:software'] || []).map(software => { - return ` - <div> - <strong>${software?.['dcc:name']?.['dcc:content'] || 'Unknown Software'}</strong> - (v${software?.['dcc:release'] || 'N/A'}) - ${software?.['dcc:type'] || 'N/A'} - </div> - `; - }).join(''); - softwareContainer.innerHTML = `<h3>Software Used</h3>${softwareList}`; - - // 🔹 CORE DATA SECTION - const coreData = adminData?.['dcc:coreData'] || {}; - const coreDataContainer = document.createElement('div'); - coreDataContainer.innerHTML = ` - <h3>Core Data</h3> - <p><strong>Country:</strong> ${coreData?.['dcc:countryCodeISO3166_1']?._text || 'N/A'}</p> - <p><strong>Languages:</strong> ${Array.isArray(coreData?.['dcc:usedLangCodeISO639_1']) - ? coreData['dcc:usedLangCodeISO639_1'].map(lang => lang._text).join(', ') - : coreData?.['dcc:usedLangCodeISO639_1']?._text || 'N/A'}</p> - <p><strong>Unique Identifier:</strong> ${coreData?.['dcc:uniqueIdentifier']?._text || 'N/A'}</p> - <p><strong>Issue Date:</strong> ${coreData?.['dcc:issueDate']?._text || 'N/A'}</p> - `; - - // 🔹 CALIBRATION LAB - const labInfo = adminData?.['dcc:calibrationLaboratory']?.['dcc:contact'] || {}; - const labContainer = document.createElement('div'); - labContainer.innerHTML = ` - <h3>Calibration Laboratory</h3> - <p><strong>Name:</strong> ${labInfo?.['dcc:name']?.['dcc:content']?._text || 'N/A'}</p> - <p><strong>Email:</strong> ${labInfo?.['dcc:eMail']?._text || 'N/A'}</p> - <p><strong>Phone:</strong> ${labInfo?.['dcc:phone']?._text || 'N/A'}</p> - `; - - // 🔹 RESPONSIBLE PERSONS - const responsiblePersons = (adminData?.['dcc:respPersons']?.['dcc:respPerson'] || []).map(person => { - return `<p>${person?.['dcc:person']?.['dcc:name']?.['dcc:content']?._text || 'Unknown Person'} - ${person?.['dcc:mainSigner'] ? '(Main Signer)' : ''}</p>`; - }).join(''); - const responsibleContainer = document.createElement('div'); - responsibleContainer.innerHTML = `<h3>Responsible Persons</h3>${responsiblePersons}`; - - // 🔹 ADD SECTIONS TO ACCORDION - container.appendChild(createAccordion("Software Used", softwareContainer)); - container.appendChild(createAccordion("Core Data", coreDataContainer)); - container.appendChild(createAccordion("Calibration Laboratory", labContainer)); - container.appendChild(createAccordion("Responsible Persons", responsibleContainer)); - - // 🔹 JSON DEBUG VIEW - container.appendChild(createAccordion("Raw JSON Data (Debug)", new JSONTreeViewer(adminData).render())); -} diff --git a/dcc-viewer/src/ui/jsonTreeViewer.js b/dcc-viewer/src/ui/jsonTreeViewer.js deleted file mode 100644 index fdb88bb..0000000 --- a/dcc-viewer/src/ui/jsonTreeViewer.js +++ /dev/null @@ -1,11 +0,0 @@ -export class JSONTreeViewer { - constructor(data) { - this.data = data; - } - - render() { - const container = document.createElement('pre'); - container.textContent = JSON.stringify(this.data, null, 2); - return container; - } -} diff --git a/dcc-viewer/src/ui/languageSelector.js b/dcc-viewer/src/ui/languageSelector.js deleted file mode 100644 index 98b697e..0000000 --- a/dcc-viewer/src/ui/languageSelector.js +++ /dev/null @@ -1,6 +0,0 @@ -import { globalOptions } from '../globalOptions.js'; - -const languageSelect = document.getElementById('language-select'); -languageSelect.addEventListener('change', (event) => { - globalOptions.preferredLanguage = event.target.value; -}); \ No newline at end of file diff --git a/dcc-viewer/src/ui/measurementRenderer.js b/dcc-viewer/src/ui/measurementRenderer.js deleted file mode 100644 index 4b64b37..0000000 --- a/dcc-viewer/src/ui/measurementRenderer.js +++ /dev/null @@ -1,63 +0,0 @@ -import { createTabs } from '../components/tabComponent.js'; -import { JSONTreeViewer } from './jsonTreeViewer.js'; -import { globalData } from '../globalData.js'; - -export function renderMeasurementResults() { - const container = document.getElementById('measurement-data-container'); - container.innerHTML = ''; // Clear previous content - - const dccRoot = globalData.dcc?.['dcc:digitalCalibrationCertificate']; - if (!dccRoot) { - container.innerHTML = "<p>No Digital Calibration Certificate Found</p>"; - return; - } - - const measurements = dccRoot?.['dcc:measurementResults']; - if (!measurements || !measurements['dcc:measurementResult']) { - container.innerHTML = "<p>No Measurement Results Found</p>"; - return; - } - - const tabs = (Array.isArray(measurements['dcc:measurementResult']) ? - measurements['dcc:measurementResult'] : [measurements['dcc:measurementResult']] - ).map((result, index) => { - const resultContainer = document.createElement('div'); - - // 🔹 Measurement Methods - const methods = result?.['dcc:usedMethods']?.['dcc:usedMethod'] || []; - const methodsList = (Array.isArray(methods) ? methods : [methods]).map(method => ` - <p><strong>${method?.['dcc:name']?.['dcc:content']?._text || 'Unknown Method'}</strong>: - ${method?.['dcc:description']?.['dcc:content']?._text || 'No description'}</p> - `).join(''); - - // 🔹 Measurement Equipment - const equipments = result?.['dcc:measuringEquipments']?.['dcc:measuringEquipment'] || []; - const equipmentList = (Array.isArray(equipments) ? equipments : [equipments]).map(eq => ` - <p><strong>${eq?.['dcc:name']?.['dcc:content']?._text || 'Unknown Equipment'}</strong> - - ${eq?.['dcc:model']?._text || 'N/A'}</p> - `).join(''); - - // 🔹 Measurement Results - const results = result?.['dcc:results']?.['dcc:result'] || []; - const resultsList = (Array.isArray(results) ? results : [results]).map(res => ` - <h4>${res?.['dcc:name']?.['dcc:content']?._text || 'Unknown Result'}</h4> - <pre>${JSON.stringify(res['dcc:data'], null, 2)}</pre> - `).join(''); - - resultContainer.innerHTML = ` - <h3>Measurement Methods</h3>${methodsList} - <h3>Equipment Used</h3>${equipmentList} - <h3>Results</h3>${resultsList} - `; - - return { - title: `Measurement ${index + 1}`, - content: resultContainer - }; - }); - - container.appendChild(createTabs(tabs)); - - // 🔹 JSON DEBUGGING VIEW - container.appendChild(createTabs([{ title: "Raw JSON", content: new JSONTreeViewer(measurements).render() }])); -} diff --git a/dcc-viewer/src/ui/themeSwitcher.js b/dcc-viewer/src/ui/themeSwitcher.js deleted file mode 100644 index 2996ddc..0000000 --- a/dcc-viewer/src/ui/themeSwitcher.js +++ /dev/null @@ -1,4 +0,0 @@ -const themeToggle = document.getElementById('theme-toggle'); -themeToggle.addEventListener('click', () => { - document.body.classList.toggle('dark-mode'); -}); \ No newline at end of file diff --git a/dcc-viewer/src/utils.js b/dcc-viewer/src/utils.js deleted file mode 100644 index aaaf614..0000000 --- a/dcc-viewer/src/utils.js +++ /dev/null @@ -1,4 +0,0 @@ -export function getLocalizedText(elements) { - if (!Array.isArray(elements)) return elements; - return elements[0]._ || ''; -} \ No newline at end of file diff --git a/dcc-viewer/src/viewerRegistry.js b/dcc-viewer/src/viewerRegistry.js deleted file mode 100644 index 8de1bf6..0000000 --- a/dcc-viewer/src/viewerRegistry.js +++ /dev/null @@ -1,5 +0,0 @@ -import { JSONTreeViewer } from './components/JSONTreeViewer.js'; - -export function getViewerForElement() { - return JSONTreeViewer; -} \ No newline at end of file diff --git a/dcc-viewer/src/xmlToJson.js b/dcc-viewer/src/xmlToJson.js deleted file mode 100644 index b25a854..0000000 --- a/dcc-viewer/src/xmlToJson.js +++ /dev/null @@ -1,6 +0,0 @@ -import { xml2json } from 'xml-js'; - -export function convertXMLToJSON(xmlString) { - const jsonData = xml2json(xmlString, { compact: true, spaces: 2 }); - return JSON.parse(jsonData); -} diff --git a/index.html b/index.html new file mode 100644 index 0000000..f5b09d4 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>DCC Viewer</title> + <link rel="stylesheet" href="/src/styles.css"> +</head> +<body> + <div id="app"></div> + <script type="module" src="/src/main.js"></script> +</body> +</html> diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..398aebb --- /dev/null +++ b/package-lock.json @@ -0,0 +1,751 @@ +{ + "name": "dcc-viewer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dcc-viewer", + "version": "1.0.0", + "dependencies": { + "jsoneditor": "^9.5.6", + "plotly.js-dist": "^2.18.2", + "xml2js": "^0.4.23" + }, + "devDependencies": { + "vite": "^4.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@sphinxxxx/color-conversion": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz", + "integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==", + "license": "ISC" + }, + "node_modules/ace-builds": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.39.0.tgz", + "integrity": "sha512-MqoZojv4gpc5QyTMor/dS6kmruDV9db9LVZbCiT4qYz6WsDiv4qyG5f7ZPc+wjUl6oLMqgCAsBjo1whdSVyMlQ==", + "license": "BSD-3-Clause" + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "license": "MIT" + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json-source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.6.1.tgz", + "integrity": "sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==", + "license": "MIT" + }, + "node_modules/jsoneditor": { + "version": "9.10.5", + "resolved": "https://registry.npmjs.org/jsoneditor/-/jsoneditor-9.10.5.tgz", + "integrity": "sha512-fVZ0NMt+zm4rqTKBv2x7zPdLeaRyKo1EjJkaR1QjK4gEM1rMwICILYSW1OPxSc1qqyAoDaA/eeNrluKoxOocCA==", + "license": "Apache-2.0", + "dependencies": { + "ace-builds": "^1.31.1", + "ajv": "^6.12.6", + "javascript-natural-sort": "^0.7.1", + "jmespath": "^0.16.0", + "json-source-map": "^0.6.1", + "jsonrepair": "3.1.0", + "mobius1-selectr": "^2.4.13", + "picomodal": "^3.0.0", + "vanilla-picker": "^2.12.2" + } + }, + "node_modules/jsonrepair": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.1.0.tgz", + "integrity": "sha512-idqReg23J0PVRAADmZMc5xQM3xeOX5bTB6OTyMnzq33IXJXmn9iJuWIEvGmrN80rQf4d7uLTMEDwpzujNcI0Rg==", + "license": "ISC", + "bin": { + "jsonrepair": "bin/cli.js" + } + }, + "node_modules/mobius1-selectr": { + "version": "2.4.13", + "resolved": "https://registry.npmjs.org/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz", + "integrity": "sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomodal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/picomodal/-/picomodal-3.0.0.tgz", + "integrity": "sha512-FoR3TDfuLlqUvcEeK5ifpKSVVns6B4BQvc8SDF6THVMuadya6LLtji0QgUDSStw0ZR2J7I6UGi5V2V23rnPWTw==", + "license": "MIT" + }, + "node_modules/plotly.js-dist": { + "version": "2.35.3", + "resolved": "https://registry.npmjs.org/plotly.js-dist/-/plotly.js-dist-2.35.3.tgz", + "integrity": "sha512-dqB9+FUyBFZN04xWnZoYwaeeF4Jj9T/m0CHYmoozmPC3R4Dy0TRJsHgbRVLPxgYQqodzniVUj17+2wmJuGaZAg==", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/rollup": { + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vanilla-picker": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.3.tgz", + "integrity": "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==", + "license": "ISC", + "dependencies": { + "@sphinxxxx/color-conversion": "^2.2.2" + } + }, + "node_modules/vite": { + "version": "4.5.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz", + "integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d6ed699 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "dcc-viewer", + "version": "1.0.0", + "description": "Digital Calibration Certificate Viewer", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "xml2js": "^0.4.23", + "jsoneditor": "^9.5.6", + "plotly.js-dist": "^2.18.2" + }, + "devDependencies": { + "vite": "^4.0.0" + } +} diff --git a/project_snapshot.json b/project_snapshot.json index 3099818..c6f2003 100644 --- a/project_snapshot.json +++ b/project_snapshot.json @@ -12,8 +12,8 @@ "src/components/tabComponent.js": "export function createTabs(tabsData) {\n const container = document.createElement('div');\n container.classList.add('tabs-container');\n\n const tabs = document.createElement('div');\n tabs.classList.add('tabs');\n\n const contentContainer = document.createElement('div');\n contentContainer.classList.add('tab-content');\n\n tabsData.forEach((tab, index) => {\n const button = document.createElement('button');\n button.textContent = tab.title;\n button.addEventListener('click', () => {\n contentContainer.innerHTML = '';\n contentContainer.appendChild(tab.content);\n });\n\n tabs.appendChild(button);\n\n if (index === 0) {\n contentContainer.appendChild(tab.content);\n }\n });\n\n container.appendChild(tabs);\n container.appendChild(contentContainer);\n return container;\n}\n", "src/ui/languageSelector.js": "import { globalOptions } from '../globalOptions.js';\n\nconst languageSelect = document.getElementById('language-select');\nlanguageSelect.addEventListener('change', (event) => {\n globalOptions.preferredLanguage = event.target.value;\n});", "src/ui/themeSwitcher.js": "const themeToggle = document.getElementById('theme-toggle');\nthemeToggle.addEventListener('click', () => {\n document.body.classList.toggle('dark-mode');\n});", - "src/ui/adminRenderer.js": "import { createAccordion } from '../components/accordionComponent.js';\nimport { JSONTreeViewer } from './jsonTreeViewer.js';\n\nexport function renderAdministrativeData(adminData) {\n const container = document.getElementById('admin-data-container');\n container.innerHTML = ''; // Clear previous content\n\n if (!adminData) {\n container.innerHTML = \"<p>No Administrative Data Found</p>\";\n return;\n }\n\n const jsonViewer = new JSONTreeViewer(adminData);\n const accordion = createAccordion(\"Administrative Data\", jsonViewer.render());\n\n container.appendChild(accordion);\n}\n", - "src/ui/measurementRenderer.js": "import { createTabs } from '../components/tabComponent.js';\nimport { JSONTreeViewer } from './jsonTreeViewer.js';\n\nexport function renderMeasurementResults(measurements) {\n const container = document.getElementById('measurement-data-container');\n container.innerHTML = ''; // Clear previous content\n\n if (!measurements || !measurements.measurementResult) {\n container.innerHTML = \"<p>No Measurement Results Found</p>\";\n return;\n }\n\n const tabs = measurements.measurementResult.map((result, index) => ({\n title: `Result ${index + 1}`,\n content: new JSONTreeViewer(result).render()\n }));\n\n const tabsComponent = createTabs(tabs);\n container.appendChild(tabsComponent);\n}\n", + "src/ui/adminRenderer.js": "import { createAccordion } from '../components/accordionComponent.js';\nimport { JSONTreeViewer } from './jsonTreeViewer.js';\nimport { globalData } from '../globalData.js';\n\nexport function renderAdministrativeData() {\n const container = document.getElementById('admin-data-container');\n container.innerHTML = ''; // Clear previous content\n\n const dccRoot = globalData.dcc?.['dcc:digitalCalibrationCertificate'];\n if (!dccRoot) {\n container.innerHTML = \"<p>No Digital Calibration Certificate Found</p>\";\n return;\n }\n\n const adminData = dccRoot?.['dcc:administrativeData'];\n if (!adminData) {\n container.innerHTML = \"<p>No Administrative Data Found</p>\";\n return;\n }\n\n // 🔹 SOFTWARE SECTION\n const softwareContainer = document.createElement('div');\n const softwareList = (adminData?.['dcc:dccSoftware']?.['dcc:software'] || []).map(software => {\n return `\n <div>\n <strong>${software?.['dcc:name']?.['dcc:content'] || 'Unknown Software'}</strong>\n (v${software?.['dcc:release'] || 'N/A'}) - ${software?.['dcc:type'] || 'N/A'}\n </div>\n `;\n }).join('');\n softwareContainer.innerHTML = `<h3>Software Used</h3>${softwareList}`;\n\n // 🔹 CORE DATA SECTION\n const coreData = adminData?.['dcc:coreData'] || {};\n const coreDataContainer = document.createElement('div');\n coreDataContainer.innerHTML = `\n <h3>Core Data</h3>\n <p><strong>Country:</strong> ${coreData?.['dcc:countryCodeISO3166_1']?._text || 'N/A'}</p>\n <p><strong>Languages:</strong> ${Array.isArray(coreData?.['dcc:usedLangCodeISO639_1'])\n ? coreData['dcc:usedLangCodeISO639_1'].map(lang => lang._text).join(', ')\n : coreData?.['dcc:usedLangCodeISO639_1']?._text || 'N/A'}</p>\n <p><strong>Unique Identifier:</strong> ${coreData?.['dcc:uniqueIdentifier']?._text || 'N/A'}</p>\n <p><strong>Issue Date:</strong> ${coreData?.['dcc:issueDate']?._text || 'N/A'}</p>\n `;\n\n // 🔹 CALIBRATION LAB\n const labInfo = adminData?.['dcc:calibrationLaboratory']?.['dcc:contact'] || {};\n const labContainer = document.createElement('div');\n labContainer.innerHTML = `\n <h3>Calibration Laboratory</h3>\n <p><strong>Name:</strong> ${labInfo?.['dcc:name']?.['dcc:content']?._text || 'N/A'}</p>\n <p><strong>Email:</strong> ${labInfo?.['dcc:eMail']?._text || 'N/A'}</p>\n <p><strong>Phone:</strong> ${labInfo?.['dcc:phone']?._text || 'N/A'}</p>\n `;\n\n // 🔹 RESPONSIBLE PERSONS\n const responsiblePersons = (adminData?.['dcc:respPersons']?.['dcc:respPerson'] || []).map(person => {\n return `<p>${person?.['dcc:person']?.['dcc:name']?.['dcc:content']?._text || 'Unknown Person'}\n ${person?.['dcc:mainSigner'] ? '(Main Signer)' : ''}</p>`;\n }).join('');\n const responsibleContainer = document.createElement('div');\n responsibleContainer.innerHTML = `<h3>Responsible Persons</h3>${responsiblePersons}`;\n\n // 🔹 ADD SECTIONS TO ACCORDION\n container.appendChild(createAccordion(\"Software Used\", softwareContainer));\n container.appendChild(createAccordion(\"Core Data\", coreDataContainer));\n container.appendChild(createAccordion(\"Calibration Laboratory\", labContainer));\n container.appendChild(createAccordion(\"Responsible Persons\", responsibleContainer));\n\n // 🔹 JSON DEBUG VIEW\n container.appendChild(createAccordion(\"Raw JSON Data (Debug)\", new JSONTreeViewer(adminData).render()));\n}\n", + "src/ui/measurementRenderer.js": "import { createTabs } from '../components/tabComponent.js';\nimport { JSONTreeViewer } from './jsonTreeViewer.js';\nimport { globalData } from '../globalData.js';\n\nexport function renderMeasurementResults() {\n const container = document.getElementById('measurement-data-container');\n container.innerHTML = ''; // Clear previous content\n\n const dccRoot = globalData.dcc?.['dcc:digitalCalibrationCertificate'];\n if (!dccRoot) {\n container.innerHTML = \"<p>No Digital Calibration Certificate Found</p>\";\n return;\n }\n\n const measurements = dccRoot?.['dcc:measurementResults'];\n if (!measurements || !measurements['dcc:measurementResult']) {\n container.innerHTML = \"<p>No Measurement Results Found</p>\";\n return;\n }\n\n const tabs = (Array.isArray(measurements['dcc:measurementResult']) ?\n measurements['dcc:measurementResult'] : [measurements['dcc:measurementResult']]\n ).map((result, index) => {\n const resultContainer = document.createElement('div');\n\n // 🔹 Measurement Methods\n const methods = result?.['dcc:usedMethods']?.['dcc:usedMethod'] || [];\n const methodsList = (Array.isArray(methods) ? methods : [methods]).map(method => `\n <p><strong>${method?.['dcc:name']?.['dcc:content']?._text || 'Unknown Method'}</strong>: \n ${method?.['dcc:description']?.['dcc:content']?._text || 'No description'}</p>\n `).join('');\n\n // 🔹 Measurement Equipment\n const equipments = result?.['dcc:measuringEquipments']?.['dcc:measuringEquipment'] || [];\n const equipmentList = (Array.isArray(equipments) ? equipments : [equipments]).map(eq => `\n <p><strong>${eq?.['dcc:name']?.['dcc:content']?._text || 'Unknown Equipment'}</strong> \n - ${eq?.['dcc:model']?._text || 'N/A'}</p>\n `).join('');\n\n // 🔹 Measurement Results\n const results = result?.['dcc:results']?.['dcc:result'] || [];\n const resultsList = (Array.isArray(results) ? results : [results]).map(res => `\n <h4>${res?.['dcc:name']?.['dcc:content']?._text || 'Unknown Result'}</h4>\n <pre>${JSON.stringify(res['dcc:data'], null, 2)}</pre>\n `).join('');\n\n resultContainer.innerHTML = `\n <h3>Measurement Methods</h3>${methodsList}\n <h3>Equipment Used</h3>${equipmentList}\n <h3>Results</h3>${resultsList}\n `;\n\n return {\n title: `Measurement ${index + 1}`,\n content: resultContainer\n };\n });\n\n container.appendChild(createTabs(tabs));\n\n // 🔹 JSON DEBUGGING VIEW\n container.appendChild(createTabs([{ title: \"Raw JSON\", content: new JSONTreeViewer(measurements).render() }]));\n}\n", "src/ui/jsonTreeViewer.js": "export class JSONTreeViewer {\n constructor(data) {\n this.data = data;\n }\n\n render() {\n const container = document.createElement('pre');\n container.textContent = JSON.stringify(this.data, null, 2);\n return container;\n }\n}\n", "public/index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>DCC Viewer</title>\n <script type=\"module\" src=\"/src/main.js\"></script>\n <link rel=\"stylesheet\" href=\"/public/styles.css\">\n</head>\n<body>\n<h1>DCC Viewer</h1>\n\n<input type=\"file\" id=\"file-input\" accept=\".xml\">\n\n<div id=\"admin-data-container\"></div>\n<div id=\"measurement-data-container\"></div>\n</body>\n</html>\n", "public/styles.css": ".accordion-header {\n background-color: #f0f0f0;\n border: none;\n padding: 10px;\n cursor: pointer;\n width: 100%;\n text-align: left;\n}\n\n.accordion-content {\n display: none;\n padding: 10px;\n}\n\n.accordion-content.open {\n display: block;\n}\n\n.tabs {\n display: flex;\n gap: 10px;\n}\n\n.tabs button {\n padding: 5px 10px;\n cursor: pointer;\n}\n\n.tab-content {\n border: 1px solid #ddd;\n padding: 10px;\n}\n" diff --git a/project_structure.json b/project_structure.json index a567036..57a1f4e 100644 --- a/project_structure.json +++ b/project_structure.json @@ -1,26 +1,15 @@ { - "dcc-viewer": { - "src": { - "main.js": "import { convertXMLToJSON } from './xmlToJson.js';\nimport { JSONTreeViewer } from './components/JSONTreeViewer.js';\n\nconst fileInput = document.getElementById('file-input');\nconst container = document.getElementById('json-container');\n\nfileInput.addEventListener('change', async (event) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n const reader = new FileReader();\n reader.onload = async () => {\n const xmlString = reader.result;\n const jsonData = await convertXMLToJSON(xmlString);\n const viewer = new JSONTreeViewer(jsonData);\n container.innerHTML = '';\n container.appendChild(viewer.render());\n };\n reader.readAsText(file);\n});", - "xmlToJson.js": "import { parseStringPromise } from 'xml2js';\n\nexport async function convertXMLToJSON(xmlString) {\n return parseStringPromise(xmlString, { explicitArray: false, mergeAttrs: true });\n}", - "idRegistry.js": "export const idRegistry = {};", - "globalData.js": "export const globalData = {};", - "globalOptions.js": "export const globalOptions = { preferredLanguage: 'en' };", - "viewerRegistry.js": "import { JSONTreeViewer } from './components/JSONTreeViewer.js';\n\nexport function getViewerForElement() {\n return JSONTreeViewer;\n}", - "utils.js": "export function getLocalizedText(elements) {\n if (!Array.isArray(elements)) return elements;\n return elements[0]._ || '';\n}", - "components": { - "BaseViewer.js": "export class BaseViewer {\n constructor(sectionData) {\n this.sectionData = sectionData;\n }\n render() {\n throw new Error('render() must be implemented in subclasses');\n }\n}", - "JSONTreeViewer.js": "import { BaseViewer } from './BaseViewer.js';\n\nexport class JSONTreeViewer extends BaseViewer {\n render() {\n const container = document.createElement('pre');\n container.textContent = JSON.stringify(this.sectionData, null, 2);\n return container;\n }\n}" - }, - "ui": { - "languageSelector.js": "import { globalOptions } from '../globalOptions.js';\n\nconst languageSelect = document.getElementById('language-select');\nlanguageSelect.addEventListener('change', (event) => {\n globalOptions.preferredLanguage = event.target.value;\n});", - "themeSwitcher.js": "const themeToggle = document.getElementById('theme-toggle');\nthemeToggle.addEventListener('click', () => {\n document.body.classList.toggle('dark-mode');\n});" - } - }, - "public": { - "index.html": "<!DOCTYPE html>\n<html lang='en'>\n<head>\n <meta charset='UTF-8'>\n <title>DCC Viewer</title>\n <script type='module' src='/src/main.js'></script>\n <link rel='stylesheet' href='/styles.css'>\n</head>\n<body>\n <input type='file' id='file-input' accept='.xml'>\n <button id='theme-toggle'>Toggle Theme</button>\n <select id='language-select'>\n <option value='en'>English</option>\n <option value='de'>German</option>\n </select>\n <div id='json-container'></div>\n</body>\n</html>", - "styles.css": "body { font-family: Arial, sans-serif; }\n.dark-mode { background-color: black; color: white; }" - }, - "package.json": "{\n \"name\": \"dcc-viewer\",\n \"version\": \"1.0.0\",\n \"scripts\": { \"dev\": \"vite\" },\n \"dependencies\": { \"xml2js\": \"^0.4.23\" }\n}" + "package.json": "{\n \"name\": \"dcc-viewer\",\n \"version\": \"1.0.0\",\n \"description\": \"Digital Calibration Certificate Viewer\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"xml2js\": \"^0.4.23\",\n \"jsoneditor\": \"^9.5.6\",\n \"plotly.js-dist\": \"^2.18.2\",\n \"events\": \"^3.3.0\"\n },\n \"devDependencies\": {\n \"vite\": \"^4.0.0\"\n }\n}\n", + "vite.config.js": "import { defineConfig } from 'vite';\n\nexport default defineConfig({\n resolve: {\n alias: {\n // Ensure that Node's events module is polyfilled\n events: 'events'\n }\n },\n optimizeDeps: {\n esbuildOptions: {\n // Define global as globalThis to help with some Node packages\n define: { global: 'globalThis' }\n }\n }\n});\n", + "index.html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>DCC Viewer</title>\n <link rel=\"stylesheet\" href=\"/src/styles.css\">\n</head>\n<body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.js\"></script>\n</body>\n</html>\n", + "src": { + "main.js": "import { initApp } from './app.js';\n\n// Wait for the DOM to be loaded before initializing\ndocument.addEventListener('DOMContentLoaded', () => {\n initApp();\n});\n", + "app.js": "import { parseString } from 'xml2js';\nimport JSONEditor from 'jsoneditor';\n\n// Import renderer functions\nimport { renderAdminData } from './renderers/AdminRenderer.js';\nimport { renderMeasurementResults } from './renderers/MeasurementRenderer.js';\n\n// Global configuration\nconst selectableLanguages = ['en', 'de', 'fr', 'es'];\nlet selectedLanguage = 'en';\nlet dccData = null;\n\nexport function initApp() {\n const appContainer = document.getElementById('app');\n\n // Create language selection dropdown\n const langSelect = document.createElement('select');\n selectableLanguages.forEach(lang => {\n const option = document.createElement('option');\n option.value = lang;\n option.textContent = lang;\n if (lang === selectedLanguage) option.selected = true;\n langSelect.appendChild(option);\n });\n langSelect.addEventListener('change', (e) => {\n selectedLanguage = e.target.value;\n renderAll();\n });\n appContainer.appendChild(langSelect);\n\n // Create containers for administrative data and measurement results\n const adminContainer = document.createElement('div');\n adminContainer.id = 'adminData';\n appContainer.appendChild(adminContainer);\n\n const measContainer = document.createElement('div');\n measContainer.id = 'measurementResults';\n appContainer.appendChild(measContainer);\n\n // Load the embedded XML file (for testing) from the data folder\n fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml')\n .then(response => response.text())\n .then(xmlText => {\n // Convert XML to JSON using xml2js\n parseString(xmlText, { explicitArray: false }, (err, result) => {\n if (err) {\n console.error('Error parsing XML:', err);\n return;\n }\n dccData = result;\n renderAll();\n });\n })\n .catch(err => console.error('Error loading XML file:', err));\n}\n\nfunction renderAll() {\n // Clear containers\n const adminContainer = document.getElementById('adminData');\n adminContainer.innerHTML = '';\n const measContainer = document.getElementById('measurementResults');\n measContainer.innerHTML = '';\n\n // Render the content if XML has been loaded and converted\n if (dccData && dccData['dcc:digitalCalibrationCertificate']) {\n const cert = dccData['dcc:digitalCalibrationCertificate'];\n if (cert['dcc:administrativeData']) {\n renderAdminData(cert['dcc:administrativeData'], selectedLanguage);\n }\n if (cert['dcc:measurementResults']) {\n renderMeasurementResults(cert['dcc:measurementResults'], selectedLanguage);\n }\n }\n}\n", + "styles.css": "body {\n font-family: Arial, sans-serif;\n margin: 20px;\n}\n\nh2, h3 {\n color: #333;\n}\n\n#adminData, #measurementResults {\n margin-top: 20px;\n border: 1px solid #ccc;\n padding: 10px;\n}\n\n.plot-table, .plot-and-table {\n margin: 10px 0;\n padding: 10px;\n border: 1px dashed #999;\n}\n", + "renderers": { + "SelectRenderer.js": "export function selectRenderer(json, language) {\n // If the JSON node has a refType matching basic_\\dIndexTable, render as plot and table\n if (json && json.$ && json.$.refType && /^basic_\\dIndexTable/.test(json.$.refType)) {\n return renderPlotAndTable(json, language);\n }\n // Fallback: render a simple JSON string\n const container = document.createElement('pre');\n container.textContent = JSON.stringify(json, null, 2);\n return container;\n}\n\nfunction renderPlotAndTable(json, language) {\n // Placeholder implementation for plot and table rendering\n const container = document.createElement('div');\n container.className = 'plot-and-table';\n container.textContent = 'Plot and Table renderer placeholder for language: ' + language;\n return container;\n}\n", + "AdminRenderer.js": "import JSONEditor from 'jsoneditor';\nimport 'jsoneditor/dist/jsoneditor.css';\n\nexport function renderAdminData(adminData, language) {\n const container = document.getElementById('adminData');\n // Title for admin data\n const title = document.createElement('h2');\n title.textContent = 'Administrative Data (' + language + ')';\n container.appendChild(title);\n\n // JSONEditor options (read-only view)\n const options = {\n mode: 'view',\n mainMenuBar: false,\n navigationBar: false,\n statusBar: false\n };\n\n // Create a new JSONEditor instance to display the adminData\n const editor = new JSONEditor(container, options);\n editor.set(adminData);\n}\n", + "MeasurementRenderer.js": "import { selectRenderer } from './SelectRenderer.js';\n\nexport function renderMeasurementResults(measurementResults, language) {\n const container = document.getElementById('measurementResults');\n const title = document.createElement('h2');\n title.textContent = 'Measurement Results (' + language + ')';\n container.appendChild(title);\n\n // measurementResult can be an object or an array\n let results = measurementResults['dcc:measurementResult'];\n if (!Array.isArray(results)) {\n results = [results];\n }\n\n results.forEach(result => {\n // Render the measurement result title\n const resultTitle = document.createElement('h3');\n if (result['dcc:name'] && result['dcc:name']['dcc:content']) {\n let nameContent = result['dcc:name']['dcc:content'];\n if (Array.isArray(nameContent)) {\n // Find the content matching the selected language or fallback\n const match = nameContent.find(item => item.$ && item.$.lang === language) || nameContent[0];\n resultTitle.textContent = match._ || match;\n } else {\n resultTitle.textContent = nameContent._ || nameContent;\n }\n } else {\n resultTitle.textContent = 'Measurement Result';\n }\n container.appendChild(resultTitle);\n\n // Render results using dcc:results -> dcc:result\n if (result['dcc:results'] && result['dcc:results']['dcc:result']) {\n let resItems = result['dcc:results']['dcc:result'];\n if (!Array.isArray(resItems)) {\n resItems = [resItems];\n }\n resItems.forEach(res => {\n // Check if the result contains a dcc:data with a dcc:list that should be rendered as plot/table\n if (res['dcc:data'] && res['dcc:data']['dcc:list']) {\n const dataContainer = document.createElement('div');\n dataContainer.className = 'plot-table';\n // Use the global selectRenderer to decide how to render this data\n const renderedContent = selectRenderer(res['dcc:data']['dcc:list'], language);\n dataContainer.appendChild(renderedContent);\n container.appendChild(dataContainer);\n } else {\n // Fallback: simple placeholder\n const defaultContainer = document.createElement('div');\n defaultContainer.className = 'default-render';\n defaultContainer.textContent = 'Default rendering for measurement result.';\n container.appendChild(defaultContainer);\n }\n });\n }\n });\n}\n" + } } } diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..95e25b5 --- /dev/null +++ b/src/app.js @@ -0,0 +1,74 @@ +import { parseString } from 'xml2js'; +import JSONEditor from 'jsoneditor'; + +// Import renderer functions +import { renderAdminData } from './renderers/AdminRenderer.js'; +import { renderMeasurementResults } from './renderers/MeasurementRenderer.js'; + +// Global configuration +const selectableLanguages = ['en', 'de', 'fr', 'es']; +let selectedLanguage = 'en'; +let dccData = null; + +export function initApp() { + const appContainer = document.getElementById('app'); + + // Create language selection dropdown + const langSelect = document.createElement('select'); + selectableLanguages.forEach(lang => { + const option = document.createElement('option'); + option.value = lang; + option.textContent = lang; + if (lang === selectedLanguage) option.selected = true; + langSelect.appendChild(option); + }); + langSelect.addEventListener('change', (e) => { + selectedLanguage = e.target.value; + renderAll(); + }); + appContainer.appendChild(langSelect); + + // Create containers for administrative data and measurement results + const adminContainer = document.createElement('div'); + adminContainer.id = 'adminData'; + appContainer.appendChild(adminContainer); + + const measContainer = document.createElement('div'); + measContainer.id = 'measurementResults'; + appContainer.appendChild(measContainer); + + // Load the embedded XML file (for testing) from the data folder + fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml') + .then(response => response.text()) + .then(xmlText => { + // Convert XML to JSON using xml2js + parseString(xmlText, { explicitArray: false }, (err, result) => { + if (err) { + console.error('Error parsing XML:', err); + return; + } + dccData = result; + renderAll(); + }); + }) + .catch(err => console.error('Error loading XML file:', err)); +} + +function renderAll() { + // Clear containers + const adminContainer = document.getElementById('adminData'); + adminContainer.innerHTML = ''; + const measContainer = document.getElementById('measurementResults'); + measContainer.innerHTML = ''; + + // Render the content if XML has been loaded and converted + if (dccData && dccData['dcc:digitalCalibrationCertificate']) { + const cert = dccData['dcc:digitalCalibrationCertificate']; + if (cert['dcc:administrativeData']) { + renderAdminData(cert['dcc:administrativeData'], selectedLanguage); + } + if (cert['dcc:measurementResults']) { + renderMeasurementResults(cert['dcc:measurementResults'], selectedLanguage); + } + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..122f3f4 --- /dev/null +++ b/src/main.js @@ -0,0 +1,6 @@ +import { initApp } from './app.js'; + +// Wait for the DOM to be loaded before initializing +document.addEventListener('DOMContentLoaded', () => { + initApp(); +}); diff --git a/src/renderers/AdminRenderer.js b/src/renderers/AdminRenderer.js new file mode 100644 index 0000000..82ffa9b --- /dev/null +++ b/src/renderers/AdminRenderer.js @@ -0,0 +1,22 @@ +import JSONEditor from 'jsoneditor'; +import 'jsoneditor/dist/jsoneditor.css'; + +export function renderAdminData(adminData, language) { + const container = document.getElementById('adminData'); + // Title for admin data + const title = document.createElement('h2'); + title.textContent = 'Administrative Data (' + language + ')'; + container.appendChild(title); + + // JSONEditor options (read-only view) + const options = { + mode: 'view', + mainMenuBar: false, + navigationBar: false, + statusBar: false + }; + + // Create a new JSONEditor instance to display the adminData + const editor = new JSONEditor(container, options); + editor.set(adminData); +} diff --git a/src/renderers/MeasurementRenderer.js b/src/renderers/MeasurementRenderer.js new file mode 100644 index 0000000..fa583a0 --- /dev/null +++ b/src/renderers/MeasurementRenderer.js @@ -0,0 +1,57 @@ +import { selectRenderer } from './SelectRenderer.js'; + +export function renderMeasurementResults(measurementResults, language) { + const container = document.getElementById('measurementResults'); + const title = document.createElement('h2'); + title.textContent = 'Measurement Results (' + language + ')'; + container.appendChild(title); + + // measurementResult can be an object or an array + let results = measurementResults['dcc:measurementResult']; + if (!Array.isArray(results)) { + results = [results]; + } + + results.forEach(result => { + // Render the measurement result title + const resultTitle = document.createElement('h3'); + if (result['dcc:name'] && result['dcc:name']['dcc:content']) { + let nameContent = result['dcc:name']['dcc:content']; + if (Array.isArray(nameContent)) { + // Find the content matching the selected language or fallback + const match = nameContent.find(item => item.$ && item.$.lang === language) || nameContent[0]; + resultTitle.textContent = match._ || match; + } else { + resultTitle.textContent = nameContent._ || nameContent; + } + } else { + resultTitle.textContent = 'Measurement Result'; + } + container.appendChild(resultTitle); + + // Render results using dcc:results -> dcc:result + if (result['dcc:results'] && result['dcc:results']['dcc:result']) { + let resItems = result['dcc:results']['dcc:result']; + if (!Array.isArray(resItems)) { + resItems = [resItems]; + } + resItems.forEach(res => { + // Check if the result contains a dcc:data with a dcc:list that should be rendered as plot/table + if (res['dcc:data'] && res['dcc:data']['dcc:list']) { + const dataContainer = document.createElement('div'); + dataContainer.className = 'plot-table'; + // Use the global selectRenderer to decide how to render this data + const renderedContent = selectRenderer(res['dcc:data']['dcc:list'], language); + dataContainer.appendChild(renderedContent); + container.appendChild(dataContainer); + } else { + // Fallback: simple placeholder + const defaultContainer = document.createElement('div'); + defaultContainer.className = 'default-render'; + defaultContainer.textContent = 'Default rendering for measurement result.'; + container.appendChild(defaultContainer); + } + }); + } + }); +} diff --git a/src/renderers/SelectRenderer.js b/src/renderers/SelectRenderer.js new file mode 100644 index 0000000..f593395 --- /dev/null +++ b/src/renderers/SelectRenderer.js @@ -0,0 +1,18 @@ +export function selectRenderer(json, language) { + // If the JSON node has a refType matching basic_\dIndexTable, render as plot and table + if (json && json.$ && json.$.refType && /^basic_\dIndexTable/.test(json.$.refType)) { + return renderPlotAndTable(json, language); + } + // Fallback: render a simple JSON string + const container = document.createElement('pre'); + container.textContent = JSON.stringify(json, null, 2); + return container; +} + +function renderPlotAndTable(json, language) { + // Placeholder implementation for plot and table rendering + const container = document.createElement('div'); + container.className = 'plot-and-table'; + container.textContent = 'Plot and Table renderer placeholder for language: ' + language; + return container; +} diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..e10ba0b --- /dev/null +++ b/src/styles.css @@ -0,0 +1,20 @@ +body { + font-family: Arial, sans-serif; + margin: 20px; +} + +h2, h3 { + color: #333; +} + +#adminData, #measurementResults { + margin-top: 20px; + border: 1px solid #ccc; + padding: 10px; +} + +.plot-table, .plot-and-table { + margin: 10px 0; + padding: 10px; + border: 1px dashed #999; +} -- GitLab