Skip to content

Commit f4cf393

Browse files
committed
feat(diff): Diff view for upload and download files.
1 parent be635de commit f4cf393

File tree

11 files changed

+223
-85
lines changed

11 files changed

+223
-85
lines changed

src/diff/abstract_diff_view.ts

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type InvioPlugin from '../main';
77
import type { LangType, LangTypeAndAuto, TransItemType } from "../i18n";
88

99
type TviewOutputFormat = `side-by-side` | `line-by-line`
10+
export type TDiffType = `LocalToRemote` | `RemoteToLocal`
1011

1112
export default abstract class DiffView extends Modal {
1213
plugin: InvioPlugin;
@@ -59,21 +60,22 @@ export default abstract class DiffView extends Modal {
5960
diffStyle: 'word',
6061
matchWordsThreshold: 0.25,
6162
outputFormat: this.viewOutputFormat,
63+
renderNothingWhenEmpty: false,
6264
rawTemplates: {
6365
'line-by-line-file-diff': `<div id="{{fileHtmlId}}" class="d2h-file-wrapper" data-lang="{{file.language}}">
6466
<div class="d2h-file-header">
65-
{{{filePath}}}
66-
</div>
67-
<div class="d2h-file-diff">
68-
<div class="d2h-code-wrapper">
69-
<table class="d2h-diff-table">
70-
<tbody class="d2h-diff-tbody">
71-
{{{diffs}}}
72-
</tbody>
73-
</table>
67+
{{{filePath}}}
7468
</div>
75-
</div>
76-
</div>`,
69+
<div class="d2h-file-diff">
70+
<div class="d2h-code-wrapper">
71+
<table class="d2h-diff-table">
72+
<tbody class="d2h-diff-tbody">
73+
{{{diffs}}}
74+
</tbody>
75+
</table>
76+
</div>
77+
</div>
78+
</div>`,
7779
'side-by-side-file-diff': `<div id="{{fileHtmlId}}" class="d2h-file-wrapper" data-lang="{{file.language}}">
7880
<div class="d2h-file-header">
7981
{{{filePath}}}
@@ -100,7 +102,14 @@ export default abstract class DiffView extends Modal {
100102
</div>
101103
</div>
102104
</div>
103-
</div>`
105+
</div>`,
106+
'generic-empty-diff': `<tr>
107+
<td class="{{CSSLineClass.INFO}}">
108+
<div class="{{contentClass}}">
109+
File without changes2
110+
</div>
111+
</td>
112+
</tr>`
104113
}
105114
};
106115
this.containerEl.addClass('diff');
@@ -109,42 +118,6 @@ export default abstract class DiffView extends Modal {
109118
cls: ['sync-history-content-container-parent'],
110119
});
111120

112-
const topAction = contentParent.createDiv({
113-
cls: 'sync-history-content-container-top'
114-
});
115-
116-
const viewChangeBtn = topAction.createDiv({
117-
cls: ['view-action', 'btn'],
118-
text: this.t('view_change_btn')
119-
})
120-
121-
const diffResetBtn = topAction.createDiv({
122-
cls: ['view-action', 'btn'],
123-
text: this.t('diff_reset_btn')
124-
})
125-
setTooltip(diffResetBtn, 'Click to replace the file with online version', {
126-
placement: 'top',
127-
});
128-
diffResetBtn.addEventListener('click', e => {
129-
e.preventDefault();
130-
this.changeFileAndCloseModal(this.leftContent);
131-
132-
new Notice(
133-
`The ${this.file.basename} file has been overwritten with the online remote version.`
134-
);
135-
})
136-
setTooltip(viewChangeBtn, 'Click to change diff view', {
137-
placement: 'top',
138-
});
139-
viewChangeBtn.addEventListener('click', e => {
140-
e.preventDefault();
141-
this.viewOutputFormat = ('line-by-line' === this.viewOutputFormat) ? 'side-by-side' : 'line-by-line';
142-
console.log('diff styles changed to ', this.viewOutputFormat)
143-
this.reload({
144-
outputFormat: this.viewOutputFormat
145-
});
146-
})
147-
148121
this.syncHistoryContentContainer = contentParent.createDiv({
149122
cls: ['sync-history-content-container', 'diff'],
150123
})
@@ -160,9 +133,6 @@ export default abstract class DiffView extends Modal {
160133
this.syncHistoryContentContainer.innerHTML =
161134
this.getDiff(config) as string;
162135
}
163-
abstract getInitialVersions(): Promise<void | boolean>;
164-
165-
abstract appendVersions(): void;
166136

167137
public getDiff(config?: Diff2HtmlConfig): string {
168138
// the second type is needed for the Git view, it reimplements getDiff
@@ -191,7 +161,7 @@ export default abstract class DiffView extends Modal {
191161
return this.plugin.i18n.t(x, vars);
192162
}
193163

194-
private async changeFileAndCloseModal(contents: string) {
164+
public async changeFileAndCloseModal(contents: string) {
195165
await this.app.vault.modify(this.file, contents);
196166
this.fileChangedHook && this.fileChangedHook(this.file);
197167
this.silentClose = true
@@ -234,16 +204,18 @@ export default abstract class DiffView extends Modal {
234204
return [syncHistoryListContainer, syncHistoryList];
235205
}
236206

237-
public basicHtml(diff: string, diffType: string): void {
207+
public basicHtml(diff: string, diffType: TDiffType): void {
238208
// set title
239-
this.titleEl.setText(diffType);
209+
this.titleEl.setText(diffType === `LocalToRemote` ? this.t('diff_view_local_title') : this.t('diff_view_remote_title'));
240210
// add diff to container
241211
this.syncHistoryContentContainer.innerHTML = diff;
242212

243213
// add history lists and diff to DOM
244214
// this.contentEl.appendChild(this.leftHistory[0]);
245215
this.contentEl.appendChild(this.syncHistoryContentContainer?.parentNode);
246-
this.contentEl.appendChild(this.rightHistory[0]);
216+
if (diffType === `LocalToRemote`) {
217+
this.contentEl.appendChild(this.rightHistory[0]);
218+
}
247219
}
248220

249221

src/diff/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import { App, TFile, Notice, Vault } from 'obsidian';
22
import { diffChars } from 'diff';
33
import LocalToRemoteDiffView, { IRemoteFile } from './local_to_remote_diff_view';
4+
import RemoteToLocalDiffView from './remote_to_local_diff_view';
5+
import { TDiffType } from './abstract_diff_view';
46
import type InvioPlugin from '../main';
57

6-
export function openDiffModal(app: App, plugin: InvioPlugin, file: TFile, remoteFile: IRemoteFile, hook?: (f?: TFile) => void): void {
8+
export * from './abstract_diff_view';
9+
10+
export function openDiffModal(app: App, plugin: InvioPlugin, file: TFile, remoteFile: IRemoteFile, diffType: TDiffType, hook?: (f?: TFile) => void): void {
11+
if (diffType === `LocalToRemote`) {
712
new LocalToRemoteDiffView(plugin, app, file, remoteFile, hook, hook).open();
13+
} else if (diffType === `RemoteToLocal`) {
14+
new RemoteToLocalDiffView(plugin, app, file, remoteFile, hook, hook).open();
15+
} else {
16+
new Notice(`Not supported diff view type`);
17+
}
818
}
919

1020

src/diff/local_to_remote_diff_view.ts

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
import { Plugin, App, TFile, Notice } from 'obsidian';
1+
import {
2+
Plugin,
3+
App,
4+
TFile,
5+
Notice,
6+
// @ts-ignore
7+
setTooltip
8+
} from 'obsidian';
29
import type InvioPlugin from '../main';
310
import type { recResult, vRecoveryItem } from './interfaces';
411
import { FILE_REC_WARNING } from './constants';
5-
import DiffView from './abstract_diff_view';
12+
import DiffView, { TDiffType } from './abstract_diff_view';
613
export interface IRemoteFile {
714
data: string;
815
ts: number;
@@ -73,11 +80,62 @@ export default class LocalToRemoteDiffView extends DiffView {
7380
await this.getInitialVersions();
7481
const diff = this.getDiff();
7582
this.makeHistoryLists(FILE_REC_WARNING);
76-
this.basicHtml(diff as string, this.t('diff_view_title'));
83+
this.basicHtml(diff as string);
7784
this.appendVersions();
7885
this.makeMoreGeneralHtml();
7986
}
8087

88+
public basicHtml(diff: string): void {
89+
// set title
90+
this.titleEl.setText(this.t('diff_view_local_title'));
91+
// set top action bar
92+
93+
const contentParent = this.syncHistoryContentContainer.parentElement;
94+
const topAction = contentParent.createDiv({
95+
cls: 'sync-history-content-container-top'
96+
});
97+
98+
const viewChangeBtn = topAction.createDiv({
99+
cls: ['view-action', 'btn'],
100+
text: this.t('view_change_btn')
101+
})
102+
103+
const diffResetBtn = topAction.createDiv({
104+
cls: ['view-action', 'btn'],
105+
text: this.t('diff_reset_btn')
106+
})
107+
setTooltip(diffResetBtn, 'Click to replace the file with online version', {
108+
placement: 'top',
109+
});
110+
diffResetBtn.addEventListener('click', e => {
111+
e.preventDefault();
112+
this.changeFileAndCloseModal(this.leftContent);
113+
114+
new Notice(
115+
`The ${this.file.basename} file has been overwritten with the online remote version.`
116+
);
117+
})
118+
setTooltip(viewChangeBtn, 'Click to change diff view', {
119+
placement: 'top',
120+
});
121+
viewChangeBtn.addEventListener('click', e => {
122+
e.preventDefault();
123+
this.viewOutputFormat = ('line-by-line' === this.viewOutputFormat) ? 'side-by-side' : 'line-by-line';
124+
console.log('diff styles changed to ', this.viewOutputFormat)
125+
this.reload({
126+
outputFormat: this.viewOutputFormat
127+
});
128+
})
129+
130+
// add diff to container
131+
this.syncHistoryContentContainer.innerHTML = diff;
132+
133+
// add history lists and diff to DOM
134+
// this.contentEl.appendChild(this.leftHistory[0]);
135+
this.contentEl.appendChild(this.syncHistoryContentContainer?.parentNode);
136+
this.contentEl.appendChild(this.rightHistory[0]);
137+
}
138+
81139
async getInitialVersions() {
82140
const fileRecovery = await this.app.internalPlugins.plugins[
83141
'file-recovery'

src/diff/remote_to_local_diff_view.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Plugin, App, TFile, Notice } from 'obsidian';
2+
import type InvioPlugin from '../main';
3+
import type { recResult, vRecoveryItem } from './interfaces';
4+
import { FILE_REC_WARNING } from './constants';
5+
import DiffView, { TDiffType } from './abstract_diff_view';
6+
export interface IRemoteFile {
7+
data: string;
8+
ts: number;
9+
path: string;
10+
}
11+
export default class RemoteToLocalDiffView extends DiffView {
12+
remote: IRemoteFile
13+
versions: recResult[];
14+
rightVList: vRecoveryItem[];
15+
constructor(plugin: InvioPlugin, app: App, file: TFile, remoteFile: IRemoteFile, fileChangedHook: (f: TFile) => void, cancelHook: () => void) {
16+
super(plugin, app, file, fileChangedHook, cancelHook);
17+
this.versions = [];
18+
this.rightVList = [];
19+
this.remote = remoteFile;
20+
this.rightContent = remoteFile?.data;
21+
this.rightName = 'remote version'
22+
this.leftName = 'local version'
23+
this.htmlConfig = {
24+
drawFileList: true,
25+
diffStyle: 'word',
26+
matchWordsThreshold: 0.25,
27+
outputFormat: this.viewOutputFormat,
28+
rawTemplates: {
29+
'line-by-line-file-diff': `<div id="{{fileHtmlId}}" class="d2h-file-wrapper" data-lang="{{file.language}}">
30+
<div class="d2h-file-header">
31+
{{{filePath}}}
32+
</div>
33+
<div class="d2h-file-diff">
34+
<div class="d2h-code-wrapper">
35+
<table class="d2h-diff-table">
36+
<tbody class="d2h-diff-tbody">
37+
{{{diffs}}}
38+
</tbody>
39+
</table>
40+
</div>
41+
</div>
42+
</div>`,
43+
'side-by-side-file-diff': `<div id="{{fileHtmlId}}" class="d2h-file-wrapper" data-lang="{{file.language}}">
44+
<div class="d2h-files-diff">
45+
<div class="d2h-file-side-diff">
46+
<div class="d2h-code-title">${this.leftName}</div>
47+
<div class="d2h-code-wrapper">
48+
<table class="d2h-diff-table">
49+
<tbody class="d2h-diff-tbody">
50+
{{{diffs.left}}}
51+
</tbody>
52+
</table>
53+
</div>
54+
</div>
55+
<div class="d2h-file-side-diff">
56+
<div class="d2h-code-title">${this.rightName}</div>
57+
<div class="d2h-code-wrapper">
58+
<table class="d2h-diff-table">
59+
<tbody class="d2h-diff-tbody">
60+
{{{diffs.right}}}
61+
</tbody>
62+
</table>
63+
</div>
64+
</div>
65+
</div>
66+
</div>`
67+
}
68+
};
69+
}
70+
71+
async onOpen() {
72+
super.onOpen();
73+
this.leftContent = await this.app.vault.read(this.file);
74+
75+
const diff = this.getDiff();
76+
this.basicHtml(diff as string);
77+
}
78+
public basicHtml(diff: string): void {
79+
// set title
80+
this.titleEl.setText(this.t('diff_view_remote_title'));
81+
// add diff to container
82+
this.syncHistoryContentContainer.innerHTML = diff;
83+
84+
// add history lists and diff to DOM
85+
// this.contentEl.appendChild(this.leftHistory[0]);
86+
this.contentEl.appendChild(this.syncHistoryContentContainer?.parentNode);
87+
}
88+
}

src/langs/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"submit": "Submit",
77
"sometext": "Here are some texts.",
88

9-
"diff_view_title": "File Contents Edit Diff",
9+
"diff_view_local_title": "Local File Contents Edit Diff",
10+
"diff_view_remote_title": "Remote File Contents Edit Diff",
1011
"diff_reset_btn": "Discard Local Changes",
1112
"view_change_btn": "ViewStyle",
1213
"diff_edit_list": "Local Edit Version List",

src/langs/zh_cn.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"submit": "提交",
77
"sometext": "这里有一段文字。",
88

9-
"diff_view_title": "文件修改记录",
9+
"diff_view_local_title": "本地文件修改记录",
10+
"diff_view_remote_title": "线上文件修改记录",
1011
"diff_reset_btn": "丢弃本地所有更改",
1112
"view_change_btn": "diff样式",
1213
"diff_edit_list": "本地编辑历史",

src/langs/zh_tw.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"submit": "提交",
77
"sometext": "這裡有一段文字。",
88

9-
"diff_view_title": "文件修改记录",
9+
"diff_view_local_title": "本地文件修改记录",
10+
"diff_view_remote_title": "线上文件修改记录",
1011
"diff_reset_btn": "丢弃本地所有更改",
1112
"view_change_btn": "diff样式",
1213
"diff_edit_list": "本地编辑历史",

0 commit comments

Comments
 (0)