szurubooru/client/js/views/post_upload_view.js

397 lines
11 KiB
JavaScript
Raw Normal View History

2016-08-20 22:40:25 +02:00
'use strict';
const events = require('../events.js');
const views = require('../util/views.js');
const FileDropperControl = require('../controls/file_dropper_control.js');
const template = views.getTemplate('post-upload');
const rowTemplate = views.getTemplate('post-upload-row');
function _mimeTypeToPostType(mimeType) {
return {
'application/x-shockwave-flash': 'flash',
'image/gif': 'image',
'image/jpeg': 'image',
'image/png': 'image',
'video/mp4': 'video',
'video/webm': 'video',
}[mimeType] || 'unknown';
}
2016-08-20 22:40:25 +02:00
class Uploadable extends events.EventTarget {
constructor() {
super();
this.lookalikes = [];
this.lookalikesConfirmed = false;
2016-08-20 22:40:25 +02:00
this.safety = 'safe';
this.flags = [];
this.tags = [];
this.relations = [];
2016-08-20 22:40:25 +02:00
this.anonymous = false;
}
destroy() {
}
get mimeType() {
return 'application/octet-stream';
}
2016-08-20 22:40:25 +02:00
get type() {
return _mimeTypeToPostType(this.mimeType);
2016-08-20 22:40:25 +02:00
}
get key() {
throw new Error('Not implemented');
}
get name() {
throw new Error('Not implemented');
}
_initComplete() {
if (['video'].includes(this.type)) {
this.flags.push('loop');
}
}
2016-08-20 22:40:25 +02:00
}
class File extends Uploadable {
constructor(file) {
super();
this.file = file;
this._previewUrl = null;
if (URL && URL.createObjectURL) {
this._previewUrl = URL.createObjectURL(file);
} else {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.addEventListener('load', e => {
this._previewUrl = e.target.result;
this.dispatchEvent(
new CustomEvent('finish', {detail: {uploadable: this}}));
});
}
this._initComplete();
}
destroy() {
if (URL && URL.createObjectURL && URL.revokeObjectURL) {
URL.revokeObjectURL(this._previewUrl);
}
2016-08-20 22:40:25 +02:00
}
get mimeType() {
return this.file.type;
2016-08-20 22:40:25 +02:00
}
get previewUrl() {
return this._previewUrl;
2016-08-20 22:40:25 +02:00
}
get key() {
return this.file.name + this.file.size;
}
get name() {
return this.file.name;
}
}
class Url extends Uploadable {
constructor(url) {
super();
this.url = url;
this.dispatchEvent(new CustomEvent('finish'));
this._initComplete();
2016-08-20 22:40:25 +02:00
}
get mimeType() {
let mime = {
'swf': 'application/x-shockwave-flash',
'jpg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'mp4': 'video/mp4',
'webm': 'video/webm',
2016-08-20 22:40:25 +02:00
};
for (let extension of Object.keys(mime)) {
2016-08-20 22:40:25 +02:00
if (this.url.toLowerCase().indexOf('.' + extension) !== -1) {
return mime[extension];
2016-08-20 22:40:25 +02:00
}
}
return 'unknown';
}
get previewUrl() {
2016-08-20 22:40:25 +02:00
return this.url;
}
get key() {
return this.url;
}
get name() {
return this.url;
}
}
class PostUploadView extends events.EventTarget {
constructor(ctx) {
2016-08-20 22:40:25 +02:00
super();
this._ctx = ctx;
2016-08-20 22:40:25 +02:00
this._hostNode = document.getElementById('content-holder');
2016-09-29 21:36:59 +02:00
2016-08-20 22:40:25 +02:00
views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
2016-09-29 21:36:59 +02:00
this._cancelButtonNode.disabled = true;
this._uploadables = [];
this._uploadables.find = u => {
return this._uploadables.findIndex(u2 => u.key === u2.key);
};
2016-08-20 22:40:25 +02:00
this._contentFileDropper = new FileDropperControl(
this._contentInputNode,
{
allowUrls: true,
allowMultiple: true,
lock: false,
});
this._contentFileDropper.addEventListener(
'fileadd', e => this._evtFilesAdded(e));
this._contentFileDropper.addEventListener(
'urladd', e => this._evtUrlsAdded(e));
2016-09-29 21:36:59 +02:00
this._cancelButtonNode.addEventListener(
'click', e => this._evtCancelButtonClick(e));
2016-08-20 22:40:25 +02:00
this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
this._formNode.classList.add('inactive');
}
enableForm() {
views.enableForm(this._formNode);
2016-09-29 21:36:59 +02:00
this._cancelButtonNode.disabled = true;
this._formNode.classList.remove('uploading');
2016-08-20 22:40:25 +02:00
}
disableForm() {
views.disableForm(this._formNode);
2016-09-29 21:36:59 +02:00
this._cancelButtonNode.disabled = false;
this._formNode.classList.add('uploading');
2016-08-20 22:40:25 +02:00
}
clearMessages() {
views.clearMessages(this._hostNode);
}
showSuccess(message) {
views.showSuccess(this._hostNode, message);
}
showError(message, uploadable) {
this._showMessage(views.showError, message, uploadable);
}
showInfo(message, uploadable) {
this._showMessage(views.showInfo, message, uploadable);
views.appendExclamationMark();
}
_showMessage(functor, message, uploadable) {
functor(uploadable ? uploadable.rowNode : this._hostNode, message);
2016-08-20 22:40:25 +02:00
}
addUploadables(uploadables) {
this._formNode.classList.remove('inactive');
let duplicatesFound = 0;
for (let uploadable of uploadables) {
if (this._uploadables.find(uploadable) !== -1) {
2016-08-20 22:40:25 +02:00
duplicatesFound++;
continue;
}
this._uploadables.push(uploadable);
2016-08-20 22:40:25 +02:00
this._emit('change');
this._renderRowNode(uploadable);
2016-08-20 22:40:25 +02:00
uploadable.addEventListener(
'finish', e => this._updateThumbnailNode(e.detail.uploadable));
2016-08-20 22:40:25 +02:00
}
if (duplicatesFound) {
let message = null;
if (duplicatesFound < uploadables.length) {
message = 'Some of the files were already added ' +
'and have been skipped.';
} else if (duplicatesFound === 1) {
message = 'This file was already added.';
} else {
message = 'These files were already added.';
}
alert(message);
}
}
removeUploadable(uploadable) {
if (this._uploadables.find(uploadable) === -1) {
2016-08-20 22:40:25 +02:00
return;
}
uploadable.destroy();
2016-08-20 22:40:25 +02:00
uploadable.rowNode.parentNode.removeChild(uploadable.rowNode);
this._uploadables.splice(this._uploadables.find(uploadable), 1);
2016-08-20 22:40:25 +02:00
this._emit('change');
if (!this._uploadables.length) {
2016-08-20 22:40:25 +02:00
this._formNode.classList.add('inactive');
this._submitButtonNode.value = 'Upload all';
2016-08-20 22:40:25 +02:00
}
}
updateUploadable(uploadable) {
uploadable.lookalikesConfirmed = true;
this._renderRowNode(uploadable);
}
2016-08-20 22:40:25 +02:00
_evtFilesAdded(e) {
this.addUploadables(e.detail.files.map(file => new File(file)));
}
_evtUrlsAdded(e) {
this.addUploadables(e.detail.urls.map(url => new Url(url)));
}
2016-09-29 21:36:59 +02:00
_evtCancelButtonClick(e) {
e.preventDefault();
this._emit('cancel');
}
2016-08-20 22:40:25 +02:00
_evtFormSubmit(e) {
e.preventDefault();
for (let uploadable of this._uploadables) {
this._updateUploadableFromDom(uploadable);
}
this._submitButtonNode.value = 'Resume upload';
2016-08-20 22:40:25 +02:00
this._emit('submit');
}
_updateUploadableFromDom(uploadable) {
const rowNode = uploadable.rowNode;
uploadable.safety =
rowNode.querySelector('.safety input:checked').value;
uploadable.anonymous =
rowNode.querySelector('.anonymous input').checked;
uploadable.flags = [];
if (rowNode.querySelector('.loop-video input:checked')) {
uploadable.flags.push('loop');
}
uploadable.tags = [];
uploadable.relations = [];
for (let [i, lookalike] of uploadable.lookalikes.entries()) {
let lookalikeNode = rowNode.querySelector(
`.lookalikes li:nth-child(${i + 1})`);
if (lookalikeNode.querySelector('[name=copy-tags]').checked) {
uploadable.tags = uploadable.tags.concat(lookalike.post.tags);
}
if (lookalikeNode.querySelector('[name=add-relation]').checked) {
uploadable.relations.push(lookalike.post.id);
}
}
2016-08-20 22:40:25 +02:00
}
_evtRemoveClick(e, uploadable) {
e.preventDefault();
if (this._uploading) {
return;
}
this.removeUploadable(uploadable);
}
_evtMoveClick(e, uploadable, delta) {
e.preventDefault();
if (this._uploading) {
return;
}
let index = this._uploadables.find(uploadable);
if ((index + delta).between(-1, this._uploadables.length)) {
let uploadable1 = this._uploadables[index];
let uploadable2 = this._uploadables[index + delta];
this._uploadables[index] = uploadable2;
this._uploadables[index + delta] = uploadable1;
if (delta === 1) {
this._listNode.insertBefore(
uploadable2.rowNode, uploadable1.rowNode);
} else {
this._listNode.insertBefore(
uploadable1.rowNode, uploadable2.rowNode);
}
}
}
_emit(eventType) {
2016-08-20 22:40:25 +02:00
this.dispatchEvent(
new CustomEvent(
eventType,
{detail: {
uploadables: this._uploadables,
skipDuplicates: this._skipDuplicatesCheckboxNode.checked,
}}));
2016-08-20 22:40:25 +02:00
}
_renderRowNode(uploadable) {
const rowNode = rowTemplate(Object.assign(
{}, this._ctx, {uploadable: uploadable}));
if (uploadable.rowNode) {
uploadable.rowNode.parentNode.replaceChild(
rowNode, uploadable.rowNode);
} else {
this._listNode.appendChild(rowNode);
}
uploadable.rowNode = rowNode;
rowNode.querySelector('a.remove').addEventListener('click',
e => this._evtRemoveClick(e, uploadable));
rowNode.querySelector('a.move-up').addEventListener('click',
e => this._evtMoveClick(e, uploadable, -1));
rowNode.querySelector('a.move-down').addEventListener('click',
e => this._evtMoveClick(e, uploadable, 1));
2016-08-20 22:40:25 +02:00
}
_updateThumbnailNode(uploadable) {
const rowNode = rowTemplate(Object.assign(
{}, this._ctx, {uploadable: uploadable}));
2016-08-20 22:40:25 +02:00
views.replaceContent(
uploadable.rowNode.querySelector('.thumbnail'),
rowNode.querySelector('.thumbnail').childNodes);
}
get _uploading() {
return this._formNode.classList.contains('uploading');
}
2016-08-20 22:40:25 +02:00
get _listNode() {
return this._hostNode.querySelector('.uploadables-container');
}
get _formNode() {
return this._hostNode.querySelector('form');
}
get _skipDuplicatesCheckboxNode() {
return this._hostNode.querySelector('form [name=skip-duplicates]');
}
2016-08-20 22:40:25 +02:00
get _submitButtonNode() {
return this._hostNode.querySelector('form [type=submit]');
}
2016-09-29 21:36:59 +02:00
get _cancelButtonNode() {
return this._hostNode.querySelector('form .cancel');
}
2016-08-20 22:40:25 +02:00
get _contentInputNode() {
return this._formNode.querySelector('.dropper-container');
}
}
module.exports = PostUploadView;