diff --git a/_layouts/default.html b/_layouts/default.html
index 9bf1301..1c6b8cf 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -53,7 +53,9 @@
{% endif %}
+
{{ content }}
+
diff --git a/src/docs.js b/src/docs.js
index 7e8cc46..bd5caa7 100644
--- a/src/docs.js
+++ b/src/docs.js
@@ -81,18 +81,6 @@ function activateMenuNesting() {
const handleMenuNesting = (e) => {
e.preventDefault();
toggleParent(e.currentTarget, "open");
- const elementType = e.currentTarget.tagName.toLowerCase();
- if (elementType === "a") {
- const linkElement = e.currentTarget;
- const linkElementParent = linkElement.parentNode;
- const destination = linkElement.href;
- if (
- destination !== window.location.href &&
- !linkElementParent.classList.contains("active")
- ) {
- window.location.href = destination;
- }
- }
};
if (menuParents) {
[...menuParents].map(elem => {
diff --git a/src/ide.ts b/src/ide.ts
index 9d9eb45..31087f4 100644
--- a/src/ide.ts
+++ b/src/ide.ts
@@ -7,23 +7,28 @@ import * as effekt from "./effekt-language";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
import type { Diagnostic, DiagnosticSeverity, Position } from "vscode-languageserver-types"
-// initialize:
-// load all code[module=...] elements and write them to the IDE
-document.querySelectorAll("code[module]").forEach( (code: HTMLElement) => {
- let module = code.getAttribute("module")
- let filename = module + ".effekt"
- let content = code.getAttribute("prelude") + code.getAttribute("content") + code.getAttribute("postlude")
- effekt.write(filename, content)
-})
-
export interface IViewModel extends monaco.editor.ITextModel {
getFullText(): string
modelPosition(pos: Position): Position
viewPosition(pos: Position): Position
}
+// initialize:
+// load all code[module=...] elements and write them to the IDE
+export function loadModules() {
+ document.querySelectorAll("code[module]").forEach( (code: HTMLElement) => {
+ let module = code.getAttribute("module")
+ let filename = module + ".effekt"
+ let content = code.getAttribute("prelude") + code.getAttribute("content") + code.getAttribute("postlude")
+ effekt.write(filename, content)
+ })
+}
+
export function createModel(filename: string, contents: string, hiddenPrelude: string, hiddenPostlude: string): IViewModel {
- let model = monaco.editor.createModel(contents.trim(), "effekt", monaco.Uri.file(filename))
+ let model = monaco.editor.getModel(monaco.Uri.file(filename));
+ if (model) model.setValue(contents.trim())
+ else model = monaco.editor.createModel(contents.trim(), "effekt", monaco.Uri.file(filename))
+
let pre = hiddenPrelude || ""
let post = hiddenPostlude || ""
let lineOffset = (hiddenPrelude.match(/\n/g) || '').length
diff --git a/src/index.ts b/src/index.ts
index c15b2bc..220dfc7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,6 +8,7 @@ async function enableEditing(code: HTMLElement, run: HTMLElement, coreOut: HTMLE
let IDE = await import(/* webpackMode: "lazy", webpackChunkName: "ide" */ "./ide")
let editor = await import(/* webpackMode: "lazy", webpackChunkName: "editor" */ "./editor")
+ IDE.loadModules();
parent.classList.remove("editor-loading")
parent.classList.add("editor")
@@ -264,17 +265,13 @@ function parseOptions(str: string): CodeOptions {
}
}
-
-
-
-window.addEventListener("DOMContentLoaded", () => {
-
+function initDOM() {
processCode()
// let codes = document.querySelectorAll("code")
// monacoEditor(codes[codes.length - 1])
hljs.configure({
- languages: ['effekt', 'bash']
+ languages: ['effekt', 'bash']
});
// highlight inline code
@@ -286,4 +283,77 @@ window.addEventListener("DOMContentLoaded", () => {
})
docs.init()
-})
+}
+
+const globalHistory = [{ url: window.location.href, scrollPosition: 0 }];
+let currentHistoryIndex = 0;
+
+function loadPage(url, addToHistory = true) {
+ fetch(url)
+ .then((response) => response.text())
+ .then((html) => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(html, "text/html");
+ const newContent = doc.querySelector("main#content");
+ document.querySelector("main#content").innerHTML = newContent.innerHTML;
+
+ initDOM();
+ addLinkListeners();
+
+ document.title = doc.querySelector("head > title").innerHTML;
+
+ if (addToHistory) {
+ globalHistory.splice(currentHistoryIndex + 1);
+ globalHistory.push({ url, scrollPosition: 0 });
+ currentHistoryIndex = globalHistory.length - 1;
+ window.history.pushState({ index: currentHistoryIndex }, "", url);
+ setTimeout(() => { // wait until content is rendered
+ window.scrollTo({ top: 0 })
+ }, 0);
+ } else {
+ setTimeout(() => { // wait until content is rendered
+ window.scrollTo({ top: globalHistory[currentHistoryIndex].scrollPosition });
+ }, 0);
+ }
+ console.log("Current history:", globalHistory, "Current index:", currentHistoryIndex);
+ })
+ .catch((err) => console.error("Failed to load page", err));
+}
+
+function addLinkListeners() {
+ const links = document.querySelectorAll(".sidebar-nav a, a.next-page, a.previous-page");
+
+ links.forEach((link) => {
+ link.addEventListener("click", (e) => {
+ e.preventDefault();
+ loadPage(link.getAttribute("href"));
+ });
+ });
+}
+
+function navigateHistory(step) {
+ globalHistory[currentHistoryIndex].scrollPosition = window.pageYOffset;
+ const newIndex = currentHistoryIndex + step;
+ if (newIndex >= 0 && newIndex < globalHistory.length) {
+ currentHistoryIndex = newIndex;
+ loadPage(globalHistory[currentHistoryIndex].url, false);
+ }
+}
+
+window.addEventListener("DOMContentLoaded", () => {
+ addLinkListeners();
+ initDOM();
+
+ window.addEventListener('popstate', (event) => {
+ if (event.state && typeof event.state.index !== 'undefined') {
+ const step = event.state.index - currentHistoryIndex;
+ navigateHistory(step);
+ }
+ });
+
+ window.addEventListener('beforeunload', () => {
+ globalHistory[currentHistoryIndex].scrollPosition = window.pageYOffset;
+ });
+});
+
+window.history.pushState({ index: 0 }, "", window.location.href);