Merge pull request #277 from rtfpessoa/improve-api-for-standalone-usage
clean: Improve diff2html-ui APIs for standalone usage
This commit is contained in:
commit
746d3e625e
7 changed files with 149 additions and 38 deletions
13
README.md
13
README.md
|
|
@ -254,8 +254,8 @@ export default {
|
||||||
> Create a Diff2HtmlUI instance
|
> Create a Diff2HtmlUI instance
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
constructor(diffInput: string | DiffFile[], target: HTMLElement) // diff2html-ui, diff2html-ui-slim
|
constructor(target: HTMLElement, diffInput?: string | DiffFile[]) // diff2html-ui, diff2html-ui-slim
|
||||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base
|
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
|
> Generate and inject in the document the Pretty HTML representation of the diff
|
||||||
|
|
@ -270,6 +270,7 @@ draw(): void
|
||||||
synchronisedScroll(): void
|
synchronisedScroll(): void
|
||||||
fileListToggle(startVisible: boolean): void
|
fileListToggle(startVisible: boolean): void
|
||||||
highlightCode(): void
|
highlightCode(): void
|
||||||
|
smartSelection(): void
|
||||||
```
|
```
|
||||||
|
|
||||||
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
> 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 targetElement = document.getElementById('destination-elem-id');
|
||||||
const configuration = { drawFileList: true, matching: 'lines' };
|
const configuration = { drawFileList: true, matching: 'lines' };
|
||||||
|
|
||||||
const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration);
|
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
|
||||||
// or
|
// or
|
||||||
const diff2htmlUi = new Diff2HtmlUI(diffJson, targetElement, configuration);
|
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffJson, configuration);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Draw
|
#### Draw
|
||||||
|
|
@ -338,7 +339,7 @@ index 0000001..0ddf2ba
|
||||||
+console.log("Hello from Diff2Html!")`;
|
+console.log("Hello from Diff2Html!")`;
|
||||||
const targetElement = document.getElementById('myDiffElement');
|
const targetElement = document.getElementById('myDiffElement');
|
||||||
const configuration = { inputFormat: 'json', drawFileList: true, matching: 'lines', highlight: true };
|
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.draw();
|
||||||
diff2htmlUi.highlightCode();
|
diff2htmlUi.highlightCode();
|
||||||
});
|
});
|
||||||
|
|
@ -359,7 +360,7 @@ index 0000001..0ddf2ba
|
||||||
```js
|
```js
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const targetElement = document.getElementById('myDiffElement');
|
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.draw();
|
||||||
diff2htmlUi.fileListToggle(false);
|
diff2htmlUi.fileListToggle(false);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -832,5 +832,109 @@ describe('Diff2Html', () => {
|
||||||
</div>"
|
</div>"
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate html correctly without escaping twice', () => {
|
||||||
|
const diff =
|
||||||
|
'--- src/index.html\n' +
|
||||||
|
'+++ src/index.html\n' +
|
||||||
|
'@@ -1,2 +1,2 @@\n' +
|
||||||
|
'-<!-- commented code -->\n' +
|
||||||
|
'-</div>\n' +
|
||||||
|
'+<html>\n' +
|
||||||
|
'+<body>';
|
||||||
|
|
||||||
|
const result = html(diff);
|
||||||
|
expect(result).toMatchInlineSnapshot(`
|
||||||
|
"<div class=\\"d2h-file-list-wrapper\\">
|
||||||
|
<div class=\\"d2h-file-list-header\\">
|
||||||
|
<span class=\\"d2h-file-list-title\\">Files changed (1)</span>
|
||||||
|
<a class=\\"d2h-file-switch d2h-hide\\">hide</a>
|
||||||
|
<a class=\\"d2h-file-switch d2h-show\\">show</a>
|
||||||
|
</div>
|
||||||
|
<ol class=\\"d2h-file-list\\">
|
||||||
|
<li class=\\"d2h-file-list-line\\">
|
||||||
|
<span class=\\"d2h-file-name-wrapper\\">
|
||||||
|
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-changed\\" height=\\"16\\" title=\\"modified\\" version=\\"1.1\\"
|
||||||
|
viewBox=\\"0 0 14 16\\" width=\\"14\\">
|
||||||
|
<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>
|
||||||
|
</svg> <a href=\\"#d2h-597266\\" class=\\"d2h-file-name\\">src/index.html</a>
|
||||||
|
<span class=\\"d2h-file-stats\\">
|
||||||
|
<span class=\\"d2h-lines-added\\">+2</span>
|
||||||
|
<span class=\\"d2h-lines-deleted\\">-2</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div><div class=\\"d2h-wrapper\\">
|
||||||
|
<div id=\\"d2h-597266\\" class=\\"d2h-file-wrapper\\" data-lang=\\"html\\">
|
||||||
|
<div class=\\"d2h-file-header\\">
|
||||||
|
<span class=\\"d2h-file-name-wrapper\\">
|
||||||
|
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
|
||||||
|
<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>
|
||||||
|
</svg> <span class=\\"d2h-file-name\\">src/index.html</span>
|
||||||
|
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
|
||||||
|
</div>
|
||||||
|
<div class=\\"d2h-file-diff\\">
|
||||||
|
<div class=\\"d2h-code-wrapper\\">
|
||||||
|
<table class=\\"d2h-diff-table\\">
|
||||||
|
<tbody class=\\"d2h-diff-tbody\\">
|
||||||
|
<tr>
|
||||||
|
<td class=\\"d2h-code-linenumber d2h-info\\"></td>
|
||||||
|
<td class=\\"d2h-info\\">
|
||||||
|
<div class=\\"d2h-code-line d2h-info\\">@@ -1,2 +1,2 @@</div>
|
||||||
|
</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
|
||||||
|
<div class=\\"line-num1\\">1</div>
|
||||||
|
<div class=\\"line-num2\\"></div>
|
||||||
|
</td>
|
||||||
|
<td class=\\"d2h-del d2h-change\\">
|
||||||
|
<div class=\\"d2h-code-line d2h-del d2h-change\\">
|
||||||
|
<span class=\\"d2h-code-line-prefix\\">-</span>
|
||||||
|
<span class=\\"d2h-code-line-ctn\\"><del><!-- commented code --></del></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
|
||||||
|
<div class=\\"line-num1\\">2</div>
|
||||||
|
<div class=\\"line-num2\\"></div>
|
||||||
|
</td>
|
||||||
|
<td class=\\"d2h-del d2h-change\\">
|
||||||
|
<div class=\\"d2h-code-line d2h-del d2h-change\\">
|
||||||
|
<span class=\\"d2h-code-line-prefix\\">-</span>
|
||||||
|
<span class=\\"d2h-code-line-ctn\\"><del></div</del>></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
|
||||||
|
<div class=\\"line-num1\\"></div>
|
||||||
|
<div class=\\"line-num2\\">1</div>
|
||||||
|
</td>
|
||||||
|
<td class=\\"d2h-ins d2h-change\\">
|
||||||
|
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
|
||||||
|
<span class=\\"d2h-code-line-prefix\\">+</span>
|
||||||
|
<span class=\\"d2h-code-line-ctn\\"><ins><html></ins></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
|
||||||
|
<div class=\\"line-num1\\"></div>
|
||||||
|
<div class=\\"line-num2\\">2</div>
|
||||||
|
</td>
|
||||||
|
<td class=\\"d2h-ins d2h-change\\">
|
||||||
|
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
|
||||||
|
<span class=\\"d2h-code-line-prefix\\">+</span>
|
||||||
|
<span class=\\"d2h-code-line-ctn\\"><ins><body</ins>></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>"
|
||||||
|
`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,11 @@ export function escapeForHtml(str: string): string {
|
||||||
/**
|
/**
|
||||||
* Deconstructs diff @line by separating the content from the prefix type
|
* 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);
|
const indexToSplit = prefixLength(isCombined);
|
||||||
return {
|
return {
|
||||||
prefix: line.substring(0, indexToSplit),
|
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 {
|
): HighlightedLines {
|
||||||
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
|
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
|
||||||
|
|
||||||
const line1 = deconstructLine(diffLine1, isCombined);
|
const line1 = deconstructLine(diffLine1, isCombined, false);
|
||||||
const line2 = deconstructLine(diffLine2, isCombined);
|
const line2 = deconstructLine(diffLine2, isCombined, false);
|
||||||
|
|
||||||
if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) {
|
if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -256,10 +256,11 @@ export function diffHighlight(
|
||||||
const highlightedLine = diff.reduce((highlightedLine, part) => {
|
const highlightedLine = diff.reduce((highlightedLine, part) => {
|
||||||
const elemType = part.added ? 'ins' : part.removed ? 'del' : null;
|
const elemType = part.added ? 'ins' : part.removed ? 'del' : null;
|
||||||
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : '';
|
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : '';
|
||||||
|
const escapedValue = escapeForHtml(part.value);
|
||||||
|
|
||||||
return elemType !== null
|
return elemType !== null
|
||||||
? `${highlightedLine}<${elemType}${addClass}>${part.value}</${elemType}>`
|
? `${highlightedLine}<${elemType}${addClass}>${escapedValue}</${elemType}>`
|
||||||
: `${highlightedLine}${part.value}`;
|
: `${highlightedLine}${escapedValue}`;
|
||||||
}, '');
|
}, '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,21 @@ export class Diff2HtmlUI {
|
||||||
|
|
||||||
currentSelectionColumnId = -1;
|
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.config = { ...defaultDiff2HtmlUIConfig, ...config };
|
||||||
this.diffHtml = html(diffInput, this.config);
|
this.diffHtml = diffInput !== undefined ? html(diffInput, this.config) : target.innerHTML;
|
||||||
this.targetElement = target;
|
this.targetElement = target;
|
||||||
if (hljs !== undefined) this.hljs = hljs;
|
if (hljs !== undefined) this.hljs = hljs;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(): void {
|
draw(): void {
|
||||||
this.targetElement.innerHTML = this.diffHtml;
|
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.synchronisedScroll) this.synchronisedScroll();
|
||||||
if (this.config.highlight) this.highlightCode();
|
if (this.config.highlight) this.highlightCode();
|
||||||
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
|
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
|
||||||
|
|
@ -142,29 +147,13 @@ export class Diff2HtmlUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
line.classList.add('hljs');
|
line.classList.add('hljs');
|
||||||
line.classList.add('result.language');
|
line.classList.add(result.language);
|
||||||
line.innerHTML = result.value;
|
line.innerHTML = result.value;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult {
|
smartSelection(): void {
|
||||||
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 {
|
|
||||||
const body = document.getElementsByTagName('body')[0];
|
const body = document.getElementsByTagName('body')[0];
|
||||||
const diffTable = body.getElementsByClassName('d2h-diff-table')[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 {
|
private getSelectedText(): string | undefined {
|
||||||
const sel = window.getSelection();
|
const sel = window.getSelection();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { DiffFile } from '../../types';
|
||||||
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
||||||
|
|
||||||
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
||||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
|
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) {
|
||||||
super(diffInput, target, config, hljs);
|
super(target, diffInput, config, hljs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { DiffFile } from '../../types';
|
||||||
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
||||||
|
|
||||||
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
||||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
|
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}) {
|
||||||
super(diffInput, target, config, hljs);
|
super(target, diffInput, config, hljs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ async function getDiff(request: Request): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
|
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();
|
diff2htmlUi.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue