Cybrkyd's Git Repositories

writegood - commit: 87d2a30

commit 87d2a30a7665c9a0329e90c63ffdcc50dc9b1fe9bf6ad65fc23a0b3ff8147914
author cybrkyd <noreply@cybrkyd.com> 2024-04-19 22:12:29 +0100
committer cybrkyd <noreply@cybrkyd.com> 2024-04-19 22:12:29 +0100

Commit Message

Simpler HTML and transition detection

- Streamline HTML layout
- Re-work logic to consolidate transition word detection
- Simplify regex sentence parsing
- Merge highlightSpan generation into single highlighting pass
- Clean up result display logic
- Remove duplicate "whereas" from transitionalWords list

📊 Diffstat

index.html 219
1 files changed, 97 insertions(+), 122 deletions(-)

Diff

diff --git a/index.html b/index.html
index be1d0f3..15db205 100644
--- a/index.html
+++ b/index.html
@@ -1,35 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
- <meta charset="UTF-8" />
+ <meta charset="UTF-8">
<title>Transition Word Checker</title>
<style>
- body { font-family: sans-serif; padding: 2em; max-width: 700px; margin: auto; }
- #editor {
- border: 1px solid #ccc;
- padding: 1em;
- height: 300px;
- resize: both;
- overflow: auto;
- margin-bottom: 1em;
- font-size: 1em;
- white-space: pre-wrap;
- }
-
- button { padding: 0.5em 1em; font-size: 1em; }
- #result { margin-top: 1em; font-size: 1.2em; font-weight: bold; }
- .low { color: red; }
- .high { color: green; }
- .highlight { background-color: yellow; }
- #breakdown { margin-top: 0.5em; font-size: 1em; font-weight: normal; }
- #breakdown ul { margin: 0.5em 0 0 1em; padding: 0; }
+ body {
+ font-family: sans-serif;
+ padding: 20px;
+ max-width: 800px;
+ margin: auto;
+ }
+ #editor {
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ overflow-y: auto;
+ overflow-x: hidden;
+ width: 100%;
+ height: 400px;
+ padding: 10px;
+ border: 1px solid #ccc;
+ font-family: monospace;
+ font-size: 0.9rem;
+ line-height: 1.5;
+ }
+ #editor:focus {
+ outline: none;
+ border: 1px solid #aaa;
+ box-shadow: 0 0 4px rgba(0,0,0,0.05);
+ }
+ .highlight {
+ background-color: yellow;
+ font-weight: bold;
+ }
+ #result.low {
+ color: red;
+ }
+ #result.high {
+ color: green;
+ }
+ #breakdown {
+ margin-top: 10px;
+ }
</style>
</head>
<body>
<h1>Transition Word Checker</h1>
- <div id="editor" contenteditable="true" spellcheck="true" placeholder="Paste article text here..."></div>
+
+ <div id="editor" contenteditable="true" spellcheck="true"></div>
+
+ <br>
<button onclick="checkTransitions()">Check</button>
- <div id="result"></div>
+
+ <p id="result"></p>
<div id="breakdown"></div>
<script>
@@ -41,127 +63,80 @@
"suggests that", "because", "especially", "still", "unless", "since", "above all"
];
- function escapeHtml(text) {
- const div = document.createElement("div");
- div.textContent = text;
- return div.innerHTML;
- }
-
- function getSentencesWithOffsets(text) {
- const regex = /[^.!?]+[.!?]+[\])'"`’”]*\s*/g;
- const sentences = [];
- let match;
- while ((match = regex.exec(text)) !== null) {
- sentences.push({ text: match[0], index: match.index });
+ function escapeHtml(text) {
+ const div = document.createElement("div");
+ div.textContent = text;
+ return div.innerHTML;
}
- return sentences;
- }
-
- function checkTransitions() {
- const editor = document.getElementById("editor");
- const inputText = editor.innerText;
- const lowerText = inputText.toLowerCase();
-
- const sentences = getSentencesWithOffsets(inputText);
- let totalCount = 0;
- let midCount = 0;
- const found = {};
- const midFound = {};
- const highlightSpans = [];
-
- for (const { text: sentence, index: sentenceStart } of sentences) {
- const lower = sentence.toLowerCase();
-
- // --- (1) Transitional words: start of sentence
- for (const phrase of transitionalWords) {
- const startRegex = new RegExp(`^\\s*${phrase}\\b`, "i");
- const semiRegex = new RegExp(`;\\s*${phrase}\\b`, "gi");
-
- // Start of sentence
- const startMatch = lower.match(startRegex);
- if (startMatch) {
- const localIndex = lower.indexOf(startMatch[0]);
- const globalStart = sentenceStart + localIndex;
- highlightSpans.push({ start: globalStart, end: globalStart + phrase.length });
- found[phrase] = (found[phrase] || 0) + 1;
- totalCount++;
- }
- // After semicolon
- let match;
- while ((match = semiRegex.exec(lower)) !== null) {
- const idx = match.index + match[0].lastIndexOf(phrase);
- const globalStart = sentenceStart + idx;
- highlightSpans.push({ start: globalStart, end: globalStart + phrase.length });
- found[phrase] = (found[phrase] || 0) + 1;
- totalCount++;
+ function highlightAndCount(text) {
+ let count = 0;
+ const found = {};
+ let highlighted = escapeHtml(text);
+
+ const sentenceRegex = /[^.!?]+[.!?]*/g;
+ const sentences = text.match(sentenceRegex) || [];
+
+ const escapeRegex = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+
+ // --- (1) Transitional words at beginning or after semicolon
+ for (let sentence of sentences) {
+ const trimmed = sentence.trim();
+ for (const phrase of transitionalWords) {
+ const pattern = new RegExp(`(^|;\\s*)(${escapeRegex(phrase)})\\b`, 'gi');
+ let match;
+ while ((match = pattern.exec(trimmed)) !== null) {
+ count++;
+ found[phrase] = (found[phrase] || 0) + 1;
+ }
}
}
// --- (2) Mid-sentence only words
for (const phrase of midSentenceOnlyWords) {
- const midRegex = new RegExp(`\\b${phrase}\\b`, "gi");
-
+ const pattern = new RegExp(`(?<!^|[.;!?]\\s*)\\b${escapeRegex(phrase)}\\b`, 'gi');
let match;
- while ((match = midRegex.exec(lower)) !== null) {
- const before = lower.slice(0, match.index).trim();
- const isStart = before.length === 0 || /[.?!]\s*$/.test(before);
- if (!isStart) {
- const globalStart = sentenceStart + match.index;
- highlightSpans.push({ start: globalStart, end: globalStart + phrase.length });
- midFound[phrase] = (midFound[phrase] || 0) + 1;
- midCount++;
- }
+ while ((match = pattern.exec(text)) !== null) {
+ count++;
+ found[phrase] = (found[phrase] || 0) + 1;
}
}
- }
-
- // Build highlighted output
- const raw = inputText;
- let output = "";
- let lastIndex = 0;
- highlightSpans.sort((a, b) => a.start - b.start);
+ // Highlight only counted phrases
+ const sortedPhrases = Object.keys(found).sort((a, b) => b.length - a.length);
+ for (const phrase of sortedPhrases) {
+ const pattern = new RegExp(`\\b(${escapeRegex(phrase)})\\b`, 'gi');
+ highlighted = highlighted.replace(pattern, `<span class="highlight">$1</span>`);
+ }
- for (const { start, end } of highlightSpans) {
- output += escapeHtml(raw.slice(lastIndex, start));
- output += `<span class="highlight">${escapeHtml(raw.slice(start, end))}</span>`;
- lastIndex = end;
+ return { count, found, highlighted, sentenceCount: sentences.length };
}
- output += escapeHtml(raw.slice(lastIndex));
- editor.innerHTML = output;
+ function checkTransitions() {
+ const editor = document.getElementById("editor");
+ const rawText = editor.innerText;
- const totalMatches = totalCount + midCount;
- const percentage = sentences.length
- ? ((totalMatches / sentences.length) * 100).toFixed(1)
- : 0;
+ const { count, found, highlighted, sentenceCount } = highlightAndCount(rawText);
- const result = document.getElementById("result");
- result.innerText = `Transitions: ${totalMatches} (${percentage}%)`;
- result.className = (percentage < 10) ? "low" : "high";
+ editor.innerHTML = highlighted;
- const breakdown = document.getElementById("breakdown");
- let html = "<div><strong>Found:</strong><ul>";
+ const percentage = sentenceCount ? (count / sentenceCount * 100).toFixed(1) : 0;
- const sorted = Object.entries(found).sort((a, b) => a[0].localeCompare(b[0]));
- for (const [word, count] of sorted) {
- html += `<li>${word}: ${count}</li>`;
- }
+ const result = document.getElementById("result");
+ result.textContent = `Transitions: ${count} (${percentage}%)`;
+ result.className = (percentage < 10) ? "low" : "high";
- if (midCount > 0) {
- html += "</ul><br><strong>Mid-sentence only:</strong><ul>";
- const sortedMid = Object.entries(midFound).sort((a, b) => a[0].localeCompare(b[0]));
- for (const [word, count] of sortedMid) {
- html += `<li>${word}: ${count}</li>`;
+ const breakdown = document.getElementById("breakdown");
+ if (count > 0) {
+ const sorted = Object.entries(found).sort((a, b) => a[0].localeCompare(b[0]));
+ breakdown.innerHTML = "<div>Found:<ul>" +
+ sorted.map(([word, c]) => `<li>${word}: ${c}</li>`).join("") +
+ "</ul></div>";
+ } else {
+ breakdown.innerHTML = "<div>No transitional words found.</div>";
}
}
-
- html += "</ul></div>";
- breakdown.innerHTML = html;
- }
- </script>
-
+ </script>
</body>
</html>