From 6880413f16d2ca3465fe036d98e4e82a5a5a3b4a Mon Sep 17 00:00:00 2001 From: mepripri <52342511+mepripri@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:39:26 -0500 Subject: [PATCH 1/3] Line Breaking Tool --- index.html | 29 +++++++++++ line-breaking.js | 96 ++++++++++++++++++++++++++++++++++ styles.css | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 index.html create mode 100644 line-breaking.js create mode 100644 styles.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..d173eb0 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + Line Breaking + + + +
+
+

Line Breaking Tool

+ + + + + +
+
+ + + + \ No newline at end of file diff --git a/line-breaking.js b/line-breaking.js new file mode 100644 index 0000000..7b7f231 --- /dev/null +++ b/line-breaking.js @@ -0,0 +1,96 @@ +let fileContent = "" + +window.addEventListener("message", async event => { + if (!event?.data) return + if (event.data.type === "SELECT_ANNOTATION" || event.data.type === "CURRENT_LINE_INDEX") { + document.getElementById("insert-text").dataset.lineId = event.data.lineId + } +}) + +document.getElementById("upload-file").addEventListener("click", () => { + document.querySelector(".file-upload").classList.toggle("display-none") +}) + +document.getElementById("file-input").addEventListener("change", (event) => { + const file = event.target.files[0] + const preview = document.querySelector(".preview") + preview.innerHTML = "" + + if (!file) { + preview.classList.remove("display-none") + preview.innerHTML = "No file selected" + document.getElementById("insert-text").classList.add("display-none") + document.getElementById("break-options").classList.add("display-none") + fileContent = "" + return + } + + if (!file.name.endsWith(".txt") && !file.name.endsWith(".xml")) { + preview.innerHTML = "Please upload a valid .txt or .xml file" + document.getElementById("break-options").classList.add("display-none") + fileContent = "" + return + } + + preview.classList.remove("display-none") + document.getElementById("insert-text").classList.remove("display-none") + + const reader = new FileReader() + reader.onload = function (e) { + fileContent = e.target.result + document.getElementById("break-options").classList.remove("display-none") + renderPreview("") + } + reader.readAsText(file) + document.querySelector(".file-upload").classList.add("display-none") +}) + +document.getElementById("break-tag").addEventListener("input", () => { + renderPreview(document.getElementById("break-tag").value.trim()) +}) + +function renderPreview(tagInput) { + if (!fileContent) return + const previewElement = document.querySelector(".preview") + + let regexParts = ["\\r?\\n"] + if (tagInput) { + const tags = tagInput.split(",").map(t => t.trim()).filter(Boolean) + tags.forEach(t => regexParts.push(t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))) + } + + const regex = new RegExp(regexParts.join("|"), "g") + const lines = fileContent.split(regex).map(line => line.trim()).filter(line => line !== "") + + const formatted = lines.map((line, i) => { + const safeLine = line.replace(/&/g, "&").replace(//g, ">") + return `
+ ${i + 1} + ${safeLine} +
` + }).join("") + + previewElement.innerHTML = formatted + + document.querySelectorAll(".preview-line").forEach((div) => { + div.addEventListener("click", () => { + document.querySelectorAll(".preview-line").forEach(d => d.classList.remove("selected")) + div.classList.add("selected") + }) + }) + + document.getElementById("insert-text").addEventListener("click", () => { + const selected = document.querySelector(".preview-line.selected .line-content") + if (!selected) return + + const lineText = selected.textContent + const lineIndex = Number(document.getElementById("insert-text").dataset.lineId) + if (isNaN(lineIndex)) return + + window.parent?.postMessage({ + type: "UPDATE_LINE_TEXT", + lineIndex: lineIndex, + text: lineText + }, "*") + }) +} \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..7e797f6 --- /dev/null +++ b/styles.css @@ -0,0 +1,130 @@ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background-color: #fef8e4; + margin: 0; + padding: 20px; + color: #333; +} + +.line-breaking { + display: flex; + justify-content: center; + align-items: flex-start; + width: 100%; + min-height: 100vh; + box-sizing: border-box; +} + +.content { + display: flex; + flex-direction: column; + gap: 15px; + align-items: stretch; + max-width: 900px; + width: 100%; +} + +button { + padding: 10px 10px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + border: 1.5px solid rgb(0, 90, 140); + border-radius: 20px; + background-color: rgb(0, 90, 140); + color: white; + transition: background-color 0.3s ease, border-color 0.3s ease; + margin-bottom: 5px; +} + +button:hover { + background-color: white; + color: rgb(0, 90, 140); +} + +.file-upload { + display: flex; + flex-direction: column; + gap: 10px; + align-items: flex-start; +} + +.display-none { + display: none; +} + +label { + font-size: 15px; + cursor: pointer; + margin-bottom: 5px; + font-weight: 600; + color: rgb(0, 90, 140); +} + +input[type="file"] { cursor: pointer; } + +input[type="text"] { + margin-top: 10px; + padding: 6px 8px; + font-size: 15px; + border: 1px solid #ccc; + border-radius: 5px; + width: 100%; + max-width: 300px; + box-sizing: border-box; +} + +.tool-title { + margin: 0; + font-size: 24px; + color: rgb(0, 90, 140); + border-bottom: 2px solid rgb(0, 90, 140); + padding-bottom: 5px; +} + +.preview { + font-family: monospace; + background: #fff; + border: 1px solid #ccc; + padding: 15px; + white-space: pre-wrap; + line-height: 1.5; + max-height: 400px; + overflow-y: auto; + width: 100%; + box-sizing: border-box; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); +} + +.preview-line { + padding: 2px 5px; + cursor: pointer; + display: flex; +} + +.preview-line:hover { + background-color: #e0f0ff; + border: 1px solid rgb(0, 90, 140); + border-radius: 5px; +} + +.preview-line.selected { + background-color: #c0e0ff; + border: 2px solid rgb(0, 90, 140); + border-radius: 5px; +} + +.line-number { + display: inline-block; + width: 2em; + color: rgb(0, 90, 140); + user-select: none; + font-weight: bold; +} + +.line-content { + display: inline-block; + margin-left: 10px; + width: calc(100% - 2em - 10px); +} \ No newline at end of file From fcefbfccb021b4759dff6cc397f62ddc6cae0a0f Mon Sep 17 00:00:00 2001 From: mepripri <52342511+mepripri@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:58:27 -0500 Subject: [PATCH 2/3] localStorage --- line-breaking.js | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/line-breaking.js b/line-breaking.js index 7b7f231..9655f7c 100644 --- a/line-breaking.js +++ b/line-breaking.js @@ -1,4 +1,20 @@ let fileContent = "" +let lines = [] + +window.addEventListener("load", () => { + const savedData = localStorage.getItem("fileData") + if (savedData) { + const parsed = JSON.parse(savedData) + fileContent = parsed.fileContent || "" + lines = parsed.lines || [] + if (fileContent && lines.length > 0) { + renderPreview("", true) + document.querySelector(".preview").classList.remove("display-none") + document.getElementById("insert-text").classList.remove("display-none") + document.getElementById("break-options").classList.remove("display-none") + } + } +}) window.addEventListener("message", async event => { if (!event?.data) return @@ -49,28 +65,30 @@ document.getElementById("break-tag").addEventListener("input", () => { renderPreview(document.getElementById("break-tag").value.trim()) }) -function renderPreview(tagInput) { - if (!fileContent) return +function renderPreview(tagInput, fromStorage = false) { const previewElement = document.querySelector(".preview") - let regexParts = ["\\r?\\n"] - if (tagInput) { - const tags = tagInput.split(",").map(t => t.trim()).filter(Boolean) - tags.forEach(t => regexParts.push(t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))) + if (!fromStorage) { + if (!fileContent) return + let regexParts = ["\\r?\\n"] + if (tagInput) { + const tags = tagInput.split(",").map(t => t.trim()).filter(Boolean) + tags.forEach(t => regexParts.push(t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))) + } + const regex = new RegExp(regexParts.join("|"), "g") + lines = fileContent.split(regex).map(line => line.trim()).filter(line => line !== "") } - const regex = new RegExp(regexParts.join("|"), "g") - const lines = fileContent.split(regex).map(line => line.trim()).filter(line => line !== "") - const formatted = lines.map((line, i) => { const safeLine = line.replace(/&/g, "&").replace(//g, ">") - return `
+ return `
${i + 1} ${safeLine}
` }).join("") previewElement.innerHTML = formatted + localStorage.setItem("fileData", JSON.stringify({ fileContent, lines })) document.querySelectorAll(".preview-line").forEach((div) => { div.addEventListener("click", () => { @@ -92,5 +110,8 @@ function renderPreview(tagInput) { lineIndex: lineIndex, text: lineText }, "*") + + lines.splice(Number(selectedDiv.dataset.line), 1) + renderPreview("", true) }) } \ No newline at end of file From 466cc3e0c88f511ef41a37074014b606f0796920 Mon Sep 17 00:00:00 2001 From: mepripri <52342511+mepripri@users.noreply.github.com> Date: Fri, 10 Oct 2025 16:00:23 -0500 Subject: [PATCH 3/3] fix --- line-breaking.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/line-breaking.js b/line-breaking.js index 9655f7c..b07de52 100644 --- a/line-breaking.js +++ b/line-breaking.js @@ -98,10 +98,10 @@ function renderPreview(tagInput, fromStorage = false) { }) document.getElementById("insert-text").addEventListener("click", () => { - const selected = document.querySelector(".preview-line.selected .line-content") + const selected = document.querySelector(".preview-line.selected") if (!selected) return - const lineText = selected.textContent + const lineText = selected.querySelector(".line-content").textContent const lineIndex = Number(document.getElementById("insert-text").dataset.lineId) if (isNaN(lineIndex)) return @@ -111,7 +111,7 @@ function renderPreview(tagInput, fromStorage = false) { text: lineText }, "*") - lines.splice(Number(selectedDiv.dataset.line), 1) + lines.splice(Number(selected.dataset.line), 1) renderPreview("", true) }) } \ No newline at end of file