This commit is contained in:
Dmitry Vasilev
2022-09-10 02:48:13 +08:00
commit fad075ad37
45 changed files with 38501 additions and 0 deletions

164
src/editor/files.js Normal file
View File

@@ -0,0 +1,164 @@
import {el} from './domutils.js'
import {map_find} from '../utils.js'
import {load_dir, create_file} from '../filesystem.js'
import {exec, get_state} from '../index.js'
export class Files {
constructor(ui) {
this.ui = ui
this.el = el('div', 'files_container')
this.render(get_state())
}
open_directory() {
load_dir(true).then(dir => {
exec('load_dir', dir)
})
}
render(state) {
if(state.project_dir == null) {
this.el.innerHTML = ''
this.el.appendChild(
el('div', 'allow_file_access',
el('a', {
href: 'javascript:void(0)',
click: this.open_directory.bind(this),
},
`Allow access to local project folder`,
),
el('div', 'subtitle', `Your files will never leave your device`)
)
)
} else {
this.render_files(state.project_dir, state.current_module)
}
}
render_files(dir, current_module) {
const files = this.el.querySelector('.files')
const children = [
this.render_file({name: '*scratch*', path: ''}, current_module),
this.render_file(dir, current_module),
]
if(files == null) {
this.el.innerHTML = ''
this.el.appendChild(
el('div', 'file_actions',
el('a', {
href: 'javascript: void(0)',
click: this.create_file.bind(this, false),
},
'Create file'
),
el('a', {
href: 'javascript: void(0)',
click: this.create_file.bind(this, true),
}, 'Create dir'),
)
)
this.el.appendChild(
el('div', 'files',
children
)
)
} else {
// Replace to preserve scroll position
files.replaceChildren(...children)
}
}
render_file(file, current_module) {
const result = el('div', 'file',
el('div', {
'class': 'file_title' + (file.path == current_module ? ' active' : ''),
click: e => this.on_click(e, file)
},
el('span', 'icon',
file.kind == 'directory'
? '\u{1F4C1}' // folder icon
: '\xa0',
),
file.name,
),
file.children == null
? null
: file.children.map(c => this.render_file(c, current_module))
)
if(file.path == current_module) {
this.active_el = result
this.active_file = file
}
return result
}
async create_file(is_dir) {
if(this.active_file == null) {
throw new Error('no active file')
}
let name = prompt(`Enter ${is_dir ? 'directory' : 'file'} name`)
if(name == null) {
return
}
let dir
const root = get_state().project_dir
if(this.active_file.path == '' /* scratch */) {
// Create in root directory
dir = root
} else {
if(this.active_file.kind == 'directory') {
dir = this.active_file
} else {
const find_parent = (dir, parent) => {
if(dir.path == this.active_file.path) {
return parent
}
if(dir.children == null) {
return null
}
return map_find(dir.children, c => find_parent(c, dir))
}
dir = find_parent(root)
if(dir == null) {
throw new Error('illegal state')
}
}
}
const path = dir == root ? name : dir.path + '/' + name
await create_file(path, is_dir)
// Reload all files for simplicity
load_dir(false).then(dir => {
if(is_dir) {
exec('load_dir', dir)
} else {
exec('create_file', dir, path)
}
})
}
on_click(e, file) {
e.stopPropagation()
this.active_el.querySelector('.file_title').classList.remove('active')
this.active_el = e.currentTarget.parentElement
e.currentTarget.classList.add('active')
this.active_file = file
if(file.kind != 'directory') {
exec('change_current_module', file.path)
}
}
}