use modern methods to render HTML diffs
This commit is contained in:
parent
551a0b407f
commit
ab5ff8d148
10 changed files with 202 additions and 195 deletions
|
|
@ -82,6 +82,7 @@ export default class LineByLineRenderer {
|
||||||
generateEmptyDiff(): string {
|
generateEmptyDiff(): string {
|
||||||
return this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
return this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
||||||
contentClass: 'd2h-code-line',
|
contentClass: 'd2h-code-line',
|
||||||
|
colspan: '2',
|
||||||
CSSLineClass: renderUtils.CSSLineClass,
|
CSSLineClass: renderUtils.CSSLineClass,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -93,35 +94,43 @@ export default class LineByLineRenderer {
|
||||||
|
|
||||||
return file.blocks
|
return file.blocks
|
||||||
.map(block => {
|
.map(block => {
|
||||||
let lines = this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
const lines: string[] = [];
|
||||||
|
|
||||||
|
lines.push(
|
||||||
|
this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
||||||
CSSLineClass: renderUtils.CSSLineClass,
|
CSSLineClass: renderUtils.CSSLineClass,
|
||||||
|
margin_colspan: '2',
|
||||||
|
colspan: '1',
|
||||||
blockHeader: file.isTooBig ? block.header : renderUtils.escapeForHtml(block.header),
|
blockHeader: file.isTooBig ? block.header : renderUtils.escapeForHtml(block.header),
|
||||||
lineClass: 'd2h-code-linenumber',
|
lineClass: 'd2h-code-linenumber',
|
||||||
contentClass: 'd2h-code-line',
|
contentClass: 'd2h-code-line',
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
|
this.applyLineGrouping(block).forEach(([contextLines, oldLines, newLines]) => {
|
||||||
if (oldLines.length && newLines.length && !contextLines.length) {
|
if (oldLines.length && newLines.length && !contextLines.length) {
|
||||||
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => {
|
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => {
|
||||||
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
||||||
lines += left;
|
lines.push(...left);
|
||||||
lines += right;
|
lines.push(...right);
|
||||||
});
|
});
|
||||||
} else if (contextLines.length) {
|
} else if (contextLines.length) {
|
||||||
contextLines.forEach(line => {
|
contextLines.forEach(line => {
|
||||||
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
|
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
|
||||||
lines += this.generateSingleLineHtml({
|
lines.push(
|
||||||
|
this.generateSingleLineHtml({
|
||||||
type: renderUtils.CSSLineClass.CONTEXT,
|
type: renderUtils.CSSLineClass.CONTEXT,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
content: content,
|
content: content,
|
||||||
oldNumber: line.oldNumber,
|
oldNumber: line.oldNumber,
|
||||||
newNumber: line.newNumber,
|
newNumber: line.newNumber,
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} else if (oldLines.length || newLines.length) {
|
} else if (oldLines.length || newLines.length) {
|
||||||
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
||||||
lines += left;
|
lines.push(...left);
|
||||||
lines += right;
|
lines.push(...right);
|
||||||
} else {
|
} else {
|
||||||
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +138,13 @@ export default class LineByLineRenderer {
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
})
|
})
|
||||||
|
.map((block_html: string[]) => {
|
||||||
|
return block_html.map(line => `<tr>${line}</tr>`).join('\n');
|
||||||
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
applyLineGroupping(block: DiffBlock): DiffLineGroups {
|
applyLineGrouping(block: DiffBlock): DiffLineGroups {
|
||||||
const blockLinesGroups: DiffLineGroups = [];
|
const blockLinesGroups: DiffLineGroups = [];
|
||||||
|
|
||||||
let oldLines: (DiffLineDeleted & DiffLineContent)[] = [];
|
let oldLines: (DiffLineDeleted & DiffLineContent)[] = [];
|
||||||
|
|
@ -189,9 +201,9 @@ export default class LineByLineRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
||||||
const fileHtml = {
|
const fileHtml: FileHtml = {
|
||||||
right: '',
|
left: [],
|
||||||
left: '',
|
right: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
||||||
|
|
@ -241,8 +253,8 @@ export default class LineByLineRenderer {
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine);
|
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine);
|
||||||
fileHtml.left += left;
|
fileHtml.left.push(...left);
|
||||||
fileHtml.right += right;
|
fileHtml.right.push(...right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileHtml;
|
return fileHtml;
|
||||||
|
|
@ -250,27 +262,34 @@ export default class LineByLineRenderer {
|
||||||
|
|
||||||
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
||||||
return {
|
return {
|
||||||
left: this.generateSingleLineHtml(oldLine),
|
left: [this.generateSingleLineHtml(oldLine)],
|
||||||
right: this.generateSingleLineHtml(newLine),
|
right: [this.generateSingleLineHtml(newLine)],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
generateSingleLineHtml(line?: DiffPreparedLine): string {
|
generateSingleLineHtml(line?: DiffPreparedLine): string {
|
||||||
if (line === undefined) return '';
|
if (line === undefined) return '';
|
||||||
|
|
||||||
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, 'numbers', {
|
const oldLineNumberHtml = this.hoganUtils.render(genericTemplatesPath, 'line-number', {
|
||||||
oldNumber: line.oldNumber || '',
|
type: line.type,
|
||||||
newNumber: line.newNumber || '',
|
lineClass: line.oldNumber ? 'd2h-code-linenumber' : 'd2h-code-emptyplaceholder',
|
||||||
|
lineNumber: line.oldNumber,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.hoganUtils.render(genericTemplatesPath, 'line', {
|
const newLineNumberHtml = this.hoganUtils.render(genericTemplatesPath, 'line-number', {
|
||||||
|
type: line.type,
|
||||||
|
lineClass: line.newNumber ? 'd2h-code-linenumber' : 'd2h-code-emptyplaceholder',
|
||||||
|
lineNumber: line.newNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
const newLineContentHtml = this.hoganUtils.render(genericTemplatesPath, 'line', {
|
||||||
type: line.type,
|
type: line.type,
|
||||||
lineClass: 'd2h-code-linenumber',
|
|
||||||
contentClass: 'd2h-code-line',
|
contentClass: 'd2h-code-line',
|
||||||
prefix: line.prefix === ' ' ? ' ' : line.prefix,
|
prefix: line.prefix === ' ' ? ' ' : line.prefix,
|
||||||
content: line.content,
|
content: line.content,
|
||||||
lineNumber: lineNumberHtml,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return oldLineNumberHtml.concat(newLineNumberHtml, newLineContentHtml);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,6 +308,6 @@ type DiffPreparedLine = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type FileHtml = {
|
type FileHtml = {
|
||||||
left: string;
|
left: string[];
|
||||||
right: string;
|
right: string[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export default class SideBySideRenderer {
|
||||||
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
|
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
|
||||||
}
|
}
|
||||||
|
|
||||||
makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {
|
makeFileDiffHtml(file: DiffFile, diffs: string): string {
|
||||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return '';
|
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return '';
|
||||||
|
|
||||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, 'file-diff');
|
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, 'file-diff');
|
||||||
|
|
@ -79,34 +79,32 @@ export default class SideBySideRenderer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
generateEmptyDiff(): FileHtml {
|
generateEmptyDiff(): string {
|
||||||
return {
|
return this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
||||||
right: '',
|
|
||||||
left: this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
|
||||||
contentClass: 'd2h-code-side-line',
|
contentClass: 'd2h-code-side-line',
|
||||||
|
colspan: '4',
|
||||||
CSSLineClass: renderUtils.CSSLineClass,
|
CSSLineClass: renderUtils.CSSLineClass,
|
||||||
}),
|
});
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generateFileHtml(file: DiffFile): FileHtml {
|
generateFileHtml(file: DiffFile): string {
|
||||||
const matcher = Rematch.newMatcherFn(
|
const matcher = Rematch.newMatcherFn(
|
||||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content),
|
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content),
|
||||||
);
|
);
|
||||||
|
|
||||||
return file.blocks
|
return file.blocks
|
||||||
.map(block => {
|
.map(block => {
|
||||||
const fileHtml = {
|
const fileHtml: FileHtml = {
|
||||||
left: this.makeHeaderHtml(block.header, file),
|
left: [this.makeHeaderHtml(block.header, file)],
|
||||||
right: this.makeHeaderHtml(''),
|
right: [''],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
|
this.applyLineGrouping(block).forEach(([contextLines, oldLines, newLines]) => {
|
||||||
if (oldLines.length && newLines.length && !contextLines.length) {
|
if (oldLines.length && newLines.length && !contextLines.length) {
|
||||||
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => {
|
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => {
|
||||||
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
||||||
fileHtml.left += left;
|
fileHtml.left.push(...left);
|
||||||
fileHtml.right += right;
|
fileHtml.right.push(...right);
|
||||||
});
|
});
|
||||||
} else if (contextLines.length) {
|
} else if (contextLines.length) {
|
||||||
contextLines.forEach(line => {
|
contextLines.forEach(line => {
|
||||||
|
|
@ -125,13 +123,13 @@ export default class SideBySideRenderer {
|
||||||
number: line.newNumber,
|
number: line.newNumber,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
fileHtml.left += left;
|
fileHtml.left.push(...left);
|
||||||
fileHtml.right += right;
|
fileHtml.right.push(...right);
|
||||||
});
|
});
|
||||||
} else if (oldLines.length || newLines.length) {
|
} else if (oldLines.length || newLines.length) {
|
||||||
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
|
||||||
fileHtml.left += left;
|
fileHtml.left.push(...left);
|
||||||
fileHtml.right += right;
|
fileHtml.right.push(...right);
|
||||||
} else {
|
} else {
|
||||||
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
||||||
}
|
}
|
||||||
|
|
@ -139,15 +137,19 @@ export default class SideBySideRenderer {
|
||||||
|
|
||||||
return fileHtml;
|
return fileHtml;
|
||||||
})
|
})
|
||||||
.reduce(
|
.map((block_html: FileHtml) => {
|
||||||
(accomulated, html) => {
|
let block_html_string = '';
|
||||||
return { left: accomulated.left + html.left, right: accomulated.right + html.right };
|
for (let block_line_index = 0; block_line_index < block_html.left.length; block_line_index++) {
|
||||||
},
|
block_html_string = block_html_string.concat(
|
||||||
{ left: '', right: '' },
|
`<tr>${block_html.left[block_line_index]} ${block_html.right[block_line_index]}</tr>`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return block_html_string;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
applyLineGroupping(block: DiffBlock): DiffLineGroups {
|
applyLineGrouping(block: DiffBlock): DiffLineGroups {
|
||||||
const blockLinesGroups: DiffLineGroups = [];
|
const blockLinesGroups: DiffLineGroups = [];
|
||||||
|
|
||||||
let oldLines: (DiffLineDeleted & DiffLineContent)[] = [];
|
let oldLines: (DiffLineDeleted & DiffLineContent)[] = [];
|
||||||
|
|
@ -206,6 +208,8 @@ export default class SideBySideRenderer {
|
||||||
makeHeaderHtml(blockHeader: string, file?: DiffFile): string {
|
makeHeaderHtml(blockHeader: string, file?: DiffFile): string {
|
||||||
return this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
return this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
||||||
CSSLineClass: renderUtils.CSSLineClass,
|
CSSLineClass: renderUtils.CSSLineClass,
|
||||||
|
margin_colspan: '1',
|
||||||
|
colspan: '3',
|
||||||
blockHeader: file?.isTooBig ? blockHeader : renderUtils.escapeForHtml(blockHeader),
|
blockHeader: file?.isTooBig ? blockHeader : renderUtils.escapeForHtml(blockHeader),
|
||||||
lineClass: 'd2h-code-side-linenumber',
|
lineClass: 'd2h-code-side-linenumber',
|
||||||
contentClass: 'd2h-code-side-line',
|
contentClass: 'd2h-code-side-line',
|
||||||
|
|
@ -213,9 +217,9 @@ export default class SideBySideRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
||||||
const fileHtml = {
|
const fileHtml: FileHtml = {
|
||||||
right: '',
|
left: [],
|
||||||
left: '',
|
right: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
||||||
|
|
@ -263,8 +267,8 @@ export default class SideBySideRenderer {
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine);
|
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine);
|
||||||
fileHtml.left += left;
|
fileHtml.left.push(...left);
|
||||||
fileHtml.right += right;
|
fileHtml.right.push(...right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileHtml;
|
return fileHtml;
|
||||||
|
|
@ -272,8 +276,8 @@ export default class SideBySideRenderer {
|
||||||
|
|
||||||
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
||||||
return {
|
return {
|
||||||
left: this.generateSingleHtml(oldLine),
|
left: [this.generateSingleHtml(oldLine)],
|
||||||
right: this.generateSingleHtml(newLine),
|
right: [this.generateSingleHtml(newLine)],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,14 +285,22 @@ export default class SideBySideRenderer {
|
||||||
const lineClass = 'd2h-code-side-linenumber';
|
const lineClass = 'd2h-code-side-linenumber';
|
||||||
const contentClass = 'd2h-code-side-line';
|
const contentClass = 'd2h-code-side-line';
|
||||||
|
|
||||||
return this.hoganUtils.render(genericTemplatesPath, 'line', {
|
const type = line?.type || `${renderUtils.CSSLineClass.CONTEXT} d2h-emptyplaceholder`;
|
||||||
type: line?.type || `${renderUtils.CSSLineClass.CONTEXT} d2h-emptyplaceholder`,
|
|
||||||
|
const line_number_cell = this.hoganUtils.render(genericTemplatesPath, 'line-number', {
|
||||||
|
type: type,
|
||||||
lineClass: line !== undefined ? lineClass : `${lineClass} d2h-code-side-emptyplaceholder`,
|
lineClass: line !== undefined ? lineClass : `${lineClass} d2h-code-side-emptyplaceholder`,
|
||||||
|
lineNumber: line?.number,
|
||||||
|
});
|
||||||
|
|
||||||
|
const line_content_cell = this.hoganUtils.render(genericTemplatesPath, 'line', {
|
||||||
|
type: type,
|
||||||
contentClass: line !== undefined ? contentClass : `${contentClass} d2h-code-side-emptyplaceholder`,
|
contentClass: line !== undefined ? contentClass : `${contentClass} d2h-code-side-emptyplaceholder`,
|
||||||
prefix: line?.prefix === ' ' ? ' ' : line?.prefix,
|
prefix: line?.prefix === ' ' ? ' ' : line?.prefix,
|
||||||
content: line?.content,
|
content: line?.content,
|
||||||
lineNumber: line?.number,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return line_number_cell.concat(line_content_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,6 +318,6 @@ type DiffPreparedLine = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type FileHtml = {
|
type FileHtml = {
|
||||||
left: string;
|
left: string[];
|
||||||
right: string;
|
right: string[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
<tr>
|
<td class="{{lineClass}} {{CSSLineClass.INFO}}" colspan="{{margin_colspan}}"></td>
|
||||||
<td class="{{lineClass}} {{CSSLineClass.INFO}}"></td>
|
<td class="{{CSSLineClass.INFO}}" colspan="{{colspan}}">
|
||||||
<td class="{{CSSLineClass.INFO}}">
|
|
||||||
<div class="{{contentClass}}">{{#blockHeader}}{{{blockHeader}}}{{/blockHeader}}{{^blockHeader}} {{/blockHeader}}</div>
|
<div class="{{contentClass}}">{{#blockHeader}}{{{blockHeader}}}{{/blockHeader}}{{^blockHeader}} {{/blockHeader}}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td class="{{CSSLineClass.INFO}}">
|
<td class="{{CSSLineClass.INFO}}" colspan="{{#colspan}}{{{.}}}{{/colspan}}{{^colspan}}2{{/colspan}}">
|
||||||
<div class="{{contentClass}}">
|
<div class="{{contentClass}}">
|
||||||
File without changes
|
File without changes
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
1
src/templates/generic-line-number.mustache
Normal file
1
src/templates/generic-line-number.mustache
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<td class="{{lineClass}} {{type}}" {{#lineNumber}}data-line-number="{{{lineNumber}}}"{{/lineNumber}}></td>
|
||||||
|
|
@ -1,21 +1,5 @@
|
||||||
<tr>
|
|
||||||
<td class="{{lineClass}} {{type}}">
|
|
||||||
{{{lineNumber}}}
|
|
||||||
</td>
|
|
||||||
<td class="{{type}}">
|
<td class="{{type}}">
|
||||||
<div class="{{contentClass}}">
|
<div class="{{contentClass}}">
|
||||||
{{#prefix}}
|
{{#prefix}}<span class="d2h-code-line-ctn d2h-code-marker" data-code-marker="{{{prefix}}}">{{/prefix}}{{^prefix}}<span class="d2h-code-line-ctn d2h-code-marker" data-code-marker=&nsbp;>{{/prefix}}{{#content}}{{content}}</span>{{/content}}{{^content}}<br></span>{{/content}}
|
||||||
<span class="d2h-code-line-prefix">{{{prefix}}}</span>
|
|
||||||
{{/prefix}}
|
|
||||||
{{^prefix}}
|
|
||||||
<span class="d2h-code-line-prefix"> </span>
|
|
||||||
{{/prefix}}
|
|
||||||
{{#content}}
|
|
||||||
<span class="d2h-code-line-ctn">{{{content}}}</span>
|
|
||||||
{{/content}}
|
|
||||||
{{^content}}
|
|
||||||
<span class="d2h-code-line-ctn"><br></span>
|
|
||||||
{{/content}}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,14 @@
|
||||||
<div class="d2h-file-diff">
|
<div class="d2h-file-diff">
|
||||||
<div class="d2h-code-wrapper">
|
<div class="d2h-code-wrapper">
|
||||||
<table class="d2h-diff-table">
|
<table class="d2h-diff-table">
|
||||||
|
<thead hidden>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Original file line number</th>
|
||||||
|
<th scope="col">Diff line number</th>
|
||||||
|
<th scope="col">Content</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
<tbody class="d2h-diff-tbody">
|
<tbody class="d2h-diff-tbody">
|
||||||
{{{diffs}}}
|
{{{diffs}}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
<div class="line-num1">{{oldNumber}}</div>
|
|
||||||
<div class="line-num2">{{newNumber}}</div>
|
|
||||||
|
|
@ -5,18 +5,25 @@
|
||||||
<div class="d2h-files-diff">
|
<div class="d2h-files-diff">
|
||||||
<div class="d2h-file-side-diff">
|
<div class="d2h-file-side-diff">
|
||||||
<div class="d2h-code-wrapper">
|
<div class="d2h-code-wrapper">
|
||||||
<table class="d2h-diff-table">
|
<table class="d2h-diff-table d2h-split-diff">
|
||||||
|
<thead hidden>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Original file line number</th>
|
||||||
|
<th scope="col">Original file content</th>
|
||||||
|
<th scope="col">Diff line number</th>
|
||||||
|
<th scope="col">Diff content</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<colgroup>
|
||||||
|
<col width="40">
|
||||||
|
<col>
|
||||||
|
<col width="40">
|
||||||
|
<col>
|
||||||
|
</colgroup>
|
||||||
|
|
||||||
<tbody class="d2h-diff-tbody">
|
<tbody class="d2h-diff-tbody">
|
||||||
{{{diffs.left}}}
|
{{{diffs}}}
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d2h-file-side-diff">
|
|
||||||
<div class="d2h-code-wrapper">
|
|
||||||
<table class="d2h-diff-table">
|
|
||||||
<tbody class="d2h-diff-tbody">
|
|
||||||
{{{diffs.right}}}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,17 @@
|
||||||
|
|
||||||
.d2h-wrapper {
|
.d2h-wrapper {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d2h-wrapper * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d2h-wrapper table {
|
||||||
|
border-spacing: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2h-file-header {
|
.d2h-file-header {
|
||||||
|
|
@ -94,9 +105,14 @@
|
||||||
|
|
||||||
.d2h-diff-table {
|
.d2h-diff-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: separate;
|
||||||
font-family: 'Menlo', 'Consolas', monospace;
|
font-family: 'Menlo', 'Consolas', monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d2h-diff-table.d2h-split-diff {
|
||||||
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2h-files-diff {
|
.d2h-files-diff {
|
||||||
|
|
@ -104,46 +120,40 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2h-file-diff {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d2h-files-diff.d2h-d-none,
|
.d2h-files-diff.d2h-d-none,
|
||||||
.d2h-file-diff.d2h-d-none {
|
.d2h-file-diff.d2h-d-none {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2h-file-side-diff {
|
.d2h-file-side-diff {
|
||||||
display: inline-block;
|
width: 100%;
|
||||||
overflow-x: scroll;
|
|
||||||
overflow-y: hidden;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d2h-code-line {
|
|
||||||
display: inline-block;
|
|
||||||
white-space: nowrap;
|
|
||||||
user-select: none;
|
|
||||||
width: calc(100% - 16em);
|
|
||||||
/* Compensate for the absolute positioning of the line numbers */
|
|
||||||
padding: 0 8em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d2h-code-line,
|
||||||
.d2h-code-side-line {
|
.d2h-code-side-line {
|
||||||
display: inline-block;
|
|
||||||
white-space: nowrap;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
width: calc(100% - 9em);
|
padding-left: 22px;
|
||||||
/* Compensate for the absolute positioning of the line numbers */
|
position: relative;
|
||||||
padding: 0 4.5em;
|
padding-right: 10px;
|
||||||
|
line-height: 20px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d2h-code-marker::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
content: attr(data-code-marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2h-code-line-ctn {
|
.d2h-code-line-ctn {
|
||||||
display: inline-block;
|
display: table-cell;
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
word-wrap: normal;
|
word-wrap: anywhere;
|
||||||
white-space: pre;
|
white-space: pre-wrap;
|
||||||
|
overflow: visible;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
@ -178,63 +188,33 @@
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-num1 {
|
.d2h-code-linenumber::before,
|
||||||
box-sizing: border-box;
|
.d2h-code-side-linenumber::before {
|
||||||
float: left;
|
content: attr(data-line-number);
|
||||||
width: 3.5em;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
padding: 0 0.5em 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line-num2 {
|
|
||||||
box-sizing: border-box;
|
|
||||||
float: right;
|
|
||||||
width: 3.5em;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
padding: 0 0.5em 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d2h-code-linenumber {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 7.5em;
|
|
||||||
/* Keep the numbers fixed on line contents scroll */
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #fff;
|
|
||||||
color: rgba(0, 0, 0, 0.3);
|
|
||||||
text-align: right;
|
|
||||||
border: solid #eeeeee;
|
|
||||||
border-width: 0 1px 0 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d2h-code-linenumber:after {
|
|
||||||
content: '\200b';
|
|
||||||
}
|
|
||||||
|
|
||||||
.d2h-code-side-linenumber {
|
|
||||||
/* Keep the numbers fixed on line contents scroll */
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 4em;
|
|
||||||
background-color: #fff;
|
|
||||||
color: rgba(0, 0, 0, 0.3);
|
|
||||||
text-align: right;
|
|
||||||
border: solid #eeeeee;
|
|
||||||
border-width: 0 1px 0 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
padding: 0 0.5em 0 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d2h-code-linenumber:after,
|
||||||
.d2h-code-side-linenumber:after {
|
.d2h-code-side-linenumber:after {
|
||||||
content: '\200b';
|
content: '\200b';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d2h-code-side-linenumber,
|
||||||
|
.d2h-code-linenumber {
|
||||||
|
/* Keep the numbers fixed on line contents scroll */
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
color: rgba(0, 0, 0, 0.3);
|
||||||
|
text-align: right;
|
||||||
|
border: solid #eeeeee;
|
||||||
|
border-width: 0 1px 0 1px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 1%;
|
||||||
|
min-width: 50px;
|
||||||
|
padding-right: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.d2h-code-side-emptyplaceholder,
|
.d2h-code-side-emptyplaceholder,
|
||||||
.d2h-emptyplaceholder {
|
.d2h-emptyplaceholder {
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue