Dynamic word tracker with added labels
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>Index-Based Text Tracker</title>
<style>
textarea {
width: 100%;
height: 150px;
margin-bottom: 10px;
padding: 10px;
font-size: 16px;
}
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
pre {
background-color: #f4f4f4;
padding: 10px;
font-size: 14px;
}
#targetTextDisplay {
border: 1px solid #ccc;
padding: 10px;
font-size: 16px;
white-space: pre-wrap;
line-height: 1.5;
background-color: #f9f9f9;
}
.word {
position: relative;
margin-right: 5px;
display: inline-block;
}
.index {
font-size: 12px;
color: #999;
position: absolute;
top: -10px;
right: 0;
}
.warning {
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Index-Based Text Tracker</h1>
<label for="sourceText">Enter Source Text:</label>
<textarea id="sourceText" placeholder="Paste the original source text here..." oninput="updateSourceWithIndexes()"></textarea>
<h2>Source Text with Indexes</h2>
<pre id="indexedSourceText"></pre>
<button onclick="addSelectedText()">Paste Selected Text</button>
<label for="targetTextDisplay">Target Text Area:</label>
<div id="targetTextDisplay"></div>
<h2>Word Indexes</h2>
<pre id="output"></pre>
</body>
</html>
CSS
body {
font-family: Arial, sans-serif;
margin: 20px;
}
div[contenteditable] {
border: 1px solid #ccc;
padding: 10px;
height: 100px;
overflow-y: auto;
margin-bottom: 10px;
}
.output {
margin-top: 10px;
}
JavaScript
let wordOccurrences = {}; // Maps words to their indexes
let indexMap = {}; // Maps indexes to words
let usedIndexes = new Set(); // Tracks used indexes
function updateSourceWithIndexes() {
const sourceText = document.getElementById('sourceText').value.trim();
const indexedSourceText = document.getElementById('indexedSourceText');
if (!sourceText) {
indexedSourceText.textContent = "No source text provided.";
return;
}
const sourceWords = sourceText.split(/\s+/);
wordOccurrences = {};
indexMap = {};
usedIndexes = new Set();
const indexedWords = sourceWords.map((word, index) => {
const lowerWord = word.toLowerCase();
const wordIndex = index + 1; // Start indexing from 1
// Map word to its indexes and indexes to words
if (!wordOccurrences[lowerWord]) {
wordOccurrences[lowerWord] = [];
}
wordOccurrences[lowerWord].push(wordIndex);
indexMap[wordIndex] = word;
return `${word}(${wordIndex})`;
});
indexedSourceText.textContent = indexedWords.join(' ');
}
function addSelectedText() {
const targetTextDisplay = document.getElementById('targetTextDisplay');
const outputElement = document.getElementById('output');
const selectedText = window.getSelection().toString().trim();
if (!selectedText) {
outputElement.textContent = "Please select text from the source text.";
return;
}
const wordsToAdd = selectedText.split(/\s+/);
const fragment = document.createDocumentFragment();
const wordIndexMap = [];
const warnings = [];
let lastIndex = -1;
wordsToAdd.forEach((word, i) => {
let index;
// Search index by word
if (lastIndex !== -1) {
index = findNextConsecutiveIndex(word.toLowerCase(), lastIndex);
}
// Fallback: find index directly and validate
if (index ===...