From bc979791f2186391b7de6b3cccfd0274ea6cc876 Mon Sep 17 00:00:00 2001 From: Kousuke Kawahira Date: Fri, 1 Dec 2023 19:13:52 +0900 Subject: [PATCH] notepad: folder selecting --- apps/notepad/notepad.js | 72 ++++++++++++++++++++++++++++++++------ apps/notepad/template.html | 3 +- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/apps/notepad/notepad.js b/apps/notepad/notepad.js index a11ff32..cc870d4 100644 --- a/apps/notepad/notepad.js +++ b/apps/notepad/notepad.js @@ -7,6 +7,12 @@ AFRAME.registerComponent('notepad-app', { this.appManager = null; let editorEl = /** @type {AFRAME.AEntity & {value: string}} */ (this.el.querySelector('[texteditor]')); let editor = editorEl.components.texteditor; + let formats = [ + { name: 'Text', type: 'text/plain', ext: 'txt' }, + { name: 'JavaScript', type: 'text/javascript', ext: 'js' }, + { name: 'Go', type: 'text/x-go', ext: 'go' }, + { name: 'C/C++', type: 'text/x-c', ext: 'c' }, + ]; editorEl.value = `# Example text Hello, world! @@ -25,7 +31,7 @@ TODO: // TODO: more languages let keywords = []; let common = ['if', 'else', 'for', 'while', 'break', 'continue', 'switch', 'case', 'default', - 'return', 'class', 'new', 'throw', 'try', 'catch', 'finally']; + 'return', 'class', 'new', 'throw', 'try', 'catch', 'finally', 'void']; if (type.startsWith('text/javascript')) { keywords = common.concat(['this', 'true', 'false', 'null', 'function', 'var', 'let', 'const', 'undefined', 'NaN', 'instanceof', 'async', 'of', 'in', 'import', 'export', 'extends']); @@ -106,6 +112,10 @@ TODO: editor.textView.undo(true); } }); + this._elByName('format-menu').addEventListener('change', async (ev) => { + setMimeType(formats[ev.detail.index].type); + }); + this._elByName('format-menu').setAttribute('values', formats.map(f => f.name).join(',')); this.el.addEventListener('app-start', async (ev) => { this.appManager = ev.detail.appManager; @@ -135,7 +145,6 @@ TODO: } }, { once: true }); - this.el.addEventListener('keydown', (ev) => { if (ev.ctrlKey && ev.code == 'KeyA') { editor.selectAll(); @@ -161,15 +170,57 @@ TODO: attrs instanceof Function ? attrs(el) : (attrs && Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v))); return el; } - let task = new Promise((resolve, reject) => { + /** @type {Folder} */ + let folder = this._appFolder(); + let task = new Promise(async (resolve, reject) => { let buttonEl = mkEl('a-xybutton', [], { label: 'Save' }); let cancelEl = mkEl('a-xybutton', [], { label: 'Cancel' }); - let inputEl = mkEl('a-xyinput', [], { value: 'Untitled.' + (options.extension || 'txt') }); + let inputEl = mkEl('a-xyinput', [], { value: 'Untitled.' + (options.extension || 'txt'), width: 3 }); + let selectFolderEl = mkEl('a-xyselect', [], { values: '' }); + // TODO: tree view + let roots = [ + [this._appFolder(), this.el.components.vrapp.app.name], + [this.el.components.vrapp.services.storage, '/'] + ]; + let path = []; + let folders = []; + let selectFolder = async (fi) => { + folder = fi[0]; + if (roots.includes(fi)) { + path = [fi]; + } else if (path.includes(fi)) { + path = path.slice(0, path.indexOf(fi) + 1); + } else { + path.push(fi); + } + let ff = path.slice(); + for (let f of (await folder.getFiles(0, 1000)).items) { + if (f.type == 'folder') { + ff.push([this.el.components.vrapp.services.storage.getFolder(f.path), f.name]); + } + } + folders = roots.slice(); + folders.splice(roots.indexOf(ff[0]), 1, ...ff); + selectFolderEl.setAttribute('values', folders.map(fi => fi[1]).join(',')); + return folders.indexOf(fi); + }; + selectFolder(roots[0]); let el = mkEl('a-xycontainer', [ + mkEl('a-entity', [], { + xyitem: 'fixed: true', + geometry: 'primitive: xy-rounded-rect; width: 4; height: 2.5', + material: 'color: #000000', + position: '0 0 -0.1', + }), + mkEl('a-xycontainer', [ + mkEl('a-xylabel', ['Folder:'], { value: 'Folder:', width: 1.5, height: 0.4 }), + selectFolderEl, + ], { direction: 'row' }), inputEl, - buttonEl, - cancelEl, - ], { position: '0 0 0.05', direction: 'row', xyitem: 'fixed: true' }); + mkEl('a-xycontainer', [buttonEl, cancelEl], { direction: 'row' }), + ], { + position: '0 0 0.2', direction: 'column', xyitem: 'fixed: true', + }); buttonEl.addEventListener('click', ev => { this.el.removeChild(el); resolve(inputEl.value); @@ -178,13 +229,14 @@ TODO: this.el.removeChild(el); reject(); }); + selectFolderEl.addEventListener('change', async (ev) => { + selectFolderEl.setAttribute('select', await selectFolder(folders[ev.detail.index])); + }); this.el.append(el); setTimeout(() => inputEl.focus(), 0); }); let name = await task; - console.log("Save", name); - let folder = this._appFolder(); - return folder.writeFile(name, content, { mkdir: true }); + return await folder.writeFile(name, content, { mkdir: true }); }, _elByName(name) { return this.el.querySelector("[name=" + name + "]"); diff --git a/apps/notepad/template.html b/apps/notepad/template.html index 13ddb75..0544a10 100644 --- a/apps/notepad/template.html +++ b/apps/notepad/template.html @@ -13,10 +13,11 @@ - + +