Add album view
This commit is contained in:
parent
9c465cd405
commit
ccd0fafd9e
@ -1,62 +1,94 @@
|
|||||||
import * as image from './data/image.js';
|
import * as image from './data/image.js';
|
||||||
|
import * as index from './data/indexType.js';
|
||||||
import { getDatabase } from './services/db.js';
|
import { getDatabase } from './services/db.js';
|
||||||
import * as imageTag from './context/manageImageTags.js';
|
import * as imageTag from './context/manageImageTags.js';
|
||||||
|
|
||||||
import './context/generateThumbnails.js';
|
import './context/generateThumbnails.js';
|
||||||
|
|
||||||
document.querySelector('#fInput').onchange = async evt => {
|
|
||||||
image.add(evt.currentTarget.files);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.__DEV__ = true;
|
window.__DEV__ = true;
|
||||||
window.db = getDatabase();
|
window.db = getDatabase();
|
||||||
|
|
||||||
image.imported.subscribe(refresh);
|
image.imported.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);
|
||||||
|
};
|
||||||
|
|
||||||
// To test the output:
|
// To test the output:
|
||||||
function refresh() {
|
function refresh() {
|
||||||
setTimeout(() => history.go(0), 100);
|
setTimeout(render, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.allDocs({ include_docs: true, attachments: true }).then(async results => {
|
function renderThumbnail(id, name, doc, tags) {
|
||||||
results.rows.forEach(r => {
|
const c = document.createElement('div');
|
||||||
const doc = r.doc;
|
const e = document.createElement('img');
|
||||||
});
|
|
||||||
|
|
||||||
function renderThumbnail(id, name, doc, tags) {
|
c.appendChild(e);
|
||||||
const c = document.createElement('div');
|
c.id = id;
|
||||||
const e = document.createElement('img');
|
c.className = 'image';
|
||||||
|
e.title = `${id} ${name}`;
|
||||||
|
e.src = `data:${doc.content_type};base64,${doc.data}`;
|
||||||
|
e.dataset.id = id;
|
||||||
|
e.onclick = evt => image.remove(evt.currentTarget.dataset.id).then(refresh);
|
||||||
|
|
||||||
c.appendChild(e);
|
Object.entries(tags)
|
||||||
c.id = id;
|
.filter(([_, visible]) => visible)
|
||||||
c.className = 'image';
|
.forEach(([title, _]) => {
|
||||||
e.title = `${id} ${name}`;
|
const t = document.createElement('span');
|
||||||
e.src = `data:${doc.content_type};base64,${doc.data}`;
|
t.textContent = title;
|
||||||
e.dataset.id = id;
|
t.className = 'tag';
|
||||||
e.onclick = evt => image.remove(evt.currentTarget.dataset.id).then(refresh);
|
t.onclick = evt => imageTag.remove(title, id).then(refresh);
|
||||||
|
c.appendChild(t);
|
||||||
|
});
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
Object.entries(tags)
|
function renderImage(imageRow, imageContainer, showTags = true) {
|
||||||
.filter(([_, visible]) => visible)
|
for (let aName in imageRow.doc._attachments) {
|
||||||
.forEach(([title, _]) => {
|
if (aName !== 'thumbnail') {
|
||||||
const t = document.createElement('span');
|
continue;
|
||||||
t.textContent = title;
|
|
||||||
t.className = 'tag';
|
|
||||||
t.onclick = evt => imageTag.remove(title, id).then(refresh);
|
|
||||||
c.appendChild(t);
|
|
||||||
});
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
results.rows.forEach(r => {
|
|
||||||
for (let aName in r.doc._attachments) {
|
|
||||||
if (aName !== 'thumbnail') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
document.body.appendChild(
|
|
||||||
renderThumbnail(r.doc._id, aName, r.doc._attachments[aName], r.doc.tags)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
imageContainer.appendChild(
|
||||||
|
renderThumbnail(
|
||||||
|
imageRow.doc._id,
|
||||||
|
aName,
|
||||||
|
imageRow.doc._attachments[aName],
|
||||||
|
showTags ? imageRow.doc.tags : []
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderAlbum(indexRow) {
|
||||||
|
const doc = indexRow.doc;
|
||||||
|
const l = document.createElement('h2');
|
||||||
|
l.innerText = indexRow.doc.props.title;
|
||||||
|
container.appendChild(l);
|
||||||
|
|
||||||
|
const albumContainer = document.createElement('div');
|
||||||
|
container.appendChild(albumContainer);
|
||||||
|
|
||||||
|
const results = await image.find(doc.members, { attachments: true });
|
||||||
|
results.rows.filter(i => i.doc).forEach(i => renderImage(i, albumContainer, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function render() {
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
if (displaySelector.value === 'i') {
|
||||||
|
header.innerText = 'Images';
|
||||||
|
const results = await image.find({ attachments: true });
|
||||||
|
results.rows.forEach(i => renderImage(i, container));
|
||||||
|
} else {
|
||||||
|
header.innerText = 'Albums';
|
||||||
|
const results = await index.find({ attachments: true });
|
||||||
|
results.rows.forEach(renderAlbum);
|
||||||
|
}
|
||||||
|
|
||||||
Array.from(document.querySelectorAll('.image')).forEach(i => {
|
Array.from(document.querySelectorAll('.image')).forEach(i => {
|
||||||
const b = document.createElement('button');
|
const b = document.createElement('button');
|
||||||
@ -64,4 +96,6 @@ db.allDocs({ include_docs: true, attachments: true }).then(async results => {
|
|||||||
b.textContent = '+';
|
b.textContent = '+';
|
||||||
i.appendChild(b);
|
i.appendChild(b);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
render();
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import * as index from '../data/indexType.js';
|
|||||||
|
|
||||||
export async function add(title, imageId, visible = true) {
|
export async function add(title, imageId, visible = true) {
|
||||||
const trimmedTitle = title.trim();
|
const trimmedTitle = title.trim();
|
||||||
await index.add(trimmedTitle, [imageId]);
|
await index.add(trimmedTitle, { title: trimmedTitle }, [imageId]);
|
||||||
return image.update(imageId, {
|
return image.update(imageId, {
|
||||||
tags: { [trimmedTitle]: visible }
|
tags: { [trimmedTitle]: visible }
|
||||||
});
|
});
|
||||||
@ -14,3 +14,7 @@ export async function remove(title, imageId) {
|
|||||||
await image.update(imageId, { tags: { [title]: undefined } });
|
await image.update(imageId, { tags: { [title]: undefined } });
|
||||||
await index.removeMember(title, imageId);
|
await index.removeMember(title, imageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image.removed.subscribe(image => {
|
||||||
|
Object.keys(image.tags).forEach(t => index.removeMember(t, image._id));
|
||||||
|
});
|
||||||
|
|||||||
@ -8,13 +8,26 @@ import { Event, backgroundTask } from '../utils/event.js';
|
|||||||
|
|
||||||
const db = getDatabase();
|
const db = getDatabase();
|
||||||
const PROCESS_PREFIX = 'importing';
|
const PROCESS_PREFIX = 'importing';
|
||||||
|
const PREFIX = 'image';
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
export const imported = new Event('Image.imported');
|
export const imported = new Event('Image.imported');
|
||||||
|
export const removed = new Event('Image.removed');
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
const getId = id => (id.startsWith(PREFIX) ? id : `${PREFIX}_${id}`);
|
||||||
|
|
||||||
export async function find(keys, options = {}) {
|
export async function find(keys, options = {}) {
|
||||||
return await db.allDocs(Object.assign({ include_docs: true }, options, { keys }));
|
let opts = { include_docs: true };
|
||||||
|
if (Array.isArray(keys)) {
|
||||||
|
Object.assign(opts, options);
|
||||||
|
opts.keys = keys.map(getId);
|
||||||
|
} else {
|
||||||
|
Object.assign(opts, keys);
|
||||||
|
opts.startkey = `${PREFIX}_0`;
|
||||||
|
opts.endkey = `${PREFIX}_\ufff0`;
|
||||||
|
}
|
||||||
|
return await db.allDocs(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function add(imageFileList) {
|
export async function add(imageFileList) {
|
||||||
@ -45,6 +58,9 @@ export async function remove(ids, rev) {
|
|||||||
try {
|
try {
|
||||||
const doc = rev ? { _id: ids, _rev: rev } : await db.get(ids);
|
const doc = rev ? { _id: ids, _rev: rev } : await db.get(ids);
|
||||||
await db.remove(doc);
|
await db.remove(doc);
|
||||||
|
if (doc._id.startsWith(PREFIX)) {
|
||||||
|
removed.fire(doc);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.status !== 404) {
|
if (e.status !== 404) {
|
||||||
@ -76,8 +92,8 @@ export async function addAttachment(doc, key, blob) {
|
|||||||
// Internal Functions
|
// Internal Functions
|
||||||
const processImportables = backgroundTask(async function _processImportables() {
|
const processImportables = backgroundTask(async function _processImportables() {
|
||||||
const result = await db.allDocs({
|
const result = await db.allDocs({
|
||||||
startkey: `${PROCESS_PREFIX}_0`,
|
startkey: `${PROCESS_PREFIX}_`,
|
||||||
endkey: `${PROCESS_PREFIX}_z`,
|
endkey: `${PROCESS_PREFIX}_\ufff0`,
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
attachments: true,
|
attachments: true,
|
||||||
binary: true,
|
binary: true,
|
||||||
@ -97,7 +113,7 @@ const processImportables = backgroundTask(async function _processImportables() {
|
|||||||
tags.DateTimeOriginal ? new Date(tags.DateTimeOriginal * 1000).toISOString() : doc.modifiedDate
|
tags.DateTimeOriginal ? new Date(tags.DateTimeOriginal * 1000).toISOString() : doc.modifiedDate
|
||||||
);
|
);
|
||||||
const { _id, _rev } = doc;
|
const { _id, _rev } = doc;
|
||||||
const id = `image_${originalDate.getTime().toString(36)}_${digest.substr(0, 6)}`;
|
const id = `${PREFIX}_${originalDate.getTime().toString(36)}_${digest.substr(0, 6)}`;
|
||||||
|
|
||||||
let continueProcessing = true;
|
let continueProcessing = true;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -13,13 +13,23 @@ export const hashString = name =>
|
|||||||
const getId = id => (id.startsWith(PREFIX) ? id : `${PREFIX}_${hashString(id)}`);
|
const getId = id => (id.startsWith(PREFIX) ? id : `${PREFIX}_${hashString(id)}`);
|
||||||
|
|
||||||
export async function find(keys, options = {}) {
|
export async function find(keys, options = {}) {
|
||||||
return await db.allDocs(Object.assign({ include_docs: true }, options, { keys: keys.map(getId) }));
|
let opts = { include_docs: true };
|
||||||
|
if (Array.isArray(keys)) {
|
||||||
|
Object.assign(opts, options);
|
||||||
|
opts.keys = keys.map(getId);
|
||||||
|
} else {
|
||||||
|
Object.assign(opts, keys);
|
||||||
|
opts.startkey = `${PREFIX}_`;
|
||||||
|
opts.endkey = `${PREFIX}_\ufff0`;
|
||||||
|
}
|
||||||
|
return await db.allDocs(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function add(id, members = []) {
|
export async function add(id, props = {}, members = []) {
|
||||||
const _id = getId(id);
|
const _id = getId(id);
|
||||||
const [results, created] = await getOrCreate({
|
const [results, created] = await getOrCreate({
|
||||||
_id,
|
_id,
|
||||||
|
props,
|
||||||
members: []
|
members: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
<body>
|
<body>
|
||||||
<div>
|
<input id='fInput' type="file" multiple accept="image/jpeg"/>
|
||||||
Images
|
<select id='display' value='i'>
|
||||||
<input id='fInput' type="file" multiple accept="image/jpeg"/>
|
<option value='i'>Images</option>
|
||||||
</div>
|
<option value='a'>Albums</option>
|
||||||
|
</select>
|
||||||
|
<h1></h1>
|
||||||
|
<div id='app'></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<script src="/assets/app.bundle.js"></script>
|
<script src="/assets/app.bundle.js"></script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user