Skip to content

Commit

Permalink
File drop support (#4247)
Browse files Browse the repository at this point in the history
  • Loading branch information
partouf committed Nov 12, 2022
1 parent 2538211 commit 750f193
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 25 deletions.
60 changes: 47 additions & 13 deletions static/multifile-service.ts
Expand Up @@ -114,7 +114,10 @@ export class MultifileService {
});

if (possibleLang.length > 0) {
return possibleLang[0].id;
const sorted = _.sortBy(possibleLang, a => {
return a.extensions.indexOf(filenameExt);
});
return sorted[0].id;
}

if (this.isCMakeFile(filename)) {
Expand Down Expand Up @@ -244,15 +247,15 @@ export class MultifileService {
}

public isEditorPartOfProject(editorId: number) {
const found = _.find(this.files, (file: MultifileFile) => {
const found = this.files.find((file: MultifileFile) => {
return file.isIncluded && file.isOpen && editorId === file.editorId;
});

return !!found;
}

public getFileByFileId(fileId: number): MultifileFile | undefined {
const file = _.find(this.files, (file: MultifileFile) => {
const file = this.files.find((file: MultifileFile) => {
return file.fileId === fileId;
});

Expand All @@ -277,17 +280,17 @@ export class MultifileService {
}

private filterOutNonsense() {
this.files = _.filter(this.files, (file: MultifileFile) => MultifileService.isValidFile(file));
this.files = this.files.filter((file: MultifileFile) => MultifileService.isValidFile(file));
}

public getFiles(): Array<FiledataPair> {
this.filterOutNonsense();

const filtered = _.filter(this.files, (file: MultifileFile) => {
const filtered = this.files.filter((file: MultifileFile) => {
return !file.isMainSource && file.isIncluded;
});

return _.map(filtered, (file: MultifileFile) => {
return filtered.map((file: MultifileFile) => {
return {
filename: file.filename,
contents: this.getFileContents(file),
Expand Down Expand Up @@ -322,7 +325,7 @@ export class MultifileService {
}

public getMainSource(): string {
const mainFile = _.find(this.files, (file: MultifileFile) => {
const mainFile = this.files.find((file: MultifileFile) => {
return file.isIncluded && this.isMainSourceFile(file);
});

Expand All @@ -334,21 +337,27 @@ export class MultifileService {
}

public getFileByEditorId(editorId: number): MultifileFile | undefined {
return _.find(this.files, (file: MultifileFile) => {
return this.files.find((file: MultifileFile) => {
return file.editorId === editorId;
});
}

public getEditorIdByFilename(filename: string): number | null {
const file = _.find(this.files, (file: MultifileFile) => {
const file = this.files.find((file: MultifileFile) => {
return file.isIncluded && file.filename === filename;
});

return file && file.editorId > 0 ? file.editorId : null;
}

private getFileByFilename(filename: string): MultifileFile | undefined {
return this.files.find((file: MultifileFile) => {
return file.filename === filename;
});
}

public getMainSourceEditorId(): number | null {
const file = _.find(this.files, (file: MultifileFile) => {
const file = this.files.find((file: MultifileFile) => {
return file.isIncluded && this.isMainSourceFile(file);
});

Expand Down Expand Up @@ -385,6 +394,14 @@ export class MultifileService {
return file;
}

public removeFileByFilename(filename: string): MultifileFile | undefined {
const file = this.getFileByFilename(filename);
if (file) {
this.files = this.files.filter((obj: MultifileFile) => obj.fileId !== file.fileId);
}
return file;
}

public async excludeByFileId(fileId: number): Promise<void> {
const file = this.getFileByFileId(fileId);
if (file) {
Expand Down Expand Up @@ -470,12 +487,29 @@ export class MultifileService {
return suggestedFilename;
}

private fileExists(filename: string, excludeFile: MultifileFile): boolean {
return !!_.find(this.files, (file: MultifileFile) => {
return file !== excludeFile && file.filename === filename;
public fileExists(filename: string, excludeFile?: MultifileFile): boolean {
return this.files.some((file: MultifileFile) => {
if (excludeFile && file === excludeFile) return false;

return file.filename === filename;
});
}

public addNewTextFile(filename: string, content: string) {
const file: MultifileFile = {
fileId: this.newFileId,
isIncluded: false,
isOpen: false,
isMainSource: false,
filename: filename,
content: content,
editorId: -1,
langId: this.getLanguageIdFromFilename(filename),
};

this.addFile(file);
}

public async renameFile(fileId: number): Promise<boolean> {
const file = this.getFileByFileId(fileId);
if (!file) return Promise.reject('File could not be found');
Expand Down
1 change: 0 additions & 1 deletion static/panes/editor.ts
Expand Up @@ -1726,7 +1726,6 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
this.clearLinkedLine();
this.fadeTimeoutId = null;
}, 5000);

}
this.updateDecorations();
}
Expand Down
129 changes: 118 additions & 11 deletions static/panes/tree.ts
Expand Up @@ -313,6 +313,20 @@ export class Tree {
this.refresh();
}

private removeFileByFilename(filename: string) {
const file = this.multifileService.removeFileByFilename(filename);
if (file) {
if (file.isOpen) {
const editor = this.hub.getEditorById(file.editorId);
if (editor) {
editor.container.close();
}
}
}

this.refresh();
}

private addRowToTreelist(file: MultifileFile) {
const item = $(this.rowTemplate.children()[0].cloneNode(true));
const stageButton = item.find('.stage-file');
Expand Down Expand Up @@ -488,17 +502,7 @@ export class Tree {
loadProjectFromFile.on('change', async e => {
const files = e.target.files;
if (files && files.length > 0) {
this.multifileService.forEachFile((file: MultifileFile) => {
this.removeFile(file.fileId);
});

await this.multifileService.loadProjectFromFile(files[0], (file: MultifileFile) => {
this.refresh();
if (file.filename === 'CMakeLists.txt') {
// todo: find a way to toggle on CMake checkbox...
this.editFile(file.fileId);
}
});
await this.openZipFile(files[0]);
}
});

Expand All @@ -518,6 +522,109 @@ export class Tree {
this.domRoot.find('.options'),
state as unknown as Record<string, boolean>
);

let drophereHideTimeout;
this.root.on('dragover', ev => {
ev.preventDefault();

if (drophereHideTimeout) clearTimeout(drophereHideTimeout);

const drophere = this.root.find('.drophere');
drophere.show();
});

this.root.on('dragleave', () => {
const drophere = this.root.find('.drophere');
drophereHideTimeout = setTimeout(() => {
drophere.hide();
}, 1000);
});

this.root.on('drop', async (ev: any) => {
ev.preventDefault();

const drophere = this.root.find('.drophere');
drophere.hide();

const dataTransfer = ev.originalEvent.dataTransfer;
if (dataTransfer.items) {
[...dataTransfer.items].forEach(async (item, i) => {
if (item.kind === 'file') {
const file = item.getAsFile();
if (file.name.endsWith('.zip')) {
this.openZipFile(file);
} else {
await this.addSingleFile(file);
}
}
});
} else {
[...dataTransfer.files].forEach(async (file, i) => {
if (file.name.endsWith('.zip')) {
this.openZipFile(file);
} else {
await this.addSingleFile(file);
}
});
}
});
}

private async openZipFile(htmlfile) {
this.multifileService.forEachFile((file: MultifileFile) => {
this.removeFile(file.fileId);
});

await this.multifileService.loadProjectFromFile(htmlfile, (file: MultifileFile) => {
this.refresh();
if (file.filename === 'CMakeLists.txt') {
// todo: find a way to toggle on CMake checkbox...
this.editFile(file.fileId);
}
});
}

private async askForOverwriteAndDo(filename): Promise<void> {
return new Promise((resolve, reject) => {
if (this.multifileService.fileExists(filename)) {
this.alertSystem.ask('Overwrite file', `${_.escape(filename)} already exists, overwrite this file?`, {
yes: () => {
this.removeFileByFilename(filename);
resolve();
},
no: () => {
reject();
},
onClose: () => {
reject();
},
yesClass: 'btn-danger',
yesHtml: 'Yes',
noClass: 'btn-primary',
noHtml: 'No',
});
} else {
resolve();
}
});
}

private async addSingleFile(htmlfile): Promise<void> {
try {
await this.askForOverwriteAndDo(htmlfile.name);

return new Promise(resolve => {
const fr = new FileReader();
fr.onload = () => {
this.multifileService.addNewTextFile(htmlfile.name, fr.result?.toString() || '');
this.refresh();
resolve();
};
fr.readAsText(htmlfile);
});
} catch {
// expected when user says no
}
}

private numberUsedLines() {
Expand Down
7 changes: 7 additions & 0 deletions static/styles/explorer.scss
Expand Up @@ -866,6 +866,13 @@ html[data-theme='dark'] {
float: right;
padding: 4px 10px 4px 0;
}
.tree .drophere {
margin: 5px;
border: dashed rgba(127, 127, 127, 0.2);
border-radius: 16px;
height: 150px;
}

.mainbar .cmake-project {
margin-top: 2px;
}
Expand Down
2 changes: 2 additions & 0 deletions views/templates/panes/tree.pug
Expand Up @@ -41,3 +41,5 @@
li.root.list-group-item.far-fa-folder
.group-header Excluded files
ul.list-group.unnamed-editors
li.drophere.row.align-items-center(style="display: none;")
span.col-lg.text-center Drop files here

0 comments on commit 750f193

Please sign in to comment.