Gallery -> DOMVM GalleryView

The whole app is converted to be base in DOMVM now.  But there are bugs.
This commit is contained in:
Timothy Farrell 2017-09-29 16:54:08 -05:00
parent ccfd757aed
commit e1c1c0e18a
9 changed files with 147 additions and 71 deletions

View File

@ -21,6 +21,7 @@
"pouchdb-binary-utils": "~6.1.2",
"pouchdb-core": "~6.1.2",
"pouchdb-replication": "~6.1.2",
"router": "2.0.0",
"webpack": "^2.3.3"
},
"devDependencies": {

View File

@ -1,68 +1,50 @@
import { createView } from 'domvm';
import { createView } from 'domvm/dist/dev/domvm.dev.js';
import * as image from './data/image.js';
import * as index from './data/indexType.js';
import { getDatabase } from './services/db.js';
import * as imageTag from './context/manageImageTags.js';
import generateThumbnails from './contextLoaders/generateThumbnails.js';
import { ImageView } from './interface/image.js';
import { AlbumView } from './interface/album.js';
import { GalleryView } from './interface/gallery.js';
import { router, routeChanged } from './services/router.js';
window.__DEV__ = true;
window.db = getDatabase();
image.imported.subscribe(refresh);
image.imported.subscribe(generateThumbnails);
image.removed.subscribe(refresh);
index.added.subscribe(refresh);
index.removed.subscribe(refresh);
const header = document.querySelector('h1');
const container = document.querySelector('#app');
const displaySelector = document.querySelector('#display');
// Events
displaySelector.onchange = refresh;
document.querySelector('#fInput').onchange = async evt => {
image.add(evt.currentTarget.files);
const NAV_OPTIONS = {
images: {
model: image,
title: 'Images'
},
albums: {
model: index,
title: 'Albums'
}
};
// To test the output:
function refresh() {
setTimeout(render, 100);
}
async function render() {
container.innerHTML = '';
if (displaySelector.value === 'i') {
header.innerText = 'Images';
const results = await image.find({ attachments: true });
results.rows.forEach(i => {
createView(ImageView, {
imageRow: i,
imageContainer: container,
showTags: true,
remove: image.remove,
removeTag: imageTag.remove
}).mount(container);
});
} else {
header.innerText = 'Albums';
const results = await index.find({ attachments: true });
results.rows.forEach(i => {
createView(AlbumView, {
albumRow: i,
remove: imageTag.remove
}).mount(container);
async function update(route) {
const o = NAV_OPTIONS[route.name];
gallery.update({
title: o.title,
members: (await o.model.find({ attachments: true })).rows
});
}
Array.from(document.querySelectorAll('.image')).forEach(i => {
const b = document.createElement('button');
b.onclick = evt => imageTag.add(prompt('Tag Name'), i.id);
b.textContent = '+';
i.appendChild(b);
});
function redraw() {
update(router.current());
}
function onRouteChange(router, route) {
update(route);
}
render();
image.imported.subscribe(generateThumbnails);
image.imported.subscribe(redraw);
image.removed.subscribe(redraw);
index.added.subscribe(redraw);
index.removed.subscribe(redraw);
routeChanged.subscribe(onRouteChange);
const gallery = createView(GalleryView, {
title: '',
members: []
}).mount(document.querySelector('#app'));
router.start('home');

View File

@ -5,12 +5,6 @@
<link rel="stylesheet" href="">
</head>
<body>
<input id='fInput' type="file" multiple accept="image/jpeg"/>
<select id='display' value='i'>
<option value='i'>Images</option>
<option value='a'>Albums</option>
</select>
<h1></h1>
<div id='app'></div>
<script src="/assets/app.bundle.js"></script>
</body>

View File

@ -8,9 +8,10 @@ export function AlbumView(vm, model) {
const title = props.title;
let images = [];
// FIXME - If the album is updated, this does not properly refresh.
image.find(members, { attachments: true }).then(res => {
images = res.rows.filter(i => i.doc);
vm.redraw(true);
vm.redraw();
});
function removeImageFromAlbum(id, rev) {
@ -21,11 +22,15 @@ export function AlbumView(vm, model) {
return el('.album', [
el('h2', [title]),
...images.map(i => {
return defineView(ImageView, {
return defineView(
ImageView,
{
imageRow: i,
showTags: false,
remove: removeImageFromAlbum
});
},
i._id
);
})
]);
};

View File

@ -0,0 +1,53 @@
import { defineView, defineElement as el } from 'domvm';
import * as image from '../data/image.js';
import * as imageTag from '../context/manageImageTags.js';
import { ImageView } from './image.js';
import { AlbumView } from './album.js';
import { router } from '../services/router.js';
export function GalleryView(vm, model) {
function uploadImages(evt) {
image.add(evt.currentTarget.files);
}
return function(vm, model, key, opts) {
const { title, members } = model;
return el('.gallery', [
el('input#fInput', {
type: 'file',
multiple: true,
accept: 'image/jpeg',
onchange: uploadImages
}),
el('a', { href: router.href('images') }, 'Images'),
el('a', { href: router.href('albums') }, 'Albums'),
el('h1', title),
...(title === 'Images'
? members.map(i => {
return defineView(
ImageView,
{
imageRow: i,
showTags: true,
addTag: imageTag.add,
remove: image.remove,
removeTag: imageTag.remove
},
i._id
);
})
: members.map(a => {
return defineView(
AlbumView,
{
albumRow: a,
addTag: imageTag.add,
remove: imageTag.remove
},
a._id
);
}))
]);
};
}

View File

@ -2,8 +2,14 @@ import { defineView, defineElement as el } from 'domvm';
import { ThumbnailView } from './thumbnail.js';
export function ImageView(vm, model) {
const { addTag } = model;
function onAddTag(image_id) {
addTag(prompt('Tag Name'), image_id);
}
return function(vm, model, key, opts) {
const { imageRow, showTags, remove, removeTag } = model;
const { imageRow, showTags, remove, addTag, removeTag } = model;
const { doc } = imageRow;
const { thumbnail } = doc._attachments;
const _showTags = showTags !== undefined ? showTags : true;
@ -18,7 +24,8 @@ export function ImageView(vm, model) {
tags: _showTags ? doc.tags : [],
remove: remove,
removeTag: removeTag
})
}),
addTag ? el('button', { onclick: [onAddTag, doc._id] }, '+') : null
]);
}

View File

@ -1,10 +1,8 @@
import { defineElement as el } from 'domvm';
export function ThumbnailView(vm, model) {
const { remove, removeTag } = model;
return function(vm, model, key, opts) {
const { id, rev, name, doc, tags } = model;
const { id, rev, name, doc, tags, remove, removeTag } = model;
const filteredTags = Object.entries(tags).filter(([_, visible]) => visible);
return el(`figure#${id}.image`, [

View File

@ -0,0 +1,31 @@
import { Router } from 'router';
import { Event } from '../utils/event.js';
export const routeChanged = new Event('Router.newRoute');
const fire = routeChanged.fire.bind(routeChanged);
export const router = Router([
{
name: 'home',
path: '/',
enter: (r, route) => {
r.goto('images');
}
},
{
name: 'images',
path: '/images',
enter: fire
},
{
name: 'albums',
path: '/albums',
enter: fire
},
{
id: '404',
path: ':vars',
enter: r => r.goto('home')
}
]);

View File

@ -14,5 +14,10 @@ module.exports = {
devServer: {
contentBase: path.resolve(__dirname, './src')
},
plugins: [
new webpack.DefinePlugin({
__DEV__: true
})
],
devtool: 'source-map'
};