all repos — h3 @ f9bcb98e362ff4f975a5dc7adf4cef4e97ed0dbe

A tiny, extremely minimalist JavaScript microframework.

Added basic routing test; update no longer seems to work.
h3rald h3rald@h3rald.com
Tue, 14 Apr 2020 12:23:19 +0200
commit

f9bcb98e362ff4f975a5dc7adf4cef4e97ed0dbe

parent

584bff33c98e23f19eec9759b40f65e41bbaa4d2

3 files changed, 44 insertions(+), 29 deletions(-)

jump to
M example/assets/js/app.jsexample/assets/js/app.js

@@ -7,7 +7,7 @@ import modules from "./modules.js";

let initialized = false; -const app = () => { +const MainView = () => { if (!initialized) { h3.dispatch("todos/load"); }

@@ -15,22 +15,30 @@ initialized = true;

const { todos, filteredTodos, filter } = h3.state(); h3.dispatch("todos/filter", filter); localStorage.setItem("h3_todo_list", JSON.stringify(todos)); - return h3("div#todolist.todo-list-container", [ + return h3("div.todo-list-container", [ h3("h1", "To Do List"), - h3("main", [ - AddTodoForm, - EmptyTodoError, - h3("div#main-area", [NavigationBar, TodoList]) - ]) + h3("main", [AddTodoForm, EmptyTodoError, NavigationBar, TodoList]), ]); -} +}; + +const SettingsView = () => { + return h3("div.settings", [ + h3("h1", "Settings"), + h3( + "a.nav-link", + { + onclick: () => h3.go("/"), + }, + "← Go Back" + ), + ]); +}; h3.init({ - element: document.getElementById('app'), + element: document.getElementById("app"), modules, - component: app - /*routes: { - "/": app - }*/ + routes: { + "/settings": SettingsView, + "/": MainView, + }, }); -
M example/assets/js/components/navigationBar.jsexample/assets/js/components/navigationBar.js

@@ -12,6 +12,13 @@ f.focus();

}; // Filtering function for todo items return h3("div.navigation-bar", [ + h3( + "a.nav-link", + { + onclick: () => h3.go("/settings"), + }, + "⚙" + ), h3("input", { id: "filter-text", placeholder: "Type to filter todo items...",
M h3.jsh3.js

@@ -349,9 +349,10 @@ this.routes = routes;

} start() { - const processPath = () => { - const path = window.location.hash.replace(/\?.+$/, "").slice(1); - const rawQuery = window.location.hash.match(/\?(.+)$/); + const processPath = (data) => { + const hash = (data && data.newURL && data.newURL.match(/(#.+)$/) && data.newURL.match(/(#.+)$/)[1] || window.location.hash); + const path = hash.replace(/\?.+$/, "").slice(1); + const rawQuery = hash.match(/\?(.+)$/); const query = rawQuery && rawQuery[1] ? rawQuery[1] : ""; const pathParts = path.split("/").slice(1); let parts = {};

@@ -373,6 +374,7 @@ }

if (match) { let fallback = false; this.route = new Route({ query, path, def, parts, fallback }); + break; } } if (!this.route) {

@@ -384,14 +386,14 @@ // Display View

while (this.element.firstChild) { this.element.removeChild(this.element.firstChild); } - this.element.appendChild(this.routes[this.route.def].render()); + this.element.appendChild(this.routes[this.route.def]().render()); }; processPath(); window.addEventListener("hashchange", processPath); } go(path, params) { - let query = Object.keys(params) + let query = Object.keys(params || {}) .map((p) => `${encodeURIComponent(p)}=${encodeURIComponent(params[p])}`) .join("&"); query = query ? `?${query}` : "";

@@ -408,9 +410,8 @@

let store = null; let router = null; let updateFn = null; -let vnode = null; -h3.init = ({element, routes, modules, component}) => { +h3.init = ({element, routes, modules}) => { if (!(element instanceof Element)) { throw new Error('Invalid element specified.'); }

@@ -420,16 +421,15 @@ (modules || []).forEach((i) => {

if (i) i(store); }); store.dispatch("$init"); - // Initialize component - vnode = component(); + // Initialize router + router = new Router({element, routes}) + router.start(); + // Configure update function + const vnode = router.routes[router.route.def](); updateFn = () => { - vnode.update({vnode: component()}); + const fn = router.routes[router.route.def]; + vnode.update({node: element, vnode: fn()}) } - // Initialize router - //router = new Router({element, routes}) - // Render - //router.start(); - element.appendChild(vnode.render()); } h3.go = (path, params) => {