diff --git a/src/snek/service/container.py b/src/snek/service/container.py
index 0beaf2c..fba5484 100644
--- a/src/snek/service/container.py
+++ b/src/snek/service/container.py
@@ -22,6 +22,13 @@ class ContainerService(BaseService):
self.event_listeners[name][event] = []
self.event_listeners[name][event].append(event_handler)
+ async def remove_event_listener(self, name, event, event_handler):
+ if name in self.event_listeners and event in self.event_listeners[name]:
+ try:
+ self.event_listeners[name][event].remove(event_handler)
+ except ValueError:
+ pass
+
async def container_event_handler(self, name, event, data):
event_listeners = self.event_listeners.get(name, {})
handlers = event_listeners.get(event, [])
diff --git a/src/snek/static/dumb-term.js b/src/snek/static/dumb-term.js
index ecc930a..6558ee4 100644
--- a/src/snek/static/dumb-term.js
+++ b/src/snek/static/dumb-term.js
@@ -1,13 +1,32 @@
-class DumbTerminal extends HTMLElement {
- constructor() {
- super();
- this.attachShadow({ mode: "open" });
- }
+import { NjetComponent } from "/njet.js";
+class WebTerminal extends NjetComponent {
+
+ commands = {
+ "clear": () => {
+ this.outputEl.innerHTML = "";
+ return "";
+ },
+ "help": () => {
+ return "Available commands: help, clear, date";
+ },
+ "date": () => {
+ return new Date().toString();
+ }
+ };
+ help = {
+ "clear": "Clear the terminal",
+ "help": "Show available commands",
+ "date": "Show the current date"
+ };
+
+
+
connectedCallback() {
- this.shadowRoot.innerHTML = `
+
+ this.innerHTML = `
-
-
+
`;
-
- this.outputEl = this.shadowRoot.getElementById("output");
- this.inputEl = this.shadowRoot.getElementById("input");
+ this.container = this.querySelector(".web-terminal");
+ this.outputEl = this.querySelector(".web-terminal-output");
+ this.inputEl = this.querySelector(".web-terminal-input");
this.history = [];
this.historyIndex = -1;
- this.inputEl.addEventListener("keydown", (e) => this.onKeyDown(e));
+ this.inputEl.addEventListener("keyup", (e) => this.onKeyDown(e));
}
onKeyDown(event) {
@@ -116,17 +136,89 @@ class DumbTerminal extends HTMLElement {
this.outputEl.scrollTop = this.outputEl.scrollHeight;
}
+ parseCommand(input) {
+ const args = [];
+ let current = '';
+ let inSingleQuote = false;
+ let inDoubleQuote = false;
+ let inTemplate = false; // For ${...}
+ let templateBuffer = '';
+
+ for (let i = 0; i < input.length; i++) {
+ const char = input[i];
+
+ // Handle template expressions
+ if (!inSingleQuote && !inDoubleQuote && char === '$' && input[i + 1] === '{') {
+ inTemplate = true;
+ i++; // Skip '{'
+ templateBuffer = '${';
+ continue;
+ }
+
+ if (inTemplate) {
+ templateBuffer += char;
+ if (char === '}') {
+ // End of template
+ args.push(eval(templateBuffer));
+ inTemplate = false;
+ templateBuffer = '';
+ }
+ continue; // Continue to next char
+ }
+
+ // Handle quotes
+ if (char === "'" && !inDoubleQuote) {
+ inSingleQuote = !inSingleQuote;
+ continue; // Skip quote
+ }
+
+ if (char === '"' && !inSingleQuote) {
+ inDoubleQuote = !inDoubleQuote;
+ continue; // Skip quote
+ }
+
+ // Handle spaces outside quotes and templates
+ if (char === ' ' && !inSingleQuote && !inDoubleQuote) {
+ if (current.length > 0) {
+ args.push(current);
+ current = '';
+ }
+ } else {
+ current += char;
+ }
+ }
+
+ if (current.length > 0) {
+ args.push(current);
+ }
+
+ return args;
+ }
+ executeScript(script) {
+ const scriptElement = document.createElement("script");
+ scriptElement.textContent = script;
+ this.appendChild(scriptElement);
+ }
mockExecute(command) {
- switch (command.trim()) {
- case "help":
- return "Available commands: help, clear, date";
- case "date":
- return new Date().toString();
- case "clear":
- this.outputEl.innerHTML = "";
- return "";
- default:
- return `Unknown command: ${command}`;
+ let args;
+ try {
+ args = this.parseCommand(command);
+ } catch (e) {
+ return e.toString();
+ }
+ console.info({ef:this})
+ console.info({af:this})
+ console.info({gf:args})
+ let cmdName = args.shift();
+ let commandHandler = this.commands[cmdName];
+ if (commandHandler) {
+ return commandHandler.apply(this, args);
+ }
+ try {
+ // Try to eval as JS
+ return this.executeScript(command);
+ } catch (e) {
+ return e.toString();
}
}
@@ -134,7 +226,7 @@ class DumbTerminal extends HTMLElement {
* Static method to create a modal dialog with the terminal
* @returns {HTMLDialogElement}
*/
- static createModal() {
+ show() {
const dialog = document.createElement("dialog");
dialog.innerHTML = `
@@ -147,4 +239,12 @@ class DumbTerminal extends HTMLElement {
}
}
+window.showTerm = function (options) {
+ const term = new WebTerminal(options);
+ term.show();
+ return term;
+}
+
customElements.define("web-terminal", WebTerminal);
+export { WebTerminal };
+
diff --git a/src/snek/static/njet.js b/src/snek/static/njet.js
index a23aeb6..3739f7f 100644
--- a/src/snek/static/njet.js
+++ b/src/snek/static/njet.js
@@ -353,6 +353,38 @@ class NjetDialog extends Component {
}
Njet.registerComponent('njet-dialog', NjetDialog);
+class NjetWindow extends Component {
+ render() {
+ this.innerHTML = '';
+ const { title, content, primaryButton, secondaryButton } = this.config;
+ this.classList.add('njet-dialog');
+ this.style.position = 'fixed';
+ this.style.top = '50%';
+ this.style.left = '50%';
+ this.style.transform = 'translate(-50%, -50%)';
+ this.style.padding = '20px';
+ this.style.border = '1px solid #444';
+ this.style.backgroundColor = '#fff';
+ this.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
+ this.style.minWidth = '300px';
+ if (title) {
+ const header = document.createElement('h2');
+ header.textContent = title;
+ this.appendChild(header);
+ }
+
+
+ }
+
+ show(){
+ document.body.appendChild(this)
+ }
+}
+Njet.registerComponent('njet-window', NjetWindow);
+
+
+
+
class NjetGrid extends Component {
render() {
this.classList.add('njet-grid');
@@ -467,7 +499,12 @@ njet.showDialog = function(args){
dialog.show()
return dialog
}
+njet.showWindow = function(args) {
+ const w = new NjetWindow(args)
+ w.show()
+ return w
+}
window.njet = njet
-export { Njet, NjetButton, NjetPanel, NjetDialog, NjetGrid, NjetComponent, njet};
+export { Njet, NjetButton, NjetPanel, NjetDialog, NjetGrid, NjetComponent, njet, NjetWindow };
diff --git a/src/snek/templates/app.html b/src/snek/templates/app.html
index 272bef4..be50cdf 100644
--- a/src/snek/templates/app.html
+++ b/src/snek/templates/app.html
@@ -23,6 +23,7 @@
+
diff --git a/src/snek/templates/sandbox.html b/src/snek/templates/sandbox.html
index cdb7896..4949247 100644
--- a/src/snek/templates/sandbox.html
+++ b/src/snek/templates/sandbox.html
@@ -2,6 +2,14 @@