Skip to content

Commit f8c11d9

Browse files
authored
Merge pull request #248 from eecs485staff/enhanced-codeblocks-newlines-duplicated
Prevent newlines from being duplicated after copying an enhanced codeblock
2 parents 9befcb4 + 9b68cef commit f8c11d9

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

src_js/components/main_content/enhanced_code_blocks/__tests__/useEnhancedCodeBlocks.test.ts

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,26 @@ $ tar -xvzf starter_files.tar.gz
1717
</code></pre></div></div>`;
1818
const PLAINTEX_BLOCK_NUM_LINES = 4;
1919

20+
const PYTHON_BLOCK = `<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""This is a docstring."""</span>
21+
<span class="kn">import</span> <span class="nn">math</span>
22+
23+
<span class="k">def</span> <span class="nf">sqrt</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
24+
<span class="s">"""Print the square root of x."""</span>
25+
<span class="k">print</span><span class="p">(</span><span class="n">math</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
26+
27+
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
28+
<span class="k">print</span><span class="p">(</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">81</span><span class="p">))</span>
29+
</code></pre></div></div>`;
30+
2031
describe('useEnhancedCodeBlocks', () => {
32+
function triggerMouseEvent(node: HTMLElement | null, eventType: string) {
33+
if (!node) {
34+
throw new Error('node cannot be null');
35+
}
36+
const mouseEvent = new CustomEvent(eventType);
37+
node.dispatchEvent(mouseEvent);
38+
}
39+
2140
test('code blocks should be transformed into tables', () => {
2241
document.body.innerHTML = `${CONSOLE_BLOCK}${PLAINTEXT_BLOCK}`;
2342

@@ -84,15 +103,6 @@ describe('useEnhancedCodeBlocks', () => {
84103
});
85104

86105
describe('code selection by clicking line numbers', () => {
87-
function triggerMouseEvent(node: HTMLElement | null, eventType: string) {
88-
if (!node) {
89-
throw new Error('node cannot be null');
90-
}
91-
const mouseEvent = document.createEvent('MouseEvents');
92-
mouseEvent.initEvent(eventType, true, true);
93-
node.dispatchEvent(mouseEvent);
94-
}
95-
96106
test('clicking a line number selects the line', () => {
97107
document.body.innerHTML = `${PLAINTEXT_BLOCK}${CONSOLE_BLOCK}`;
98108

@@ -131,4 +141,39 @@ describe('useEnhancedCodeBlocks', () => {
131141
);
132142
});
133143
});
144+
145+
describe('copy an enhanced codeblock', () => {
146+
test('clicking the copy button on a codeblock with empty lines copies all the lines using correct whitespace', () => {
147+
// jsdom doesn't implement window.navigator, so we need to mock it.
148+
Object.defineProperty(window, 'navigator', {
149+
value: {
150+
clipboard: {
151+
writeText: jest.fn().mockImplementation(() => Promise.resolve()),
152+
},
153+
},
154+
});
155+
156+
document.body.innerHTML = PYTHON_BLOCK;
157+
158+
useEnhancedCodeBlocks({ current: document.body });
159+
160+
const buttons = document.querySelectorAll('button');
161+
expect(buttons.length).toBe(1);
162+
163+
const copyButton = buttons[0];
164+
triggerMouseEvent(copyButton, 'click');
165+
166+
expect(window.navigator.clipboard.writeText)
167+
.toHaveBeenCalledWith(`"""This is a docstring."""
168+
import math
169+
170+
def sqrt(x):
171+
"""Print the square root of x."""
172+
print(math.sqrt(x))
173+
174+
if __name__ == "__main__":
175+
print(sqrt(81))
176+
`);
177+
});
178+
});
134179
});

src_js/components/main_content/enhanced_code_blocks/genCopyButton.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ export function genCopyButton(codeblockId: string, isConsoleBlock?: boolean) {
5757
);
5858
}
5959

60-
const DEFAULT_COPY_LINES_MAP_FN = (line: HTMLElement) => line.innerText;
60+
// If a line's only text is \n, set it to the empty string to prevent newlines
61+
// from being duplicated. textContent returns text from all descendant nodes.
62+
const DEFAULT_COPY_LINES_MAP_FN = (line: HTMLElement) =>
63+
line.textContent !== '\n' ? line.textContent : '';
6164
const CONSOLE_COPY_LINES_MAP_FN = (line: HTMLElement) => {
6265
// (1) Skip console output lines
6366
// (Class name 'go' refers to the Rouge class `Generic::Output`.)

0 commit comments

Comments
 (0)