From c284c9fb5bd8850a1d508a466fa0a9b6a067cc3e Mon Sep 17 00:00:00 2001
From: Benedikt Seeger <benedikt.seeger@ptb.de>
Date: Thu, 27 Feb 2025 20:00:35 +0100
Subject: [PATCH] refactored app.js to be used as module later on

---
 README.md   | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/app.js  | 108 +++++++++++++++++++++++++------------------------
 src/main.js |  12 ++++--
 3 files changed, 179 insertions(+), 54 deletions(-)
 create mode 100644 README.md

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..87a1a69
--- /dev/null
+++ b/README.md
@@ -0,0 +1,113 @@
+
+# DCC Viewer JavaScript
+
+A lightweight JavaScript/HTML application for displaying Digital Calibration Certificates (DCC) from XML files. The application parses a DCC XML file, renders administrative data and measurement results interactively (including charts and tables), and supports multiple languages based on the certificate’s data.
+
+## Project Structure
+
+```
+├── data
+│   ├── 1DTableDataWithRenderingComments.xml      # Example XML file with table rendering comments
+│   └── sin_acceleration_example_dcc_WithExampleConformatyStatment.xml  # Example DCC XML file
+├── dcc-viewer                 # (Optional) Output directory for built package
+├── index.html                 # Main HTML file
+├── package.json               # NPM package file
+├── readME.md                  # This file
+├── src
+│   ├── app.js                 # Main application module (initializes the app, loads XML, renders UI)
+│   ├── dccQuantity.js         # Module for parsing DCC quantities and conformity data
+│   ├── main.js                # Entry point – initializes app after DOM loads and loads test XML (for development)
+│   ├── renderers
+│   │   ├── AdminRenderer.js   # Renders administrative data (using a JSON tree viewer)
+│   │   ├── MeasurementRenderer.js  # Renders measurement results in a tabbed layout with charts, tables, etc.
+│   │   └── SelectRenderer.js  # (Optional) For selecting which renderer to use for a given XML section
+│   └── styles.css             # Application styling
+└── vite.config.js             # Vite configuration file
+```
+
+## Features
+
+- **Multi-Language Support:**  
+  Automatically extracts available languages from the XML's administrative data and builds a dynamic language dropdown.
+
+- **Interactive Measurement Rendering:**  
+  Measurement results are rendered in a tabbed layout, with interactive charts (using Plotly) and tables that update with scaling options and tolerance markings.
+
+- **Expandable Sections:**  
+  Used methods and influence conditions are rendered in collapsible sections using JSONEditor.
+
+## Installation
+
+1. **Clone the Repository:**
+
+   ```bash
+   git clone <repository_url>
+   cd dccviewertypescript
+   ```
+
+2. **Install Dependencies:**
+
+   ```bash
+   npm install
+   ```
+
+## Development
+
+This project uses [Vite](https://vitejs.dev/) for development.
+
+1. **Start the Development Server:**
+
+   ```bash
+   npm run dev
+   ```
+
+   This will start the server (usually on `http://localhost:5173/`). The app uses `src/main.js` as its entry point.
+
+2. **View Example:**
+
+   For testing purposes, the development version loads a sample XML file from the `data` directory. You can change the XML in `main.js` if needed.
+
+## Building & Packaging
+
+1. **Build for Production:**
+
+   ```bash
+   npm run build
+   ```
+
+   This command uses Vite to build a production version of your application. The output is typically placed in a `dist` directory.
+
+2. **Packaging as an NPM Module:**
+
+    - Remove the test XML file loading from your module (it's now handled in `main.js`).
+    - Publish your module to npm (or use it locally) so that the consuming project can call your exported `init(xmlStr, options)` function to load and render a DCC XML file.
+
+## Usage in a Standalone HTML File
+
+If you want to use the module in a simple HTML file, you can create an HTML file like this:
+
+```html
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>DCC Viewer</title>
+  <link rel="stylesheet" href="dist/styles.css" />
+</head>
+<body>
+  <div id="app"></div>
+  <script type="module">
+    import { init } from './dist/app.js';
+    // Replace the following XML string with your own XML data.
+    fetch('path/to/your/dcc.xml')
+      .then(response => response.text())
+      .then(xmlStr => {
+        init(xmlStr, { containerId: 'app', language: 'en' });
+      });
+  </script>
+</body>
+</html>
+```
+
+This example shows how to initialize the app by passing an XML string and configuration options (such as the container ID and language).
+## License
\ No newline at end of file
diff --git a/src/app.js b/src/app.js
index 6a2a9c9..96acbfc 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1,69 +1,75 @@
 import { parseString } from 'xml2js';
-
-// Import our interactive measurement renderer
 import { renderMeasurementResults } from './renderers/MeasurementRenderer.js';
 import { renderAdminData } from './renderers/AdminRenderer.js';
 
-// Global configuration
-const selectableLanguages = ['en', 'de', 'fr', 'es'];
-let selectedLanguage = 'en';
-let dccData = null;
+export function init(xmlStr, options = {}) {
+  const containerId = options.containerId || 'app';
+  const appContainer = document.getElementById(containerId);
+  if (!appContainer) {
+    console.error('No container found with id', containerId);
+    return;
+  }
+  appContainer.innerHTML = '';
 
-export function initApp() {
-  const appContainer = document.getElementById('app');
+  // Parse the XML string first
+  parseString(xmlStr, { explicitArray: false }, (err, result) => {
+    if (err) {
+      console.error('Error parsing XML:', err);
+      return;
+    }
+    const dccData = result;
+    const cert = dccData['dcc:digitalCalibrationCertificate'];
+    if (!cert) {
+      console.error("No dcc:digitalCalibrationCertificate found in XML");
+      return;
+    }
 
-  // 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);
+    // Extract available languages from the administrative data coreData section
+    let languages = [];
+    if (cert['dcc:administrativeData'] && cert['dcc:administrativeData']['dcc:coreData']) {
+      const coreData = cert['dcc:administrativeData']['dcc:coreData'];
+      let langs = coreData['dcc:usedLangCodeISO639_1'];
+      if (langs) {
+        if (!Array.isArray(langs)) { langs = [langs]; }
+        languages = langs;
+      }
+    }
 
-  // Create containers for admin data and measurement results
-  const adminContainer = document.createElement('div');
-  adminContainer.id = 'adminData';
-  appContainer.appendChild(adminContainer);
+    // Use provided default language if available and present, else use the first available or fallback to 'en'
+    let selectedLanguage = (options.language && languages.includes(options.language))
+        ? options.language
+        : (languages.length ? languages[0] : 'en');
 
-  const measContainer = document.createElement('div');
-  measContainer.id = 'measurementResults';
-  appContainer.appendChild(measContainer);
+    // Build a dynamic language dropdown based on the extracted languages
+    const langSelect = document.createElement('select');
+    languages.forEach(lang => {
+      const option = document.createElement('option');
+      option.value = lang;
+      option.textContent = lang;
+      if (lang === selectedLanguage) option.selected = true;
+      langSelect.appendChild(option);
+    });
+    // When the language is changed, reinitialize the app with the same XML but new language.
+    langSelect.addEventListener('change', (e) => {
+      init(xmlStr, { containerId, language: e.target.value });
+    });
+    appContainer.appendChild(langSelect);
 
-  // Load the XML file from the data folder
-  fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml')
-    .then(response => response.text())
-    .then(xmlText => {
-      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));
-}
+    // Create containers for admin data and measurement results
+    const adminContainer = document.createElement('div');
+    adminContainer.id = 'adminData';
+    appContainer.appendChild(adminContainer);
 
-function renderAll() {
-  // Clear containers
-  document.getElementById('adminData').innerHTML = '';
-  document.getElementById('measurementResults').innerHTML = '';
+    const measContainer = document.createElement('div');
+    measContainer.id = 'measurementResults';
+    appContainer.appendChild(measContainer);
 
-  if (dccData && dccData['dcc:digitalCalibrationCertificate']) {
-    const cert = dccData['dcc:digitalCalibrationCertificate'];
+    // Render admin and measurement data if available
     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
index 06d04af..8c2f1c6 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,6 +1,12 @@
-import { initApp } from './app.js';
+import { init } from './app.js';
 
-// Initialize after DOM loads
+// Initialize the app once the DOM is loaded.
+// In production you can supply your own XML string to init().
 document.addEventListener('DOMContentLoaded', () => {
-  initApp();
+  fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml')
+      .then(response => response.text())
+      .then(xmlText => {
+        init(xmlText, { containerId: 'app', language: 'en' });
+      })
+      .catch(err => console.error('Error loading XML file:', err));
 });
-- 
GitLab