diff --git a/aio/src/app/embedded/code/code.component.spec.ts b/aio/src/app/embedded/code/code.component.spec.ts index 56609dcbf3..bf67fef024 100644 --- a/aio/src/app/embedded/code/code.component.spec.ts +++ b/aio/src/app/embedded/code/code.component.spec.ts @@ -218,7 +218,29 @@ describe('CodeComponent', () => { const copierService: CopierService = TestBed.get(CopierService); const spy = spyOn(copierService, 'copyText'); getButton().click(); - expect(spy.calls.argsFor(0)[0]).toEqual(oneLineCode, 'after click'); + expect(spy.calls.argsFor(0)[0]).toBe(oneLineCode, 'after click'); + }); + + it('should preserve newlines in the copied code', () => { + const copierService: CopierService = TestBed.get(CopierService); + const spy = spyOn(copierService, 'copyText'); + const expectedCode = smallMultiLineCode.trim().replace(/</g, '<').replace(/>/g, '>'); + let actualCode; + + hostComponent.code = smallMultiLineCode; + + [false, true, 42].forEach(linenums => { + hostComponent.linenums = linenums; + fixture.detectChanges(); + codeComponent.ngOnChanges(); + getButton().click(); + actualCode = spy.calls.mostRecent().args[0]; + + expect(actualCode).toBe(expectedCode, `when linenums=${linenums}`); + expect(actualCode.match(/\r?\n/g).length).toBe(5); + + spy.calls.reset(); + }); }); it('should display a message when copy succeeds', () => { diff --git a/aio/src/app/embedded/code/code.component.ts b/aio/src/app/embedded/code/code.component.ts index 98e3315799..5a982c7390 100644 --- a/aio/src/app/embedded/code/code.component.ts +++ b/aio/src/app/embedded/code/code.component.ts @@ -51,6 +51,11 @@ export class CodeComponent implements OnChanges { @Input() code: string; + /** + * The code to be copied when clicking the copy button, this should not be HTML encoded + */ + private codeText: string; + /** * set to true if the copy button is not to be shown */ @@ -116,6 +121,7 @@ export class CodeComponent implements OnChanges { const linenums = this.getLinenums(); this.setCodeHtml(this.code); // start with unformatted code + this.codeText = this.getCodeText(); // store the unformatted code as text (for copying) this.pretty.formatCode(this.code, this.language, linenums).subscribe( formattedCode => this.setCodeHtml(formattedCode), err => { /* ignore failure to format */ } @@ -128,9 +134,15 @@ export class CodeComponent implements OnChanges { this.codeContainer.nativeElement.innerHTML = formattedCode; } + private getCodeText() { + // `prettify` may remove newlines, e.g. when `linenums` are on. Retrieve the content of the + // container as text, before prettifying it. + // We take the textContent because we don't want it to be HTML encoded. + return this.codeContainer.nativeElement.textContent; + } + doCopy() { - // We take the textContent because we don't want it to be HTML encoded - const code = this.codeContainer.nativeElement.textContent.trim(); + const code = this.codeText; if (this.copier.copyText(code)) { this.logger.log('Copied code to clipboard:', code); // success snackbar alert