2bf361c64a
Anonymous node does not exist in view when a user without anonymous upload permission tries to post upload. So in this case we should check for the existence of anonymousNode first.
406 lines
12 KiB
JavaScript
406 lines
12 KiB
JavaScript
'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';
|
|
}
|
|
|
|
class Uploadable extends events.EventTarget {
|
|
constructor() {
|
|
super();
|
|
this.lookalikes = [];
|
|
this.lookalikesConfirmed = false;
|
|
this.safety = 'safe';
|
|
this.flags = [];
|
|
this.tags = [];
|
|
this.relations = [];
|
|
this.anonymous = false;
|
|
}
|
|
|
|
destroy() {
|
|
}
|
|
|
|
get mimeType() {
|
|
return 'application/octet-stream';
|
|
}
|
|
|
|
get type() {
|
|
return _mimeTypeToPostType(this.mimeType);
|
|
}
|
|
|
|
get key() {
|
|
throw new Error('Not implemented');
|
|
}
|
|
|
|
get name() {
|
|
throw new Error('Not implemented');
|
|
}
|
|
|
|
_initComplete() {
|
|
if (['video'].includes(this.type)) {
|
|
this.flags.push('loop');
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
get mimeType() {
|
|
return this.file.type;
|
|
}
|
|
|
|
get previewUrl() {
|
|
return this._previewUrl;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
get mimeType() {
|
|
let mime = {
|
|
'swf': 'application/x-shockwave-flash',
|
|
'jpg': 'image/jpeg',
|
|
'png': 'image/png',
|
|
'gif': 'image/gif',
|
|
'mp4': 'video/mp4',
|
|
'webm': 'video/webm',
|
|
};
|
|
for (let extension of Object.keys(mime)) {
|
|
if (this.url.toLowerCase().indexOf('.' + extension) !== -1) {
|
|
return mime[extension];
|
|
}
|
|
}
|
|
return 'unknown';
|
|
}
|
|
|
|
get previewUrl() {
|
|
return this.url;
|
|
}
|
|
|
|
get key() {
|
|
return this.url;
|
|
}
|
|
|
|
get name() {
|
|
return this.url;
|
|
}
|
|
}
|
|
|
|
class PostUploadView extends events.EventTarget {
|
|
constructor(ctx) {
|
|
super();
|
|
this._ctx = ctx;
|
|
this._hostNode = document.getElementById('content-holder');
|
|
|
|
views.replaceContent(this._hostNode, template());
|
|
views.syncScrollPosition();
|
|
|
|
this._cancelButtonNode.disabled = true;
|
|
|
|
this._uploadables = [];
|
|
this._uploadables.find = u => {
|
|
return this._uploadables.findIndex(u2 => u.key === u2.key);
|
|
};
|
|
|
|
this._contentFileDropper = new FileDropperControl(
|
|
this._contentInputNode,
|
|
{
|
|
extraText:
|
|
'Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf',
|
|
allowUrls: true,
|
|
allowMultiple: true,
|
|
lock: false,
|
|
});
|
|
this._contentFileDropper.addEventListener(
|
|
'fileadd', e => this._evtFilesAdded(e));
|
|
this._contentFileDropper.addEventListener(
|
|
'urladd', e => this._evtUrlsAdded(e));
|
|
|
|
this._cancelButtonNode.addEventListener(
|
|
'click', e => this._evtCancelButtonClick(e));
|
|
this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
|
|
this._formNode.classList.add('inactive');
|
|
}
|
|
|
|
enableForm() {
|
|
views.enableForm(this._formNode);
|
|
this._cancelButtonNode.disabled = true;
|
|
this._formNode.classList.remove('uploading');
|
|
}
|
|
|
|
disableForm() {
|
|
views.disableForm(this._formNode);
|
|
this._cancelButtonNode.disabled = false;
|
|
this._formNode.classList.add('uploading');
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
addUploadables(uploadables) {
|
|
this._formNode.classList.remove('inactive');
|
|
let duplicatesFound = 0;
|
|
for (let uploadable of uploadables) {
|
|
if (this._uploadables.find(uploadable) !== -1) {
|
|
duplicatesFound++;
|
|
continue;
|
|
}
|
|
this._uploadables.push(uploadable);
|
|
this._emit('change');
|
|
this._renderRowNode(uploadable);
|
|
uploadable.addEventListener(
|
|
'finish', e => this._updateThumbnailNode(e.detail.uploadable));
|
|
}
|
|
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) {
|
|
return;
|
|
}
|
|
uploadable.destroy();
|
|
uploadable.rowNode.parentNode.removeChild(uploadable.rowNode);
|
|
this._uploadables.splice(this._uploadables.find(uploadable), 1);
|
|
this._emit('change');
|
|
if (!this._uploadables.length) {
|
|
this._formNode.classList.add('inactive');
|
|
this._submitButtonNode.value = 'Upload all';
|
|
}
|
|
}
|
|
|
|
updateUploadable(uploadable) {
|
|
uploadable.lookalikesConfirmed = true;
|
|
this._renderRowNode(uploadable);
|
|
}
|
|
|
|
_evtFilesAdded(e) {
|
|
this.addUploadables(e.detail.files.map(file => new File(file)));
|
|
}
|
|
|
|
_evtUrlsAdded(e) {
|
|
this.addUploadables(e.detail.urls.map(url => new Url(url)));
|
|
}
|
|
|
|
_evtCancelButtonClick(e) {
|
|
e.preventDefault();
|
|
this._emit('cancel');
|
|
}
|
|
|
|
_evtFormSubmit(e) {
|
|
e.preventDefault();
|
|
for (let uploadable of this._uploadables) {
|
|
this._updateUploadableFromDom(uploadable);
|
|
}
|
|
this._submitButtonNode.value = 'Resume upload';
|
|
this._emit('submit');
|
|
}
|
|
|
|
_updateUploadableFromDom(uploadable) {
|
|
const rowNode = uploadable.rowNode;
|
|
|
|
const safetyNode = rowNode.querySelector('.safety input:checked');
|
|
if (safetyNode) {
|
|
uploadable.safety = safetyNode.value;
|
|
}
|
|
|
|
const anonymousNode = rowNode.querySelector('.anonymous input:checked');
|
|
if (anonymousNode) {
|
|
uploadable.anonymous = true;
|
|
}
|
|
|
|
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.tagNames);
|
|
}
|
|
if (lookalikeNode.querySelector('[name=add-relation]').checked) {
|
|
uploadable.relations.push(lookalike.post.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
_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) {
|
|
this.dispatchEvent(
|
|
new CustomEvent(
|
|
eventType,
|
|
{detail: {
|
|
uploadables: this._uploadables,
|
|
skipDuplicates: this._skipDuplicatesCheckboxNode.checked,
|
|
}}));
|
|
}
|
|
|
|
_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));
|
|
}
|
|
|
|
_updateThumbnailNode(uploadable) {
|
|
const rowNode = rowTemplate(Object.assign(
|
|
{}, this._ctx, {uploadable: uploadable}));
|
|
views.replaceContent(
|
|
uploadable.rowNode.querySelector('.thumbnail'),
|
|
rowNode.querySelector('.thumbnail').childNodes);
|
|
}
|
|
|
|
get _uploading() {
|
|
return this._formNode.classList.contains('uploading');
|
|
}
|
|
|
|
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]');
|
|
}
|
|
|
|
get _submitButtonNode() {
|
|
return this._hostNode.querySelector('form [type=submit]');
|
|
}
|
|
|
|
get _cancelButtonNode() {
|
|
return this._hostNode.querySelector('form .cancel');
|
|
}
|
|
|
|
get _contentInputNode() {
|
|
return this._formNode.querySelector('.dropper-container');
|
|
}
|
|
}
|
|
|
|
module.exports = PostUploadView;
|