[JavaScript] HTML-Tabellen mit ExcelJS exportieren

<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Export Tabelle mit ExcelJS</title>
</head>
<body>
  <table id="tblTestData">
    <caption>Tabelle 1</caption>
    <thead>
      <tr>
        <th class="sub">Name</th>
        <th class="sub">Vorname</th>
        <th class="sub">Alter</th>
      </tr>
    </thead>
    <tbody>
      <tr><td>Müller</td><td>Horst</td><td>50</td></tr>
      <tr><td>Lehmann</td><td>Eduard</td><td>64</td></tr>
      <tr><td>Meier</td><td>Inge</td><td>71</td></tr>
    </tbody>
  </table>

  <div class="controls">
    <button id="btnExport" class="btn" type="button">Tabelle exportieren</button>
  </div>

  <!-- ExcelJS und FileSaver (CDN) -->
  <script src="https://cdn.jsdelivr.net/npm/exceljs/dist/exceljs.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>

  <script>
    (function () {
      const btn = document.getElementById('btnExport');

      // Näherung: 1 Excel-Char ≈ 7 Pixel
      function pxToExcelChars(px) {
        return Math.ceil(px / 7);
      }

      // charsForLen mit padding +5
      function charsForLen(len, minChars) {
        return Math.min(Math.max(len + 5, minChars), 50);
      }

      // Hilfsfunktion: ARGB aus hex (z.B. "#2f6f9f" -> "FF2F6F9F")
      function hexToARGB(hex) {
        if (!hex) return 'FFFFFFFF';
        const h = hex.replace('#','').toUpperCase();
        return (h.length === 6) ? ('FF' + h) : ('FF' + h.slice(-6));
      }

      btn.addEventListener('click', async function () {
        // HTML-Tabelle
        const table = document.getElementById('tblTestData');

        // Workbook
        const workbook = new ExcelJS.Workbook();
        // Worksheet mit Bezeichner 'Tabelle1'
        const sheet = workbook.addWorksheet('Tabelle1');

        // Farben
        const headerColor = '#2f6f9f';     // Farbe Header-Zeile
        const headerFontColor = '#FFFFFF'; // Farbe Header Schrift
        const rowOddColor = '#fbfbfb';     // Farbe gerade Zeile
        const rowEvenColor = '#FFFFFF';    // Farbe ungerade Zeile
        
        // Header-Zeile
        const headerCells = Array.from(table.tHead.rows[0].cells).map(th => th.textContent.trim());
        sheet.addRow(headerCells);
		
        // Datenzeilen aus HTML-Tabelle
		const tbody = table.tBodies[0];
		
		const iCols = table.tHead.rows[0].cells.length;
		const iRows = tbody.rows.length;

        for (let r = 0; r < iRows; r++) {
          const cells = Array.from(tbody.rows[r].cells).map(td => td.textContent.trim());
          sheet.addRow(cells);
        }

        // Beispiel: Zellen mergen
        //sheet.mergeCells('A1:C1'); // A-C

        const headerARGB = hexToARGB(headerColor);
        const headerFontARGB = hexToARGB(headerFontColor);
        const oddARGB = hexToARGB(rowOddColor);
        const evenARGB = hexToARGB(rowEvenColor);

        // Setze Arial und Standardformat für alle Zellen
        sheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
          row.eachCell({ includeEmpty: true }, function(cell, colNumber) {
            cell.font = cell.font || {};
            cell.font.name = 'Arial';
            // Default alignment left for non-specified cells
            cell.alignment = cell.alignment || { vertical: 'middle', horizontal: 'left' };
          });
        });

        // Formatierung für Header
        for (let c = 1; c <= iCols; c++) {
          const cell1 = sheet.getCell(1, c);
          cell1.font = Object.assign({}, cell1.font, { name: 'Arial', bold: true, color: { argb: headerFontARGB } });
          cell1.alignment = { vertical: 'middle', horizontal: 'center' };
          cell1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: headerARGB } };
        }

        // für gemergedte Zellen (D1, I1, N1) loopen
        // ['D1','I1','N1'].forEach(addr => {
        //  const cell = sheet.getCell(addr);
        //  cell...
        //});

        // Datenzeilen zentrieren
        const firstDataRow = 1;
        const startCol = 3; // C
        const endCol = 3;   // C
        for (let r = firstDataRow; r <= sheet.rowCount; r++) {
          const row = sheet.getRow(r);
          for (let c = startCol; c <= endCol; c++) {
            const cell = row.getCell(c);
            cell.alignment = Object.assign({}, cell.alignment || {}, { horizontal: 'center', vertical: 'middle' });
            cell.font = Object.assign({}, cell.font || {}, { name: 'Arial' });
          }
        }

        // alternierende Datenzeilen-Farben
        for (let r = 0; r < tbody.rows.length; r++) {
          const excelRowIndex = 2 + r; // ab der zweiten Zeile (ohne Header)
          const isOdd = (r % 2 === 0); // r=0 -> erste data row -> odd style (#fbfbfb)
          const fillColor = isOdd ? oddARGB : evenARGB;
          for (let c = 1; c <= iCols; c++) {
            const cell = sheet.getCell(excelRowIndex, c);
            cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
          }
        }

        // Spaltenbreiten: orientiert an der Header-Zeile (padding +5)
        const headerLens = headerCells.map(h => h ? String(h).length : 0);

        function maxLen(startIdx, endIdx) {
          let m = 0;
          for (let i = startIdx; i <= endIdx; i++) {
            if (headerLens[i] > m) m = headerLens[i];
          }
          return m;
        }

        // Spaltenbreite
        const maxColLen = maxLen(0, iCols - 1);  // A(0) .. C(2)
        // Mindestbreite 20px in Excel-Char-Einheiten
        const minChars = pxToExcelChars(20);
        // Spaltenbreite mit Padding (+5 px)
        const maxColLenPad = charsForLen(maxColLen, minChars);
		
        const cols = [];
		
        for (let i = 0; i < iCols; i++) {
          cols.push({ width: maxColLenPad });
        }
        sheet.columns = cols;

        // Rahmen
        const thinBorder = { style: 'thin' };
        const fullBorder = { top: thinBorder, left: thinBorder, bottom: thinBorder, right: thinBorder };
        // Iteriere über alle Zeilen und Spalten und setze border
        for (let r = 1; r <= sheet.rowCount; r++) {
          const row = sheet.getRow(r);
          for (let c = 1; c <= iCols; c++) {
            const cell = row.getCell(c);
            cell.border = fullBorder;
          }
        }

        // Datei: Export über Buffer für Kompatibiliät mit allen Browsern
        const buf = await workbook.xlsx.writeBuffer();

        const filename = `Test.xlsx`;

        const blob = new Blob([buf], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
		
        saveAs(blob, filename);
      });
    })();
  </script>
