Merge pull request #326 from zwagoth/uploader-preview

Add webm uploader preview
This commit is contained in:
Zwagoth 2021-10-17 02:32:36 -04:00 committed by GitHub
commit 1cd0229edb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 119 additions and 84 deletions

View File

@ -4,6 +4,7 @@ class UploadsController < ApplicationController
respond_to :html, :json
content_security_policy only: [:new] do |p|
p.img_src :self, :data, "*"
p.media_src :self, :data, "*"
end
def new

View File

@ -29,7 +29,7 @@
<script>
import Vue from 'vue';
import relatedTags from './uploader_related.vue';
import tagPreview from './uploader_preview.vue';
import tagPreview from './uploader_tag_preview.vue';
import Post from './posts';
import Autocomplete from "./autocomplete.js.erb";
import Utility from "./utility.js";

View File

@ -2,7 +2,7 @@
<div class="flex-grid-outer">
<div class="col box-section" style="flex: 2 0 0;">
<div class="the_secret_switch" @click="toggleNormalMode"></div>
<div class="box-section sect_red" v-show="overDims">
<div class="box-section sect_red" v-show="filePreview.overDims">
One of the image dimensions is above the maximum allowed of 15,000px and will fail to upload.
</div>
<div class="flex-grid border-bottom">
@ -13,7 +13,7 @@
<div class="col2">
<div v-if="!disableFileUpload">
<label>File:
<input type="file" ref="post_file" @change="updatePreview" @keyup="updatePreview"
<input type="file" ref="post_file" @change="updateFilePreview" @keyup="updateFilePreview"
accept="image/png,image/apng,image/jpeg,image/gif,video/webm,.png,.apng,.jpg,.jpeg,.gif,.webm"
:disabled="disableFileUpload"/>
</label>
@ -25,7 +25,7 @@
You should review <a href="/wiki_pages/howto:sites_and_sources">the sourcing guide</a>.
</div>
<label>{{!disableFileUpload ? '(or) ' : '' }}URL:
<input type="text" size="50" v-model="uploadURL" @keyup="updatePreview" @paste="updatePreviewOnPaste($event)"
<input type="text" size="50" v-model="uploadURL" @keyup="updateFilePreview" @paste="updateFilePreviewOnPaste($event)"
:disabled="disableURLUpload"/>
</label>
<div id="whitelist-warning" v-show="whitelist.visible"
@ -38,11 +38,7 @@
</div>
</div>
</div>
<div class="box-section upload_preview_container in-editor below-upload">
<div class="upload_preview_dims">{{ previewDimensions }}</div>
<img class="upload_preview_img" :src="previewURL" style="max-width: 100%;"
referrerpolicy="no-referrer"/>
</div>
<file-preview classes="box-section in-editor below-upload" :preview="filePreview"></file-preview>
<div class="flex-grid border-bottom">
<div class="col">
<label class="section-label" for="post_sources">Sources</label>
@ -190,21 +186,17 @@
</div>
</div>
<div class="col2">
<div class="box-section upload_preview_container in-editor">
<div class="upload_preview_dims">{{ previewDimensions }}</div>
<img class="upload_preview_img" :src="previewURL" style="max-width: 100%;"
referrerpolicy="no-referrer"/>
</div>
<file-preview classes="box-section in-editor" :preview="filePreview"></file-preview>
<div class="box-section sect_red" v-show="showErrors && notEnoughTags">
You must provide at least <b>{{4 - tagCount}}</b> more tags. Tags in other sections count
towards this total.
</div>
<div v-show="!preview.show">
<div v-show="!tagPreview.show">
<textarea class="tag-textarea" id="post_tags" v-model="tagEntries.other" rows="5"
ref="otherTags" data-autocomplete="tag-edit"></textarea>
</div>
<div v-show="preview.show">
<tag-preview :tags="preview.tags" :loading="preview.loading"
<div v-show="tagPreview.show">
<tag-preview :tags="tagPreview.tags" :loading="tagPreview.loading"
@close="previewFinalTags"></tag-preview>
</div>
@ -279,11 +271,7 @@
</div>
</div>
<div id="preview-sidebar" class="col box-section" style="margin-left: 10px; padding: 10px;">
<div class="upload_preview_container in-sidebar">
<div class="upload_preview_dims">{{ previewDimensions }}</div>
<img class="upload_preview_img" :src="previewURL" style="max-width: 100%;" @load="updatePreviewDims"
@error="previewError"/>
</div>
<file-preview classes="in-sidebar" :preview="filePreview" @load="updateFilePreviewDims" @error="filePreviewError"></file-preview>
</div>
</div>
</template>
@ -293,16 +281,15 @@
import source from './uploader_source.vue';
import checkbox from './uploader_checkbox.vue';
import relatedTags from './uploader_related.vue';
import tagPreview from './uploader_preview.vue';
import tagPreview from './uploader_tag_preview.vue';
import filePreview from './uploader_file_preview.vue';
const thumbURLs = [
"/images/notfound-preview.png",
"/images/download-preview.png",
"/images/webm-preview.png",
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
];
const thumbs = {
webm: "/images/webm-preview.png",
flash: "/images/download-preview.png",
notfound: "/images/notfound-preview.png",
none: 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
@ -342,24 +329,24 @@
{name: 'Human'},
{name: 'Taur'}];
function updatePreviewDims(e) {
const img = e.target;
function updateFilePreviewDims(e) {
const target = e.target;
if (thumbURLs.filter(function (x) {
return img.src.indexOf(x) !== -1;
return target.src.indexOf(x) !== -1;
}).length !== 0)
return;
this.previewHeight = img.naturalHeight;
this.previewWidth = img.naturalWidth;
this.overDims = (img.naturalHeight > 15000 || img.naturalWidth > 15000);
this.filePreview.height = target.naturalHeight || target.videoHeight;
this.filePreview.width = target.naturalWidth || target.videoHeight;
this.filePreview.overDims = (this.filePreview.height > 15000 || this.filePreview.width > 15000);
}
function previewError() {
this.previewWidth = this.previewHeight = 0;
this.overDims = false;
function filePreviewError() {
this.filePreview.width = this.filePreview.height = 0;
this.filePreview.overDims = false;
if (this.uploadURL === '' && !this.$refs['post_file']) {
this.previewURL = thumbs.none;
this.setPreviewImage(thumbs.none);
} else {
this.previewURL = thumbs.notfound;
this.setPreviewImage(thumbs.notfound);
}
}
@ -367,16 +354,18 @@
const self = this;
const reader = new FileReader();
const file = this.$refs['post_file'].files[0];
this.previewHeight = 0;
this.previewWidth = 0;
this.filePreview.height = 0;
this.filePreview.width = 0;
this.resetFilePreview();
reader.onload = function (e) {
let src = e.target.result;
if (file.type.match('video/webm'))
src = thumbs.webm;
self.setPreviewVideo(src);
else if (file.type.match('application/x-shockwave-flash'))
src = thumbs.flash;
self.previewURL = src;
self.setPreviewImage(thumbs.flash);
else
self.setPreviewImage(src);
};
reader.readAsDataURL(file);
@ -388,7 +377,9 @@
if (this.uploadURL.length === 0 || (this.$refs['post_file'] && this.$refs['post_file'].files.length > 0)) {
this.disableFileUpload = false;
this.oldDomain = '';
this.overDims = false;
this.filePreview.width = 0;
this.filePreview.height = 0;
this.resetFilePreview();
self.clearWhitelistWarning();
return;
}
@ -400,7 +391,7 @@
if (data.domain) {
self.whitelistWarning(data.is_allowed, data.domain, data.reason);
if (!data.is_allowed)
self.previewURL = thumbs.none;
self.setPreviewImage(thumbs.none);
}
});
} else if (!domain) {
@ -408,24 +399,39 @@
}
this.oldDomain = domain;
let src = thumbs.none;
if (this.uploadURL.match(/^(https?\:\/\/|www).*?\.(swf)$/))
src = thumbs.flash;
this.setPreviewImage(thumbs.flash);
else if (this.uploadURL.match(/^(https?\:\/\/|www).*?\.(webm)$/))
src = thumbs.webm;
this.setPreviewVideo(this.uploadURL);
else if (this.uploadURL.match(/^(https?\:\/\/|www).*?$/))
src = this.uploadURL;
this.previewURL = src;
this.setPreviewImage(this.uploadURL);
else
this.setPreviewImage(thumbs.none);
}
function updatePreview() {
function updateFilePreview() {
if (this.$refs['post_file'] && this.$refs['post_file'].files[0])
updatePreviewFile.call(this);
else
updatePreviewURL.call(this);
}
function setPreviewImage(url) {
this.filePreview.isVideo = false;
this.filePreview.url = url;
}
function setPreviewVideo(url) {
this.filePreview.isVideo = true;
this.filePreview.url = url;
}
function resetFilePreview() {
this.filePreview.isVideo = false;
this.filePreview.url = thumbs.none;
this.filePreview.overDims = false;
}
function directURLCheck(url) {
var patterns = [
{reason: 'Thumbnail URL', test: /[at]\.facdn\.net/gi},
@ -449,10 +455,8 @@
return;
this.$refs['post_file'].value = null;
this.disableURLUpload = this.disableFileUpload = false;
this.previewURL = thumbs.none;
this.previewHeight = this.previewWidth = 0;
this.overDims = false;
this.updatePreview();
this.resetFilePreview();
this.updateFilePreview();
}
function tagSorter(a, b) {
@ -473,7 +477,8 @@
'image-source': source,
'image-checkbox': checkbox,
'related-tags': relatedTags,
'tag-preview': tagPreview
'tag-preview': tagPreview,
'file-preview': filePreview
},
data() {
const allChecks = {};
@ -504,12 +509,15 @@
disableFileUpload: false,
disableURLUpload: false,
previewHeight: 0,
previewWidth: 0,
overDims: false,
uploadURL: '',
previewURL: thumbs.none,
filePreview: {
heigth: 0,
width: 0,
overDims: false,
url: thumbs.none,
isVideo: false,
},
uploadURL: '',
oldDomain: '',
noSource: false,
@ -533,7 +541,7 @@
other: '',
},
preview: {
tagPreview: {
loading: false,
show: false,
tags: []
@ -581,7 +589,7 @@
};
fillField('uploadURL', 'upload_url');
if(params.has('upload_url'))
this.updatePreview();
this.updateFilePreview();
fillField('parentID', 'parent');
fillField('description', 'description');
fillTags();
@ -594,14 +602,17 @@
fillField('lockedTags', 'locked_tags');
},
methods: {
updatePreview,
updatePreviewOnPaste(evt) {
updateFilePreview,
updateFilePreviewOnPaste(evt) {
this.uploadURL = (event.clipboardData || window.clipboardData).getData('text');
this.updatePreview();
this.updateFilePreview();
evt.preventDefault();
},
updatePreviewDims,
previewError,
updateFilePreviewDims,
setPreviewImage,
setPreviewVideo,
resetFilePreview,
filePreviewError,
clearFile: clearFileUpload,
whitelistWarning(allowed, domain, reason) {
this.whitelist.allowed = allowed;
@ -708,7 +719,7 @@
});
},
pushTag(tag, add) {
this.preview.show = false;
this.tagPreview.show = false;
const isCheck = typeof this.checkboxes.all[tag] !== "undefined";
// In advanced mode we need to push these into the tags area because there are no checkboxes or other
// tag fields so we can't see them otherwise.
@ -729,15 +740,15 @@
this.tagEntries.other = tags.join(' ') + ' ';
},
previewFinalTags() {
if (this.preview.loading)
if (this.tagPreview.loading)
return;
if (this.preview.show) {
this.preview.show = false;
if (this.tagPreview.show) {
this.tagPreview.show = false;
return;
}
this.preview.loading = true;
this.preview.show = true;
this.preview.tags = [];
this.tagPreview.loading = true;
this.tagPreview.show = true;
this.tagPreview.tags = [];
const self = this;
const data = {tags: this.tags};
jQuery.ajax("/tags/preview.json", {
@ -745,13 +756,13 @@
type: 'POST',
data: data,
success: function (result) {
self.preview.loading = false;
self.preview.tags = result;
self.tagPreview.loading = false;
self.tagPreview.tags = result;
},
error: function (result) {
self.preview.loading = false;
self.preview.tags = [];
self.preview.show = false;
self.tagPreview.loading = false;
self.tagPreview.tags = [];
self.tagPreview.show = false;
Danbooru.error('Error loading tag preview ' + result);
}
})
@ -813,11 +824,6 @@
tagsArray() {
return this.tags.toLowerCase().split(' ');
},
previewDimensions() {
if (this.previewWidth && this.previewHeight)
return this.previewWidth + '×' + this.previewHeight;
return '';
},
directURLProblem: function () {
return directURLCheck(this.uploadURL);
},

View File

@ -0,0 +1,28 @@
<template>
<div class="upload_preview_container" :class="classes">
<div class="upload_preview_dims">{{ previewDimensions }}</div>
<img class="upload_preview_img" :src="preview.url" style="max-width: 100%;"
referrerpolicy="no-referrer"
v-if="!preview.isVideo"
v-on:load="$emit('load', $event)" v-on:error="$emit('error')"/>
<video class="upload_preview_img" controls :src="preview.url" style="max-width: 100%;"
v-on:loadeddata="$emit('load', $event)" v-on:error="$emit('error')"
v-if="preview.isVideo"></video>
</div>
</template>
<script>
export default {
props: {
classes: String,
preview: Object
},
computed: {
previewDimensions() {
if (this.preview.width && this.preview.height)
return this.preview.width + '×' + this.preview.height;
return '';
},
}
};
</script>