From b8dec606982f9483251dae1169b06eef7484049e Mon Sep 17 00:00:00 2001 From: twinkal3453 Date: Fri, 9 Jan 2026 23:55:57 +0530 Subject: [PATCH 1/2] #108: resolved the issue Latex syntext was not rendering --- index.html | 109 +++++--- src/main.js | 788 ++++++++++++++++++++++++++++------------------------ 2 files changed, 493 insertions(+), 404 deletions(-) diff --git a/index.html b/index.html index 6f6b1a0..d71f019 100644 --- a/index.html +++ b/index.html @@ -1,28 +1,34 @@ - - - - - + + + + + - - + + + + + Markdown Live Preview - + -
-
- -
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
diff --git a/src/main.js b/src/main.js index e1ac898..2d9169d 100644 --- a/src/main.js +++ b/src/main.js @@ -1,19 +1,20 @@ -import Storehouse from 'storehouse-js'; -import * as monaco from 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/+esm'; -import { marked } from 'marked'; -import DOMPurify from 'dompurify'; +import Storehouse from "storehouse-js"; +import * as monaco from "https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/+esm"; +import { marked } from "marked"; +import DOMPurify from "dompurify"; const init = () => { - let hasEdited = false; - let scrollBarSync = false; - - const localStorageNamespace = 'com.markdownlivepreview'; - const localStorageKey = 'last_state'; - const localStorageScrollBarKey = 'scroll_bar_settings'; - const localStorageThemeKey = 'theme_settings'; - const confirmationMessage = 'Are you sure you want to reset? Your changes will be lost.'; - // default template - const defaultInput = `# Markdown syntax guide + let hasEdited = false; + let scrollBarSync = false; + + const localStorageNamespace = "com.markdownlivepreview"; + const localStorageKey = "last_state"; + const localStorageScrollBarKey = "scroll_bar_settings"; + const localStorageThemeKey = "theme_settings"; + const confirmationMessage = + "Are you sure you want to reset? Your changes will be lost."; + // default template + const defaultInput = `# Markdown syntax guide ## Headers @@ -84,362 +85,423 @@ ${"`"}${"`"}${"`"} This web site is using ${"`"}markedjs/marked${"`"}. `; - self.MonacoEnvironment = { - getWorker(_, label) { - return new Proxy({}, { get: () => () => { } }); - } - } - - let setupEditor = () => { - let editor = monaco.editor.create(document.querySelector('#editor'), { - fontSize: 14, - language: 'markdown', - minimap: { enabled: false }, - scrollBeyondLastLine: false, - automaticLayout: true, - scrollbar: { - vertical: 'visible', - horizontal: 'visible' - }, - wordWrap: 'on', - hover: { enabled: false }, - quickSuggestions: false, - suggestOnTriggerCharacters: false, - folding: false - }); - - editor.onDidChangeModelContent(() => { - let changed = editor.getValue() != defaultInput; - if (changed) { - hasEdited = true; - } - let value = editor.getValue(); - convert(value); - saveLastContent(value); - }); - - editor.onDidScrollChange((e) => { - if (!scrollBarSync) { - return; - } - - const scrollTop = e.scrollTop; - const scrollHeight = e.scrollHeight; - const height = editor.getLayoutInfo().height; - - const maxScrollTop = scrollHeight - height; - const scrollRatio = scrollTop / maxScrollTop; - - let previewElement = document.querySelector('#preview'); - let targetY = (previewElement.scrollHeight - previewElement.clientHeight) * scrollRatio; - previewElement.scrollTo(0, targetY); - }); - - return editor; - }; - - // Render markdown text as html - let convert = (markdown) => { - let options = { - headerIds: false, - mangle: false - }; - let html = marked.parse(markdown, options); - let sanitized = DOMPurify.sanitize(html); - document.querySelector('#output').innerHTML = sanitized; - }; - - // Reset input text - let reset = () => { - let changed = editor.getValue() != defaultInput; - if (hasEdited || changed) { - var confirmed = window.confirm(confirmationMessage); - if (!confirmed) { - return; - } - } - presetValue(defaultInput); - document.querySelectorAll('.column').forEach((element) => { - element.scrollTo({ top: 0 }); - }); + self.MonacoEnvironment = { + getWorker(_, label) { + return new Proxy({}, { get: () => () => {} }); + }, + }; + + let setupEditor = () => { + let editor = monaco.editor.create(document.querySelector("#editor"), { + fontSize: 14, + language: "markdown", + minimap: { enabled: false }, + scrollBeyondLastLine: false, + automaticLayout: true, + scrollbar: { + vertical: "visible", + horizontal: "visible", + }, + wordWrap: "on", + hover: { enabled: false }, + quickSuggestions: false, + suggestOnTriggerCharacters: false, + folding: false, + }); + + editor.onDidChangeModelContent(() => { + let changed = editor.getValue() != defaultInput; + if (changed) { + hasEdited = true; + } + let value = editor.getValue(); + convert(value); + saveLastContent(value); + }); + + editor.onDidScrollChange((e) => { + if (!scrollBarSync) { + return; + } + + const scrollTop = e.scrollTop; + const scrollHeight = e.scrollHeight; + const height = editor.getLayoutInfo().height; + + const maxScrollTop = scrollHeight - height; + const scrollRatio = scrollTop / maxScrollTop; + + let previewElement = document.querySelector("#preview"); + let targetY = + (previewElement.scrollHeight - previewElement.clientHeight) * + scrollRatio; + previewElement.scrollTo(0, targetY); + }); + + return editor; + }; + + // Render markdown text as html + let convert = (markdown) => { + let options = { + headerIds: false, + mangle: false, }; - let presetValue = (value) => { - editor.setValue(value); - editor.revealPosition({ lineNumber: 1, column: 1 }); - editor.focus(); - hasEdited = false; - }; - - // ----- sync scroll position ----- - - let initScrollBarSync = (settings) => { - let checkbox = document.querySelector('#sync-scroll-checkbox'); - checkbox.checked = settings; - scrollBarSync = settings; - - checkbox.addEventListener('change', (event) => { - let checked = event.currentTarget.checked; - scrollBarSync = checked; - saveScrollBarSettings(checked); - }); - }; - - // ----- preview CSS loader (switch github-markdown css) ----- - const PREVIEW_CSS_LIGHT = 'css/github-markdown-light.css?v=1.11.0'; - const PREVIEW_CSS_DARK = 'css/github-markdown-dark_dimmed.css?v=1.11.0'; - - let setPreviewCss = (useDark) => { - const link = document.getElementById('gh-markdown-link'); - if (!link) { - // fallback: create link element - const newLink = document.createElement('link'); - newLink.id = 'gh-markdown-link'; - newLink.rel = 'stylesheet'; - newLink.href = useDark ? PREVIEW_CSS_DARK : PREVIEW_CSS_LIGHT; - document.head.appendChild(newLink); - return; - } - - // Only update if href differs to avoid unnecessary reload - const desired = useDark ? PREVIEW_CSS_DARK : PREVIEW_CSS_LIGHT; - if (link.getAttribute('href') !== desired) { - link.setAttribute('href', desired); - } - }; - - // ----- theme toggle (dark/light) ----- - let setTheme = (enabled) => { - document.documentElement.setAttribute('data-theme', enabled ? 'dark' : 'light'); - }; - - let initThemeToggle = (settings) => { - let checkbox = document.querySelector('#theme-checkbox'); - if (!checkbox) return; - checkbox.checked = settings; - setTheme(settings); - - // set Monaco editor theme to match page theme - if (monaco && monaco.editor && typeof monaco.editor.setTheme === 'function') { - monaco.editor.setTheme(settings ? 'vs-dark' : 'vs'); - } - // set preview css to match theme - setPreviewCss(settings); - - checkbox.addEventListener('change', (event) => { - let checked = event.currentTarget.checked; - setTheme(checked); - saveThemeSettings(checked); - setPreviewCss(checked); - if (monaco && monaco.editor && typeof monaco.editor.setTheme === 'function') { - monaco.editor.setTheme(checked ? 'vs-dark' : 'vs'); - } - }); - }; - - let enableScrollBarSync = () => { - scrollBarSync = true; - }; - - let disableScrollBarSync = () => { - scrollBarSync = false; - }; - - // ----- clipboard utils ----- - - let copyToClipboard = (text, successHandler, errorHandler) => { - navigator.clipboard.writeText(text).then( - () => { - successHandler(); - }, + // Markdown → HTML + let html = marked.parse(markdown, options); + + // Sanitize HTML + let sanitized = DOMPurify.sanitize(html); + + const outputEl = document.querySelector("#output"); + outputEl.innerHTML = sanitized; + + // Render LaTeX (KaTeX) + renderMathInElement(outputEl, { + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true }, + ], + throwOnError: false, + }); + }; + + // Reset input text + let reset = () => { + let changed = editor.getValue() != defaultInput; + if (hasEdited || changed) { + var confirmed = window.confirm(confirmationMessage); + if (!confirmed) { + return; + } + } + presetValue(defaultInput); + document.querySelectorAll(".column").forEach((element) => { + element.scrollTo({ top: 0 }); + }); + }; + + let presetValue = (value) => { + editor.setValue(value); + editor.revealPosition({ lineNumber: 1, column: 1 }); + editor.focus(); + hasEdited = false; + }; + + // ----- sync scroll position ----- + + let initScrollBarSync = (settings) => { + let checkbox = document.querySelector("#sync-scroll-checkbox"); + checkbox.checked = settings; + scrollBarSync = settings; + + checkbox.addEventListener("change", (event) => { + let checked = event.currentTarget.checked; + scrollBarSync = checked; + saveScrollBarSettings(checked); + }); + }; + + // ----- preview CSS loader (switch github-markdown css) ----- + const PREVIEW_CSS_LIGHT = "css/github-markdown-light.css?v=1.11.0"; + const PREVIEW_CSS_DARK = "css/github-markdown-dark_dimmed.css?v=1.11.0"; + + let setPreviewCss = (useDark) => { + const link = document.getElementById("gh-markdown-link"); + if (!link) { + // fallback: create link element + const newLink = document.createElement("link"); + newLink.id = "gh-markdown-link"; + newLink.rel = "stylesheet"; + newLink.href = useDark ? PREVIEW_CSS_DARK : PREVIEW_CSS_LIGHT; + document.head.appendChild(newLink); + return; + } - () => { - errorHandler(); - } + // Only update if href differs to avoid unnecessary reload + const desired = useDark ? PREVIEW_CSS_DARK : PREVIEW_CSS_LIGHT; + if (link.getAttribute("href") !== desired) { + link.setAttribute("href", desired); + } + }; + + // ----- theme toggle (dark/light) ----- + let setTheme = (enabled) => { + document.documentElement.setAttribute( + "data-theme", + enabled ? "dark" : "light" + ); + }; + + let initThemeToggle = (settings) => { + let checkbox = document.querySelector("#theme-checkbox"); + if (!checkbox) return; + checkbox.checked = settings; + setTheme(settings); + + // set Monaco editor theme to match page theme + if ( + monaco && + monaco.editor && + typeof monaco.editor.setTheme === "function" + ) { + monaco.editor.setTheme(settings ? "vs-dark" : "vs"); + } + // set preview css to match theme + setPreviewCss(settings); + + checkbox.addEventListener("change", (event) => { + let checked = event.currentTarget.checked; + setTheme(checked); + saveThemeSettings(checked); + setPreviewCss(checked); + if ( + monaco && + monaco.editor && + typeof monaco.editor.setTheme === "function" + ) { + monaco.editor.setTheme(checked ? "vs-dark" : "vs"); + } + }); + }; + + let enableScrollBarSync = () => { + scrollBarSync = true; + }; + + let disableScrollBarSync = () => { + scrollBarSync = false; + }; + + // ----- clipboard utils ----- + + let copyToClipboard = (text, successHandler, errorHandler) => { + navigator.clipboard.writeText(text).then( + () => { + successHandler(); + }, + + () => { + errorHandler(); + } + ); + }; + + let notifyCopied = () => { + let labelElement = document.querySelector("#copy-button a"); + labelElement.innerHTML = "Copied!"; + setTimeout(() => { + labelElement.innerHTML = "Copy"; + }, 1000); + }; + + // ----- setup ----- + + // setup navigation actions + let setupResetButton = () => { + document + .querySelector("#reset-button") + .addEventListener("click", (event) => { + event.preventDefault(); + reset(); + }); + }; + + let setupCopyButton = (editor) => { + document + .querySelector("#copy-button") + .addEventListener("click", (event) => { + event.preventDefault(); + let value = editor.getValue(); + copyToClipboard( + value, + () => { + notifyCopied(); + }, + () => { + // nothing to do + } ); - }; - - let notifyCopied = () => { - let labelElement = document.querySelector("#copy-button a"); - labelElement.innerHTML = "Copied!"; - setTimeout(() => { - labelElement.innerHTML = "Copy"; - }, 1000) - }; - - // ----- setup ----- - - // setup navigation actions - let setupResetButton = () => { - document.querySelector("#reset-button").addEventListener('click', (event) => { - event.preventDefault(); - reset(); - }); - }; - - let setupCopyButton = (editor) => { - document.querySelector("#copy-button").addEventListener('click', (event) => { - event.preventDefault(); - let value = editor.getValue(); - copyToClipboard(value, () => { - notifyCopied(); - }, - () => { - // nothing to do - }); - }); - }; - - // ----- local state ----- - - let loadLastContent = () => { - let lastContent = Storehouse.getItem(localStorageNamespace, localStorageKey); - return lastContent; - }; - - let saveLastContent = (content) => { - let expiredAt = new Date(2099, 1, 1); - Storehouse.setItem(localStorageNamespace, localStorageKey, content, expiredAt); - }; - - let loadScrollBarSettings = () => { - let lastContent = Storehouse.getItem(localStorageNamespace, localStorageScrollBarKey); - return lastContent; - }; - - let loadThemeSettings = () => { - let last = Storehouse.getItem(localStorageNamespace, localStorageThemeKey); - if (last === null || last === undefined) { - try { - // fallback to raw localStorage boot key used by inline script - const raw = localStorage.getItem('com.markdownlivepreview_theme'); - if (raw === 'dark') return true; - if (raw === 'light') return false; - } catch (e) { - // ignore - } - } - return last; - }; - - let saveScrollBarSettings = (settings) => { - let expiredAt = new Date(2099, 1, 1); - Storehouse.setItem(localStorageNamespace, localStorageScrollBarKey, settings, expiredAt); - }; - - let saveThemeSettings = (settings) => { - let expiredAt = new Date(2099, 1, 1); - Storehouse.setItem(localStorageNamespace, localStorageThemeKey, settings, expiredAt); - try { - localStorage.setItem('com.markdownlivepreview_theme', settings ? 'dark' : 'light'); - } catch (e) { - // ignore storage errors - } - }; - - let setupDivider = () => { - let lastLeftRatio = 0.5; - const divider = document.getElementById('split-divider'); - const leftPane = document.getElementById('edit'); - const rightPane = document.getElementById('preview'); - const container = document.getElementById('container'); - - let isDragging = false; - - divider.addEventListener('mouseenter', () => { - divider.classList.add('hover'); - }); - - divider.addEventListener('mouseleave', () => { - if (!isDragging) { - divider.classList.remove('hover'); - } - }); - - divider.addEventListener('mousedown', () => { - isDragging = true; - divider.classList.add('active'); - document.body.style.cursor = 'col-resize'; - }); - - divider.addEventListener('dblclick', () => { - const containerRect = container.getBoundingClientRect(); - const totalWidth = containerRect.width; - const dividerWidth = divider.offsetWidth; - const halfWidth = (totalWidth - dividerWidth) / 2; - - leftPane.style.width = halfWidth + 'px'; - rightPane.style.width = halfWidth + 'px'; - }); - - document.addEventListener('mousemove', (e) => { - if (!isDragging) return; - document.body.style.userSelect = 'none'; - const containerRect = container.getBoundingClientRect(); - const totalWidth = containerRect.width; - const offsetX = e.clientX - containerRect.left; - const dividerWidth = divider.offsetWidth; - - // Prevent overlap or out-of-bounds - const minWidth = 100; - const maxWidth = totalWidth - minWidth - dividerWidth; - const leftWidth = Math.max(minWidth, Math.min(offsetX, maxWidth)); - leftPane.style.width = leftWidth + 'px'; - rightPane.style.width = (totalWidth - leftWidth - dividerWidth) + 'px'; - lastLeftRatio = leftWidth / (totalWidth - dividerWidth); - }); - - document.addEventListener('mouseup', () => { - if (isDragging) { - isDragging = false; - divider.classList.remove('active'); - divider.classList.remove('hover'); - document.body.style.cursor = 'default'; - document.body.style.userSelect = ''; - } - }); - - window.addEventListener('resize', () => { - const containerRect = container.getBoundingClientRect(); - const totalWidth = containerRect.width; - const dividerWidth = divider.offsetWidth; - const availableWidth = totalWidth - dividerWidth; - - const newLeft = availableWidth * lastLeftRatio; - const newRight = availableWidth * (1 - lastLeftRatio); - - leftPane.style.width = newLeft + 'px'; - rightPane.style.width = newRight + 'px'; - }); - }; - - // ----- entry point ----- - let lastContent = loadLastContent(); - let editor = setupEditor(); - if (lastContent) { - presetValue(lastContent); - } else { - presetValue(defaultInput); + }); + }; + + // ----- local state ----- + + let loadLastContent = () => { + let lastContent = Storehouse.getItem( + localStorageNamespace, + localStorageKey + ); + return lastContent; + }; + + let saveLastContent = (content) => { + let expiredAt = new Date(2099, 1, 1); + Storehouse.setItem( + localStorageNamespace, + localStorageKey, + content, + expiredAt + ); + }; + + let loadScrollBarSettings = () => { + let lastContent = Storehouse.getItem( + localStorageNamespace, + localStorageScrollBarKey + ); + return lastContent; + }; + + let loadThemeSettings = () => { + let last = Storehouse.getItem(localStorageNamespace, localStorageThemeKey); + if (last === null || last === undefined) { + try { + // fallback to raw localStorage boot key used by inline script + const raw = localStorage.getItem("com.markdownlivepreview_theme"); + if (raw === "dark") return true; + if (raw === "light") return false; + } catch (e) { + // ignore + } } - setupResetButton(); - setupCopyButton(editor); - - let scrollBarSettings = loadScrollBarSettings() || false; - initScrollBarSync(scrollBarSettings); - - // initialize theme (dark/light) - let themeSettings = loadThemeSettings(); - // normalize to boolean (Storehouse may return string or boolean) - if (themeSettings === 'true' || themeSettings === true) { - themeSettings = true; - } else { - themeSettings = false; + return last; + }; + + let saveScrollBarSettings = (settings) => { + let expiredAt = new Date(2099, 1, 1); + Storehouse.setItem( + localStorageNamespace, + localStorageScrollBarKey, + settings, + expiredAt + ); + }; + + let saveThemeSettings = (settings) => { + let expiredAt = new Date(2099, 1, 1); + Storehouse.setItem( + localStorageNamespace, + localStorageThemeKey, + settings, + expiredAt + ); + try { + localStorage.setItem( + "com.markdownlivepreview_theme", + settings ? "dark" : "light" + ); + } catch (e) { + // ignore storage errors } - initThemeToggle(themeSettings); - - setupDivider(); + }; + + let setupDivider = () => { + let lastLeftRatio = 0.5; + const divider = document.getElementById("split-divider"); + const leftPane = document.getElementById("edit"); + const rightPane = document.getElementById("preview"); + const container = document.getElementById("container"); + + let isDragging = false; + + divider.addEventListener("mouseenter", () => { + divider.classList.add("hover"); + }); + + divider.addEventListener("mouseleave", () => { + if (!isDragging) { + divider.classList.remove("hover"); + } + }); + + divider.addEventListener("mousedown", () => { + isDragging = true; + divider.classList.add("active"); + document.body.style.cursor = "col-resize"; + }); + + divider.addEventListener("dblclick", () => { + const containerRect = container.getBoundingClientRect(); + const totalWidth = containerRect.width; + const dividerWidth = divider.offsetWidth; + const halfWidth = (totalWidth - dividerWidth) / 2; + + leftPane.style.width = halfWidth + "px"; + rightPane.style.width = halfWidth + "px"; + }); + + document.addEventListener("mousemove", (e) => { + if (!isDragging) return; + document.body.style.userSelect = "none"; + const containerRect = container.getBoundingClientRect(); + const totalWidth = containerRect.width; + const offsetX = e.clientX - containerRect.left; + const dividerWidth = divider.offsetWidth; + + // Prevent overlap or out-of-bounds + const minWidth = 100; + const maxWidth = totalWidth - minWidth - dividerWidth; + const leftWidth = Math.max(minWidth, Math.min(offsetX, maxWidth)); + leftPane.style.width = leftWidth + "px"; + rightPane.style.width = totalWidth - leftWidth - dividerWidth + "px"; + lastLeftRatio = leftWidth / (totalWidth - dividerWidth); + }); + + document.addEventListener("mouseup", () => { + if (isDragging) { + isDragging = false; + divider.classList.remove("active"); + divider.classList.remove("hover"); + document.body.style.cursor = "default"; + document.body.style.userSelect = ""; + } + }); + + window.addEventListener("resize", () => { + const containerRect = container.getBoundingClientRect(); + const totalWidth = containerRect.width; + const dividerWidth = divider.offsetWidth; + const availableWidth = totalWidth - dividerWidth; + + const newLeft = availableWidth * lastLeftRatio; + const newRight = availableWidth * (1 - lastLeftRatio); + + leftPane.style.width = newLeft + "px"; + rightPane.style.width = newRight + "px"; + }); + }; + + // ----- entry point ----- + let lastContent = loadLastContent(); + let editor = setupEditor(); + if (lastContent) { + presetValue(lastContent); + } else { + presetValue(defaultInput); + } + setupResetButton(); + setupCopyButton(editor); + + let scrollBarSettings = loadScrollBarSettings() || false; + initScrollBarSync(scrollBarSettings); + + // initialize theme (dark/light) + let themeSettings = loadThemeSettings(); + // normalize to boolean (Storehouse may return string or boolean) + if (themeSettings === "true" || themeSettings === true) { + themeSettings = true; + } else { + themeSettings = false; + } + initThemeToggle(themeSettings); + + setupDivider(); }; window.addEventListener("load", () => { - init(); + init(); }); From 190aa50531dcbedc67729c8d12811e9a8de0d0bc Mon Sep 17 00:00:00 2001 From: twinkal3453 Date: Sat, 10 Jan 2026 00:36:31 +0530 Subject: [PATCH 2/2] #108: Improved the "convert()" function where the metrics in the letex was not rendering after letex fixes. --- src/main.js | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/main.js b/src/main.js index 2d9169d..f2adc96 100644 --- a/src/main.js +++ b/src/main.js @@ -143,30 +143,54 @@ This web site is using ${"`"}markedjs/marked${"`"}. // Render markdown text as html let convert = (markdown) => { + // Ignore everything inside $$ ... $$ + const mathExtension = { + name: "blockMath", + level: "block", + start(src) { + return src.match(/\$\$/)?.index; + }, + tokenizer(src) { + const rule = /^\$\$([\s\S]+?)\$\$/; + const match = rule.exec(src); + if (match) { + return { + type: "blockMath", + raw: match[0], + text: match[1].trim(), + }; + } + }, + renderer(token) { + // Return the raw $$math$$ string so KaTeX can find it later + return `

$$${token.text}$$

`; + }, + }; + + marked.use({ extensions: [mathExtension] }); + let options = { headerIds: false, mangle: false, }; - // Markdown → HTML + // Parse and Sanitize let html = marked.parse(markdown, options); - - // Sanitize HTML let sanitized = DOMPurify.sanitize(html); const outputEl = document.querySelector("#output"); outputEl.innerHTML = sanitized; - // Render LaTeX (KaTeX) - renderMathInElement(outputEl, { - delimiters: [ - { left: "$$", right: "$$", display: true }, - { left: "$", right: "$", display: false }, - { left: "\\(", right: "\\)", display: false }, - { left: "\\[", right: "\\]", display: true }, - ], - throwOnError: false, - }); + // Render with KaTeX + if (typeof renderMathInElement === "function") { + renderMathInElement(outputEl, { + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + ], + throwOnError: false, + }); + } }; // Reset input text