</body>
</html>

[JavaScript] JSON-Datei per fetch( ) oder FilePicker laden

Im Beispiel wird eine JSON-Datei eingelesen. Hierzu gibt es zwei Vorgehensweisen:

  1. Zuerst wird versucht die Datei per fetch() zu laden. Herbei kann es zum Fehler „Failed to fetch“ kommen. Die Fehlerursache ist häufig, dass der Browser den Zugriff auf lokale Dateien blockiert oder die Anfrage wegen einer Cross‑Origin‑Policy ablehnt.
  2. Falls fetch( ) fehlschlägt, kann per OpenDialog (FilePicker) lokal eine Datei ausgewählt werden.
<!doctype html>
<html lang="de">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1" />
    <title>JSON-Datei per URL oder lokal laden</title>
    <style>
      #filePicker {
        margin: 8px 0;
      }
    </style>
  </head>
  <body>
    <div id="container">
      <div id="statusText">JSON-Datei laden</div>
      <br />
      <div
        id="filePicker"
        style="display: none">
        <label>JSON-Datei auswählen:</label>
        <input
          type="file"
          id="fileOpenDialog"
          accept=".json" />
      </div>
      <br />
      <div id="fileContentText">-</div>
    </div>

    <script>
      // Datei mit Beispieldaten (URL)
      //const JSON_SRC = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
      // Datei mit Beispieldaten (lokal)
      const JSON_SRC = "MyLocalFile.json";

      // Beispielhafte Weiterverarbeitung der JSON-Daten
      function processJSON(json) {
        if (json != null) {
          document.getElementById("statusText").textContent =
            "JSON-Datei wurde geladen und wird nun weiter verarbeitet.";

          const text = JSON.stringify(json, null, 2);

          document.getElementById("fileContentText").textContent = text;
        }
      }

      document.addEventListener("DOMContentLoaded", () => {
        const txtStatusText = document.getElementById("statusText");

        // erst automatischer Ladevorgang per fetch( ) probieren,
        // bei Fehler Fallback: manueller Datei-Upload
        fetch(JSON_SRC)
          .then((resp) => {
            if (!resp.ok) throw new Error("HTTP " + resp.status);

            // JSON zu Objekt parsen
            return resp.json();
          })
          .then((json) => {
            // ggf. statusText ausblenden
            // txtStatusText.style.display = 'none';

            // JSON verarbeiten
            processJSON(json);
          })
          .catch((err) => {
            txtStatusText.textContent =
              "Fehler beim automatischen Laden: " + err.message;

            // wenn Datei nicht per fetch( ) geladen werden kann,
            // FilePicker anzeigen und dann manuelle Angabe der Datei
            document.getElementById("filePicker").style.display = "block";
          });

        const fileInput = document.getElementById("fileOpenDialog");
        // manueller Datei‑Upload

        fileInput.addEventListener("change", (ev) => {
          const f = ev.target.files && ev.target.files[0];

          if (!f) return;

          const reader = new FileReader();

          reader.onload = function (e) {
            try {
              // JSON zu Objekt parsen
              const json = JSON.parse(e.target.result);

              // ggf. statusText ausblenden
              //document.getElementById('statusText').style.display = 'none';

              // JSON verarbeiten
              processJSON(json);
            } catch (ex) {
              document.getElementById("statusText").textContent =
                "Fehler: Ungültige JSON-Datei.";
            }
          };

          reader.onerror = function () {
            document.getElementById("statusText").textContent =
              "Fehler beim Lesen der Datei.";
          };

          reader.readAsText(f);
        });
      });
    </script>
  </body>
