diff --git a/css/elements.css b/css/elements.css
index 0a51f48b..94347e74 100644
--- a/css/elements.css
+++ b/css/elements.css
@@ -125,6 +125,7 @@ body.oldtoc {
span[aria-hidden='true'] {
font-size: 0;
+ white-space: pre;
}
a {
diff --git a/js/listNumbers.js b/js/listNumbers.js
index 81d43b80..dec4aad1 100644
--- a/js/listNumbers.js
+++ b/js/listNumbers.js
@@ -80,6 +80,7 @@ const counterByDepth = [];
function addStepNumberText(
ol,
depth = 0,
+ indent = '',
special = [...ol.classList].some(c => c.startsWith('nested-')),
) {
let counter = !special && counterByDepth[depth];
@@ -103,8 +104,11 @@ function addStepNumberText(
let i = (Number(ol.getAttribute('start')) || 1) - 1;
for (const li of ol.children) {
const marker = document.createElement('span');
- marker.textContent = `${i < cache.length ? cache[i] : getTextForIndex(i)}. `;
+ const markerText = i < cache.length ? cache[i] : getTextForIndex(i);
+ const extraIndent = ' '.repeat(markerText.length + 2);
+ marker.textContent = `${indent}${markerText}. `;
marker.setAttribute('aria-hidden', 'true');
+ marker.setAttribute('class', 'list-marker');
const attributesContainer = li.querySelector('.attributes-tag');
if (attributesContainer == null) {
li.prepend(marker);
@@ -112,7 +116,7 @@ function addStepNumberText(
attributesContainer.insertAdjacentElement('afterend', marker);
}
for (const sublist of li.querySelectorAll(':scope > ol')) {
- addStepNumberText(sublist, depth + 1, special);
+ addStepNumberText(sublist, depth + 1, indent + extraIndent, special);
}
i++;
}
@@ -123,3 +127,49 @@ document.addEventListener('DOMContentLoaded', () => {
addStepNumberText(ol);
});
});
+
+// Omit indendation when copying a single algorithm step.
+document.addEventListener('copy', evt => {
+ // Construct a DOM from the selection.
+ const doc = document.implementation.createHTMLDocument('');
+ const domRoot = doc.createElement('div');
+ const html = evt.clipboardData.getData('text/html');
+ if (html) {
+ domRoot.innerHTML = html;
+ } else {
+ const selection = getSelection();
+ const singleRange = selection?.rangeCount === 1 && selection.getRangeAt(0);
+ const container = singleRange?.commonAncestorContainer;
+ if (!container?.querySelector?.('.list-marker')) {
+ return;
+ }
+ domRoot.append(singleRange.cloneContents());
+ }
+
+ // Preserve the indentation if there is no hidden list marker, or if selection
+ // of more than one step is indicated by either multiple such markers or by
+ // visible text before the first one.
+ const listMarkers = domRoot.querySelectorAll('.list-marker');
+ if (listMarkers.length !== 1) {
+ return;
+ }
+ const treeWalker = document.createTreeWalker(domRoot, undefined, {
+ acceptNode(node) {
+ return node.nodeType === Node.TEXT_NODE || node === listMarkers[0]
+ ? NodeFilter.FILTER_ACCEPT
+ : NodeFilter.FILTER_SKIP;
+ },
+ });
+ while (treeWalker.nextNode()) {
+ const node = treeWalker.currentNode;
+ if (node.nodeType === Node.ELEMENT_NODE) break;
+ if (/\S/u.test(node.data)) return;
+ }
+
+ // Strip leading indentation from the plain text representation.
+ evt.clipboardData.setData('text/plain', domRoot.textContent.trimStart());
+ if (!html) {
+ evt.clipboardData.setData('text/html', domRoot.innerHTML);
+ }
+ evt.preventDefault();
+});
diff --git a/spec/index.html b/spec/index.html
index ded4e569..8c0398d7 100644
--- a/spec/index.html
+++ b/spec/index.html
@@ -367,7 +367,10 @@
Example
1. Set _length_ to _length_ + 1.
1. Let _weight_ be GetWeight of _node_.
1. If _length_ = 10<sup>9</sup> or _weight_ > 2<sup>_length_ + 1</sup>, then
- 1. Throw a *RangeError* exception.
+ 1. NOTE: This is an out-of-bounds state.
+ 1. If _ignoreErrors_ is not *true*, then
+ 1. Throw a *RangeError* exception.
+ 1. Set _hadError_ to *true*.
</emu-alg>
@@ -386,7 +389,10 @@ Result
1. Set _length_ to _length_ + 1.
1. Let _weight_ be GetWeight of _node_.
1. If _length_ = 109 or _weight_ > 2_length_ + 1, then
- 1. Throw a *RangeError* exception.
+ 1. NOTE: This is an out-of-bounds state.
+ 1. If _ignoreErrors_ is not *true*, then
+ 1. Throw a *RangeError* exception.
+ 1. Set _hadError_ to *true*.
diff --git a/test/baselines/generated-reference/assets-inline.html b/test/baselines/generated-reference/assets-inline.html
index 302974cc..4f72c8ee 100644
--- a/test/baselines/generated-reference/assets-inline.html
+++ b/test/baselines/generated-reference/assets-inline.html
@@ -1439,6 +1439,7 @@
function addStepNumberText(
ol,
depth = 0,
+ indent = '',
special = [...ol.classList].some(c => c.startsWith('nested-')),
) {
let counter = !special && counterByDepth[depth];
@@ -1462,8 +1463,11 @@
let i = (Number(ol.getAttribute('start')) || 1) - 1;
for (const li of ol.children) {
const marker = document.createElement('span');
- marker.textContent = `${i < cache.length ? cache[i] : getTextForIndex(i)}. `;
+ const markerText = i < cache.length ? cache[i] : getTextForIndex(i);
+ const extraIndent = ' '.repeat(markerText.length + 2);
+ marker.textContent = `${indent}${markerText}. `;
marker.setAttribute('aria-hidden', 'true');
+ marker.setAttribute('class', 'list-marker');
const attributesContainer = li.querySelector('.attributes-tag');
if (attributesContainer == null) {
li.prepend(marker);
@@ -1471,7 +1475,7 @@
attributesContainer.insertAdjacentElement('afterend', marker);
}
for (const sublist of li.querySelectorAll(':scope > ol')) {
- addStepNumberText(sublist, depth + 1, special);
+ addStepNumberText(sublist, depth + 1, indent + extraIndent, special);
}
i++;
}
@@ -1483,6 +1487,52 @@
});
});
+// Omit indendation when copying a single algorithm step.
+document.addEventListener('copy', evt => {
+ // Construct a DOM from the selection.
+ const doc = document.implementation.createHTMLDocument('');
+ const domRoot = doc.createElement('div');
+ const html = evt.clipboardData.getData('text/html');
+ if (html) {
+ domRoot.innerHTML = html;
+ } else {
+ const selection = getSelection();
+ const singleRange = selection?.rangeCount === 1 && selection.getRangeAt(0);
+ const container = singleRange?.commonAncestorContainer;
+ if (!container?.querySelector?.('.list-marker')) {
+ return;
+ }
+ domRoot.append(singleRange.cloneContents());
+ }
+
+ // Preserve the indentation if there is no hidden list marker, or if selection
+ // of more than one step is indicated by either multiple such markers or by
+ // visible text before the first one.
+ const listMarkers = domRoot.querySelectorAll('.list-marker');
+ if (listMarkers.length !== 1) {
+ return;
+ }
+ const treeWalker = document.createTreeWalker(domRoot, undefined, {
+ acceptNode(node) {
+ return node.nodeType === Node.TEXT_NODE || node === listMarkers[0]
+ ? NodeFilter.FILTER_ACCEPT
+ : NodeFilter.FILTER_SKIP;
+ },
+ });
+ while (treeWalker.nextNode()) {
+ const node = treeWalker.currentNode;
+ if (node.nodeType === Node.ELEMENT_NODE) break;
+ if (/\S/u.test(node.data)) return;
+ }
+
+ // Strip leading indentation from the plain text representation.
+ evt.clipboardData.setData('text/plain', domRoot.textContent.trimStart());
+ if (!html) {
+ evt.clipboardData.setData('text/html', domRoot.innerHTML);
+ }
+ evt.preventDefault();
+});
+
'use strict';
// Update superscripts to not suffer misinterpretation when copied and pasted as plain text.
@@ -1684,6 +1734,7 @@
span[aria-hidden='true'] {
font-size: 0;
+ white-space: pre;
}
a {