diff --git a/packages/gallery/src/interface/attachmentImage.js b/packages/gallery/src/interface/attachmentImage.js new file mode 100644 index 0000000..c51b475 --- /dev/null +++ b/packages/gallery/src/interface/attachmentImage.js @@ -0,0 +1,62 @@ +import { defineElement as el } from 'domvm'; +import { prop, computed, bundle } from 'frptools'; + +import * as imageType from '../data/image.js'; + +export function AttachmentImageView(vm, params) { + const model = bundle({ + doc: prop(params.src), + attachmentKey: prop(params.attachmentKey || 'image') + }); + + const blobURL = prop(''); + + const imageID = computed(doc => doc._id, [model.doc]); + const imageURL = computed((doc, key, bURL) => bURL || doc.attachmentUrls[key], [ + model.doc, + model.attachmentKey, + blobURL + ]); + const imageSignature = computed((id, key) => id + ' ' + key, [imageID, model.attachmentKey]); + + async function loadImageFromBlob() { + const id = imageID(); + const key = model.attachmentKey(); + + try { + const data = await imageType.getAttachment(id, key); + if (blobURL()) { + URL.revokeObjectURL(blobURL()); + } + blobURL(URL.createObjectURL(data)); + } catch (err) { + // Probably hasn't created the thumbnail yet. + console.log("Probably hasn't created the thumbnail yet.", err); + } + } + + function cleanup() { + redrawOff(); + URL.revokeObjectURL(blobURL()); + } + + const redrawOff = imageURL.subscribe(() => vm.redraw()); + + return function render(vm, params) { + const imgSig = imageSignature(); + model(params); + if (imgSig !== imageSignature()) { + URL.revokeObjectURL(blobURL()); + blobURL(''); + } + + return el('img', { + src: imageURL(), + onerror: loadImageFromBlob, + _key: imageSignature(), + _hooks: { + didRemove: cleanup + } + }); + }; +} diff --git a/packages/gallery/src/interface/thumbnail.js b/packages/gallery/src/interface/thumbnail.js index 581ddbb..459dec0 100644 --- a/packages/gallery/src/interface/thumbnail.js +++ b/packages/gallery/src/interface/thumbnail.js @@ -1,12 +1,11 @@ -import { defineView, defineElement as el } from 'domvm'; +import { defineView as vw, defineElement as el } from 'domvm'; import { prop, computed } from 'frptools'; import * as image from '../data/image.js'; +import { AttachmentImageView } from './attachmentImage.js'; export function ThumbnailView(vm, model) { const { addTag } = model; - const imageData = prop(null); - let imageId = null; function onAddTag(image_id) { addTag(prompt('Tag Name'), image_id); @@ -17,31 +16,17 @@ export function ThumbnailView(vm, model) { const { _id: id, _rev: rev, tags } = doc; const _showTags = showTags !== undefined ? showTags : true; const filteredTags = _showTags ? Object.entries(doc.tags).filter(([_, visible]) => visible) : []; - if (imageId !== id) { - image - .getAttachment(id, 'thumbnail') - .then(thumbnail => { - if (imageData()) { - URL.revokeObjectURL(imageData()); - } - imageData(URL.createObjectURL(thumbnail)); - vm.redraw(); - }) - .catch(err => { - // Probably hasn't created the thumbnail yet. - console.log("Probably hasn't created the thumbnail yet.", err); - imageId = null; - }); - imageId = id; - } - if (imageData()) { - return el('div', { _key: id }, [ - el(`figure#${doc._id}.image`, [ - el('img', { - src: imageData(), - title: `${id} ${name}`, - onclick: [remove, id, rev] + return el('div', { _key: id }, [ + el( + `figure#${doc._id}.image`, + { + onclick: { img: [remove, id, rev] } + }, + [ + vw(AttachmentImageView, { + src: doc, + attachmentKey: 'thumbnail' }), filteredTags.length ? el( @@ -51,11 +36,9 @@ export function ThumbnailView(vm, model) { ) ) : null - ]), - addTag ? el('button', { onclick: [onAddTag, id] }, '+') : null - ]); - } - - return el('span'); + ] + ), + addTag ? el('button', { onclick: [onAddTag, id] }, '+') : null + ]); }; }