'use strict' function call(method, params) { return m.request({ method: "POST", url: `/api/${method}`, body: params, }) } let BrowseModel = { path: undefined, subdirectories: [], entries: [], async reload(path) { if (this.path !== path) { this.path = path this.subdirectories = [] this.entries = [] } let resp = await call('browse', {path: path}) this.subdirectories = resp.subdirectories this.entries = resp.entries }, joinPath(parent, child) { if (!parent) return child if (!child) return parent return `${parent}/${child}` }, getBrowseLinks() { if (this.path === undefined) return [] let links = [{name: "Root", path: "", level: -1}], path for (const crumb of this.path.split('/').filter(s => !!s)) { path = this.joinPath(path, crumb) links.push({name: crumb, path: path, level: -1}) } links[links.length - 1].level = 0 for (const sub of this.subdirectories) { links.push( {name: sub, path: this.joinPath(this.path, sub), level: +1}) } return links }, } let Browse = { // Reload the model immediately, to improve responsivity. // But we don't need to: https://mithril.js.org/route.html#preloading-data // Also see: https://mithril.js.org/route.html#route-cancellation--blocking oninit(vnode) { let path = vnode.attrs.key || "" BrowseModel.reload(path) }, view(vnode) { return m('.container', {}, [ m('.header', {}, "Browse"), m('ul', BrowseModel.getBrowseLinks().map(link => { // TODO: Differentiate the level as CSS classes. // - Last entry (current path) should look selected. return m('li', m(m.route.Link, { href: `/browse/:key`, params: {key: link.path}, }, `${link.level} ${link.name}`)) })), m('.browser', {}, BrowseModel.entries.map(e => { return m(m.route.Link, {href: `/view/${e.sha1}`}, m('img', {src: `/thumb/${e.sha1}`, width: e.thumbW, height: e.thumbH, title: e.name})) })), ]) }, } let ViewModel = { sha1: undefined, paths: [], tags: {}, async reload(sha1) { this.sha1 = sha1 this.paths = [] this.tags = {} let resp = await call('info', {sha1: sha1}) this.paths = resp.paths this.tags = resp.tags }, } let View = { oninit(vnode) { let sha1 = vnode.attrs.key || "" ViewModel.reload(sha1) }, view(vnode) { return m('.container', {}, [ m('.header', {}, "View"), ViewModel.sha1 !== undefined ? m('img', {src: `/image/${ViewModel.sha1}`}) : "No image.", m('h2', "Locations"), m('ul', ViewModel.paths.map(sd => m('li', sd))), m('h2', "Tags"), Object.entries(ViewModel.tags).map(([group, tags]) => [ m("h3", group), m("ul", Object.entries(tags).map( ([tag, weight]) => m("li", `${tag}: ${weight}`))), ]), ]) }, } window.addEventListener('load', () => { m.route(document.body, "/browse/", { // The path doesn't need to be escaped, perhaps change that (":key..."). "/browse/": Browse, "/browse/:key": Browse, "/view/:key": View, "/similar/:sha1": undefined, "/tags": undefined, "/tags/:space": undefined, "/tags/:space/:tag": undefined, }) })