Skip to content

Commit 746d3e6

Browse files
authored
Merge pull request #277 from rtfpessoa/improve-api-for-standalone-usage
clean: Improve diff2html-ui APIs for standalone usage
2 parents aa6dd18 + 8b5111f commit 746d3e6

7 files changed

Lines changed: 149 additions & 38 deletions

File tree

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ export default {
254254
> Create a Diff2HtmlUI instance
255255
256256
```ts
257-
constructor(diffInput: string | DiffFile[], target: HTMLElement) // diff2html-ui, diff2html-ui-slim
258-
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base
257+
constructor(target: HTMLElement, diffInput?: string | DiffFile[]) // diff2html-ui, diff2html-ui-slim
258+
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base
259259
```
260260

261261
> Generate and inject in the document the Pretty HTML representation of the diff
@@ -270,6 +270,7 @@ draw(): void
270270
synchronisedScroll(): void
271271
fileListToggle(startVisible: boolean): void
272272
highlightCode(): void
273+
smartSelection(): void
273274
```
274275

275276
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
@@ -303,9 +304,9 @@ highlightCode(): void
303304
const targetElement = document.getElementById('destination-elem-id');
304305
const configuration = { drawFileList: true, matching: 'lines' };
305306

306-
const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration);
307+
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
307308
// or
308-
const diff2htmlUi = new Diff2HtmlUI(diffJson, targetElement, configuration);
309+
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffJson, configuration);
309310
```
310311

311312
#### Draw
@@ -338,7 +339,7 @@ index 0000001..0ddf2ba
338339
+console.log("Hello from Diff2Html!")`;
339340
const targetElement = document.getElementById('myDiffElement');
340341
const configuration = { inputFormat: 'json', drawFileList: true, matching: 'lines', highlight: true };
341-
const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration);
342+
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
342343
diff2htmlUi.draw();
343344
diff2htmlUi.highlightCode();
344345
});
@@ -359,7 +360,7 @@ index 0000001..0ddf2ba
359360
```js
360361
document.addEventListener('DOMContentLoaded', () => {
361362
const targetElement = document.getElementById('myDiffElement');
362-
var diff2htmlUi = new Diff2HtmlUI(lineDiffExample, targetElement, { drawFileList: true, matching: 'lines' });
363+
var diff2htmlUi = new Diff2HtmlUI(targetElement, lineDiffExample, { drawFileList: true, matching: 'lines' });
363364
diff2htmlUi.draw();
364365
diff2htmlUi.fileListToggle(false);
365366
});

src/__tests__/diff2html-tests.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,5 +832,109 @@ describe('Diff2Html', () => {
832832
</div>"
833833
`);
834834
});
835+
836+
it('should generate html correctly without escaping twice', () => {
837+
const diff =
838+
'--- src/index.html\n' +
839+
'+++ src/index.html\n' +
840+
'@@ -1,2 +1,2 @@\n' +
841+
'-<!-- commented code -->\n' +
842+
'-</div>\n' +
843+
'+<html>\n' +
844+
'+<body>';
845+
846+
const result = html(diff);
847+
expect(result).toMatchInlineSnapshot(`
848+
"<div class=\\"d2h-file-list-wrapper\\">
849+
<div class=\\"d2h-file-list-header\\">
850+
<span class=\\"d2h-file-list-title\\">Files changed (1)</span>
851+
<a class=\\"d2h-file-switch d2h-hide\\">hide</a>
852+
<a class=\\"d2h-file-switch d2h-show\\">show</a>
853+
</div>
854+
<ol class=\\"d2h-file-list\\">
855+
<li class=\\"d2h-file-list-line\\">
856+
<span class=\\"d2h-file-name-wrapper\\">
857+
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-changed\\" height=\\"16\\" title=\\"modified\\" version=\\"1.1\\"
858+
viewBox=\\"0 0 14 16\\" width=\\"14\\">
859+
<path d=\\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z\\"></path>
860+
</svg> <a href=\\"#d2h-597266\\" class=\\"d2h-file-name\\">src/index.html</a>
861+
<span class=\\"d2h-file-stats\\">
862+
<span class=\\"d2h-lines-added\\">+2</span>
863+
<span class=\\"d2h-lines-deleted\\">-2</span>
864+
</span>
865+
</span>
866+
</li>
867+
</ol>
868+
</div><div class=\\"d2h-wrapper\\">
869+
<div id=\\"d2h-597266\\" class=\\"d2h-file-wrapper\\" data-lang=\\"html\\">
870+
<div class=\\"d2h-file-header\\">
871+
<span class=\\"d2h-file-name-wrapper\\">
872+
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
873+
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
874+
</svg> <span class=\\"d2h-file-name\\">src/index.html</span>
875+
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
876+
</div>
877+
<div class=\\"d2h-file-diff\\">
878+
<div class=\\"d2h-code-wrapper\\">
879+
<table class=\\"d2h-diff-table\\">
880+
<tbody class=\\"d2h-diff-tbody\\">
881+
<tr>
882+
<td class=\\"d2h-code-linenumber d2h-info\\"></td>
883+
<td class=\\"d2h-info\\">
884+
<div class=\\"d2h-code-line d2h-info\\">@@ -1,2 +1,2 @@</div>
885+
</td>
886+
</tr><tr>
887+
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
888+
<div class=\\"line-num1\\">1</div>
889+
<div class=\\"line-num2\\"></div>
890+
</td>
891+
<td class=\\"d2h-del d2h-change\\">
892+
<div class=\\"d2h-code-line d2h-del d2h-change\\">
893+
<span class=\\"d2h-code-line-prefix\\">-</span>
894+
<span class=\\"d2h-code-line-ctn\\"><del>&lt;!-- commented code --&gt;</del></span>
895+
</div>
896+
</td>
897+
</tr><tr>
898+
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
899+
<div class=\\"line-num1\\">2</div>
900+
<div class=\\"line-num2\\"></div>
901+
</td>
902+
<td class=\\"d2h-del d2h-change\\">
903+
<div class=\\"d2h-code-line d2h-del d2h-change\\">
904+
<span class=\\"d2h-code-line-prefix\\">-</span>
905+
<span class=\\"d2h-code-line-ctn\\"><del>&lt;&#x2F;div</del>&gt;</span>
906+
</div>
907+
</td>
908+
</tr><tr>
909+
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
910+
<div class=\\"line-num1\\"></div>
911+
<div class=\\"line-num2\\">1</div>
912+
</td>
913+
<td class=\\"d2h-ins d2h-change\\">
914+
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
915+
<span class=\\"d2h-code-line-prefix\\">+</span>
916+
<span class=\\"d2h-code-line-ctn\\"><ins>&lt;html&gt;</ins></span>
917+
</div>
918+
</td>
919+
</tr><tr>
920+
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
921+
<div class=\\"line-num1\\"></div>
922+
<div class=\\"line-num2\\">2</div>
923+
</td>
924+
<td class=\\"d2h-ins d2h-change\\">
925+
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
926+
<span class=\\"d2h-code-line-prefix\\">+</span>
927+
<span class=\\"d2h-code-line-ctn\\"><ins>&lt;body</ins>&gt;</span>
928+
</div>
929+
</td>
930+
</tr>
931+
</tbody>
932+
</table>
933+
</div>
934+
</div>
935+
</div>
936+
</div>"
937+
`);
938+
});
835939
});
836940
});

src/render-utils.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ export function escapeForHtml(str: string): string {
9393
/**
9494
* Deconstructs diff @line by separating the content from the prefix type
9595
*/
96-
export function deconstructLine(line: string, isCombined: boolean): DiffLineParts {
96+
export function deconstructLine(line: string, isCombined: boolean, escape = true): DiffLineParts {
9797
const indexToSplit = prefixLength(isCombined);
9898
return {
9999
prefix: line.substring(0, indexToSplit),
100-
content: escapeForHtml(line.substring(indexToSplit)),
100+
content: escape ? escapeForHtml(line.substring(indexToSplit)) : line.substring(indexToSplit),
101101
};
102102
}
103103

@@ -216,8 +216,8 @@ export function diffHighlight(
216216
): HighlightedLines {
217217
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
218218

219-
const line1 = deconstructLine(diffLine1, isCombined);
220-
const line2 = deconstructLine(diffLine2, isCombined);
219+
const line1 = deconstructLine(diffLine1, isCombined, false);
220+
const line2 = deconstructLine(diffLine2, isCombined, false);
221221

222222
if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) {
223223
return {
@@ -256,10 +256,11 @@ export function diffHighlight(
256256
const highlightedLine = diff.reduce((highlightedLine, part) => {
257257
const elemType = part.added ? 'ins' : part.removed ? 'del' : null;
258258
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : '';
259+
const escapedValue = escapeForHtml(part.value);
259260

260261
return elemType !== null
261-
? `${highlightedLine}<${elemType}${addClass}>${part.value}</${elemType}>`
262-
: `${highlightedLine}${part.value}`;
262+
? `${highlightedLine}<${elemType}${addClass}>${escapedValue}</${elemType}>`
263+
: `${highlightedLine}${escapedValue}`;
263264
}, '');
264265

265266
return {

src/ui/js/diff2html-ui-base.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,21 @@ export class Diff2HtmlUI {
2929

3030
currentSelectionColumnId = -1;
3131

32-
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) {
32+
constructor(
33+
target: HTMLElement,
34+
diffInput?: string | DiffFile[],
35+
config: Diff2HtmlUIConfig = {},
36+
hljs?: HighlightJS,
37+
) {
3338
this.config = { ...defaultDiff2HtmlUIConfig, ...config };
34-
this.diffHtml = html(diffInput, this.config);
39+
this.diffHtml = diffInput !== undefined ? html(diffInput, this.config) : target.innerHTML;
3540
this.targetElement = target;
3641
if (hljs !== undefined) this.hljs = hljs;
3742
}
3843

3944
draw(): void {
4045
this.targetElement.innerHTML = this.diffHtml;
41-
if (this.config.smartSelection) this.initSelection();
46+
if (this.config.smartSelection) this.smartSelection();
4247
if (this.config.synchronisedScroll) this.synchronisedScroll();
4348
if (this.config.highlight) this.highlightCode();
4449
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
@@ -142,29 +147,13 @@ export class Diff2HtmlUI {
142147
}
143148

144149
line.classList.add('hljs');
145-
line.classList.add('result.language');
150+
line.classList.add(result.language);
146151
line.innerHTML = result.value;
147152
});
148153
});
149154
}
150155

151-
private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult {
152-
return 'top' in object;
153-
}
154-
155-
private getHashTag(): string | null {
156-
const docUrl = document.URL;
157-
const hashTagIndex = docUrl.indexOf('#');
158-
159-
let hashTag = null;
160-
if (hashTagIndex !== -1) {
161-
hashTag = docUrl.substr(hashTagIndex + 1);
162-
}
163-
164-
return hashTag;
165-
}
166-
167-
private initSelection(): void {
156+
smartSelection(): void {
168157
const body = document.getElementsByTagName('body')[0];
169158
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
170159

@@ -200,6 +189,22 @@ export class Diff2HtmlUI {
200189
});
201190
}
202191

192+
private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult {
193+
return 'top' in object;
194+
}
195+
196+
private getHashTag(): string | null {
197+
const docUrl = document.URL;
198+
const hashTagIndex = docUrl.indexOf('#');
199+
200+
let hashTag = null;
201+
if (hashTagIndex !== -1) {
202+
hashTag = docUrl.substr(hashTagIndex + 1);
203+
}
204+
205+
return hashTag;
206+
}
207+
203208
private getSelectedText(): string | undefined {
204209
const sel = window.getSelection();
205210

src/ui/js/diff2html-ui-slim.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { DiffFile } from '../../types';
44
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
55

66
export class Diff2HtmlUI extends Diff2HtmlUIBase {
7-
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
8-
super(diffInput, target, config, hljs);
7+
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) {
8+
super(target, diffInput, config, hljs);
99
}
1010
}
1111

src/ui/js/diff2html-ui.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { DiffFile } from '../../types';
44
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
55

66
export class Diff2HtmlUI extends Diff2HtmlUIBase {
7-
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
8-
super(diffInput, target, config, hljs);
7+
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) {
8+
super(target, diffInput, config, hljs);
99
}
1010
}
1111

website/templates/pages/demo/demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async function getDiff(request: Request): Promise<string> {
151151
}
152152

153153
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
154-
const diff2htmlUi = new Diff2HtmlUI(diffString, elements.structure.diffTarget, config);
154+
const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config);
155155
diff2htmlUi.draw();
156156
}
157157

0 commit comments

Comments
 (0)