life-diary
Version:
Life Diary ❤️ your albums, your journey, your data
233 lines (202 loc) • 6.45 kB
HTML
<style>
ld-album {
display: block;
}
</style>
<style scoped>
form > fieldset {
border: 0;
}
fieldset > legend {
display: none;
}
form {
display: flex;
align-items: center;
flex-direction: row;
min-height: 100px;
}
form > h1 {
flex-grow: 1;
margin: 0;
display: flex;
align-items: center;
}
form > h1 > button.remover {
padding: 16px;
}
div[ref="list"] {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
</style>
<ld-album>
<form ref="form" onsubmit={{preventDefault}}
method="post" action="/upload" enctype="multipart/form-data">
<h1>
<button title="Home" class="remover" onclick={{home}}>🏡</button>
{{album}}
</h1>
<fieldset>
<legend>Upload new files</legend>
<input onchange={{uploadFiles}} type="file" name="upload"
accept="audio/*,image/*,video/*,.jpeg,.jpg,.JPEG,.JPG,.HEIC,.heic" multiple required>
<ld-progress ref="progress"></ld-progress>
</fieldset>
</form>
<masonry-rows ref="list"></masonry-rows>
</ld-album>
<script type="module">
/**
* ISC License
*
* Copyright (c) 2020, Andrea Giammarchi, @WebReflection
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
*/
import {render, html, ref} from '@uce';
const cursor = {
char: ['⠦', '⠧', '⠇', '⠏', '⠋', '⠙', '⠹', '⠸', '⠼', '⠴'],
i: 0,
next() {
if (this.i < 0)
this.i = 0;
return this.char[this.i++ % this.char.length];
}
};
export default {
props: {data: {}},
setup(element) {
const renderFiles = files => {
const fullscreen = event => {
let {currentTarget, target} = event;
if (/^a$/i.test(target.nodeName))
target = target.firstElementChild;
if (/^(?:img|video)$/i.test(target.nodeName)) {
event.preventDefault();
element.data.fullscreen.fullscreen(files, files.indexOf(currentTarget.data));
}
};
const removeMedia = ({detail: file}) => {
const i = files.indexOf(file);
if (-1 < i) {
files.splice(i, 1);
renderFiles(files);
}
};
render(ref(element).list, html.for(files, 'album')`
${files.map(file => html.for(file, 'media-preview')`
<ld-media-preview
onclick=${fullscreen}
ondeleted=${removeMedia}
.data=${file}
/>
`)}
`);
};
element.connected = () => {
renderFiles(element.data.files);
};
return {
get album() { return element.data.album; },
preventDefault(event) {
event.preventDefault();
},
home(event) {
event.preventDefault();
event.stopImmediatePropagation();
element.data.listAlbums();
},
uploadFiles() {
const {data} = element;
const {form, progress} = ref(element);
const {upload} = form;
const {disabled, files: uploads} = upload;
if (disabled || uploads.length < 1)
return;
const {reduce} = [];
const sum = (total, {size}) => total + size;
const method = 'POST';
navigator.wakeLock.request('screen').then(wakeLock => {
const max = reduce.call(uploads, sum, 0);
const {length} = uploads;
let uploading = true;
let nextValue = 0;
let value = 0;
let isMOV = false;
progress.max = max;
progress.value = value;
progress.details = `processing 0/${length}`;
upload.disabled = true;
const fail = () => {
uploadFile(length);
alert(`Unable to upload ${uploads[i].name}`);
};
const uploadFile = i => {
if (i === length) {
data.fetching = false;
upload.value = '';
progress.details = '';
upload.disabled = uploading = false;
wakeLock.release();
}
else {
isMOV = /\.mov$/i.test(uploads[i].name);
nextValue += uploads[i].size;
const encoded = encodeURIComponent(element.data.album);
const body = new FormData();
body.append('upload', uploads[i]);
fetch(
`${form.action}?album=${encoded}`,
{method, body}
)
.then(res => res.json())
.then(file => {
if (file) {
data.files.push(file);
progress.details = `processing ${++i + 1}/${length}`;
renderFiles(data.files);
uploadFile(i);
}
else
fail();
})
.catch(fail);
}
};
data.fetching = true;
uploadFile(0);
let frames = 0;
(function update() {
if (uploading) {
value += (nextValue - value) * (isMOV ? .005 : .02);
progress.value = value;
if (!(frames++ % 6))
progress.spinner = cursor.next();
requestAnimationFrame(update);
}
else {
progress.value = 0;
progress.spinner = '';
}
}());
}, () => {
alert('Please confirm lock-screen to upload');
});
}
};
}
};
</script>