</html>

Links

[CSS] Icons per Bootstrap 3 und Font Awesome anzeigen

Für die korrekte Darstellung der Icons sollten die passenden Bibliotheksversionen für Bootstrap und Font Awesome eingebunden werden.
Font Awesome 5 benutzt das Prefix „fas“, Font Awesome 4 benutzt das Präfix „fa“.

<!DOCTYPE html>
<html lang="de">
	<head>
		<meta charset="utf-8"/>
		<meta name="viewport" content="width=device-width,initial-scale=1"/>
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
		<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css">
		<title>Font Awesome Test</title>
	</head>
	<body>
		<div class="app">
			<button class="btn btn-danger">
				<i class="fas fa-trash" aria-hidden="true"></i>
				<span class="btn-text"> Löschen</span>
			</button>
			</br>
			<button class="btn">
				<i class="fas fa-download" aria-hidden="true"></i>
				<span class="btn-text"> Download</span>
			</button>
			</br>
			<label class="control-label">
				<i class="fas fa-user" aria-hidden="true"></i>
				<span class="btn-text"> Benutzer</span>
			</label>
		</div>
	</body>
</html>

Links

[ABAP] JavaScript-Code über MSScriptControl ausführen

* http://www.thescarms.com/VBasic/Scripting.aspx

* JS-Code mit Beispielfunktionen einfügen
DATA(it_js_code) = VALUE stringtab( ( |var oJSON = \{| )
                                    ( |  "name" : "Heinz",| )
                                    ( |  "age"  : 56,| )
                                    ( |  "city" : "Hamburg"| )
                                    ( |\};| )
                                    ( |function add(a, b) \{| )
                                    ( |  return a + b;| )
                                    ( |\};| )
                                    ( |function getJSONString() \{| )
                                    ( |  return oJSON["name"];| )
                                    ( |\};| )
                                   ).

DATA: lv_jscode TYPE string.

* VBA-Code in String wandeln
LOOP AT it_js_code ASSIGNING FIELD-SYMBOL(<c>).
  DATA(lv_codeline) = condense( <c> ).
  IF lv_jscode IS INITIAL.
    lv_jscode = lv_codeline.
  ELSE.
    lv_jscode = |{ lv_jscode }{ cl_abap_char_utilities=>cr_lf }{ lv_codeline }|.
  ENDIF.
ENDLOOP.

* Scriptcontrol-Objekt erzeugen
DATA: o_scr TYPE ole2_object.
* Variablen für Fehleranalyse
DATA: o_error TYPE ole2_object.
DATA: lv_line TYPE string.
DATA: lv_number TYPE string.
DATA: lv_desc TYPE string.
DATA: lv_source TYPE string.

CREATE OBJECT o_scr 'MSScriptControl.ScriptControl'.

* wenn Erzeugung ok
IF sy-subrc = 0 AND o_scr-handle <> 0 AND o_scr-type = 'OLE2'.
  WRITE: / 'Header', o_scr-header.
  WRITE: / 'Type', o_scr-type.
  WRITE: / 'Handle', o_scr-handle.
  WRITE: / 'CB-Index', o_scr-cb_index.
  WRITE: / 'CLSID', o_scr-clsid.

