Replace file uploads with dropzone

This commit is contained in:
Timothy Farrell 2017-11-22 21:25:36 -06:00
parent 549d5be3f6
commit c83066082c
5 changed files with 148 additions and 38 deletions

View File

@ -10,7 +10,7 @@ import { EventEmitter } from 'events';
EventEmitter.defaultMaxListeners = 1000; // https://github.com/pouchdb/pouchdb/issues/6123 EventEmitter.defaultMaxListeners = 1000; // https://github.com/pouchdb/pouchdb/issues/6123
// Attach our root view to the DOM // Attach our root view to the DOM
createView(GalleryView, {}).mount(document.querySelector('#app')); createView(GalleryView, {}).mount(document.body);
// Start the router // Start the router
router.start('home'); router.start('home');

View File

@ -5,7 +5,6 @@
<link rel="stylesheet" href="/assets/app.css"> <link rel="stylesheet" href="/assets/app.css">
</head> </head>
<body> <body>
<div id='app'></div>
<script src="/assets/app.bundle.js"></script> <script src="/assets/app.bundle.js"></script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,75 @@
import { prop, computed } from 'frptools';
import { injectStyle, el } from '../services/style';
const CSS_DROPZONE = {
width: '200px',
height: '200px',
border: '2px #666 dashed',
borderRadius: '5px'
};
const CSS_DROPZONE_ACTIVE = {
borderStyle: 'solid',
backgroundColor: '#eee'
};
export function Dropzone(vm, model) {
const { ondrop, ondragenter, ondragleave } = model;
const enterCounter = prop(0);
enterCounter.subscribe(() => vm.redraw());
function onDragOver(evt) {
// allows the browser to accept drops.
evt.preventDefault();
}
function onDragEnter() {
enterCounter(enterCounter() + 1);
if (ondragenter) {
ondragenter();
}
}
function onDragLeave() {
enterCounter(enterCounter() - 1);
if (ondragleave) {
ondragleave();
}
}
function onDrop(evt) {
evt.preventDefault();
enterCounter(0);
if (ondrop) {
ondrop(evt.dataTransfer.files);
}
}
return function render(vm, model) {
const { className, activeClassName, class: _class, children } = model;
const class_ = Object.assign(
{
[className || injectStyle(CSS_DROPZONE)]: true,
[activeClassName || injectStyle(CSS_DROPZONE_ACTIVE)]: enterCounter() > 0
},
_class || {}
);
return el(
'div',
{
class: class_,
ondragenter: onDragEnter,
ondragover: onDragOver,
ondragleave: onDragLeave,
ondrop: onDrop
},
...children
);
};
}

View File

@ -3,8 +3,9 @@ import { ImageType } from '../data/image.js';
import { AlbumType } from '../data/album.js'; import { AlbumType } from '../data/album.js';
import { ThumbnailView } from './thumbnail.js'; import { ThumbnailView } from './thumbnail.js';
import { AlbumView } from './album.js'; import { AlbumView } from './album.js';
import { Dropzone } from './dropzone.js';
import { router, routeChanged } from '../services/router.js'; import { router, routeChanged } from '../services/router.js';
import { styled, el } from '../services/style.js'; import { injectStyle, styled, el } from '../services/style.js';
export function GalleryView(vm, model) { export function GalleryView(vm, model) {
const { db } = model; const { db } = model;
@ -28,8 +29,8 @@ export function GalleryView(vm, model) {
let laCleanup = null; let laCleanup = null;
let title = ''; let title = '';
function uploadImages(evt) { function uploadImages(files) {
Array.from(evt.currentTarget.files).forEach(ImageType.upload); Array.from(files).forEach(ImageType.upload);
} }
function deleteImage(i) { function deleteImage(i) {
@ -64,21 +65,8 @@ export function GalleryView(vm, model) {
}); });
}); });
return function(vm, model, key, opts) { function renderDropzone() {
return el('.gallery', [ return [
header([
el('div', { css: { fontSize: '20pt' } }, 'Gallery'),
el('button', { onclick: addAlbum }, 'Add Album'),
el('input#fInput', {
type: 'file',
multiple: true,
accept: 'image/jpeg',
onchange: uploadImages
})
]),
...(!data || !data.ready()
? [el('h1', 'Loading...')]
: [
el('a', { href: router.href('images') }, 'Images'), el('a', { href: router.href('images') }, 'Images'),
el('a', { href: router.href('albums') }, 'Albums'), el('a', { href: router.href('albums') }, 'Albums'),
el('h1', title), el('h1', title),
@ -91,14 +79,46 @@ export function GalleryView(vm, model) {
showTags: true, showTags: true,
remove: deleteImage remove: deleteImage
}, },
i._id + i._rev i._hash()
); );
}) })
: data().map(a => { : data().map(a => {
return vw(AlbumView, a, a._id + a._rev); return vw(AlbumView, a, a._hash());
})) }))
]) ];
]); }
return function render(vm, params, key, opts) {
if (!data || !data.ready()) {
return el('h1', 'Loading...');
}
return el(
'.gallery',
{ class: slate },
header([
el('div', { css: { fontSize: '20pt' } }, 'Gallery'),
headerRight(
{
css: { visibility: /* selectMode */ true ? 'visible' : 'hidden' }
},
[el('button', { onclick: addAlbum }, 'Add Album')]
)
]),
vw(
Dropzone,
{
className: slate,
activeClassName: 'dropHover',
ondrop: uploadImages,
type: 'file',
multiple: true, // FIXME - these don't carry through to the input tag
accept: 'image/jpeg',
children: renderDropzone()
},
'dz'
)
);
}; };
} }
@ -109,3 +129,15 @@ const header = styled({
display: 'flex', display: 'flex',
alignItems: 'center' alignItems: 'center'
}); });
const headerRight = styled({
display: 'flex',
alignItems: 'center'
});
const slate = injectStyle({
display: 'flex',
flex: 1,
flexDirection: 'column'
// overflow: 'hidden',
});

View File

@ -7,7 +7,7 @@ import find from 'pouchdb-find';
import { log, warn } from './console.js'; import { log, warn } from './console.js';
import { isObject } from '../utils/comparators.js'; import { isObject } from '../utils/comparators.js';
import { LiveArray } from '../utils/livearray.js'; import { LiveArray } from '../utils/livearray.js';
import { deepAssign } from '../utils/conversion.js'; import { deepAssign, pouchDocHash } from '../utils/conversion.js';
export const PouchDB = core export const PouchDB = core
.plugin(idb) .plugin(idb)
@ -43,6 +43,10 @@ export class TypeSpec {
return doc; return doc;
} }
_hash() {
return pouchDocHash(this);
}
async delete() { async delete() {
return await this.update({ _deleted: true }); return await this.update({ _deleted: true });
} }