154 lines
4.6 KiB
JavaScript
154 lines
4.6 KiB
JavaScript
|
|
import { api } from '../api.js';
|
||
|
|
|
||
|
|
class CodeEditorView extends HTMLElement {
|
||
|
|
constructor() {
|
||
|
|
super();
|
||
|
|
this.editor = null;
|
||
|
|
this.file = null;
|
||
|
|
this.previousView = null;
|
||
|
|
this.boundHandleClick = this.handleClick.bind(this);
|
||
|
|
this.boundHandleEscape = this.handleEscape.bind(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
connectedCallback() {
|
||
|
|
this.addEventListener('click', this.boundHandleClick);
|
||
|
|
document.addEventListener('keydown', this.boundHandleEscape);
|
||
|
|
}
|
||
|
|
|
||
|
|
disconnectedCallback() {
|
||
|
|
this.removeEventListener('click', this.boundHandleClick);
|
||
|
|
document.removeEventListener('keydown', this.boundHandleEscape);
|
||
|
|
if (this.editor) {
|
||
|
|
this.editor.toTextArea();
|
||
|
|
this.editor = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
handleEscape(e) {
|
||
|
|
if (e.key === 'Escape') {
|
||
|
|
this.goBack();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async setFile(file, previousView = 'files') {
|
||
|
|
this.file = file;
|
||
|
|
this.previousView = previousView;
|
||
|
|
await this.loadAndRender();
|
||
|
|
}
|
||
|
|
|
||
|
|
async loadAndRender() {
|
||
|
|
try {
|
||
|
|
const blob = await api.downloadFile(this.file.id);
|
||
|
|
const content = await blob.text();
|
||
|
|
this.render(content);
|
||
|
|
this.initializeEditor(content);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to load file:', error);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'Failed to load file: ' + error.message, type: 'error' }
|
||
|
|
}));
|
||
|
|
this.render('');
|
||
|
|
window.history.back();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
getMimeType(filename) {
|
||
|
|
const extension = filename.split('.').pop().toLowerCase();
|
||
|
|
const mimeMap = {
|
||
|
|
'js': 'text/javascript',
|
||
|
|
'json': 'application/json',
|
||
|
|
'py': 'text/x-python',
|
||
|
|
'md': 'text/x-markdown',
|
||
|
|
'html': 'text/html',
|
||
|
|
'xml': 'application/xml',
|
||
|
|
'css': 'text/css',
|
||
|
|
'txt': 'text/plain',
|
||
|
|
'log': 'text/plain',
|
||
|
|
'sh': 'text/x-sh',
|
||
|
|
'yaml': 'text/x-yaml',
|
||
|
|
'yml': 'text/x-yaml'
|
||
|
|
};
|
||
|
|
return mimeMap[extension] || 'text/plain';
|
||
|
|
}
|
||
|
|
|
||
|
|
render(content) {
|
||
|
|
this.innerHTML = `
|
||
|
|
<div class="code-editor-view">
|
||
|
|
<div class="code-editor-header">
|
||
|
|
<div class="header-left">
|
||
|
|
<button class="button" id="back-btn">Back</button>
|
||
|
|
<h2 class="editor-filename">${this.file.name}</h2>
|
||
|
|
</div>
|
||
|
|
<div class="header-right">
|
||
|
|
<button class="button button-primary" id="save-btn">Save</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="code-editor-body">
|
||
|
|
<textarea id="code-editor-textarea">${content}</textarea>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
|
||
|
|
initializeEditor(content) {
|
||
|
|
const textarea = this.querySelector('#code-editor-textarea');
|
||
|
|
if (!textarea) return;
|
||
|
|
|
||
|
|
this.editor = CodeMirror.fromTextArea(textarea, {
|
||
|
|
value: content,
|
||
|
|
mode: this.getMimeType(this.file.name),
|
||
|
|
lineNumbers: true,
|
||
|
|
theme: 'default',
|
||
|
|
lineWrapping: true,
|
||
|
|
indentUnit: 4,
|
||
|
|
indentWithTabs: false,
|
||
|
|
extraKeys: {
|
||
|
|
'Ctrl-S': () => this.save(),
|
||
|
|
'Cmd-S': () => this.save()
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
this.editor.setSize('100%', '100%');
|
||
|
|
}
|
||
|
|
|
||
|
|
handleClick(e) {
|
||
|
|
if (e.target.id === 'back-btn') {
|
||
|
|
this.goBack();
|
||
|
|
} else if (e.target.id === 'save-btn') {
|
||
|
|
this.save();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async save() {
|
||
|
|
if (!this.editor) return;
|
||
|
|
|
||
|
|
try {
|
||
|
|
const content = this.editor.getValue();
|
||
|
|
await api.updateFile(this.file.id, content);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'File saved successfully!', type: 'success' }
|
||
|
|
}));
|
||
|
|
} catch (error) {
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'Failed to save file: ' + error.message, type: 'error' }
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
goBack() {
|
||
|
|
window.history.back();
|
||
|
|
}
|
||
|
|
|
||
|
|
hide() {
|
||
|
|
document.removeEventListener('keydown', this.boundHandleEscape);
|
||
|
|
if (this.editor) {
|
||
|
|
this.editor.toTextArea();
|
||
|
|
this.editor = null;
|
||
|
|
}
|
||
|
|
this.remove();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
customElements.define('code-editor-view', CodeEditorView);
|
||
|
|
export { CodeEditorView };
|