Add auto complete, theme select, & full screen toggle in editors
This commit is contained in:
1698
static/js/mithril.js
Normal file
1698
static/js/mithril.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,19 @@ const Editor = {
|
|||||||
this.generateUrl = vnode.attrs.generateUrl;
|
this.generateUrl = vnode.attrs.generateUrl;
|
||||||
this.logsUrl = vnode.attrs.logsUrl; // Needed for debug feature
|
this.logsUrl = vnode.attrs.logsUrl; // Needed for debug feature
|
||||||
|
|
||||||
|
// Editor Features State
|
||||||
|
this.isFullScreen = false;
|
||||||
|
this.editorTheme = localStorage.getItem('editorTheme') || 'auto';
|
||||||
|
this.availableThemes = [
|
||||||
|
{ id: 'auto', name: 'Auto' },
|
||||||
|
{ id: 'monokai', name: 'Monokai' },
|
||||||
|
{ id: 'chrome', name: 'Chrome' },
|
||||||
|
{ id: 'github', name: 'GitHub' },
|
||||||
|
{ id: 'tomorrow', name: 'Tomorrow' },
|
||||||
|
{ id: 'twilight', name: 'Twilight' },
|
||||||
|
{ id: 'dracula', name: 'Dracula' }
|
||||||
|
];
|
||||||
|
|
||||||
// AI State
|
// AI State
|
||||||
this.naturalLanguageQuery = "";
|
this.naturalLanguageQuery = "";
|
||||||
this.aiLoading = false; // General AI loading state
|
this.aiLoading = false; // General AI loading state
|
||||||
@@ -56,13 +69,23 @@ const Editor = {
|
|||||||
|
|
||||||
oncreate() {
|
oncreate() {
|
||||||
this.editorJS = ace.edit("js-editor");
|
this.editorJS = ace.edit("js-editor");
|
||||||
this.editorJS.setOptions({ maxLines: 100 });
|
|
||||||
|
|
||||||
// Determine initial theme
|
// safe require of language tools
|
||||||
const isDark = document.documentElement.classList.contains('dark');
|
try {
|
||||||
const theme = isDark ? "ace/theme/monokai" : "ace/theme/chrome";
|
ace.require("ace/ext/language_tools");
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Ace language tools not loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editorJS.setOptions({
|
||||||
|
minLines: this.isFullScreen ? undefined : 15,
|
||||||
|
maxLines: this.isFullScreen ? undefined : 100,
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableLiveAutocompletion: true
|
||||||
|
});
|
||||||
|
|
||||||
this.editorJS.setTheme(theme);
|
this.applyTheme();
|
||||||
|
|
||||||
this.editorJS.session.setMode(
|
this.editorJS.session.setMode(
|
||||||
this.runtime === "python" ? "ace/mode/python" : "ace/mode/javascript"
|
this.runtime === "python" ? "ace/mode/python" : "ace/mode/javascript"
|
||||||
);
|
);
|
||||||
@@ -74,8 +97,12 @@ const Editor = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.editorJSON = ace.edit("json-editor");
|
this.editorJSON = ace.edit("json-editor");
|
||||||
this.editorJSON.setOptions({ maxLines: 100 });
|
this.editorJSON.setOptions({
|
||||||
this.editorJSON.setTheme(theme);
|
minLines: 15,
|
||||||
|
maxLines: 100,
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableLiveAutocompletion: true
|
||||||
|
});
|
||||||
this.editorJSON.session.setMode("ace/mode/json");
|
this.editorJSON.session.setMode("ace/mode/json");
|
||||||
this.editorJSON.setValue(this.jsonValue, -1);
|
this.editorJSON.setValue(this.jsonValue, -1);
|
||||||
|
|
||||||
@@ -86,17 +113,68 @@ const Editor = {
|
|||||||
|
|
||||||
// Listen for theme changes
|
// Listen for theme changes
|
||||||
this.themeListener = (e) => {
|
this.themeListener = (e) => {
|
||||||
const newTheme = e.detail.theme === 'dark' ? "ace/theme/monokai" : "ace/theme/chrome";
|
if (this.editorTheme === 'auto') {
|
||||||
this.editorJS.setTheme(newTheme);
|
this.applyTheme();
|
||||||
this.editorJSON.setTheme(newTheme);
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener('themeChanged', this.themeListener);
|
window.addEventListener('themeChanged', this.themeListener);
|
||||||
|
|
||||||
|
// Listen for Escape key to exit full screen
|
||||||
|
this.escListener = (e) => {
|
||||||
|
if (this.isFullScreen && e.key === 'Escape') {
|
||||||
|
this.toggleFullScreen();
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', this.escListener);
|
||||||
|
},
|
||||||
|
|
||||||
|
applyTheme() {
|
||||||
|
let themeToSet = this.editorTheme;
|
||||||
|
if (themeToSet === 'auto') {
|
||||||
|
const isDark = document.documentElement.classList.contains('dark');
|
||||||
|
themeToSet = isDark ? 'monokai' : 'chrome';
|
||||||
|
}
|
||||||
|
const aceTheme = `ace/theme/${themeToSet}`;
|
||||||
|
if (this.editorJS) this.editorJS.setTheme(aceTheme);
|
||||||
|
if (this.editorJSON) this.editorJSON.setTheme(aceTheme);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleFullScreen() {
|
||||||
|
this.isFullScreen = !this.isFullScreen;
|
||||||
|
if (this.isFullScreen) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for Mithril to redraw so the DOM is updated (classes/styles applied)
|
||||||
|
// before resizing the editor.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.editorJS) {
|
||||||
|
this.editorJS.setOptions({
|
||||||
|
minLines: this.isFullScreen ? undefined : 15,
|
||||||
|
maxLines: this.isFullScreen ? undefined : 100
|
||||||
|
});
|
||||||
|
this.editorJS.resize();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
setTheme(themeId) {
|
||||||
|
this.editorTheme = themeId;
|
||||||
|
localStorage.setItem('editorTheme', themeId);
|
||||||
|
this.applyTheme();
|
||||||
},
|
},
|
||||||
|
|
||||||
onremove() {
|
onremove() {
|
||||||
if (this.themeListener) {
|
if (this.themeListener) {
|
||||||
window.removeEventListener('themeChanged', this.themeListener);
|
window.removeEventListener('themeChanged', this.themeListener);
|
||||||
}
|
}
|
||||||
|
if (this.escListener) {
|
||||||
|
document.removeEventListener('keydown', this.escListener);
|
||||||
|
}
|
||||||
|
document.body.style.overflow = '';
|
||||||
},
|
},
|
||||||
|
|
||||||
async execute() {
|
async execute() {
|
||||||
@@ -298,12 +376,19 @@ const Editor = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
return m("div", { class: "" }, [
|
const fullScreenStyle = this.isFullScreen
|
||||||
|
? { position: "fixed", top: "0", left: "0", width: "100vw", height: "100vh", zIndex: "9999", backgroundColor: this.editorTheme === 'monokai' || this.editorTheme === 'twilight' || this.editorTheme === 'dracula' ? '#1a1a1a' : '#ffffff' }
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return m("div", {
|
||||||
|
class: this.isFullScreen ? "flex flex-col" : "",
|
||||||
|
style: fullScreenStyle
|
||||||
|
}, [
|
||||||
/* Header */
|
/* Header */
|
||||||
m(
|
m(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "flex items-center justify-between pl-2",
|
class: "flex items-center justify-between pl-2 " + (this.isFullScreen ? "p-4 border-b border-gray-200 dark:border-gray-800" : ""),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
this.showHeader
|
this.showHeader
|
||||||
@@ -417,7 +502,7 @@ const Editor = {
|
|||||||
: null,
|
: null,
|
||||||
])
|
])
|
||||||
: m("div"),
|
: m("div"),
|
||||||
m("div"),
|
m("div", { class: "flex items-center space-x-2" }),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -473,7 +558,35 @@ const Editor = {
|
|||||||
this.aiLoading && m("div", {class: "animate-spin h-4 w-4 border-2 border-blue-500 border-t-transparent rounded-full ml-2"})
|
this.aiLoading && m("div", {class: "animate-spin h-4 w-4 border-2 border-blue-500 border-t-transparent rounded-full ml-2"})
|
||||||
]),
|
]),
|
||||||
|
|
||||||
m("div", { class: "flex items-center space-x-4" }, [
|
m("div", { class: "flex items-center space-x-2" }, [
|
||||||
|
// Theme Selector
|
||||||
|
m("select", {
|
||||||
|
key: "theme-selector",
|
||||||
|
class: "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500",
|
||||||
|
value: this.editorTheme,
|
||||||
|
onchange: (e) => this.setTheme(e.target.value)
|
||||||
|
}, this.availableThemes.map(theme =>
|
||||||
|
m("option", { value: theme.id }, theme.name)
|
||||||
|
)),
|
||||||
|
|
||||||
|
// Full Screen Toggle
|
||||||
|
m("button", {
|
||||||
|
key: "fullscreen-toggle",
|
||||||
|
class: "p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400",
|
||||||
|
onclick: () => this.toggleFullScreen(),
|
||||||
|
title: this.isFullScreen ? "Exit Full Screen (Esc)" : "Full Screen"
|
||||||
|
}, m("svg", {
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
fill: "none",
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-width": 2,
|
||||||
|
class: "w-5 h-5"
|
||||||
|
}, this.isFullScreen
|
||||||
|
? m("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25" })
|
||||||
|
: m("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" })
|
||||||
|
)),
|
||||||
|
|
||||||
m(
|
m(
|
||||||
"select",
|
"select",
|
||||||
{
|
{
|
||||||
@@ -570,7 +683,9 @@ const Editor = {
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
m("div", { id: "js-editor", class: "rounded shadow h-64" }),
|
m("div", { class: "relative rounded shadow " + (this.isFullScreen ? "flex-1" : "") }, [
|
||||||
|
m("div", { id: "js-editor", style: "width: 100%; height: 100%;" })
|
||||||
|
]),
|
||||||
|
|
||||||
m(
|
m(
|
||||||
"div",
|
"div",
|
||||||
@@ -607,7 +722,9 @@ const Editor = {
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
m("div", { id: "json-editor", class: "rounded shadow h-64" }),
|
m("div", { class: "relative rounded shadow" }, [
|
||||||
|
m("div", { id: "json-editor", style: "width: 100%; height: 100%;" })
|
||||||
|
]),
|
||||||
|
|
||||||
m("input", { type: "hidden", name: "script", value: this.jsValue }),
|
m("input", { type: "hidden", name: "script", value: this.jsValue }),
|
||||||
m("input", {
|
m("input", {
|
||||||
|
|||||||
@@ -28,8 +28,10 @@
|
|||||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.1/theme-chrome.min.js" crossorigin="anonymous"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.1/theme-chrome.min.js" crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer"></script>
|
referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.1/ext-language_tools.min.js"
|
||||||
|
referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/mithril/mithril.js"></script>
|
<script src="/static/js/mithril.js"></script>
|
||||||
<script src="/static/js/mithril/editor.js"></script>
|
<script src="/static/js/mithril/editor.js"></script>
|
||||||
<script src="/static/js/mithril/responseView.js"></script>
|
<script src="/static/js/mithril/responseView.js"></script>
|
||||||
<script src="/static/js/mithril/alert.js"></script>
|
<script src="/static/js/mithril/alert.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user