* GUI anzeigen
  SET PROPERTY OF o_scr 'AllowUI' = 1.
* Sprache ist 'JScript'
  SET PROPERTY OF o_scr 'Language' = 'JScript'.

* Code hinzufügen und Syntaxcheck
  CALL METHOD OF o_scr 'AddCode'
    EXPORTING
      #1 = lv_jscode.

* wenn Syntax ok
  IF sy-subrc = 0.
* Funktionsaufruf mit Übergabeparametern
    DATA: lv_res_i TYPE i.
    CALL METHOD OF o_scr 'Eval' = lv_res_i
      EXPORTING
        #1 = 'add(1, 2)'.

    WRITE: / 'add(1, 2) =', lv_res_i.

* Aufruf Stringfunktion
    DATA: lv_res_str TYPE string.
    CALL METHOD OF o_scr 'Eval' = lv_res_str
      EXPORTING
        #1 = 'getJSONString()'.

    WRITE: / 'getJSONString() =', lv_res_str.

* Aufruf einer nicht vorhandenen Funktion --> Fehlerauswertung
    DATA: lv_res_input TYPE string.
    CALL METHOD OF o_scr 'Eval' = lv_res_input
      EXPORTING
        #1 = 'getInput()'.

    IF sy-subrc = 0.
      WRITE: / 'getInput() =', lv_res_input.
    ELSE.
* Fehlerauswertung
      GET PROPERTY OF o_scr 'Error' = o_error.
      GET PROPERTY OF o_error 'Line' = lv_line.
      GET PROPERTY OF o_error 'Number' = lv_number.
      GET PROPERTY OF o_error 'Description' = lv_desc.
      GET PROPERTY OF o_error 'Source' = lv_source.

      WRITE: / 'Line:', lv_line.
      WRITE: / 'Number:', lv_number.
      WRITE: / 'Desc:', lv_desc.
      WRITE: / 'Source:', lv_source.
    ENDIF.
  ELSE.
    WRITE: / 'Fehler im Code: ', sy-subrc.
  ENDIF.

* Objekt zerstören
  FREE OBJECT o_scr.
ENDIF.

[JavaScript] Nützliche JavaScript Bibliotheken

toastrjs

  • Javascript library for Gnome / Growl type non-blocking notifications

moment.js

  • Parse, validate, manipulate, and display dates and times in JavaScript

Wickedpicker

  • A simple jQuery timepicker plugin – Turn any input element into a elegant timepicker

CodeMirror

  • a versatile text editor implemented in JavaScript for the browser

async

  • Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript

CryptoJS

  • JavaScript implementations of standard and secure cryptographic algorithms

FingerprintJS

  • client-side, browser fingerprinting library

Leaflet

  • Open-source JavaScript library for mobile-friendly interactive maps

PDF.js

  • Open Source JavaScript PDF Viewer-Bibliothek

JsonTree.je

  • JSON Visualisierung

jsTree

  • interaktive, anpassbare Baumansicht

TreeJS

  • simple JavaScript library, to display a TreeView like in the windows filebrowser

Fancytree

  • JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag’n’drop, and lazy loading
  • https://wwwendt.de/tech/fancytree/

wunderbaum

Papa Parse

  • The powerful, in-browser CSV parser for big boys and girls

SheetJS CE

  • Import und Export von Tabellendaten mit verschiedenen Formaten (HTML-Table, JSON, CSV, xlsx, ods …)

ExcelJS

Chart.js

  • Simple, flexible JavaScript charting library

Plotly.js

  • 2D / 3D Chart Library

Babylon.js

  • Open Source Web 3D Engine

Three.js

  • JavaScript 3D library

[JavaScript] RegEx verwenden

Variante 1

let str = '123456';
let regex = /^(\d{6})?$/;

// RegEx testen
// Besp: String muss aus 6 Zahlen bestehen
if (regex.test(str))
{
    console.log('match');
}
else
{
    console.log('no match');
}

Variante 2

let str = '123456';

// RegEx testen
// Besp: String muss aus 6 Zahlen bestehen
if (/^(\d{6})?$/.test(str))
{
    console.log('match');
}
else
{
    console.log('no match');
}

[AJAX] $.post()

Allgemein

$.post(URL, data, callback); 

Beispiel

// https://www.w3schools.com/jquery/jquery_ajax_get_post.asp
$("btn1").click(function(){
    // url
    $.post("btn1_post.php",
    // data
    {
        data1: "some data1",
        data2: "some data2"
    },
    // callback
    function(data, status){
        console.log("Data: " + data);
        console.log("Status: " + status);
    });
});