diff --git a/dsiUnits-js/src/dsiUnitInput.js b/dsiUnits-js/src/dsiUnitInput.js index 00d7db445f3f733cdd394797ff82cee2778753b7..9b4fd76f3d8bd46e8796c800ffb4c4638f3d3e6e 100644 --- a/dsiUnits-js/src/dsiUnitInput.js +++ b/dsiUnits-js/src/dsiUnitInput.js @@ -130,8 +130,7 @@ export class DSIUnitInput extends HTMLElement { return Object.keys(dsiUnitsHTML); } else if (prevToken in dsiUnitsHTML) { // After a unit, suggest all allowed tokens. - // If "\per" exists in the value, omit "per". - if (value.includes("\\per")) { + if (value.includes("\\per") || value.includes("/")) { return this.allowedTokens.filter(token => token !== "per"); } return this.allowedTokens; @@ -144,6 +143,15 @@ 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. + 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; + } + } this.selectedSuggestionIndex = -1; this.updateSuggestions(); if (this.liveUpdate) { @@ -154,29 +162,41 @@ export class DSIUnitInput extends HTMLElement { updateSuggestions() { const cursorPos = this.input.selectionStart; const value = this.input.value; - // Check: if caret is inside the braces of a "tothe" token, do not show suggestions. + // Do not show suggestions if caret is inside the braces of a tothe token. const regexTothe = /\\tothe\{([^}]*)$/; const substring = value.substring(0, cursorPos); const matchTothe = substring.match(regexTothe); if (matchTothe) { + console.log("State: inside tothe braces → no suggestions"); this.suggestions.style.display = "none"; return; } - - // Use regex to capture current token (may be empty). + // Capture the current token (which may be empty). const regex = /\\([a-zA-Z]*)$/; const match = substring.match(regex); let currentToken = ""; if (match) { - currentToken = match[1]; // might be empty + currentToken = match[1]; } - // Determine suggestions based on context. + // If currentToken exactly matches a known prefix, treat it as complete. + if (currentToken && (currentToken in dsiPrefixesHTML)) { + console.log("Token complete: currentToken matches known prefix:", currentToken); + currentToken = ""; + } + const tokens = value.split("\\").filter(Boolean); + let prevToken = tokens.length >= 2 ? tokens[tokens.length - 2] : "<empty>"; const contextSuggestions = this.getContextualSuggestions(); - const suggestions = currentToken === "" + let filtered = currentToken === "" ? contextSuggestions : contextSuggestions.filter(token => token.startsWith(currentToken)); - this.selectedSuggestionIndex = suggestions.length > 0 ? 0 : -1; - this.showSuggestions(suggestions, value.length - currentToken.length); + if (filtered.length === 0) { + console.log("State: prevToken =", prevToken, "currentToken =", currentToken, "→ No suggestions (filtered empty)"); + this.suggestions.style.display = "none"; + return; + } + this.selectedSuggestionIndex = 0; + console.log("State: prevToken =", prevToken, "currentToken =", currentToken, "contextSuggestions =", contextSuggestions, "filtered =", filtered); + this.showSuggestions(filtered, value.length - currentToken.length); } showSuggestions(list, tokenStartIndex) { @@ -187,6 +207,7 @@ export class DSIUnitInput extends HTMLElement { } list.forEach((token, index) => { const item = document.createElement("div"); + // For suggestion display, always show with a backslash. item.textContent = "\\" + token; item.className = "autocomplete-item"; if (index === this.selectedSuggestionIndex) { @@ -220,7 +241,7 @@ export class DSIUnitInput extends HTMLElement { if (this.selectedSuggestionIndex !== -1) { e.preventDefault(); const selectedItem = items[this.selectedSuggestionIndex]; - const token = selectedItem.textContent.slice(1); // remove backslash + const token = selectedItem.textContent.slice(1); // remove leading backslash const tokenStartIndex = this.input.value.lastIndexOf("\\"); this.acceptSuggestion(token, tokenStartIndex); } @@ -249,6 +270,10 @@ 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; @@ -259,7 +284,9 @@ export class DSIUnitInput extends HTMLElement { renderOutput() { try { - const unit = new DSIUnit(this.input.value); + // 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(); if (unit.warnings && unit.warnings.length > 0) { this.display.title = unit.warnings.join("; "); @@ -295,4 +322,4 @@ export class DSIUnitInput extends HTMLElement { } } -customElements.define("dsi-unit-input", DSIUnitInput); +customElements.define("dsi-unit-input", DSIUnitInput); \ No newline at end of file