diff --git a/dsiUnits-js/src/dsiUnit.js b/dsiUnits-js/src/dsiUnit.js index 93de7ae411f4114a9182adf3703ecad617b35212..9a26986c46e9cd0c50e44d43c57c5e19d3c4dc9c 100644 --- a/dsiUnits-js/src/dsiUnit.js +++ b/dsiUnits-js/src/dsiUnit.js @@ -14,37 +14,39 @@ export class DSIUnit { this.scaleFactor = 1.0; } - toHTML({ wrapper = '', prefix = '', suffix = '' } = {}) { + toHTML(options = {}) { let htmlOutput = ''; if (this.nonDsiUnit) { - // For non-DSI units, ignore warnings and do not apply error wrapping. const content = `<span class="dsi-nonunit">${this.dsiString.startsWith('|') ? this.dsiString.slice(1) : this.dsiString}</span>`; htmlOutput = content; } else if (this.tree.length === 1) { - htmlOutput = this.tree[0].map(node => node.toHTML()).join('<span class="dsi-mul"> </span>'); + htmlOutput = this.tree[0].map(node => node.toHTML(options)).join(options.oneLine ? " " : '<span class="dsi-mul"> </span>'); } else if (this.tree.length === 2) { - const numerator = this.tree[0].map(node => node.toHTML()).join('<span class="dsi-mul"> </span>'); - const denominator = this.tree[1].map(node => node.toHTML()).join('<span class="dsi-mul"> </span>'); - htmlOutput = `<span class="dsi-fraction"><span class="dsi-numerator">${numerator}</span><span class="dsi-denom">${denominator}</span></span>`; + if (options.oneLine) { + const numerator = this.tree[0].map(node => node.toHTML(options)).join(" "); + const denominator = this.tree[1].map(node => node.toHTML(options)).join(" "); + htmlOutput = `${numerator} / ${denominator}`; + } else { + const numerator = this.tree[0].map(node => node.toHTML(options)).join('<span class="dsi-mul"> </span>'); + const denominator = this.tree[1].map(node => node.toHTML(options)).join('<span class="dsi-mul"> </span>'); + htmlOutput = `<span class="dsi-fraction"><span class="dsi-numerator">${numerator}</span><span class="dsi-denom">${denominator}</span></span>`; + } } else { - htmlOutput = this.tree.map(frac => frac.map(node => node.toHTML()).join('<span class="dsi-mul"> </span>')) - .join('<span class="dsi-invalid">/</span>'); + htmlOutput = this.tree.map(frac => frac.map(node => node.toHTML(options)).join(options.oneLine ? " " : '<span class="dsi-mul"> </span>')) + .join(options.oneLine ? " / " : '<span class="dsi-invalid">/</span>'); } if (this.scaleFactor !== 1.0) { htmlOutput = `<span class="dsi-scale">${this.scaleFactor}·</span>` + htmlOutput; } - // Only wrap in error styling if it's a DSI unit (not nonDSI) and not valid. if (!this.nonDsiUnit && !this.valid) { htmlOutput = `<span class="dsi-error">${htmlOutput}</span>`; } - // Add a tooltip if there are warnings (only for DSI units). let tooltip = ""; if (!this.nonDsiUnit && this.warnings && this.warnings.length > 0) { - // Replace double backslashes with a single one for display in the tooltip. const tooltipText = this.warnings.map(w => w.replace(/\\\\/g, '\\')).join("; "); tooltip = ` title="${tooltipText}"`; } - return `<span class="dsi-unit-wrapper"${tooltip}>${wrapper}${prefix}${htmlOutput}${suffix}${wrapper}</span>`; + return `<span class="dsi-unit-wrapper"${tooltip}>${htmlOutput}</span>`; } toString() { diff --git a/dsiUnits-js/src/dsiUnitInput.js b/dsiUnits-js/src/dsiUnitInput.js index 9b4fd76f3d8bd46e8796c800ffb4c4638f3d3e6e..200f37ba951ca13221eefab7b8fb284b3e3c3bc9 100644 --- a/dsiUnits-js/src/dsiUnitInput.js +++ b/dsiUnits-js/src/dsiUnitInput.js @@ -130,7 +130,7 @@ export class DSIUnitInput extends HTMLElement { return Object.keys(dsiUnitsHTML); } else if (prevToken in dsiUnitsHTML) { // After a unit, suggest all allowed tokens. - if (value.includes("\\per") || value.includes("/")) { + if (value.includes("\\per")) { return this.allowedTokens.filter(token => token !== "per"); } return this.allowedTokens; @@ -143,10 +143,9 @@ export class DSIUnitInput extends HTMLElement { onInput(e) { this._rawValue = this.input.value; - // Auto-insert a backslash if user types a space after a complete token. + // Auto-insert a backslash if the user types a space after a complete token. if (this.input.value.endsWith(" ")) { const trimmed = this.input.value.trimEnd(); - // Check if last token is complete (i.e. non-empty and doesn't already end with a backslash). if (!trimmed.endsWith("\\")) { this.input.value = trimmed + "\\"; this._rawValue = this.input.value; @@ -207,7 +206,7 @@ export class DSIUnitInput extends HTMLElement { } list.forEach((token, index) => { const item = document.createElement("div"); - // For suggestion display, always show with a backslash. + // Always render suggestions with a backslash. item.textContent = "\\" + token; item.className = "autocomplete-item"; if (index === this.selectedSuggestionIndex) { @@ -241,7 +240,7 @@ export class DSIUnitInput extends HTMLElement { if (this.selectedSuggestionIndex !== -1) { e.preventDefault(); const selectedItem = items[this.selectedSuggestionIndex]; - const token = selectedItem.textContent.slice(1); // remove leading backslash + const token = selectedItem.textContent.slice(1); // remove backslash const tokenStartIndex = this.input.value.lastIndexOf("\\"); this.acceptSuggestion(token, tokenStartIndex); } @@ -270,10 +269,6 @@ export class DSIUnitInput extends HTMLElement { this._rawValue = this.input.value; const newPos = before.length + token.length + 2; this.input.setSelectionRange(newPos, newPos); - } else if (token === "per") { - // Insert "/" instead of "\per" in the input field. - this.input.value = before + "/" + after; - this._rawValue = this.input.value; } else { this.input.value = before + "\\" + token + after; this._rawValue = this.input.value; @@ -284,10 +279,10 @@ export class DSIUnitInput extends HTMLElement { renderOutput() { try { - // Convert any "/" in the input value back to "\per" before parsing. - const processedValue = this.input.value.replace(/\//g, "\\per"); - const unit = new DSIUnit(processedValue); - this.display.innerHTML = unit.toHTML(); + // No special conversion for "per" is needed now. + const unit = new DSIUnit(this.input.value); + // Pass oneLine option if desired. + this.display.innerHTML = unit.toHTML({ oneLine: true }); if (unit.warnings && unit.warnings.length > 0) { this.display.title = unit.warnings.join("; "); } else { @@ -322,4 +317,4 @@ export class DSIUnitInput extends HTMLElement { } } -customElements.define("dsi-unit-input", DSIUnitInput); \ No newline at end of file +customElements.define("dsi-unit-input", DSIUnitInput); diff --git a/dsiUnits-js/src/dsiUnitNode.js b/dsiUnits-js/src/dsiUnitNode.js index 1b99a8342dee72a0ac1ce6e0cec4089abb115295..5d3d6fdf9b087c1ff14798dfb4f8631805f266c5 100644 --- a/dsiUnits-js/src/dsiUnitNode.js +++ b/dsiUnits-js/src/dsiUnitNode.js @@ -1,5 +1,5 @@ // src/dsiUnitNode.js -import { dsiPrefixesHTML, dsiUnitsHTML } from './unitStrings.js'; +import { dsiPrefixesHTML, dsiUnitsHTML } from "./unitStrings.js"; export class DSIUnitNode { constructor(prefix, unit, exponent = '', valid = true, scaleFactor = 1.0) { @@ -15,8 +15,7 @@ export class DSIUnitNode { this.scaleFactor = scaleFactor; } - toHTML() { - // Build prefix HTML + toHTML(options = {}) { let prefixHTML = ''; if (this.prefix) { if (this.prefix in dsiPrefixesHTML) { @@ -25,7 +24,6 @@ export class DSIUnitNode { prefixHTML = `<span class="dsi-unit"><span class="dsi-invalid">${this.prefix}</span></span>`; } } - // Build unit HTML let unitHTML = ''; if (this.unit) { if (this.unit in dsiUnitsHTML) { @@ -35,24 +33,29 @@ export class DSIUnitNode { } } let baseHTML = prefixHTML + unitHTML; - - // Handle exponent output: if exponent is not 1, check for common fractional exponents. if (this.exponent !== 1) { if (typeof this.exponent === 'number') { if (Math.abs(this.exponent - 0.5) < 0.0001) { - // Square root - return `<span class="dsi-root"><span class="dsi-root-symbol">√</span><span class="dsi-root-content">${baseHTML}</span></span>`; + // Square root. + return options.oneLine ? `√(${baseHTML})` + : `<span class="dsi-root"><span class="dsi-root-symbol">√</span><span class="dsi-root-content">${baseHTML}</span></span>`; } else if (Math.abs(this.exponent - 0.333333) < 0.0001) { - // Cube root - return `<span class="dsi-root"><span class="dsi-root-symbol">∛</span><span class="dsi-root-content">${baseHTML}</span></span>`; + // Cube root. + return options.oneLine ? `∛(${baseHTML})` + : `<span class="dsi-root"><span class="dsi-root-symbol">∛</span><span class="dsi-root-content">${baseHTML}</span></span>`; } else if (Math.abs(this.exponent - 0.25) < 0.0001) { - // Fourth root - return `<span class="dsi-root"><span class="dsi-root-symbol">∜</span><span class="dsi-root-content">${baseHTML}</span></span>`; + // Fourth root. + return options.oneLine ? `∜(${baseHTML})` + : `<span class="dsi-root"><span class="dsi-root-symbol">∜</span><span class="dsi-root-content">${baseHTML}</span></span>`; } else { - return `${baseHTML}<sup class="dsi-exponent">${this.exponent}</sup>`; + return options.oneLine + ? `${baseHTML}^(${this.exponent})` + : `${baseHTML}<sup class="dsi-exponent">${this.exponent}</sup>`; } } else { - return `${baseHTML}<sup class="dsi-exponent"><span class="dsi-invalid">${this.exponent}</span></sup>`; + return options.oneLine + ? `${baseHTML}^(<span class="dsi-invalid">${this.exponent}</span>)` + : `${baseHTML}<sup class="dsi-exponent"><span class="dsi-invalid">${this.exponent}</span></sup>`; } } return baseHTML;