Skip to content

Commit

Permalink
feat(Import): import local files by dropping in editor
Browse files Browse the repository at this point in the history
  • Loading branch information
hatemhosny committed Aug 8, 2024
1 parent e0342ef commit 09c69f6
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 45 deletions.
49 changes: 4 additions & 45 deletions src/livecodes/UI/import.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable import/no-internal-modules */
import type { SourceFile, populateConfig as populateConfigFn } from '../import/utils';
import type { populateConfig as populateConfigFn } from '../import/utils';
import type { createModal } from '../modal';
import type { Config, ContentConfig, User, Screen } from '../models';
import type { createNotifications } from '../notifications';
Expand All @@ -9,7 +9,7 @@ import { defaultConfig } from '../config/default-config';
import { importScreen } from '../html';
import { fetchWithHandler } from '../utils/utils';
import { importCode } from '../import/import';
import { importFromZip } from '../import/zip';
import { importFromFiles } from '../import/files';
import {
getBulkImportFileInput,
getBulkImportJsonUrlButton,
Expand Down Expand Up @@ -100,52 +100,11 @@ export const createImportUI = ({
}
});

const loadFiles = (input: HTMLInputElement) =>
new Promise<Partial<ContentConfig>>((resolve, reject) => {
const files = Array.from(input.files as FileList);
const sourceFiles: SourceFile[] = [];

for (const file of files) {
// Max 100 MB allowed
const maxSizeAllowed = 100 * 1024 * 1024;
if (file.size > maxSizeAllowed) {
reject('Error: Exceeded size 100 MB');
return;
}

const reader = new FileReader();
eventsManager.addEventListener(reader, 'load', async (event: any) => {
const text = (event.target?.result as string) || '';
sourceFiles.push({
filename: file.name,
content: text,
});

if (sourceFiles.length === files.length) {
resolve(populateConfig(sourceFiles, {}));
}
});

eventsManager.addEventListener(reader, 'error', () => {
reject('Error: Failed to read file');
});

reader.readAsText(file);
}
});

const loadZipFile = (input: HTMLInputElement) => importFromZip(input.files![0], populateConfig);

const codeImportInput = getCodeImportInput(importContainer);
eventsManager.addEventListener(codeImportInput, 'change', () => {
if (codeImportInput.files?.length === 0) return;

const getConfigFromFiles =
codeImportInput.files?.length === 1 && codeImportInput.files[0].name.endsWith('.zip')
? loadZipFile
: loadFiles;
if (!codeImportInput.files?.length) return;

getConfigFromFiles(codeImportInput)
importFromFiles(codeImportInput.files, populateConfig, eventsManager)
.then(loadConfig)
.then(modal.close)
.catch((message) => {
Expand Down
22 changes: 22 additions & 0 deletions src/livecodes/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import {
import { customEvents } from './events/custom-events';
import { populateConfig } from './import/utils';
import { permanentUrlService } from './services/permanent-url';
import { importFromFiles } from './import/files';

// declare global dependencies
declare const window: Window & {
Expand Down Expand Up @@ -3883,6 +3884,26 @@ const handleFullscreen = async () => {
});
};

const handleDropFiles = () => {
if (isEmbed) return;

eventsManager.addEventListener(document, 'drop', (event: DragEvent) => {
event.preventDefault();
const files = event.dataTransfer?.files;
if (!files?.length) return;

importFromFiles(files, populateConfig, eventsManager)
.then(loadConfig)
.catch((message) => {
notifications.error(message);
});
});

eventsManager.addEventListener(document, 'dragover', (event: DragEvent) => {
event.preventDefault();
});
};

const handleUnload = () => {
window.onbeforeunload = () => {
if (!isSaved) {
Expand Down Expand Up @@ -4007,6 +4028,7 @@ const extraHandlers = async () => {
handleAbout();
handleResultPopup();
handleBroadcastStatus();
handleDropFiles();
handleUnload();
};

Expand Down
52 changes: 52 additions & 0 deletions src/livecodes/import/files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { createEventsManager } from '../events';
import type { ContentConfig } from '../models';
import type { populateConfig as populateConfigFn, SourceFile } from './utils';
import { importFromZip } from './zip';

export const importFromFiles = async (
files: FileList,
populateConfig: typeof populateConfigFn,
eventsManager: ReturnType<typeof createEventsManager>,
) => {
const loadFiles = (files: FileList) =>
new Promise<Partial<ContentConfig>>((resolve, reject) => {
const sourceFiles: SourceFile[] = [];

for (const file of files) {
// Max 100 MB allowed
const maxSizeAllowed = 100 * 1024 * 1024;
if (file.size > maxSizeAllowed) {
reject('Error: Exceeded size 100 MB');
return;
}

const reader = new FileReader();
eventsManager.addEventListener(reader, 'load', (event: any) => {
const text = (event.target?.result as string) || '';
sourceFiles.push({
filename: file.name,
content: text,
});

if (sourceFiles.length === files.length) {
resolve(populateConfig(sourceFiles, {}));
}
});

eventsManager.addEventListener(reader, 'error', () => {
reject('Error: Failed to read file');
});

reader.readAsText(file);
}
});

const loadZipFile = (files: FileList) => importFromZip(files[0], populateConfig);

if (!files?.length) return {};

const getConfigFromFiles =
files?.length === 1 && files[0].name.endsWith('.zip') ? loadZipFile : loadFiles;

return getConfigFromFiles(files);
};

0 comments on commit 09c69f6

Please sign in to comment.