From 21dc4a401e1b6a7df4d6d5b413a4d7447ecbd8ef Mon Sep 17 00:00:00 2001 From: Oliver Geer Date: Fri, 18 Jul 2025 16:27:06 +0100 Subject: [PATCH] Make selectionchange work with popup; Add selectionStart parameter to popup callback (Fixes #151) --- code-input.d.ts | 4 ++-- plugins/autocomplete.js | 6 +++--- tests/tester.js | 25 ++++++++++++++++++------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/code-input.d.ts b/code-input.d.ts index 284b2c2..8ec5d67 100644 --- a/code-input.d.ts +++ b/code-input.d.ts @@ -96,9 +96,9 @@ export namespace plugins { class Autocomplete extends Plugin { /** * Pass in a function to create a plugin that displays the popup that takes in (popup element, textarea, textarea.selectionEnd). - * @param {(popupElement: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number) => void} updatePopupCallback a function to display the popup that takes in (popup element, textarea, textarea.selectionEnd). + * @param {(popupElement: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number, selectionStart?: number) => void} updatePopupCallback a function to display the popup that takes in (popup element, textarea, textarea.selectionEnd). */ - constructor(updatePopupCallback: (popupElem: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number) => void); + constructor(updatePopupCallback: (popupElem: HTMLElement, textarea: HTMLTextAreaElement, selectionEnd: number, selectionStart?: number) => void); } /** diff --git a/plugins/autocomplete.js b/plugins/autocomplete.js index ba9b8eb..d94cf1b 100644 --- a/plugins/autocomplete.js +++ b/plugins/autocomplete.js @@ -20,7 +20,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin { popupElem.style.left = caretCoords.left + "px"; if(!onlyScrolled) { - this.updatePopupCallback(popupElem, textarea, textarea.selectionEnd); + this.updatePopupCallback(popupElem, textarea, textarea.selectionEnd, textarea.selectionStart); } } /* Create the popup element */ @@ -45,7 +45,7 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin { let textarea = codeInput.textareaElement; textarea.addEventListener("input", () => { this.updatePopup(codeInput, false)}); - textarea.addEventListener("click", () => { this.updatePopup(codeInput, false)}); + textarea.addEventListener("selectionchange", () => { this.updatePopup(codeInput, false)}); } /** * Return the coordinates of the caret in a code-input @@ -85,4 +85,4 @@ codeInput.plugins.Autocomplete = class extends codeInput.Plugin { return {"top": afterSpan.offsetTop - textarea.scrollTop, "left": afterSpan.offsetLeft - textarea.scrollLeft}; } updatePopupCallback = function() {}; -} \ No newline at end of file +} diff --git a/tests/tester.js b/tests/tester.js index 4a34264..2e1b7d8 100644 --- a/tests/tester.js +++ b/tests/tester.js @@ -110,8 +110,8 @@ function beginTest(isHLJS) { if(isHLJS) { codeInput.registerTemplate("code-editor", new codeInput.templates.Hljs(hljs, [ new codeInput.plugins.AutoCloseBrackets(), - new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd) { - if(textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") { + new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd, selectionStart) { + if(selectionStart == selectionEnd && textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") { // Show popup popupElem.style.display = "block"; popupElem.innerHTML = "Here's your popup!"; @@ -129,8 +129,8 @@ function beginTest(isHLJS) { } else { codeInput.registerTemplate("code-editor", new codeInput.templates.Prism(Prism, [ new codeInput.plugins.AutoCloseBrackets(), - new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd) { - if(textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") { + new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd, selectionStart) { + if(selectionStart == selectionEnd && textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") { // Show popup popupElem.style.display = "block"; popupElem.innerHTML = "Here's your popup!"; @@ -343,12 +343,23 @@ console.log("I've got another line!", 2 < 3, "should be true."); await waitAsync(50); // Wait for popup to be rendered - testAssertion("Autocomplete", "Popup Shows", confirm("Does the autocomplete popup display correctly? (OK=Yes)"), "user-judged"); - backspace(textarea); + testAssertion("Autocomplete", "Popup Shows on input", confirm("Does the autocomplete popup display correctly? (OK=Yes)"), "user-judged"); + move(textarea, -1); await waitAsync(50); // Wait for popup disappearance to be rendered - testAssertion("Autocomplete", "Popup Disappears", confirm("Has the popup disappeared? (OK=Yes)"), "user-judged"); + testAssertion("Autocomplete", "Popup Disappears on arrow key", confirm("Has the popup disappeared? (OK=Yes)"), "user-judged"); + move(textarea, 1); + + await waitAsync(50); // Wait for popup to be rendered + + testAssertion("Autocomplete", "Popup Shows on arrow key", confirm("Does the autocomplete popup display correctly? (OK=Yes)"), "user-judged"); + backspace(textarea); + + await waitAsync(50); // Wait for popup disappearance to be rendered + + testAssertion("Autocomplete", "Popup Disappears on backspace", confirm("Has the popup disappeared? (OK=Yes)"), "user-judged"); + move(textarea, 1); backspace(textarea); backspace(textarea); backspace(textarea);