Skip to content
Snippets Groups Projects
Commit a97d0cfe authored by Benedikt's avatar Benedikt
Browse files

improved sugestions

parent 089c3dba
No related branches found
No related tags found
No related merge requests found
......@@ -14,11 +14,12 @@ export class DSIUnitInput extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
// Internal state: store raw value.
// Internal state.
this._rawValue = "";
this.liveUpdate = true;
this.allowedTokens = defaultAllowedTokens;
this.selectedSuggestionIndex = -1;
this.lastAcceptedToken = ""; // NEW: track last accepted token
// Create elements.
this.input = document.createElement("input");
......@@ -29,18 +30,18 @@ export class DSIUnitInput extends HTMLElement {
this.suggestions.className = "autocomplete-list";
this.suggestions.style.display = "none";
this.display = document.createElement("div"); // For rendered output on blur.
this.display = document.createElement("div"); // Rendered output on blur.
this.display.id = "dsiDisplay";
this.display.style.cursor = "text"; // Make it clickable for editing.
this.display.style.cursor = "text";
// Container for input and suggestions.
// Container.
const container = document.createElement("div");
container.style.position = "relative";
container.appendChild(this.input);
container.appendChild(this.suggestions);
container.appendChild(this.display);
// Append styles.
// Styles.
const style = document.createElement("style");
style.textContent = `
#dsiInput {
......@@ -76,7 +77,7 @@ export class DSIUnitInput extends HTMLElement {
`;
this.shadowRoot.append(style, container);
// Bind event handlers.
// Bind handlers.
this.onInput = this.onInput.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.onBlur = this.onBlur.bind(this);
......@@ -117,19 +118,22 @@ export class DSIUnitInput extends HTMLElement {
this.display.removeEventListener("click", this.onFocus);
}
// Determine contextual suggestions based on previous complete token.
// Determines contextual suggestions.
getContextualSuggestions() {
const value = this.input.value;
const tokens = value.split("\\").filter(Boolean);
// If there are no complete tokens, allow all suggestions.
if (tokens.length <= 1) {
return this.allowedTokens;
}
// Use last accepted token if available.
if (this.lastAcceptedToken && (this.lastAcceptedToken in dsiPrefixesHTML)) {
return Object.keys(dsiUnitsHTML);
}
const prevToken = tokens[tokens.length - 2];
if (prevToken in dsiPrefixesHTML) {
// After a prefix, suggest only allowed units.
return Object.keys(dsiUnitsHTML);
} else if (prevToken in dsiUnitsHTML) {
// After a unit, suggest all allowed tokens.
if (value.includes("\\per")) {
return this.allowedTokens.filter(token => token !== "per");
}
......@@ -143,7 +147,7 @@ export class DSIUnitInput extends HTMLElement {
onInput(e) {
this._rawValue = this.input.value;
// Auto-insert a backslash if the user types a space after a complete token.
// Auto-insert a backslash after a token if a space is typed.
if (this.input.value.endsWith(" ")) {
const trimmed = this.input.value.trimEnd();
if (!trimmed.endsWith("\\")) {
......@@ -161,7 +165,7 @@ export class DSIUnitInput extends HTMLElement {
updateSuggestions() {
const cursorPos = this.input.selectionStart;
const value = this.input.value;
// Do not show suggestions if caret is inside the braces of a tothe token.
// Suppress suggestions if caret is inside tothe braces.
const regexTothe = /\\tothe\{([^}]*)$/;
const substring = value.substring(0, cursorPos);
const matchTothe = substring.match(regexTothe);
......@@ -170,16 +174,23 @@ export class DSIUnitInput extends HTMLElement {
this.suggestions.style.display = "none";
return;
}
// Capture the current token (which may be empty).
// Capture current token (which may be empty).
const regex = /\\([a-zA-Z]*)$/;
const match = substring.match(regex);
let currentToken = "";
if (match) {
currentToken = match[1];
}
// If currentToken exactly matches a known prefix, treat it as complete.
// If current token exactly matches a known prefix, treat it as complete.
if (currentToken && (currentToken in dsiPrefixesHTML)) {
console.log("Token complete: currentToken matches known prefix:", currentToken);
console.log("Token complete: using accepted prefix", currentToken);
// Update lastAcceptedToken.
this.lastAcceptedToken = currentToken;
// Auto-complete by appending a trailing backslash if not already present.
if (!value.endsWith("\\")) {
this.input.value = value + "\\";
this._rawValue = this.input.value;
}
currentToken = "";
}
const tokens = value.split("\\").filter(Boolean);
......@@ -206,7 +217,6 @@ export class DSIUnitInput extends HTMLElement {
}
list.forEach((token, index) => {
const item = document.createElement("div");
// Always render suggestions with a backslash.
item.textContent = "\\" + token;
item.className = "autocomplete-item";
if (index === this.selectedSuggestionIndex) {
......@@ -240,7 +250,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);
}
......@@ -264,14 +274,15 @@ export class DSIUnitInput extends HTMLElement {
const before = value.substring(0, tokenStartIndex);
const after = value.substring(this.input.selectionStart);
if (token === "tothe") {
// Append {} and place caret inside.
this.input.value = before + "\\" + token + "{}" + after;
this._rawValue = this.input.value;
this.lastAcceptedToken = token;
const newPos = before.length + token.length + 2;
this.input.setSelectionRange(newPos, newPos);
} else {
this.input.value = before + "\\" + token + after;
this._rawValue = this.input.value;
this.lastAcceptedToken = token;
}
this.suggestions.style.display = "none";
this.renderOutput();
......@@ -279,9 +290,8 @@ export class DSIUnitInput extends HTMLElement {
renderOutput() {
try {
// No special conversion for "per" is needed now.
const unit = new DSIUnit(this.input.value);
// Pass oneLine option if desired.
// Call DSIUnit.toHTML with oneLine option.
this.display.innerHTML = unit.toHTML({ oneLine: true });
if (unit.warnings && unit.warnings.length > 0) {
this.display.title = unit.warnings.join("; ");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment