Compare commits

...

2 Commits

5 changed files with 92 additions and 19 deletions

View File

@ -8,6 +8,9 @@
<title>Karlkoder Playground</title>
<link rel="stylesheet" href="./style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.43.2/ace.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.43.2/ext-language_tools.js"
></script>
<script src="./src/index.js" type="module"></script>
</head>
<body>
@ -126,6 +129,7 @@ lib.startGameLoop(loop);
<div id="sprite-editor-preview">
<p id="sprite-editor-preview-title"></p>
<img id="sprite-editor-preview-image" src="">
<code id="sprite-editor-preview-snippet">test</code>
</div>
<button id="sprite-editor-upload-button">Upload new sprite</button>
<ul id="sprite-editor-sprite-list"></ul>

36
src/gamelib_completer.js Normal file
View File

@ -0,0 +1,36 @@
import { Gamelib } from "./gamelib.js";
export class GamelibCompleter {
getCompletions(_editor, session, pos, prefix, callback) {
// Check if user has written "lib."
const line = session.doc["$lines"][pos.row].slice(0, pos.column);
if (!line.match(/lib\.\w*$/)) {
callback(null, []);
return;
}
if (prefix.length === 0) {
callback(null, []);
return;
}
const functions = Object.getOwnPropertyNames(Gamelib.prototype);
const wordList = functions.map((func) => {
const definition = Gamelib.prototype[func].toString();
const signature = definition.slice(0, definition.indexOf(")") + 1);
return {
"name": func,
"value": func,
"snippet": func + "($0)",
"caption": func,
"score": 300,
"meta": "function",
"docHTML": signature,
};
});
return callback(null, wordList);
}
}

View File

@ -9,6 +9,7 @@ import { Gamelib } from "./gamelib.js";
import { CodeStopper } from "./code_stopper.js";
import { Vermiparous } from "./vermiparous.js";
import { promptUpload } from "./prompt_upload.js";
import { GamelibCompleter } from "./gamelib_completer.js";
const playgroundConsole = new PlaygroundConsole(
document.querySelector("#console-code"),
@ -19,7 +20,7 @@ const codeStopper = new CodeStopper();
const spriteProvider = new SpriteProvider();
const codeRunner = new CodeRunner(playgroundConsole, codeStopper);
const spriteEditor = new SpriteEditor(document.querySelector("#sprite-editor"), []);
const spriteEditor = new SpriteEditor(document.querySelector("#sprite-editor-container"), []);
const gamelib = new Gamelib(
playgroundConsole,
@ -38,6 +39,12 @@ const editor = ace.edit("editor");
editor.setTheme("ace/theme/gruvbox");
editor.session.setMode("ace/mode/javascript");
const langTools = ace.require("ace/ext/language_tools");
editor.setOptions({ enableBasicAutocompletion: true, enableLiveAutocompletion: true });
langTools.addCompleter(new GamelibCompleter());
editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
const importButton = document.querySelector("#import-button");
@ -176,20 +183,4 @@ saveKarlkoderButton.onclick = (ev) => {
);
};
toggleSpriteEditorButton.addEventListener("click", () => {
const container = document.querySelector("#sprite-editor-container");
const editor = document.querySelector("#sprite-editor");
const button = document.querySelector("#toggle-sprite-editor-button");
if (getComputedStyle(editor).display === "none") {
editor.style.display = "block";
container.style.flexGrow = "1";
button.innerHTML = "&rsaquo;";
button.setAttribute("expanded", true);
} else {
editor.style.display = "none";
container.style.flexGrow = "0";
button.innerHTML = "&lsaquo;";
button.removeAttribute("expanded");
}
});
toggleSpriteEditorButton.addEventListener("click", () => spriteEditor.toggleEditor());

View File

@ -3,9 +3,14 @@ import { promptUpload } from "./prompt_upload.js";
export class SpriteEditor {
constructor(rootEl, sprites) {
this.list = rootEl.querySelector("#sprite-editor-sprite-list");
this.editor = rootEl.querySelector("#sprite-editor");
this.toggleButton = rootEl.querySelector("#toggle-sprite-editor-button");
this.container = rootEl;
this.preview = {};
this.preview.title = rootEl.querySelector("#sprite-editor-preview-title");
this.preview.image = rootEl.querySelector("#sprite-editor-preview-image");
this.preview.snippet = rootEl.querySelector("#sprite-editor-preview-snippet");
this.sprites = sprites;
rootEl.querySelector("#sprite-editor-upload-button").addEventListener("click", () => {
@ -52,6 +57,13 @@ export class SpriteEditor {
const sprite = this.sprites.find((x) => x.id === id);
this.preview.title.textContent = sprite.name;
this.preview.image.src = `data:${sprite.mime};base64,${sprite.bytes.toBase64()}`;
const sanitizedName = sprite.name.replace(/</g, "&lt;").replace(/&/g, "&amp;");
this.preview.snippet.innerHTML = "lib.drawImage(<br>" +
" x, y,<br>" +
" width, height,<br>" +
` "${sanitizedName}"<br>` +
");";
}
renderList() {
@ -70,4 +82,18 @@ export class SpriteEditor {
this.list.replaceChildren(...children);
}
toggleEditor() {
if (getComputedStyle(this.editor).display === "none") {
this.editor.style.display = "block";
this.container.style.flexGrow = "1";
this.toggleButton.innerHTML = "&rsaquo;";
this.toggleButton.setAttribute("expanded", true);
} else {
this.editor.style.display = "none";
this.container.style.flexGrow = "0";
this.toggleButton.innerHTML = "&lsaquo;";
this.toggleButton.removeAttribute("expanded");
}
}
}

View File

@ -49,10 +49,14 @@ section canvas {
margin-right: auto;
}
section *:last-child {
section {
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
overflow-y: hidden;
}
section > :last-child {
flex: 1;
}
@ -277,3 +281,15 @@ footer {
#sprite-editor-upload-button {
margin: 1rem;
}
#sprite-editor-preview-snippet {
background-color: black;
border-radius: 0.25rem;
padding: 0.125rem 0.25rem;
margin: 0.5rem;
white-space: pre;
}
#sprite-editor-preview-title:empty {
display: none;
}