clean: Remove as type casts and use runtime typechecks with fallback when possible
This commit is contained in:
parent
fe8365bcc1
commit
076e14400b
3 changed files with 74 additions and 35 deletions
|
|
@ -52,10 +52,13 @@ export class Diff2HtmlUI {
|
||||||
|
|
||||||
synchronisedScroll(): void {
|
synchronisedScroll(): void {
|
||||||
this.targetElement.querySelectorAll('.d2h-file-wrapper').forEach(wrapper => {
|
this.targetElement.querySelectorAll('.d2h-file-wrapper').forEach(wrapper => {
|
||||||
const [left, right] = [].slice.call(wrapper.querySelectorAll('.d2h-file-side-diff')) as HTMLElement[];
|
const [left, right] = Array<Element>().slice.call(wrapper.querySelectorAll('.d2h-file-side-diff'));
|
||||||
|
|
||||||
if (left === undefined || right === undefined) return;
|
if (left === undefined || right === undefined) return;
|
||||||
|
|
||||||
const onScroll = (event: Event): void => {
|
const onScroll = (event: Event): void => {
|
||||||
if (event === null || event.target === null) return;
|
if (event === null || event.target === null) return;
|
||||||
|
|
||||||
if (event.target === left) {
|
if (event.target === left) {
|
||||||
right.scrollTop = left.scrollTop;
|
right.scrollTop = left.scrollTop;
|
||||||
right.scrollLeft = left.scrollLeft;
|
right.scrollLeft = left.scrollLeft;
|
||||||
|
|
@ -70,29 +73,28 @@ export class Diff2HtmlUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileListToggle(startVisible: boolean): void {
|
fileListToggle(startVisible: boolean): void {
|
||||||
const hashTag = this.getHashTag();
|
const showBtn: HTMLElement | null = this.targetElement.querySelector('d2h-show');
|
||||||
|
const hideBtn: HTMLElement | null = this.targetElement.querySelector('.d2h-hide');
|
||||||
const showBtn = this.targetElement.querySelector('.d2h-show') as HTMLElement;
|
const fileList: HTMLElement | null = this.targetElement.querySelector('.d2h-file-list');
|
||||||
const hideBtn = this.targetElement.querySelector('.d2h-hide') as HTMLElement;
|
|
||||||
const fileList = this.targetElement.querySelector('.d2h-file-list') as HTMLElement;
|
|
||||||
|
|
||||||
if (showBtn === null || hideBtn === null || fileList === null) return;
|
if (showBtn === null || hideBtn === null || fileList === null) return;
|
||||||
|
|
||||||
function show(): void {
|
const show: () => void = () => {
|
||||||
showBtn.style.display = 'none';
|
showBtn.style.display = 'none';
|
||||||
hideBtn.style.display = 'inline';
|
hideBtn.style.display = 'inline';
|
||||||
fileList.style.display = 'block';
|
fileList.style.display = 'block';
|
||||||
}
|
};
|
||||||
|
|
||||||
function hide(): void {
|
const hide: () => void = () => {
|
||||||
showBtn.style.display = 'inline';
|
showBtn.style.display = 'inline';
|
||||||
hideBtn.style.display = 'none';
|
hideBtn.style.display = 'none';
|
||||||
fileList.style.display = 'none';
|
fileList.style.display = 'none';
|
||||||
}
|
};
|
||||||
|
|
||||||
showBtn.addEventListener('click', () => show());
|
showBtn.addEventListener('click', () => show());
|
||||||
hideBtn.addEventListener('click', () => hide());
|
hideBtn.addEventListener('click', () => hide());
|
||||||
|
|
||||||
|
const hashTag = this.getHashTag();
|
||||||
if (hashTag === 'files-summary-show') show();
|
if (hashTag === 'files-summary-show') show();
|
||||||
else if (hashTag === 'files-summary-hide') hide();
|
else if (hashTag === 'files-summary-hide') hide();
|
||||||
else if (startVisible) show();
|
else if (startVisible) show();
|
||||||
|
|
@ -117,11 +119,11 @@ export class Diff2HtmlUI {
|
||||||
if (this.hljs === null) return;
|
if (this.hljs === null) return;
|
||||||
|
|
||||||
const text = line.textContent;
|
const text = line.textContent;
|
||||||
const lineParent = line.parentNode as HTMLElement;
|
const lineParent = line.parentNode;
|
||||||
|
|
||||||
if (lineParent === null || text === null) return;
|
if (text === null || lineParent === null || !this.isElement(lineParent)) return;
|
||||||
|
|
||||||
const lineState = lineParent.className.indexOf('d2h-del') !== -1 ? oldLinesState : newLinesState;
|
const lineState = lineParent.classList.contains('d2h-del') ? oldLinesState : newLinesState;
|
||||||
|
|
||||||
const language = file.getAttribute('data-lang');
|
const language = file.getAttribute('data-lang');
|
||||||
const result =
|
const result =
|
||||||
|
|
@ -130,9 +132,9 @@ export class Diff2HtmlUI {
|
||||||
: this.hljs.highlightAuto(text);
|
: this.hljs.highlightAuto(text);
|
||||||
|
|
||||||
if (this.instanceOfIHighlightResult(result)) {
|
if (this.instanceOfIHighlightResult(result)) {
|
||||||
if (lineParent.className.indexOf('d2h-del') !== -1) {
|
if (lineParent.classList.contains('d2h-del')) {
|
||||||
oldLinesState = result.top;
|
oldLinesState = result.top;
|
||||||
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
|
} else if (lineParent.classList.contains('d2h-ins')) {
|
||||||
newLinesState = result.top;
|
newLinesState = result.top;
|
||||||
} else {
|
} else {
|
||||||
oldLinesState = result.top;
|
oldLinesState = result.top;
|
||||||
|
|
@ -159,18 +161,15 @@ export class Diff2HtmlUI {
|
||||||
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
|
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
|
||||||
|
|
||||||
diffTable.addEventListener('mousedown', event => {
|
diffTable.addEventListener('mousedown', event => {
|
||||||
if (event === null || event.target === null) return;
|
if (event === null || !this.isElement(event.target)) return;
|
||||||
|
|
||||||
const mouseEvent = event as MouseEvent;
|
|
||||||
const target = mouseEvent.target as HTMLElement;
|
|
||||||
const table = target.closest('.d2h-diff-table');
|
|
||||||
|
|
||||||
|
const table = event.target.closest('.d2h-diff-table');
|
||||||
if (table !== null) {
|
if (table !== null) {
|
||||||
if (target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
|
if (event.target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
|
||||||
table.classList.remove('selecting-left');
|
table.classList.remove('selecting-left');
|
||||||
table.classList.add('selecting-right');
|
table.classList.add('selecting-right');
|
||||||
this.currentSelectionColumnId = 1;
|
this.currentSelectionColumnId = 1;
|
||||||
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
|
} else if (event.target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
|
||||||
table.classList.remove('selecting-right');
|
table.classList.remove('selecting-right');
|
||||||
table.classList.add('selecting-left');
|
table.classList.add('selecting-left');
|
||||||
this.currentSelectionColumnId = 0;
|
this.currentSelectionColumnId = 0;
|
||||||
|
|
@ -179,8 +178,9 @@ export class Diff2HtmlUI {
|
||||||
});
|
});
|
||||||
|
|
||||||
diffTable.addEventListener('copy', event => {
|
diffTable.addEventListener('copy', event => {
|
||||||
const clipboardEvent = event as ClipboardEvent;
|
if (!this.isClipboardEvent(event)) return;
|
||||||
const clipboardData = clipboardEvent.clipboardData;
|
|
||||||
|
const clipboardData = event.clipboardData;
|
||||||
const text = this.getSelectedText();
|
const text = this.getSelectedText();
|
||||||
|
|
||||||
if (clipboardData === null || text === undefined) return;
|
if (clipboardData === null || text === undefined) return;
|
||||||
|
|
@ -231,4 +231,12 @@ export class Diff2HtmlUI {
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isElement(arg?: unknown): arg is Element {
|
||||||
|
return arg !== null && (arg as Element)?.classList !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isClipboardEvent(arg?: unknown): arg is ClipboardEvent {
|
||||||
|
return arg !== null && (arg as ClipboardEvent)?.clipboardData !== undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,10 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
|
||||||
let result = '';
|
let result = '';
|
||||||
const nodeStack = [];
|
const nodeStack = [];
|
||||||
|
|
||||||
|
function isElement(arg?: unknown): arg is Element {
|
||||||
|
return arg !== null && (arg as Element)?.attributes !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function selectStream(): NodeEvent[] {
|
function selectStream(): NodeEvent[] {
|
||||||
if (!original.length || !highlighted.length) {
|
if (!original.length || !highlighted.length) {
|
||||||
return original.length ? original : highlighted;
|
return original.length ? original : highlighted;
|
||||||
|
|
@ -88,9 +92,12 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(node: Node): void {
|
function open(node: Node): void {
|
||||||
const htmlNode = node as HTMLElement;
|
if (!isElement(node)) {
|
||||||
result += `<${tag(node)} ${[].map
|
throw new Error('Node is not an Element');
|
||||||
.call(htmlNode.attributes, (attr: Attr) => `${attr.nodeName}="${escape(attr.value)}"`)
|
}
|
||||||
|
|
||||||
|
result += `<${tag(node)} ${Array<Attr>()
|
||||||
|
.map.call(node.attributes, attr => `${attr.nodeName}="${escape(attr.value)}"`)
|
||||||
.join(' ')}>`;
|
.join(' ')}>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,30 @@ type Elements = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isHTMLInputElement(arg?: unknown): arg is HTMLInputElement {
|
||||||
|
return arg !== null && (arg as HTMLInputElement)?.value !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHTMLInputElementById(id: string): HTMLInputElement {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!isHTMLInputElement(element)) {
|
||||||
|
throw new Error(`Could not find html input element with id '${id}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHTMLElementById(id: string): HTMLElement {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
|
||||||
|
if (element === null) {
|
||||||
|
throw new Error(`Could not find html element with id '${id}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
// Improves browser compatibility
|
// Improves browser compatibility
|
||||||
require('whatwg-fetch');
|
require('whatwg-fetch');
|
||||||
|
|
@ -226,20 +250,20 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
const elements: Elements = {
|
const elements: Elements = {
|
||||||
structure: {
|
structure: {
|
||||||
diffTarget: document.getElementById('url-diff-container') as HTMLElement,
|
diffTarget: getHTMLElementById('url-diff-container'),
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
input: document.getElementById('url') as HTMLInputElement,
|
input: getHTMLInputElementById('url'),
|
||||||
button: document.getElementById('url-btn') as HTMLElement,
|
button: getHTMLElementById('url-btn'),
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
outputFormat: document.getElementById('diff-url-options-output-format') as HTMLInputElement,
|
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
|
||||||
matching: document.getElementById('diff-url-options-matching') as HTMLInputElement,
|
matching: getHTMLInputElementById('diff-url-options-matching'),
|
||||||
wordsThreshold: document.getElementById('diff-url-options-match-words-threshold') as HTMLInputElement,
|
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
|
||||||
matchingMaxComparisons: document.getElementById('diff-url-options-matching-max-comparisons') as HTMLInputElement,
|
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
|
||||||
},
|
},
|
||||||
checkboxes: {
|
checkboxes: {
|
||||||
drawFileList: document.getElementById('diff-url-options-show-files') as HTMLInputElement,
|
drawFileList: getHTMLInputElementById('diff-url-options-show-files'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue