stack2
by Julian
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Word Index Tracker</title>
<style>
:root {
font: 2ch/1.5 "Segoe UI"
}
#toggle {
margin-bottom: 1rem;
padding: 5px 10px;
border-radius: 8px;
font: inherit;
cursor: pointer;
background:
radial-gradient(
ellipse at center,
rgba(197,222,234,1) 0%,
rgba(138,187,215,1) 31%,
rgba(6,109,171,1) 100%);
}
#toggle::before {
content: "Edit Mode"
}
#toggle::after {
content: " ON";
}
#toggle.off {
color: #fff;
background:
radial-gradient(
ellipse at center,
rgba(125, 126, 125, 1) 0%,
rgba(14, 14, 14, 1) 100%);
}
#toggle.off::after {
content: " OFF";
}
.off + #source {
opacity: 0.7;
pointer-events: none;
}
#source {
min-height: 5rem;
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
overflow-wrap: break-word;
white-space: pre-wrap;
}
mark {
background-color: transparent
}
mark.highlight {
background: gold;
}
</style>
</head>
<body>
<h1>Track Words</h1>
<form id="indexer">
<button id="toggle" class="off" type="button"></button>
<textarea id="source" style="min-height: 5rem; padding: 0.75rem; border: 1px solid #ccc; border-radius: 4px; width: 100%;" placeholder="Enter or paste text here..."></textarea>
<output id="selected">
<ol></ol>
</output>
<button id="download" type="button">Download JSON</button>
</form>
</body>
</html>
CSS
:root {
font: 2ch/1.5 "Segoe UI"
}
#toggle {
margin-bottom: 1rem;
padding: 5px 10px;
border-radius: 8px;
font: inherit;
cursor: pointer;
background:
radial-gradient(
ellipse at center,
rgba(197,222,234,1) 0%,
rgba(138,187,215,1) 31%,
rgba(6,109,171,1) 100%);
}
#toggle::before {
content: "Edit Mode"
}
#toggle::after {
content: " ON";
}
#toggle.off {
color: #fff;
background:
radial-gradient(
ellipse at center,
rgba(125, 126, 125, 1) 0%,
rgba(14, 14, 14, 1) 100%);
}
#toggle.off::after {
content: " OFF";
}
.off + #source {
opacity: 0.7;
pointer-events: none;
}
#source {
min-height: 5rem;
padding-top: 0.75rem;
border-radius: 4px;
}
mark {
background-color: transparent
}
mark.highlight {
background: gold;
}
JavaScript
// Reference <form>
const form = document.forms.indexer;
/**
* Reference all form controls of <form>
* In this layout it is:
* - <button>
* - <textarea>
* - <output>
*/
const io = form.elements;
// Reference <button>
const btn = io.toggle;
const downloadBtn = document.getElementById("download");
// Reference <textarea>
const src = document.getElementById("source");
// Reference <output>
const sel = io.selected;
// Declaration for two arrays (not made yet).
let marked;
let indices;
/**
* Index each word by extracting the string,
* converting the string into an array of
* substrings, and wrapping each word with
* a <mark> element. Each <mark> is then
* assigned a [data-idx] attribute with the
* corresponding index number.
*/
const indexText = () => {
const text = src.value;
let marks = text.split(" ");
marks[0] = `<mark>${marks[0]}`;
marks[marks.length - 1] = `${marks[marks.length - 1]}</mark>`;
const outputHTML = marks.join(`</mark> <mark>`).trim();
const tempDiv = document.createElement("div");
tempDiv.innerHTML = outputHTML;
marked = [...tempDiv.querySelectorAll("mark")];
marked.forEach((mrk, idx) => mrk.dataset.idx = idx);
src.value = tempDiv.textContent; // Update text area with raw text.
};
/**
* Handle "click" event when the user clicks
* button#toggle. Enables indexing for textarea content.
* @param {object} e - Event object
*/
const editText = (e) => {
e.target.classList.toggle("off");
indexText();
};
/**
* Handle "click" event for the download button.
* Creates a JSON file containing the highlighted
* words and their indices and triggers download.
*/
const downloadJSON = () => {
const data = JSON.stringify(indices, null, 2);
const blob = new Blob([data], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "words_indices.json";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
...