mirror of
https://github.com/Sternenlabor/fabaccess-sticker-generator.git
synced 2025-03-11 14:31:41 +01:00
added some comments, fix test server, better formatting
This commit is contained in:
parent
0009b4fc55
commit
77ae56924e
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
.vscode/
|
||||
|
||||
.DS_Store
|
||||
|
||||
node_modules/
|
||||
|
9
.prettierrc.json
Normal file
9
.prettierrc.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"singleAttributePerLine": false,
|
||||
"html.format.wrapLineLength": 0,
|
||||
"printWidth": 140
|
||||
}
|
@ -2,6 +2,7 @@ import SVGRenderer from '/src/SVGRenderer.mjs'
|
||||
import PNGRenderer from '/src/PNGRenderer.mjs'
|
||||
import PDFRenderer from '/src/PDFRenderer.mjs'
|
||||
|
||||
// Get references to the custom elements
|
||||
const box = document.querySelector('fabaccess-preview-box')
|
||||
const form = document.querySelector('fabaccess-settings-form')
|
||||
|
||||
@ -12,10 +13,12 @@ form.addEventListener('change', (e) => {
|
||||
box.update()
|
||||
})
|
||||
|
||||
// Add click event listeners to the buttons
|
||||
document.querySelector('#download-qr-code-svg').addEventListener('click', () => SVGRenderer.downloadSVG(form.machineID, form.size))
|
||||
document.querySelector('#download-qr-code-png').addEventListener('click', () => PNGRenderer.downloadPNG(form.machineID, form.size))
|
||||
document.querySelector('#add-qr-code-to-page').addEventListener('click', () => PDFRenderer.addToPDF(form.machineID, form.size))
|
||||
document.querySelector('#download-pdf').addEventListener('click', () => PDFRenderer.downloadPDF())
|
||||
|
||||
// Initialize the preview box
|
||||
box.setAttribute('value', form.machineID)
|
||||
box.setAttribute('size', form.size)
|
||||
|
1997
package-lock.json
generated
Normal file
1997
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@ -1,16 +1,25 @@
|
||||
{
|
||||
"name": "fabaccess-sticker-generator",
|
||||
"version": "1.0.0",
|
||||
"description": "FabAccess Sticker Generator",
|
||||
"homepage": "https://fabaccess-sticker-generator.sternenlabor.de/",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
"start": "light-server --serve ./"
|
||||
},
|
||||
"author": "André Fiedler",
|
||||
"license": "CC0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Sternenlabor/fabaccess-sticker-generator/issues"
|
||||
},
|
||||
"dependencies": {}
|
||||
"name": "fabaccess-sticker-generator",
|
||||
"version": "1.0.0",
|
||||
"description": "FabAccess Sticker Generator",
|
||||
"homepage": "https://fabaccess-sticker-generator.sternenlabor.de/",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
"start": "npm run lite",
|
||||
"lite": "lite-server"
|
||||
},
|
||||
"author": "André Fiedler",
|
||||
"license": "CC0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Sternenlabor/fabaccess-sticker-generator/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.7.8",
|
||||
"lite-server": "^2.6.1"
|
||||
},
|
||||
"overrides": {
|
||||
"localtunnel": {
|
||||
"axios": "1.6.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +1,60 @@
|
||||
// Create a template element to define the structure of the custom checkbox component
|
||||
const template = document.createElement('template')
|
||||
template.innerHTML = /* html */ `
|
||||
<style> @import url("/src/Checkbox.css"); </style>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="checkbox" />
|
||||
<span class="checkmark"></span>
|
||||
<slot></slot>
|
||||
</label>`
|
||||
<style> @import url("/src/Checkbox.css"); </style>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="checkbox" />
|
||||
<span class="checkmark"></span>
|
||||
<slot></slot>
|
||||
</label>`
|
||||
|
||||
// Define a custom Checkbox class that extends HTMLElement
|
||||
class Checkbox extends HTMLElement {
|
||||
#root = null
|
||||
#root = null // Private property to store the root node
|
||||
|
||||
/**
|
||||
* Creates an instance of Checkbox and initializes the shadow DOM.
|
||||
*/
|
||||
constructor() {
|
||||
super()
|
||||
super() // Call the parent class constructor
|
||||
|
||||
// Attach a shadow DOM tree to this element
|
||||
this.attachShadow({ mode: 'open' })
|
||||
|
||||
// Append the cloned template content to the shadow root
|
||||
this.shadowRoot.append(template.content.cloneNode(true))
|
||||
|
||||
// Get the root node of the shadow DOM
|
||||
this.#root = this.shadowRoot.getRootNode()
|
||||
|
||||
// Get the checkbox input element from the shadow DOM
|
||||
const checkbox = this.#root.getElementById('checkbox')
|
||||
|
||||
// Add an event listener for the 'change' event on the checkbox
|
||||
checkbox.addEventListener('change', this.#handleChange.bind(this), {
|
||||
passive: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the 'change' event of the checkbox input.
|
||||
* @param {Event} e - The event object.
|
||||
* @private
|
||||
*/
|
||||
#handleChange(e) {
|
||||
const val = e.target.checked
|
||||
const val = e.target.checked // Get the checked state of the checkbox
|
||||
|
||||
// Dispatch a custom 'change' event from the custom element
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('change', {
|
||||
detail: {
|
||||
checked: val
|
||||
checked: val // Include the checked state in the event detail
|
||||
},
|
||||
composed: true
|
||||
composed: true // Allow the event to bubble up through the shadow DOM boundary
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Define the custom element 'fabaccess-checkbox' associated with the Checkbox class
|
||||
customElements.define('fabaccess-checkbox', Checkbox)
|
||||
|
@ -1,54 +1,70 @@
|
||||
import Color from '/lib/color.js'
|
||||
import Color from '/lib/color.js' // Import the Color library
|
||||
|
||||
// Thanks to Firefox who's not supporting all color stuff in SVG like Chrome does ... we need to do this...
|
||||
// Due to Firefox not supporting all color functionalities in SVG like Chrome does, we need to do this workaround
|
||||
export default class ColorUtils {
|
||||
/**
|
||||
* Converts a CSS color function to a hex color code.
|
||||
* @param {string} cssColorFunction - The CSS color function string to convert.
|
||||
* @returns {string|null} - The converted hex color code or null if conversion is not possible.
|
||||
*/
|
||||
static convertColor(cssColorFunction) {
|
||||
// Regular expression to match hex color codes
|
||||
// Regular expression to match hex color codes (e.g., #FFF or #FFFFFF)
|
||||
const hexColorRegex = /^#(?:[0-9a-fA-F]{3}){1,2}$/
|
||||
|
||||
// Check if the input is a valid hex color code
|
||||
if (hexColorRegex.test(cssColorFunction)) {
|
||||
return cssColorFunction // Return the hex color code if it matches the pattern
|
||||
} else {
|
||||
// Extracting the adjustments and hex value
|
||||
// Extract the adjustments and hex value from the CSS color function
|
||||
const result = this.extractAdjustmentsAndHex(cssColorFunction)
|
||||
|
||||
if (result) {
|
||||
// Create a new Color object from the extracted hex value and convert it to OKLCH color space
|
||||
const oklch = new Color(result.hex).to('oklch')
|
||||
|
||||
console.log(oklch.l, oklch.c, oklch.h)
|
||||
console.log(oklch.l, oklch.c, oklch.h) // Log the original OKLCH values
|
||||
|
||||
// Apply the adjustments to the OKLCH components
|
||||
oklch.l += result.lAdjust
|
||||
oklch.c += result.cAdjust
|
||||
oklch.h += result.hAdjust
|
||||
|
||||
console.log(oklch.l, oklch.c, oklch.h)
|
||||
console.log(oklch.l, oklch.c, oklch.h) // Log the adjusted OKLCH values
|
||||
|
||||
// Convert the adjusted OKLCH color back to a hex color code in A98 RGB color space
|
||||
const hex = oklch.to('a98rgb').toString({ format: 'hex' })
|
||||
|
||||
console.log(hex)
|
||||
console.log(hex) // Log the final hex color code
|
||||
|
||||
return hex
|
||||
return hex // Return the final hex color code
|
||||
} else {
|
||||
// If no adjustments and hex value could be extracted, log a message
|
||||
console.log('No values found.', cssColorFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts adjustments and hex value from a CSS OKLCH color function string.
|
||||
* @param {string} css - The CSS color function string to extract from.
|
||||
* @returns {Object|null} - An object containing hex, lAdjust, cAdjust, hAdjust or null if no matches found.
|
||||
*/
|
||||
static extractAdjustmentsAndHex(css) {
|
||||
// Regular expression to match the specific OKLCH color function format
|
||||
const regex = /oklch\(from (#\w{6}) calc\(l \+ ([\d\.\-]+)\) calc\(c \+ ([\d\.\-]+)\) calc\(h - ([\d\.\-]+)\)\)/
|
||||
const matches = css.match(regex)
|
||||
|
||||
if (matches) {
|
||||
// Destructure the matches to extract hex value and adjustments
|
||||
const [_, hex, lAdjust, cAdjust, hAdjust] = matches
|
||||
return {
|
||||
hex: hex,
|
||||
lAdjust: parseFloat(lAdjust),
|
||||
cAdjust: parseFloat(cAdjust),
|
||||
hAdjust: parseFloat(hAdjust)
|
||||
hex: hex, // Original hex color code
|
||||
lAdjust: parseFloat(lAdjust), // Adjustment for lightness
|
||||
cAdjust: parseFloat(cAdjust), // Adjustment for chroma
|
||||
hAdjust: parseFloat(hAdjust) // Adjustment for hue
|
||||
}
|
||||
} else {
|
||||
// Return null or some default values if no matches found
|
||||
// Return null if no matches found
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,49 @@
|
||||
// Implementation of a custom EventTarget class to manage event listeners and dispatch events
|
||||
export default class EventTarget {
|
||||
#listeners = {}
|
||||
#listeners = {} // Private property to store event listeners
|
||||
|
||||
/**
|
||||
* Adds an event listener for a specific event type.
|
||||
* @param {string} event - The event type to listen for.
|
||||
* @param {Function} callback - The callback function to be called when the event is dispatched.
|
||||
*/
|
||||
addEventListener(event, callback) {
|
||||
// Initialize the listeners array for the event if it doesn't exist
|
||||
if (!this.#listeners[event]) {
|
||||
this.#listeners[event] = []
|
||||
}
|
||||
// Add the callback to the listeners array for the event
|
||||
this.#listeners[event].push(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event listener for a specific event type.
|
||||
* @param {string} event - The event type for which the listener should be removed.
|
||||
* @param {Function} callback - The callback function to remove from the listeners.
|
||||
*/
|
||||
removeEventListener(event, callback) {
|
||||
// If there are no listeners for the event, exit the method
|
||||
if (!this.#listeners[event]) {
|
||||
return
|
||||
}
|
||||
// Find the index of the callback in the listeners array
|
||||
const callbackIndex = this.#listeners[event].indexOf(callback)
|
||||
// If the callback exists, remove it from the array
|
||||
if (callbackIndex > -1) {
|
||||
this.#listeners[event].splice(callbackIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event to all registered listeners of the event's type.
|
||||
* @param {Object} event - The event object to dispatch. Should have a 'type' property.
|
||||
*/
|
||||
dispatchEvent(event) {
|
||||
// If there are no listeners for the event type, exit the method
|
||||
if (!this.#listeners[event.type]) {
|
||||
return
|
||||
}
|
||||
// Call each listener's callback function with the event object
|
||||
this.#listeners[event.type].forEach((callback) => {
|
||||
callback(event)
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ import { changeDpiBlob } from '/lib/changeDPI/index.js'
|
||||
import Utils from '/src/Utils.mjs'
|
||||
import SVGRenderer from '/src/SVGRenderer.mjs'
|
||||
|
||||
// Constants for rendering
|
||||
const DPI = 300.0
|
||||
const SVG_PIXEL_HEIGHT = 108.0
|
||||
const SVG_PIXEL_WIDTH = 197.0
|
||||
@ -16,10 +17,15 @@ const PAGE_MARGIN_Y = 10.0 // mm
|
||||
const SPACE_BETWEEN_CODE_AND_LABEL = 4.0 // mm
|
||||
|
||||
export default class PDFRenderer {
|
||||
static #qrCodes = []
|
||||
static #pdfDoc = null
|
||||
static #listeners = {}
|
||||
static #qrCodes = [] // Array to store QR code data
|
||||
static #pdfDoc = null // PDF document instance
|
||||
static #listeners = {} // Event listeners
|
||||
|
||||
/**
|
||||
* Adds an event listener for a specific event type.
|
||||
* @param {string} event - The event type to listen for.
|
||||
* @param {Function} callback - The callback function to be called when the event is dispatched.
|
||||
*/
|
||||
static addEventListener(event, callback) {
|
||||
if (!this.#listeners[event]) {
|
||||
this.#listeners[event] = []
|
||||
@ -27,6 +33,11 @@ export default class PDFRenderer {
|
||||
this.#listeners[event].push(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an event listener for a specific event type.
|
||||
* @param {string} event - The event type for which the listener should be removed.
|
||||
* @param {Function} callback - The callback function to remove from the listeners.
|
||||
*/
|
||||
static removeEventListener(event, callback) {
|
||||
if (!this.#listeners[event]) {
|
||||
return
|
||||
@ -37,6 +48,10 @@ export default class PDFRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event to all registered listeners of the event's type.
|
||||
* @param {Object} event - The event object to dispatch. Should have a 'type' property.
|
||||
*/
|
||||
static dispatchEvent(event) {
|
||||
if (!this.#listeners[event.type]) {
|
||||
return
|
||||
@ -46,30 +61,39 @@ export default class PDFRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a QR code to the PDF document.
|
||||
* @param {string} machineID - The machine ID to encode in the QR code.
|
||||
* @param {number|string} size - The size of the QR code in millimeters.
|
||||
*/
|
||||
static async addToPDF(machineID, size) {
|
||||
const mmHeight = parseFloat(size)
|
||||
const mmWidth = (mmHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH
|
||||
const mmHeight = parseFloat(size) // Convert size to float
|
||||
const mmWidth = (mmHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH // Calculate width proportionally
|
||||
const inches = mmHeight /* mm */ / 25.4 // There are 25.4 millimeters in an inch
|
||||
const pixelHeight = inches * DPI
|
||||
const pixelWidth = (pixelHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH
|
||||
const pixelHeight = inches * DPI // Calculate pixel height
|
||||
const pixelWidth = (pixelHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH // Calculate pixel width
|
||||
|
||||
const height = Math.round(pixelHeight)
|
||||
const width = Math.round(pixelWidth)
|
||||
const height = Math.round(pixelHeight) // Round to nearest integer
|
||||
const width = Math.round(pixelWidth) // Round to nearest integer
|
||||
|
||||
// Generate SVG code for the QR code
|
||||
const svgCode = SVGRenderer.getCode(machineID, height, width)
|
||||
|
||||
// Create an offscreen canvas to render the SVG
|
||||
const c = new OffscreenCanvas(width, height)
|
||||
const ctx = c.getContext('2d')
|
||||
// Use canvg to render SVG to canvas
|
||||
const v = await canvg.Canvg.fromString(ctx, svgCode, canvg.presets.offscreen())
|
||||
|
||||
v.resize(width, height, 'xMidYMid meet')
|
||||
v.resize(width, height, 'xMidYMid meet') // Resize the SVG to fit the canvas
|
||||
|
||||
await v.render()
|
||||
await v.render() // Render the SVG onto the canvas
|
||||
|
||||
let b = await c.convertToBlob()
|
||||
b = await changeDpiBlob(b, DPI)
|
||||
const imgData = URL.createObjectURL(b)
|
||||
let b = await c.convertToBlob() // Convert canvas to Blob
|
||||
b = await changeDpiBlob(b, DPI) // Change the DPI of the blob
|
||||
const imgData = URL.createObjectURL(b) // Create a URL for the blob
|
||||
|
||||
// Store QR code data
|
||||
this.#qrCodes.push({
|
||||
machineID,
|
||||
mmHeight,
|
||||
@ -79,12 +103,17 @@ export default class PDFRenderer {
|
||||
imgData
|
||||
})
|
||||
|
||||
// Render the PDF with the new QR code
|
||||
this.renderPDF()
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the PDF document with all added QR codes.
|
||||
*/
|
||||
static async renderPDF() {
|
||||
const compress = 'fast'
|
||||
const compress = 'fast' // Compression option for images
|
||||
|
||||
// Create a new jsPDF document
|
||||
this.#pdfDoc = new jspdf.jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
@ -94,47 +123,55 @@ export default class PDFRenderer {
|
||||
compressPdf: false
|
||||
})
|
||||
|
||||
this.#pdfDoc.setFontSize(9)
|
||||
this.#pdfDoc.setTextColor('#3c474d')
|
||||
this.#pdfDoc.setFontSize(9) // Set font size for labels
|
||||
this.#pdfDoc.setTextColor('#3c474d') // Set text color
|
||||
|
||||
// Get page dimensions
|
||||
const pageSize = this.#pdfDoc.internal.pageSize
|
||||
const pageHeight = pageSize.height ? pageSize.height : pageSize.getHeight()
|
||||
const pageWidth = this.#pdfDoc.internal.pageSize.width || this.#pdfDoc.internal.pageSize.getWidth()
|
||||
const pageWidth = pageSize.width ? pageSize.width : pageSize.getWidth()
|
||||
|
||||
// Sort QR codes by height
|
||||
this.#qrCodes.sort((a, b) => a.mmHeight - b.mmHeight)
|
||||
|
||||
let curX = PAGE_MARGIN_X
|
||||
let curY = PAGE_MARGIN_Y
|
||||
let curX = PAGE_MARGIN_X // Current X position
|
||||
let curY = PAGE_MARGIN_Y // Current Y position
|
||||
|
||||
for (let i = 0; i < this.#qrCodes.length; i++) {
|
||||
const { machineID, imgData, mmWidth, mmHeight } = this.#qrCodes[i]
|
||||
|
||||
// Add QR code image to PDF
|
||||
this.#pdfDoc.addImage(imgData, 'PNG', curX, curY, Math.round(mmWidth), Math.round(mmHeight), undefined, compress)
|
||||
|
||||
// Get dimensions of the machine ID text
|
||||
const txtDim = this.#pdfDoc.getTextDimensions(machineID)
|
||||
|
||||
// Add machine ID text below the QR code, centered
|
||||
this.#pdfDoc.text(machineID, curX + (mmWidth - txtDim.w) / 2, curY + mmHeight + SPACE_BETWEEN_CODE_AND_LABEL)
|
||||
|
||||
curX += mmWidth + PADDING_BETWEEN_CODES_X
|
||||
curX += mmWidth + PADDING_BETWEEN_CODES_X // Update X position
|
||||
|
||||
if (i < this.#qrCodes.length - 1) {
|
||||
// we are not at the end
|
||||
// We are not at the end
|
||||
if (curX + PADDING_BETWEEN_CODES_X + this.#qrCodes[i + 1].mmWidth > pageWidth) {
|
||||
// next code will not fit on the current line
|
||||
curX = PAGE_MARGIN_X
|
||||
curY += mmHeight + SPACE_BETWEEN_CODE_AND_LABEL + txtDim.h + PADDING_BETWEEN_CODES_Y
|
||||
// Next code will not fit on the current line
|
||||
curX = PAGE_MARGIN_X // Reset X position
|
||||
curY += mmHeight + SPACE_BETWEEN_CODE_AND_LABEL + txtDim.h + PADDING_BETWEEN_CODES_Y // Move to next line
|
||||
}
|
||||
if (curY + PADDING_BETWEEN_CODES_Y + this.#qrCodes[i + 1].mmHeight + SPACE_BETWEEN_CODE_AND_LABEL + txtDim.h > pageHeight) {
|
||||
this.#pdfDoc.addPage()
|
||||
curX = PAGE_MARGIN_X
|
||||
curY = PAGE_MARGIN_Y
|
||||
// Next code will not fit on the current page
|
||||
this.#pdfDoc.addPage() // Add a new page
|
||||
curX = PAGE_MARGIN_X // Reset X position
|
||||
curY = PAGE_MARGIN_Y // Reset Y position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate blob from PDF and create URL
|
||||
var blobPDF = new Blob([this.#pdfDoc.output('blob')], { type: 'application/pdf' })
|
||||
var blobUrl = URL.createObjectURL(blobPDF)
|
||||
|
||||
// Dispatch event with the PDF URL
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('change', {
|
||||
detail: {
|
||||
@ -145,7 +182,10 @@ export default class PDFRenderer {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the download of the generated PDF document.
|
||||
*/
|
||||
static downloadPDF() {
|
||||
this.#pdfDoc?.save(Utils.getFilename('pdf'))
|
||||
this.#pdfDoc?.save(Utils.getFilename('pdf')) // Save the PDF with a generated filename
|
||||
}
|
||||
}
|
||||
|
@ -5,98 +5,124 @@ import PDFRenderer from '/src/PDFRenderer.mjs'
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/jspdf/build/pdf.worker.mjs'
|
||||
|
||||
// Create a template element to define the structure of the PDF viewer component
|
||||
const template = document.createElement('template')
|
||||
template.innerHTML = /* html */ `
|
||||
<style> @import url("/src/PDFViewer.css"); </style>
|
||||
<div id="pdf-viewer">
|
||||
<div class="toolbar">
|
||||
<button id="prev" class="toolbar-button" title="Previous Page">
|
||||
<span>Previous</span>
|
||||
</button>
|
||||
<button id="next" class="toolbar-button" title="Next Page">
|
||||
<span>Next</span>
|
||||
</button>
|
||||
<span id="npages"></span>
|
||||
<style> @import url("/src/PDFViewer.css"); </style>
|
||||
<div id="pdf-viewer">
|
||||
<div class="toolbar">
|
||||
<button id="prev" class="toolbar-button" title="Previous Page">
|
||||
<span>Previous</span>
|
||||
</button>
|
||||
<button id="next" class="toolbar-button" title="Next Page">
|
||||
<span>Next</span>
|
||||
</button>
|
||||
<span id="npages"></span>
|
||||
|
||||
<span id="pdf-title">PDF</span>
|
||||
<span id="pdf-title">PDF</span>
|
||||
|
||||
<!--
|
||||
<button id="print" class="toolbar-button" title="Print">
|
||||
<span>Print</span>
|
||||
</button>
|
||||
-->
|
||||
<button id="download" class="toolbar-button" title="Save">
|
||||
<span>Save</span>
|
||||
</button>
|
||||
</div>
|
||||
<canvas id="cnv"></canvas>
|
||||
</div>`
|
||||
<!--
|
||||
<button id="print" class="toolbar-button" title="Print">
|
||||
<span>Print</span>
|
||||
</button>
|
||||
-->
|
||||
<button id="download" class="toolbar-button" title="Save">
|
||||
<span>Save</span>
|
||||
</button>
|
||||
</div>
|
||||
<canvas id="cnv"></canvas>
|
||||
</div>`
|
||||
|
||||
// Define a custom PDFViewer class that extends HTMLElement
|
||||
class PDFViewer extends HTMLElement {
|
||||
#root = null
|
||||
#root = null // Private property to store the root node
|
||||
|
||||
/**
|
||||
* Creates an instance of PDFViewer and initializes the component.
|
||||
*/
|
||||
constructor() {
|
||||
super()
|
||||
super() // Call the parent class constructor
|
||||
|
||||
// Attach a shadow DOM tree to this element
|
||||
this.attachShadow({ mode: 'open' })
|
||||
// Append the cloned template content to the shadow root
|
||||
this.shadowRoot.append(template.content.cloneNode(true))
|
||||
|
||||
// Get the root node of the shadow DOM
|
||||
this.#root = this.shadowRoot.getRootNode()
|
||||
|
||||
//this.#root.querySelector('#print').addEventListener('click', () => {})
|
||||
// Add event listener for the 'download' button to download the PDF
|
||||
// this.#root.querySelector('#print').addEventListener('click', () => {})
|
||||
this.#root.querySelector('#download').addEventListener('click', () => PDFRenderer.downloadPDF())
|
||||
|
||||
// Listen for 'change' events from PDFRenderer to display the PDF
|
||||
PDFRenderer.addEventListener('change', (e) => {
|
||||
this.showPDF(e.detail.pdf)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the PDF document in the viewer.
|
||||
* @param {string} blobUrl - The URL of the PDF blob to display.
|
||||
*/
|
||||
async showPDF(blobUrl) {
|
||||
// Load the PDF document
|
||||
const loadingTask = pdfjsLib.getDocument(blobUrl)
|
||||
const canvas = this.#root.querySelector('#cnv')
|
||||
const ctx = canvas.getContext('2d')
|
||||
const scale = 1.5
|
||||
let numPage = 1
|
||||
const canvas = this.#root.querySelector('#cnv') // Get the canvas element
|
||||
const ctx = canvas.getContext('2d') // Get the 2D rendering context
|
||||
const scale = 1.5 // Scale for rendering the PDF pages
|
||||
let numPage = 1 // Current page number
|
||||
|
||||
const doc = await loadingTask.promise
|
||||
const doc = await loadingTask.promise // Wait for the PDF to be loaded
|
||||
|
||||
/**
|
||||
* Renders a specific page of the PDF document.
|
||||
* @param {number} numPage - The page number to display.
|
||||
*/
|
||||
const showPage = async (numPage) => {
|
||||
const page = await doc.getPage(numPage)
|
||||
let viewport = page.getViewport({ scale: scale })
|
||||
canvas.height = viewport.height
|
||||
canvas.width = viewport.width
|
||||
const page = await doc.getPage(numPage) // Get the page
|
||||
let viewport = page.getViewport({ scale: scale }) // Get the viewport at the desired scale
|
||||
canvas.height = viewport.height // Set canvas height
|
||||
canvas.width = viewport.width // Set canvas width
|
||||
|
||||
let renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
}
|
||||
|
||||
page.render(renderContext)
|
||||
await page.render(renderContext) // Render the page into the canvas
|
||||
|
||||
// Update the page number display
|
||||
this.#root.querySelector('#npages').innerHTML = `Page ${numPage} / ${doc.numPages}`
|
||||
}
|
||||
|
||||
// Show the first page
|
||||
this.#root.querySelector('#npages').innerHTML = `Page 1 / ${doc.numPages}`
|
||||
showPage(numPage)
|
||||
|
||||
// Function to go to the previous page
|
||||
const prevPage = () => {
|
||||
if (numPage === 1) {
|
||||
return
|
||||
return // Do nothing if already at the first page
|
||||
}
|
||||
numPage--
|
||||
showPage(numPage)
|
||||
}
|
||||
|
||||
// Function to go to the next page
|
||||
const nextPage = () => {
|
||||
if (numPage >= doc.numPages) {
|
||||
return
|
||||
return // Do nothing if already at the last page
|
||||
}
|
||||
numPage++
|
||||
showPage(numPage)
|
||||
}
|
||||
|
||||
// Add event listeners for the 'prev' and 'next' buttons
|
||||
this.#root.querySelector('#prev').addEventListener('click', prevPage)
|
||||
this.#root.querySelector('#next').addEventListener('click', nextPage)
|
||||
}
|
||||
}
|
||||
|
||||
// Define the custom element 'fabaccess-pdf-viewer' associated with the PDFViewer class
|
||||
customElements.define('fabaccess-pdf-viewer', PDFViewer)
|
||||
|
@ -11,32 +11,43 @@ const SVG_PIXEL_HEIGHT = 108.0
|
||||
const SVG_PIXEL_WIDTH = 197.0
|
||||
|
||||
export default class PNGRenderer {
|
||||
/**
|
||||
* Downloads a PNG image of a QR code for the given machine ID and size.
|
||||
* @param {string} machineID - The machine ID to encode in the QR code.
|
||||
* @param {number|string} height - The height of the image in millimeters.
|
||||
* @param {number|null} [width=null] - The width of the image in millimeters (optional).
|
||||
*/
|
||||
static async downloadPNG(machineID, height, width = null) {
|
||||
const n = Utils.getFilename('png')
|
||||
|
||||
// Convert height from millimeters to inches
|
||||
const inches = parseFloat(height) /* mm */ / 25.4 // There are 25.4 millimeters in an inch
|
||||
const pixelHeight = inches * DPI
|
||||
const pixelWidth = (pixelHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH
|
||||
const pixelHeight = inches * DPI // Calculate pixel height based on DPI
|
||||
const pixelWidth = (pixelHeight / SVG_PIXEL_HEIGHT) * SVG_PIXEL_WIDTH // Calculate pixel width proportionally
|
||||
|
||||
const heightPx = Math.round(pixelHeight)
|
||||
const widthPx = Math.round(pixelWidth)
|
||||
const heightPx = Math.round(pixelHeight) // Round pixel height to nearest integer
|
||||
const widthPx = Math.round(pixelWidth) // Round pixel width to nearest integer
|
||||
|
||||
// Generate SVG code for the QR code
|
||||
const svgCode = SVGRenderer.getCode(machineID, heightPx, widthPx)
|
||||
|
||||
// Create an offscreen canvas to render the SVG
|
||||
const c = new OffscreenCanvas(widthPx, heightPx)
|
||||
const ctx = c.getContext('2d')
|
||||
// Use canvg to render SVG to canvas
|
||||
const v = await canvg.Canvg.fromString(ctx, svgCode, canvg.presets.offscreen())
|
||||
|
||||
v.resize(widthPx, heightPx, 'xMidYMid meet')
|
||||
v.resize(widthPx, heightPx, 'xMidYMid meet') // Resize the SVG to fit the canvas
|
||||
|
||||
await v.render()
|
||||
await v.render() // Render the SVG onto the canvas
|
||||
|
||||
let b = await c.convertToBlob()
|
||||
let b = await c.convertToBlob() // Convert canvas to Blob
|
||||
|
||||
b = await changeDpiBlob(b, DPI)
|
||||
b = await changeDpiBlob(b, DPI) // Change the DPI of the blob
|
||||
|
||||
// Handle file download for different browsers
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveOrOpenBlob(b, n)
|
||||
window.navigator.msSaveOrOpenBlob(b, n) // For IE and Edge
|
||||
} else {
|
||||
const a = document.createElement('a')
|
||||
const u = URL.createObjectURL(b)
|
||||
|
@ -1,65 +1,100 @@
|
||||
import SVGRenderer from '/src/SVGRenderer.mjs'
|
||||
|
||||
// Create a template element to define the structure of the preview box component
|
||||
const template = document.createElement('template')
|
||||
template.innerHTML = /* html */ `
|
||||
<style> @import url("/src/PreviewBox.css"); </style>
|
||||
<div id="box"></div>`
|
||||
<style> @import url("/src/PreviewBox.css"); </style>
|
||||
<div id="box"></div>`
|
||||
|
||||
// Define a custom PreviewBox class that extends HTMLElement
|
||||
class PreviewBox extends HTMLElement {
|
||||
value = ''
|
||||
size = 0
|
||||
value = '' // The value to be encoded in the QR code
|
||||
size = 0 // The size of the QR code
|
||||
|
||||
#root = null
|
||||
#box = null
|
||||
#animationId = 0
|
||||
#root = null // Private property to store the root node
|
||||
#box = null // Private property to store the box element
|
||||
#animationId = 0 // Private property for requestAnimationFrame
|
||||
|
||||
/**
|
||||
* Creates an instance of PreviewBox and initializes the component.
|
||||
*/
|
||||
constructor() {
|
||||
super()
|
||||
super() // Call the parent class constructor
|
||||
|
||||
// Attach a shadow DOM tree to this element
|
||||
this.attachShadow({ mode: 'open' })
|
||||
// Append the cloned template content to the shadow root
|
||||
this.shadowRoot.append(template.content.cloneNode(true))
|
||||
|
||||
// Get the root node of the shadow DOM
|
||||
this.#root = this.shadowRoot.getRootNode()
|
||||
// Get the box element from the shadow DOM
|
||||
this.#box = this.#root.getElementById('box')
|
||||
|
||||
// Initialize value and size from attributes
|
||||
this.value = this.getAttribute('value') || ''
|
||||
this.size = parseFloat(this.getAttribute('size'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Observed attributes for the custom element.
|
||||
* @returns {Array<string>} - The list of attributes to observe.
|
||||
*/
|
||||
static get observedAttributes() {
|
||||
return ['value', 'size']
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when one of the observed attributes changes.
|
||||
* @param {string} name - The name of the attribute that changed.
|
||||
* @param {string} oldValue - The old value of the attribute.
|
||||
* @param {string} newValue - The new value of the attribute.
|
||||
*/
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (newValue != oldValue) {
|
||||
switch (name) {
|
||||
case 'value':
|
||||
this[name] = newValue
|
||||
this[name] = newValue // Update the value property
|
||||
break
|
||||
case 'size':
|
||||
this[name] = parseFloat(newValue)
|
||||
this[name] = parseFloat(newValue) // Update the size property
|
||||
break
|
||||
}
|
||||
|
||||
this.#render()
|
||||
this.#render() // Re-render the QR code
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method to update the QR code rendering.
|
||||
*/
|
||||
update() {
|
||||
this.#render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the content of the box element.
|
||||
* @private
|
||||
*/
|
||||
#clear() {
|
||||
while (this.#box.childNodes[0]) {
|
||||
this.#box.removeChild(this.#box.childNodes[0])
|
||||
while (this.#box.firstChild) {
|
||||
this.#box.removeChild(this.#box.firstChild)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the QR code inside the box element.
|
||||
* @private
|
||||
*/
|
||||
#render() {
|
||||
// Cancel any pending animation frame
|
||||
window.cancelAnimationFrame(this.#animationId)
|
||||
// Schedule the rendering in the next animation frame
|
||||
this.#animationId = window.requestAnimationFrame(() => {
|
||||
this.#clear()
|
||||
this.#clear() // Clear existing content
|
||||
const time = new Date()
|
||||
|
||||
// Generate the QR code SVG and insert it into the box
|
||||
this.#box.innerHTML = SVGRenderer.getCode(this.value, `${this.size}mm`)
|
||||
|
||||
console.log('QRCode generation time: ' + (new Date() - time) + ' ms')
|
||||
@ -67,4 +102,5 @@ class PreviewBox extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
// Define the custom element 'fabaccess-preview-box' associated with the PreviewBox class
|
||||
customElements.define('fabaccess-preview-box', PreviewBox)
|
||||
|
@ -7,6 +7,13 @@ const SVG_PIXEL_WIDTH = 197.0
|
||||
export default class SVGRenderer {
|
||||
static optimizeForPrint = false
|
||||
|
||||
/**
|
||||
* Generates the SVG code for a QR code with the given machine ID and dimensions.
|
||||
* @param {string} machineID - The machine ID to encode in the QR code.
|
||||
* @param {number|string} height - The height of the SVG in pixels or millimeters.
|
||||
* @param {number|null} [width=null] - The width of the SVG in pixels or millimeters (optional).
|
||||
* @returns {string} - The generated SVG code.
|
||||
*/
|
||||
static getCode(machineID, height, width = null) {
|
||||
const data = {
|
||||
msg: `urn:fabaccess:resource:${machineID}`,
|
||||
@ -27,6 +34,7 @@ export default class SVGRenderer {
|
||||
wh += `height="${height}" `
|
||||
}
|
||||
|
||||
// Generate the SVG code with placeholders for colors
|
||||
let svgCode = `
|
||||
<svg version="1.1" viewBox="0 0 ${SVG_PIXEL_WIDTH} ${SVG_PIXEL_HEIGHT}" ${wh} xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges">
|
||||
<path d="m7.35 0c-4.06 0-7.33 3.27-7.33 7.33v23h-0.0197v70.7c0 4.06 3.27 7.33 7.33 7.33h182c4.06 0 7.33-3.27 7.33-7.33v-14.2h0.0197v-79.4c0-4.06-3.27-7.33-7.33-7.33z"
|
||||
@ -55,15 +63,23 @@ export default class SVGRenderer {
|
||||
return svgCode
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the generated SVG code as an SVG file.
|
||||
* @param {string} machineID - The machine ID to encode in the QR code.
|
||||
* @param {number|string} height - The height of the SVG in pixels or millimeters.
|
||||
* @param {number|null} [width=null] - The width of the SVG in pixels or millimeters (optional).
|
||||
*/
|
||||
static async downloadSVG(machineID, height, width = null) {
|
||||
const svgCode = this.getCode(machineID, height, width)
|
||||
|
||||
const n = Utils.getFilename('svg')
|
||||
|
||||
// Create a new Blob object with the SVG code
|
||||
const b = new Blob([svgCode], {
|
||||
type: 'image/svg+xml'
|
||||
})
|
||||
|
||||
// Handle file download
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveOrOpenBlob(b, n)
|
||||
} else {
|
||||
|
@ -1,51 +1,66 @@
|
||||
import SVGRenderer from '/src/SVGRenderer.mjs'
|
||||
import {} from '/src/Checkbox.mjs'
|
||||
|
||||
// Create a template element to define the structure of the settings form component
|
||||
const template = document.createElement('template')
|
||||
template.innerHTML = /* html */ `
|
||||
<style> @import url("/src/SettingsForm.css"); </style>
|
||||
<style> @import url("/src/SettingsForm.css"); </style>
|
||||
|
||||
<div class="form-group group-1">
|
||||
<label for="machineID">Machine ID:</label>
|
||||
<input type="text" name="machineID" id="machineID" placeholder="Enter the machine ID" />
|
||||
</div>
|
||||
<div class="form-group group-1">
|
||||
<label for="machineID">Machine ID:</label>
|
||||
<input type="text" name="machineID" id="machineID" placeholder="Enter the machine ID" />
|
||||
</div>
|
||||
|
||||
<div class="form-group group-2">
|
||||
<label for="size">QR Code Height:</label>
|
||||
<div class="select-wrapper">
|
||||
<select name="size" id="size">
|
||||
<option value="15">15 mm</option>
|
||||
<option value="25" selected>25 mm</option>
|
||||
<option value="40">40 mm</option>
|
||||
<option value="80">80 mm</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group group-2">
|
||||
<label for="size">QR Code Height:</label>
|
||||
<div class="select-wrapper">
|
||||
<select name="size" id="size">
|
||||
<option value="15">15 mm</option>
|
||||
<option value="25" selected>25 mm</option>
|
||||
<option value="40">40 mm</option>
|
||||
<option value="80">80 mm</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fabaccess-checkbox id="optimize-for-laser-printer" />Optimize Colors for Laser printing</fabaccess-checkbox>`
|
||||
|
||||
`
|
||||
|
||||
|
||||
// Define a custom SettingsForm class that extends HTMLElement
|
||||
class SettingsForm extends HTMLElement {
|
||||
machineID = ''
|
||||
size = 25
|
||||
optimizeForPrint = false
|
||||
machineID = '' // The machine ID entered by the user
|
||||
size = 25 // The selected size for the QR code
|
||||
optimizeForPrint = false // Whether to optimize colors for laser printing
|
||||
|
||||
#root = null
|
||||
#root = null // Private property to store the root node
|
||||
|
||||
/**
|
||||
* Creates an instance of SettingsForm and initializes the component.
|
||||
*/
|
||||
constructor() {
|
||||
super()
|
||||
super() // Call the parent class constructor
|
||||
|
||||
// Attach a shadow DOM tree to this element
|
||||
this.attachShadow({ mode: 'open' })
|
||||
// Append the cloned template content to the shadow root
|
||||
this.shadowRoot.append(template.content.cloneNode(true))
|
||||
|
||||
// Get the root node of the shadow DOM
|
||||
this.#root = this.shadowRoot.getRootNode()
|
||||
|
||||
// Initialize properties from attributes
|
||||
this.machineID = this.getAttribute('machineid') || ''
|
||||
this.size = parseFloat(this.getAttribute('size') || 25)
|
||||
this.optimizeForPrint = this.getAttribute('optimizeforprint') == 'true' || this.getAttribute('optimizeforprint') == '1'
|
||||
|
||||
// Get form elements from the shadow DOM
|
||||
const machineIdInput = this.#root.getElementById('machineID')
|
||||
const optimizeForPrint = this.#root.getElementById('optimize-for-laser-printer')
|
||||
const size = this.#root.getElementById('size')
|
||||
|
||||
// Add event listener for input changes
|
||||
machineIdInput.addEventListener('keyup', this.#handleInputChange.bind(this), {
|
||||
passive: false
|
||||
})
|
||||
@ -58,13 +73,24 @@ class SettingsForm extends HTMLElement {
|
||||
passive: false
|
||||
})
|
||||
|
||||
// Set focus to the machine ID input after the element is rendered
|
||||
setTimeout(() => machineIdInput.focus(), 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Observed attributes for the custom element.
|
||||
* @returns {Array<string>} - The list of attributes to observe.
|
||||
*/
|
||||
static get observedAttributes() {
|
||||
return ['value', 'size']
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when one of the observed attributes changes.
|
||||
* @param {string} name - The name of the attribute that changed.
|
||||
* @param {string} oldValue - The old value of the attribute.
|
||||
* @param {string} newValue - The new value of the attribute.
|
||||
*/
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (newValue != oldValue) {
|
||||
switch (name) {
|
||||
@ -78,11 +104,17 @@ class SettingsForm extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input changes in the machine ID input field.
|
||||
* @param {Event} e - The event object.
|
||||
* @private
|
||||
*/
|
||||
#handleInputChange(e) {
|
||||
e.stopPropagation()
|
||||
const val = e.target.value
|
||||
this.machineID = val
|
||||
|
||||
// Dispatch a custom 'change' event with the updated values
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('change', {
|
||||
detail: {
|
||||
@ -95,11 +127,17 @@ class SettingsForm extends HTMLElement {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes in the size select dropdown.
|
||||
* @param {Event} e - The event object.
|
||||
* @private
|
||||
*/
|
||||
#handleSelectChange(e) {
|
||||
e.stopPropagation()
|
||||
const val = e.target.value
|
||||
this.size = parseInt(val, 10)
|
||||
|
||||
// Dispatch a custom 'change' event with the updated values
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('change', {
|
||||
detail: {
|
||||
@ -112,11 +150,17 @@ class SettingsForm extends HTMLElement {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes in the optimize for print checkbox.
|
||||
* @param {Event} e - The event object.
|
||||
* @private
|
||||
*/
|
||||
#handleCheckboxChange(e) {
|
||||
e.stopPropagation()
|
||||
const val = e.detail.checked
|
||||
this.optimizeForPrint = val
|
||||
|
||||
// Dispatch a custom 'change' event with the updated values
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('change', {
|
||||
detail: {
|
||||
@ -130,4 +174,5 @@ class SettingsForm extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
// Define the custom element 'fabaccess-settings-form' associated with the SettingsForm class
|
||||
customElements.define('fabaccess-settings-form', SettingsForm)
|
||||
|
@ -1,32 +1,55 @@
|
||||
import ColorUtils from '/src/ColorUtils.mjs'
|
||||
import ColorUtils from '/src/ColorUtils.mjs' // Import the ColorUtils module
|
||||
|
||||
// Define the Utils class providing utility functions
|
||||
export default class Utils {
|
||||
/**
|
||||
* Replaces all occurrences of specified substrings in a string with their corresponding replacements.
|
||||
* @param {string} d - The original string to perform replacements on.
|
||||
* @param {Object} r - An object where keys are substrings to replace, and values are their replacements.
|
||||
* @returns {string} - The modified string with replacements made.
|
||||
*/
|
||||
static replace(d, r) {
|
||||
// Iterate over each key in the replacements object
|
||||
for (const k of Object.keys(r)) {
|
||||
// Replace all occurrences of the key with its corresponding value
|
||||
d = d.replaceAll(k, r[k])
|
||||
}
|
||||
return d
|
||||
return d // Return the modified string
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a filename based on the current date and time and the specified file type.
|
||||
* @param {string} type - The file extension or type (e.g., 'svg', 'png', 'pdf').
|
||||
* @returns {string} - The generated filename.
|
||||
*/
|
||||
static getFilename(type) {
|
||||
// Get the current date and time in ISO format and remove special characters
|
||||
const dateTime = this.replace(new Date().toISOString().slice(0, 19), {
|
||||
':': '',
|
||||
'-': '',
|
||||
T: '-'
|
||||
})
|
||||
// Determine the filename format based on the file type
|
||||
switch (type) {
|
||||
case 'svg':
|
||||
case 'png':
|
||||
return `fabaccess-qrcode-${dateTime}.${type}`
|
||||
return `fabaccess-qrcode-${dateTime}.${type}` // For SVG and PNG files
|
||||
case 'pdf':
|
||||
return `fabaccess-qrcodes-${dateTime}.pdf`
|
||||
return `fabaccess-qrcodes-${dateTime}.pdf` // For PDF files
|
||||
}
|
||||
// Default filename format if type doesn't match known cases
|
||||
return `fabaccess-${dateTime}.${type}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the computed CSS value of a given property.
|
||||
* @param {string} prop - The CSS property name.
|
||||
* @returns {string} - The computed CSS value.
|
||||
*/
|
||||
static getCssValue(prop) {
|
||||
// Get the computed style of the root document element for the given property
|
||||
const cssColorFunction = getComputedStyle(document.documentElement).getPropertyValue(prop)
|
||||
return cssColorFunction
|
||||
//return ColorUtils.convertColor(cssColorFunction) //fuuuu Firefox
|
||||
return cssColorFunction // Return the computed CSS value
|
||||
//return ColorUtils.convertColor(cssColorFunction) // fuuuu Firefox
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user