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

improved sugestions

parent 089c3dba
Branches
No related tags found
No related merge requests found
...@@ -14,11 +14,12 @@ export class DSIUnitInput extends HTMLElement { ...@@ -14,11 +14,12 @@ export class DSIUnitInput extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: "open" }); this.attachShadow({ mode: "open" });
// Internal state: store raw value. // Internal state.
this._rawValue = ""; this._rawValue = "";
this.liveUpdate = true; this.liveUpdate = true;
this.allowedTokens = defaultAllowedTokens; this.allowedTokens = defaultAllowedTokens;
this.selectedSuggestionIndex = -1; this.selectedSuggestionIndex = -1;
this.lastAcceptedToken = ""; // NEW: track last accepted token
// Create elements. // Create elements.
this.input = document.createElement("input"); this.input = document.createElement("input");
...@@ -29,18 +30,18 @@ export class DSIUnitInput extends HTMLElement { ...@@ -29,18 +30,18 @@ export class DSIUnitInput extends HTMLElement {
this.suggestions.className = "autocomplete-list"; this.suggestions.className = "autocomplete-list";
this.suggestions.style.display = "none"; 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.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"); const container = document.createElement("div");
container.style.position = "relative"; container.style.position = "relative";
container.appendChild(this.input); container.appendChild(this.input);
container.appendChild(this.suggestions); container.appendChild(this.suggestions);
container.appendChild(this.display); container.appendChild(this.display);
// Append styles. // Styles.
const style = document.createElement("style"); const style = document.createElement("style");
style.textContent = ` style.textContent = `
#dsiInput { #dsiInput {
...@@ -76,7 +77,7 @@ export class DSIUnitInput extends HTMLElement { ...@@ -76,7 +77,7 @@ export class DSIUnitInput extends HTMLElement {
`; `;
this.shadowRoot.append(style, container); this.shadowRoot.append(style, container);
// Bind event handlers. // Bind handlers.
this.onInput = this.onInput.bind(this); this.onInput = this.onInput.bind(this);
this.onKeyDown = this.onKeyDown.bind(this); this.onKeyDown = this.onKeyDown.bind(this);
this.onBlur = this.onBlur.bind(this); this.onBlur = this.onBlur.bind(this);
...@@ -117,19 +118,22 @@ export class DSIUnitInput extends HTMLElement { ...@@ -117,19 +118,22 @@ export class DSIUnitInput extends HTMLElement {
this.display.removeEventListener("click", this.onFocus); this.display.removeEventListener("click", this.onFocus);
} }
// Determine contextual suggestions based on previous complete token. // Determines contextual suggestions.
getContextualSuggestions() { getContextualSuggestions() {
const value = this.input.value; const value = this.input.value;
const tokens = value.split("\\").filter(Boolean); const tokens = value.split("\\").filter(Boolean);
// If there are no complete tokens, allow all suggestions.
if (tokens.length <= 1) { if (tokens.length <= 1) {
return this.allowedTokens; 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]; const prevToken = tokens[tokens.length - 2];
if (prevToken in dsiPrefixesHTML) { if (prevToken in dsiPrefixesHTML) {
// After a prefix, suggest only allowed units.
return Object.keys(dsiUnitsHTML); return Object.keys(dsiUnitsHTML);
} else if (prevToken in dsiUnitsHTML) { } else if (prevToken in dsiUnitsHTML) {
// After a unit, suggest all allowed tokens.
if (value.includes("\\per")) { if (value.includes("\\per")) {
return this.allowedTokens.filter(token => token !== "per"); return this.allowedTokens.filter(token => token !== "per");
} }
...@@ -143,7 +147,7 @@ export class DSIUnitInput extends HTMLElement { ...@@ -143,7 +147,7 @@ export class DSIUnitInput extends HTMLElement {
onInput(e) { onInput(e) {
this._rawValue = this.input.value; 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(" ")) { if (this.input.value.endsWith(" ")) {
const trimmed = this.input.value.trimEnd(); const trimmed = this.input.value.trimEnd();
if (!trimmed.endsWith("\\")) { if (!trimmed.endsWith("\\")) {
...@@ -161,7 +165,7 @@ export class DSIUnitInput extends HTMLElement { ...@@ -161,7 +165,7 @@ export class DSIUnitInput extends HTMLElement {
updateSuggestions() { updateSuggestions() {
const cursorPos = this.input.selectionStart; const cursorPos = this.input.selectionStart;
const value = this.input.value; 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 regexTothe = /\\tothe\{([^}]*)$/;
const substring = value.substring(0, cursorPos); const substring = value.substring(0, cursorPos);
const matchTothe = substring.match(regexTothe); const matchTothe = substring.match(regexTothe);
...@@ -170,16 +174,23 @@ export class DSIUnitInput extends HTMLElement { ...@@ -170,16 +174,23 @@ export class DSIUnitInput extends HTMLElement {
this.suggestions.style.display = "none"; this.suggestions.style.display = "none";
return; return;
} }
// Capture the current token (which may be empty). // Capture current token (which may be empty).
const regex = /\\([a-zA-Z]*)$/; const regex = /\\([a-zA-Z]*)$/;
const match = substring.match(regex); const match = substring.match(regex);
let currentToken = ""; let currentToken = "";
if (match) { if (match) {
currentToken = match[1]; 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)) { 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 = ""; currentToken = "";
} }
const tokens = value.split("\\").filter(Boolean); const tokens = value.split("\\").filter(Boolean);
...@@ -206,7 +217,6 @@ export class DSIUnitInput extends HTMLElement { ...@@ -206,7 +217,6 @@ export class DSIUnitInput extends HTMLElement {
} }
list.forEach((token, index) => { list.forEach((token, index) => {
const item = document.createElement("div"); const item = document.createElement("div");
// Always render suggestions with a backslash.
item.textContent = "\\" + token; item.textContent = "\\" + token;
item.className = "autocomplete-item"; item.className = "autocomplete-item";
if (index === this.selectedSuggestionIndex) { if (index === this.selectedSuggestionIndex) {
...@@ -240,7 +250,7 @@ export class DSIUnitInput extends HTMLElement { ...@@ -240,7 +250,7 @@ export class DSIUnitInput extends HTMLElement {
if (this.selectedSuggestionIndex !== -1) { if (this.selectedSuggestionIndex !== -1) {
e.preventDefault(); e.preventDefault();
const selectedItem = items[this.selectedSuggestionIndex]; 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("\\"); const tokenStartIndex = this.input.value.lastIndexOf("\\");
this.acceptSuggestion(token, tokenStartIndex); this.acceptSuggestion(token, tokenStartIndex);
} }
...@@ -264,14 +274,15 @@ export class DSIUnitInput extends HTMLElement { ...@@ -264,14 +274,15 @@ export class DSIUnitInput extends HTMLElement {
const before = value.substring(0, tokenStartIndex); const before = value.substring(0, tokenStartIndex);
const after = value.substring(this.input.selectionStart); const after = value.substring(this.input.selectionStart);
if (token === "tothe") { if (token === "tothe") {
// Append {} and place caret inside.
this.input.value = before + "\\" + token + "{}" + after; this.input.value = before + "\\" + token + "{}" + after;
this._rawValue = this.input.value; this._rawValue = this.input.value;
this.lastAcceptedToken = token;
const newPos = before.length + token.length + 2; const newPos = before.length + token.length + 2;
this.input.setSelectionRange(newPos, newPos); this.input.setSelectionRange(newPos, newPos);
} else { } else {
this.input.value = before + "\\" + token + after; this.input.value = before + "\\" + token + after;
this._rawValue = this.input.value; this._rawValue = this.input.value;
this.lastAcceptedToken = token;
} }
this.suggestions.style.display = "none"; this.suggestions.style.display = "none";
this.renderOutput(); this.renderOutput();
...@@ -279,9 +290,8 @@ export class DSIUnitInput extends HTMLElement { ...@@ -279,9 +290,8 @@ export class DSIUnitInput extends HTMLElement {
renderOutput() { renderOutput() {
try { try {
// No special conversion for "per" is needed now.
const unit = new DSIUnit(this.input.value); 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 }); this.display.innerHTML = unit.toHTML({ oneLine: true });
if (unit.warnings && unit.warnings.length > 0) { if (unit.warnings && unit.warnings.length > 0) {
this.display.title = unit.warnings.join("; "); 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