From 8b5111f8defd51b56654a6547f990fc1435348a6 Mon Sep 17 00:00:00 2001 From: Rodrigo Fernandes Date: Wed, 8 Jan 2020 22:40:46 +0000 Subject: [PATCH] clean: Improve diff2html-ui APIs for standalone usage --- README.md | 13 ++-- src/__tests__/diff2html-tests.ts | 104 +++++++++++++++++++++++++++ src/render-utils.ts | 13 ++-- src/ui/js/diff2html-ui-base.ts | 47 ++++++------ src/ui/js/diff2html-ui-slim.ts | 4 +- src/ui/js/diff2html-ui.ts | 4 +- website/templates/pages/demo/demo.ts | 2 +- 7 files changed, 149 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 44103a3..21ab8bd 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,8 @@ export default { > Create a Diff2HtmlUI instance ```ts -constructor(diffInput: string | DiffFile[], target: HTMLElement) // diff2html-ui, diff2html-ui-slim -constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base +constructor(target: HTMLElement, diffInput?: string | DiffFile[]) // diff2html-ui, diff2html-ui-slim +constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base ``` > Generate and inject in the document the Pretty HTML representation of the diff @@ -270,6 +270,7 @@ draw(): void synchronisedScroll(): void fileListToggle(startVisible: boolean): void highlightCode(): void +smartSelection(): void ``` > Check out the [docs/demo.html](./docs/demo.html) for a demo example. @@ -303,9 +304,9 @@ highlightCode(): void const targetElement = document.getElementById('destination-elem-id'); const configuration = { drawFileList: true, matching: 'lines' }; -const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration); +const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration); // or -const diff2htmlUi = new Diff2HtmlUI(diffJson, targetElement, configuration); +const diff2htmlUi = new Diff2HtmlUI(targetElement, diffJson, configuration); ``` #### Draw @@ -338,7 +339,7 @@ index 0000001..0ddf2ba +console.log("Hello from Diff2Html!")`; const targetElement = document.getElementById('myDiffElement'); const configuration = { inputFormat: 'json', drawFileList: true, matching: 'lines', highlight: true }; - const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration); + const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration); diff2htmlUi.draw(); diff2htmlUi.highlightCode(); }); @@ -359,7 +360,7 @@ index 0000001..0ddf2ba ```js document.addEventListener('DOMContentLoaded', () => { const targetElement = document.getElementById('myDiffElement'); - var diff2htmlUi = new Diff2HtmlUI(lineDiffExample, targetElement, { drawFileList: true, matching: 'lines' }); + var diff2htmlUi = new Diff2HtmlUI(targetElement, lineDiffExample, { drawFileList: true, matching: 'lines' }); diff2htmlUi.draw(); diff2htmlUi.fileListToggle(false); }); diff --git a/src/__tests__/diff2html-tests.ts b/src/__tests__/diff2html-tests.ts index 80784c8..b662c1a 100644 --- a/src/__tests__/diff2html-tests.ts +++ b/src/__tests__/diff2html-tests.ts @@ -832,5 +832,109 @@ describe('Diff2Html', () => { " `); }); + + it('should generate html correctly without escaping twice', () => { + const diff = + '--- src/index.html\n' + + '+++ src/index.html\n' + + '@@ -1,2 +1,2 @@\n' + + '-\n' + + '-\n' + + '+\n' + + '+'; + + const result = html(diff); + expect(result).toMatchInlineSnapshot(` + "
+
+ Files changed (1) + hide + show +
+
    +
  1. + + + + src/index.html + + +2 + -2 + + +
  2. +
+
+
+
+ + + + src/index.html + CHANGED +
+
+
+ + + + + + + + + + + + + + + + + + + +
+
@@ -1,2 +1,2 @@
+
+
1
+
+
+
+ - + <!-- commented code --> +
+
+
2
+
+
+
+ - + </div> +
+
+
+
1
+
+
+ + + <html> +
+
+
+
2
+
+
+ + + <body> +
+
+
+
+
+
" + `); + }); }); }); diff --git a/src/render-utils.ts b/src/render-utils.ts index 6cdf7b8..cf91361 100644 --- a/src/render-utils.ts +++ b/src/render-utils.ts @@ -93,11 +93,11 @@ export function escapeForHtml(str: string): string { /** * Deconstructs diff @line by separating the content from the prefix type */ -export function deconstructLine(line: string, isCombined: boolean): DiffLineParts { +export function deconstructLine(line: string, isCombined: boolean, escape = true): DiffLineParts { const indexToSplit = prefixLength(isCombined); return { prefix: line.substring(0, indexToSplit), - content: escapeForHtml(line.substring(indexToSplit)), + content: escape ? escapeForHtml(line.substring(indexToSplit)) : line.substring(indexToSplit), }; } @@ -216,8 +216,8 @@ export function diffHighlight( ): HighlightedLines { const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config }; - const line1 = deconstructLine(diffLine1, isCombined); - const line2 = deconstructLine(diffLine2, isCombined); + const line1 = deconstructLine(diffLine1, isCombined, false); + const line2 = deconstructLine(diffLine2, isCombined, false); if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) { return { @@ -256,10 +256,11 @@ export function diffHighlight( const highlightedLine = diff.reduce((highlightedLine, part) => { const elemType = part.added ? 'ins' : part.removed ? 'del' : null; const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : ''; + const escapedValue = escapeForHtml(part.value); return elemType !== null - ? `${highlightedLine}<${elemType}${addClass}>${part.value}` - : `${highlightedLine}${part.value}`; + ? `${highlightedLine}<${elemType}${addClass}>${escapedValue}` + : `${highlightedLine}${escapedValue}`; }, ''); return { diff --git a/src/ui/js/diff2html-ui-base.ts b/src/ui/js/diff2html-ui-base.ts index 0c7d116..71805d8 100644 --- a/src/ui/js/diff2html-ui-base.ts +++ b/src/ui/js/diff2html-ui-base.ts @@ -29,16 +29,21 @@ export class Diff2HtmlUI { currentSelectionColumnId = -1; - constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) { + constructor( + target: HTMLElement, + diffInput?: string | DiffFile[], + config: Diff2HtmlUIConfig = {}, + hljs?: HighlightJS, + ) { this.config = { ...defaultDiff2HtmlUIConfig, ...config }; - this.diffHtml = html(diffInput, this.config); + this.diffHtml = diffInput !== undefined ? html(diffInput, this.config) : target.innerHTML; this.targetElement = target; if (hljs !== undefined) this.hljs = hljs; } draw(): void { this.targetElement.innerHTML = this.diffHtml; - if (this.config.smartSelection) this.initSelection(); + if (this.config.smartSelection) this.smartSelection(); if (this.config.synchronisedScroll) this.synchronisedScroll(); if (this.config.highlight) this.highlightCode(); if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible); @@ -142,29 +147,13 @@ export class Diff2HtmlUI { } line.classList.add('hljs'); - line.classList.add('result.language'); + line.classList.add(result.language); line.innerHTML = result.value; }); }); } - private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult { - return 'top' in object; - } - - private getHashTag(): string | null { - const docUrl = document.URL; - const hashTagIndex = docUrl.indexOf('#'); - - let hashTag = null; - if (hashTagIndex !== -1) { - hashTag = docUrl.substr(hashTagIndex + 1); - } - - return hashTag; - } - - private initSelection(): void { + smartSelection(): void { const body = document.getElementsByTagName('body')[0]; const diffTable = body.getElementsByClassName('d2h-diff-table')[0]; @@ -200,6 +189,22 @@ export class Diff2HtmlUI { }); } + private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult { + return 'top' in object; + } + + private getHashTag(): string | null { + const docUrl = document.URL; + const hashTagIndex = docUrl.indexOf('#'); + + let hashTag = null; + if (hashTagIndex !== -1) { + hashTag = docUrl.substr(hashTagIndex + 1); + } + + return hashTag; + } + private getSelectedText(): string | undefined { const sel = window.getSelection(); diff --git a/src/ui/js/diff2html-ui-slim.ts b/src/ui/js/diff2html-ui-slim.ts index 86d40af..2644e7e 100644 --- a/src/ui/js/diff2html-ui-slim.ts +++ b/src/ui/js/diff2html-ui-slim.ts @@ -4,8 +4,8 @@ import { DiffFile } from '../../types'; import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base'; export class Diff2HtmlUI extends Diff2HtmlUIBase { - constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) { - super(diffInput, target, config, hljs); + constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) { + super(target, diffInput, config, hljs); } } diff --git a/src/ui/js/diff2html-ui.ts b/src/ui/js/diff2html-ui.ts index eaefad2..fc51604 100644 --- a/src/ui/js/diff2html-ui.ts +++ b/src/ui/js/diff2html-ui.ts @@ -4,8 +4,8 @@ import { DiffFile } from '../../types'; import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base'; export class Diff2HtmlUI extends Diff2HtmlUIBase { - constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) { - super(diffInput, target, config, hljs); + constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) { + super(target, diffInput, config, hljs); } } diff --git a/website/templates/pages/demo/demo.ts b/website/templates/pages/demo/demo.ts index d4920cf..82010ca 100644 --- a/website/templates/pages/demo/demo.ts +++ b/website/templates/pages/demo/demo.ts @@ -151,7 +151,7 @@ async function getDiff(request: Request): Promise { } function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void { - const diff2htmlUi = new Diff2HtmlUI(diffString, elements.structure.diffTarget, config); + const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config); diff2htmlUi.draw(); }