From 4baa484b84c5184286cac2743575251454a5ee2b Mon Sep 17 00:00:00 2001 From: Agando Date: Mon, 25 May 2026 18:02:02 +0200 Subject: auto: 2026-05-25_18:02 changes --- modules/ext/mindmap.js | 217 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 modules/ext/mindmap.js (limited to 'modules/ext/mindmap.js') diff --git a/modules/ext/mindmap.js b/modules/ext/mindmap.js new file mode 100644 index 0000000..012bae7 --- /dev/null +++ b/modules/ext/mindmap.js @@ -0,0 +1,217 @@ +class MindmapModule { + constructor() { + this.commands = {}; + this.terminal = null; + this.root = null; + this.colors = ['red', 'green', 'yellow', 'blue', 'cyan', 'magenta', 'white']; + this._colorIdx = 0; + } + getHelpInfo() { + return { 'mindmap': 'mindmap [...] — Create and manage interactive mindmaps' }; + } + _nextColor() { + const c = this.colors[this._colorIdx % this.colors.length]; + this._colorIdx++; + return c; + } + _genId() { + return Math.random().toString(36).slice(2, 6); + } + _findNode(id, node) { + if (node.id === id) return node; + for (const child of (node.children || [])) { + const found = this._findNode(id, child); + if (found) return found; + } + return null; + } + _treeLines(node, prefix, isLast) { + const lines = []; + const connector = isLast ? '\u2514\u2500\u2500 ' : '\u251c\u2500\u2500 '; + const tagStr = (node.tags && node.tags.length) ? ' [' + node.tags.join(', ') + ']' : ''; + const colorTag = node.color ? '[' + node.color + ']' : ''; + lines.push(prefix + connector + colorTag + node.text + ' (' + node.id + ')' + tagStr); + if (node.children) { + const sorted = node.children; + sorted.forEach((child, i) => { + const subPrefix = prefix + (isLast ? ' ' : '\u2502 '); + this._treeLines(child, subPrefix, i === sorted.length - 1).forEach(l => lines.push(l)); + }); + } + return lines; + } + registerCommands() { + const self = this; + this.commands['mindmap'] = (args) => { + if (!args[0]) return this.terminal.print('Usage: mindmap [...]', 'warning'); + const sub = args[0]; + const rest = args.slice(1); + switch (sub) { + case 'new': return this._new(rest); + case 'add': return this._add(rest); + case 'show': return this._show(rest); + case 'export': return this._export(rest); + case 'save': return this._save(rest); + case 'load': return this._load(rest); + case 'list': return this._list(); + case 'delete': return this._delete(rest); + case 'rename': return this._rename(rest); + case 'color': return this._color(rest); + case 'tag': return this._tag(rest); + default: this.terminal.print('Unknown subcommand: ' + sub + '. Try: new, add, show, export, save, load, list, delete, rename, color, tag', 'warning'); + } + }; + } + _parseTags(args) { + const tagIdx = args.indexOf('-t'); + let tags = []; + if (tagIdx >= 0) { + tags = args[tagIdx + 1] ? args[tagIdx + 1].split(',').map(t => t.trim()).filter(Boolean) : []; + args.splice(tagIdx, 2); + } + return { args, tags }; + } + _new(args) { + const { args: clean, tags } = this._parseTags([...args]); + if (!clean.length) return this.terminal.print('Usage: mindmap new [-t tag1,tag2]', 'warning'); + if (this.root) return this.terminal.print('A mindmap already exists. Use mindmap add to extend it.', 'warning'); + this.root = { + id: this._genId(), + text: clean.join(' '), + color: this._nextColor(), + tags: tags, + children: [] + }; + this.terminal.print('Created root: [' + this.root.color + '] ' + this.root.text + ' (' + this.root.id + ')', 'success'); + } + _add(args) { + const { args: clean, tags } = this._parseTags([...args]); + if (clean.length < 2) return this.terminal.print('Usage: mindmap add [-t tag1,tag2]', 'warning'); + if (!this.root) return this.terminal.print('No mindmap. Create one with mindmap new first.', 'warning'); + const parentId = clean[0]; + const text = clean.slice(1).join(' '); + const parent = this._findNode(parentId, this.root); + if (!parent) return this.terminal.print('Node not found: ' + parentId, 'error'); + const node = { + id: this._genId(), + text: text, + color: this._nextColor(), + tags: tags, + children: [] + }; + parent.children.push(node); + this.terminal.print('Added [' + node.color + '] ' + text + ' (' + node.id + ')', 'success'); + } + _show(args) { + if (!this.root) return this.terminal.print('No mindmap. Create one with mindmap new first.', 'warning'); + let node = this.root; + if (args.length && args[0]) { + const found = this._findNode(args[0], this.root); + if (!found) return this.terminal.print('Node not found: ' + args[0], 'error'); + node = found; + } + const lines = this._treeLines(node, '', true); + lines.forEach(l => this.terminal.print(l)); + this.terminal.print('(' + node.text + ' — ' + this._countNodes(node) + ' nodes total)', 'info'); + } + _countNodes(node) { + let c = 1; + for (const child of (node.children || [])) c += this._countNodes(child); + return c; + } + _export(args) { + if (!this.root) return this.terminal.print('No mindmap. Create one with mindmap new first.', 'warning'); + let node = this.root; + if (args.length && args[0]) { + const found = this._findNode(args[0], this.root); + if (!found) return this.terminal.print('Node not found: ' + args[0], 'error'); + node = found; + } + const md = this._toMarkdown(node, 0); + this.terminal.print(md); + this.terminal.print('(Markdown copied to clipboard)', 'info'); + if (navigator.clipboard) { + navigator.clipboard.writeText(md); + } + } + _toMarkdown(node, depth) { + const prefix = ' '.repeat(depth) + '- '; + const tagStr = (node.tags && node.tags.length) ? ' *[' + node.tags.join(', ') + ']*' : ''; + let out = prefix + '**' + node.text + '**' + tagStr + '\n'; + if (node.children) { + node.children.forEach(c => { out += this._toMarkdown(c, depth + 1); }); + } + return out; + } + _save(args) { + if (!args[0]) return this.terminal.print('Usage: mindmap save ', 'warning'); + if (!this.root) return this.terminal.print('No mindmap to save.', 'warning'); + try { + localStorage.setItem('webx11_mindmap_' + args[0], JSON.stringify(this.root)); + this.terminal.print('Mindmap saved as: ' + args[0], 'success'); + } catch (e) { + this.terminal.print('Failed to save: ' + e.message, 'error'); + } + } + _load(args) { + if (!args[0]) return this.terminal.print('Usage: mindmap load ', 'warning'); + try { + const data = localStorage.getItem('webx11_mindmap_' + args[0]); + if (!data) return this.terminal.print('No saved mindmap: ' + args[0], 'error'); + this.root = JSON.parse(data); + this.terminal.print('Loaded mindmap: ' + args[0] + ' (' + this._countNodes(this.root) + ' nodes)', 'success'); + } catch (e) { + this.terminal.print('Failed to load: ' + e.message, 'error'); + } + } + _list() { + const keys = []; + for (let i = 0; i < localStorage.length; i++) { + const k = localStorage.key(i); + if (k && k.startsWith('webx11_mindmap_')) keys.push(k.replace('webx11_mindmap_', '')); + } + if (!keys.length) return this.terminal.print('No saved mindmaps.', 'info'); + this.terminal.print('=== Saved Mindmaps ===', 'info'); + keys.forEach(k => this.terminal.print(' ' + k)); + } + _delete(args) { + if (!args[0]) return this.terminal.print('Usage: mindmap delete ', 'warning'); + localStorage.removeItem('webx11_mindmap_' + args[0]); + this.terminal.print('Deleted mindmap: ' + args[0], 'success'); + } + _rename(args) { + if (args.length < 2) return this.terminal.print('Usage: mindmap rename ', 'warning'); + if (!this.root) return this.terminal.print('No mindmap.', 'warning'); + const id = args[0]; + const text = args.slice(1).join(' '); + const node = this._findNode(id, this.root); + if (!node) return this.terminal.print('Node not found: ' + id, 'error'); + node.text = text; + this.terminal.print('Renamed ' + id + ' to: ' + text, 'success'); + } + _color(args) { + if (args.length < 2) return this.terminal.print('Usage: mindmap color ', 'warning'); + if (!this.root) return this.terminal.print('No mindmap.', 'warning'); + const id = args[0]; + const color = args[1].toLowerCase(); + if (!this.colors.includes(color)) return this.terminal.print('Available colors: ' + this.colors.join(', '), 'warning'); + const node = this._findNode(id, this.root); + if (!node) return this.terminal.print('Node not found: ' + id, 'error'); + node.color = color; + this.terminal.print('Set color for ' + id + ' to ' + color, 'success'); + } + _tag(args) { + if (args.length < 2) return this.terminal.print('Usage: mindmap tag ', 'warning'); + if (!this.root) return this.terminal.print('No mindmap.', 'warning'); + const id = args[0]; + const tag = args.slice(1).join(' '); + const node = this._findNode(id, this.root); + if (!node) return this.terminal.print('Node not found: ' + id, 'error'); + if (!node.tags) node.tags = []; + node.tags.push(tag); + this.terminal.print('Added tag "' + tag + '" to ' + id, 'success'); + } +} +if (typeof window.webx11 !== 'undefined' && window.webx11) { + webx11.moduleManager.registerModule(new MindmapModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/mindmap.js'); +} -- cgit v1.2.3