diff options
| -rw-r--r-- | main.go | 16 | ||||
| -rw-r--r-- | public/gallery.js | 59 | 
2 files changed, 54 insertions, 21 deletions
@@ -183,7 +183,6 @@ func handleThumbs(w http.ResponseWriter, r *http.Request) {  func getSubdirectories(tx *sql.Tx, parent int64) (names []string, err error) {  	// TODO: This is like dbCollectStrings(), just needs an argument. -	// TODO: Should this return full paths, or not? Clean it up.  	rows, err := tx.Query(  		`SELECT name FROM directory WHERE IFNULL(parent, 0) = ?`, parent)  	if err != nil { @@ -282,7 +281,7 @@ func getImagePaths(sha1 string) (paths []string, err error) {  		UNION ALL  		SELECT d.parent, d.name || '/' || p.path  		FROM directory AS d JOIN paths AS p ON d.id = p.parent -	) SELECT '/' || path FROM paths WHERE parent IS NULL`, sha1) +	) SELECT path FROM paths WHERE parent IS NULL`, sha1)  	if err != nil {  		return nil, err  	} @@ -430,16 +429,15 @@ func idForPath(tx *sql.Tx, path []string, create bool) (int64, error) {  }  func decodeWebPath(path string) []string { -	// Trailing slashes don't provide information. -	path = strings.TrimSuffix(path, "/") -  	// Relative paths could be handled differently,  	// but right now, they're assumed to start at the root. -	list := strings.Split(path, "/") -	if len(list) > 0 && list[0] == "" { -		list = list[1:] +	result := []string{} +	for _, crumb := range strings.Split(path, "/") { +		if crumb != "" { +			result = append(result, crumb) +		}  	} -	return list +	return result  }  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/gallery.js b/public/gallery.js index d25c544..940b0d2 100644 --- a/public/gallery.js +++ b/public/gallery.js @@ -14,35 +14,64 @@ let BrowseModel = {  	entries: [],  	async reload(path) { -		this.path = path -		this.subdirectories = [] -		this.entries = [] +		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 responsibility. +	// 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 || "/" +		let path = vnode.attrs.key || ""  		BrowseModel.reload(path)  	},  	view(vnode) {  		return m('.container', {}, [  			m('.header', {}, "Browse"), -			m('h1', "Root"), -			m('ul', BrowseModel.subdirectories.map(sd => { -				const name = sd.split('/').pop() +			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: `${BrowseModel.path}/${sd}`}, -				}, name)) +					params: {key: link.path}, +				}, `${link.level} ${link.name}`))  			})),  			m('.browser', {}, BrowseModel.entries.map(e => {  				return m(m.route.Link, {href: `/view/${e.sha1}`}, @@ -76,13 +105,19 @@ let View = {  	},  	view(vnode) { -		// TODO: Show more information.  		return m('.container', {}, [  			m('.header', {}, "View"), -			m('ul', ViewModel.paths.map(sd => m('li', sd))),  			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}`))), +			]),  		])  	},  }  | 
