Retrieve text nodes within a specified range.
by Imri Paloja
HTML
<link crossorigin="anonymous"
href="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/fancybox/fancybox.css"
integrity="sha512-hfp7UiPWaDAND/ZE+RrbMpthca5iYNxJl/uWQTOqeZqur4C6Y/kiDUsBKoUeQTvyz6EJFyDrtPefVpidGFzk+Q=="
referrerpolicy="no-referrer"
rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script crossorigin="anonymous"
integrity="sha512-v80Z62SYCVHA3UxmFG69Vclopt+3ngQDocRjtxnB3htcTs6l9mnXc6SixuDae1rJ3L2J6p2KAuG+soHbhVd+6g=="
referrerpolicy="no-referrer"
src="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/fancybox/fancybox.umd.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
<div class="container">
<button onclick="showTagForm('A')">Insert Link</button>
<button onclick="showTagForm('ABBR')">Insert Abbreviation</button>
<button onclick="showTagForm('AUDIO')">Insert Audio</button>
<button onclick="showLinkForm()">showLinkForm</button>
<div id="editor">
<h1>Notes From Underground By Fyodor Dostoyevsky</h1>
<p>A man living alone in St. Petersburg writes memoirs describing his alienation from modern society.</p>
<hr>
<p>44,336 words (2 hours 42 minutes) with a reading ease of 69.92 (fairly easy)</p>
<p>Translated by Constance Garnett.</p>
<p>Fiction</p>
<hr>
<p>Notes from Underground is a fictional collection of memoirs written by a civil servant living alone in
St. Petersburg. The man is never named and is generally referred to as the Underground Man. The
“underground” in the book refers to the narrator’s isolation, which he described in chapter 11 as
“listening through a crack under the floor.”</p>
...
CSS
html,
body {
color: #f9f9f9 !important;
background-color: #212121;
}
button,input {
color: inherit;
}
JavaScript
function showLinkForm() {
const formHTML = `
<form id="linkForm" style="display:flex; flex-direction:column; gap:10px; width:300px;">
<label>URL: <input type="url" name="href" required placeholder="https://example.com"></label>
<label>Target:
<select name="target">
<option value="_self">Same Tab (_self)</option>
<option value="_blank" selected>New Tab (_blank)</option>
</select>
</label>
<button type="submit">Insert Link</button>
</form>
`;
Fancybox.show([{
src: formHTML,
type: "html",
on: {
reveal: (fancybox, slide) => {
// Now the form is guaranteed in the DOM
const form = slide.$slide.querySelector("#linkForm");
form.addEventListener("submit", function(e) {
e.preventDefault(); // critical: prevent default form submission
const formData = new FormData(form);
const attrs = {
href: formData.get("href"),
target: formData.get("target")
};
insertLink(attrs);
Fancybox.close();
});
}
}
}]);
}
// Wrap selection in <a> with attributes
function insertLink(attrs) {
const selection = window.getSelection();
if (!selection.rangeCount) return;
const range = selection.getRangeAt(0);
const editor = document.getElementById("editor");
if (!editor.contains(range.commonAncestorContainer)) return;
if (range.collapsed) return;
// Check if selection is already wrapped
let node = selection.focusNode;
while (node && node !== editor) {
if (node.nodeType === 1 && node.tagName === "A") {
unwrap(node);
return;
}
node =...