forked from e621ng/e621ng
Partial of new uploader
This commit is contained in:
parent
f29e90f508
commit
ae77880b10
@ -59,7 +59,7 @@ class UploadsController < ApplicationController
|
|||||||
|
|
||||||
def upload_params
|
def upload_params
|
||||||
permitted_params = %i[
|
permitted_params = %i[
|
||||||
file direct_url source tag_string rating status parent_id artist_commentary_title
|
file direct_url source tag_string rating parent_id description artist_commentary_title
|
||||||
artist_commentary_desc include_artist_commentary referer_url
|
artist_commentary_desc include_artist_commentary referer_url
|
||||||
md5_confirmation as_pending
|
md5_confirmation as_pending
|
||||||
]
|
]
|
||||||
|
@ -41,7 +41,7 @@ class TagAlias < TagRelationship
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
ForumUpdater.new(
|
ForumUpdater.new(
|
||||||
forum_topic,
|
forum_topic,
|
||||||
forum_post: post,
|
forum_post: post,
|
||||||
expected_title: TagAliasRequest.topic_title(antecedent_name, consequent_name),
|
expected_title: TagAliasRequest.topic_title(antecedent_name, consequent_name),
|
||||||
skip_update: !TagRelationship::SUPPORT_HARD_CODED
|
skip_update: !TagRelationship::SUPPORT_HARD_CODED
|
||||||
@ -178,7 +178,7 @@ class TagAlias < TagRelationship
|
|||||||
|
|
||||||
def rename_wiki_and_artist
|
def rename_wiki_and_artist
|
||||||
antecedent_wiki = WikiPage.titled(antecedent_name).first
|
antecedent_wiki = WikiPage.titled(antecedent_name).first
|
||||||
if antecedent_wiki.present?
|
if antecedent_wiki.present?
|
||||||
if WikiPage.titled(consequent_name).blank?
|
if WikiPage.titled(consequent_name).blank?
|
||||||
CurrentUser.scoped(creator, creator_ip_addr) do
|
CurrentUser.scoped(creator, creator_ip_addr) do
|
||||||
antecedent_wiki.update(title: consequent_name, skip_secondary_validations: true)
|
antecedent_wiki.update(title: consequent_name, skip_secondary_validations: true)
|
||||||
|
@ -201,8 +201,8 @@ class TagImplication < TagRelationship
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
ForumUpdater.new(
|
ForumUpdater.new(
|
||||||
forum_topic,
|
forum_topic,
|
||||||
forum_post: post,
|
forum_post: post,
|
||||||
expected_title: TagImplicationRequest.topic_title(antecedent_name, consequent_name),
|
expected_title: TagImplicationRequest.topic_title(antecedent_name, consequent_name),
|
||||||
skip_update: !TagRelationship::SUPPORT_HARD_CODED
|
skip_update: !TagRelationship::SUPPORT_HARD_CODED
|
||||||
)
|
)
|
||||||
|
@ -1,153 +1,692 @@
|
|||||||
<div id="c-uploads">
|
<%= render partial: "uploads/upload_partials/css" %>
|
||||||
<div id="a-new">
|
<%= render partial: "uploads/upload_partials/tag_preview" %>
|
||||||
<h1>Upload</h1>
|
<%= render partial: "uploads/upload_partials/source" %>
|
||||||
|
<%= render partial: "uploads/upload_partials/related" %>
|
||||||
<% if CurrentUser.can_upload? %>
|
<%= render partial: "uploads/upload_partials/uploader" %>
|
||||||
<div id="upload-guide-notice">
|
<div id="post-add">
|
||||||
<%= format_text(@upload_notice_wiki.try(&:body)) %>
|
<div style="margin-bottom: 1rem;" class="section">
|
||||||
</div>
|
<h2>Before uploading, read
|
||||||
|
the <%= link_to "how to upload guide", wiki_pages_path(id: "howto:upload") %>.</h2>
|
||||||
<% unless CurrentUser.can_upload_free? %>
|
<p>Make sure you're not posting something on
|
||||||
<p>Upload limit: <strong><%= CurrentUser.user.presenter.upload_limit(self) %></strong>.</p>
|
the <%= link_to "Avoid Posting List", help_pages_path(id: 'avoid_posting') %><br>
|
||||||
<% end %>
|
Review the <%= link_to "Uploading Guidelines", help_pages_path(id: "uploading_guidelines") %>
|
||||||
|
<br>
|
||||||
<%= render "image" %>
|
Unsure what to tag your post
|
||||||
<%= render "related_posts", source: @source %>
|
with? <%= link_to "Tagging Checklist", help_pages_path(id: "tagging_checklist") %></p>
|
||||||
<%= render "sources/info" %>
|
</div>
|
||||||
|
<%# if current_user.is_member_or_lower? && (current_user.upload_limit <= 5 || current_user.post_upload_throttle <= 5) %>
|
||||||
<div id="client-errors" class="error-messages ui-state-error ui-corner-all" style="display:none"></div>
|
<!-- <div id="post-uploads-remaining" class="section<%# if [current_user.upload_limit, current_user.post_upload_throttle].min <= 0 %> sect_red<%# end %>" style="width:640px;">-->
|
||||||
|
<!-- <p>-->
|
||||||
<%= form_for(@upload, :html => {:multipart => true, :class => "simple_form", :id => "form"}) do |f| %>
|
<!-- You currently have <span class="post-uploads-remaining-count"><%#= current_user.upload_limit %></span> upload<%#= current_user.upload_limit!=1?"s":"" %> remaining.-->
|
||||||
<%= f.hidden_field :md5_confirmation %>
|
|
||||||
<%= f.hidden_field :referer_url, value: params[:ref] %>
|
<%# if current_user.pending_flagged_posts.count > 0 %>
|
||||||
|
<!-- This number will go up as some of your <%#= link_to "<span class='post-uploads-remaining-count'>#{current_user.pending_flagged_posts.count}</span> pending/flagged posts", action: "index",tags: "user:#{current_user.name} status:pending" %> are approved.-->
|
||||||
<% if CurrentUser.can_upload_free? %>
|
<%# end %>
|
||||||
<div class="input">
|
<!-- </p>-->
|
||||||
<label for="upload_as_pending">
|
<!-- You have <span class="post-uploads-remaining-count"><%#= current_user.post_upload_throttle %></span> uploads remaining this hour.-->
|
||||||
<%= f.check_box :as_pending, :checked => params[:as_pending].present? %>
|
<!-- See <%#= link_to "here", controller: "user", action: "upload_limit" %> for more details.-->
|
||||||
Upload for approval
|
<!-- </div>-->
|
||||||
</label>
|
<%# elsif current_user.post_upload_throttle <= 5 %>
|
||||||
</div>
|
<!-- <div id="post-uploads-remaining" class="section<%# if current_user.post_upload_throttle <= 0 %> sect_red<%# end %>" style="width:640px;">-->
|
||||||
<% end %>
|
<!-- You have <span class="post-uploads-remaining-count"><%#= current_user.post_upload_throttle %></span> uploads remaining this hour.-->
|
||||||
|
<!-- See <%#= link_to "here", controller: "user", action: "upload_limit" %> for more details.-->
|
||||||
<div class="input">
|
<!-- </div>-->
|
||||||
<%= f.label :file %>
|
<%# end %>
|
||||||
<%= f.file_field :file, :size => 50 %>
|
<post-creator :safe="<%= CurrentUser.safe_mode? %>"></post-creator>
|
||||||
</div>
|
</div>
|
||||||
|
<!--<script type="text/javascript">-->
|
||||||
<div class="input">
|
<!-- var userUploadTags = <%#= current_user.uploaded_tags_with_types.to_json %>;-->
|
||||||
<%= f.label :direct_url %>
|
<!-- var userRecentTags = <%#= current_user.recent_tags_with_types.to_json %>;-->
|
||||||
<%= f.text_field :direct_url, size: 50, value: params[:url] %>
|
<!-- var userArtistTags = <%#= @artists.to_json %>;-->
|
||||||
<%= button_tag "Similar", :id => "similar-button", :type => "button", :class => "ui-button ui-widget ui-corner-all sub" %>
|
<!--</script>-->
|
||||||
<div id="whitelist-warning"></div>
|
<script>
|
||||||
<span class="hint">You can enter a URL to have <%= Danbooru.config.app_name %> automatically download and process it</span>
|
var userUploadTags = [];
|
||||||
</div>
|
var userRecentTags = [];
|
||||||
|
var userArtistTags = [];
|
||||||
<div class="input">
|
</script>
|
||||||
<%= f.label :source, "Sources" %>
|
<script src="/vendor/vue.js"></script>
|
||||||
<%= f.text_area :source, size: "60x5", value: params[:url] %>
|
<script type="text/javascript">
|
||||||
</div>
|
const thumbURLs = [
|
||||||
|
"/images/notfound-preview.png",
|
||||||
<div class="input">
|
"/images/download-preview.png",
|
||||||
<%= f.label :rating %>
|
"/images/webm-preview.png",
|
||||||
|
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
|
||||||
<fieldset class="ratings">
|
];
|
||||||
<%= f.radio_button :rating, :e, :checked => (params[:rating] == "e") %>
|
const thumbs = {
|
||||||
<%= f.label :rating_e, "Explicit", :title => "Hardcore porn, visible genitals" %>
|
webm: "/images/webm-preview.png",
|
||||||
|
flash: "/images/download-preview.png",
|
||||||
<%= f.radio_button :rating, :q, :checked => (params[:rating] == "q") %>
|
notfound: "/images/notfound-preview.png",
|
||||||
<%= f.label :rating_q, "Questionable", :title => "Nudity, anything erotic" %>
|
none: 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
|
||||||
|
};
|
||||||
<%= f.radio_button :rating, :s, :checked => (params[:rating] == "s") %>
|
const artist_checks = [
|
||||||
<%= f.label :rating_s, "Safe", :title => "Everything else" %>
|
{name: 'Unknown Artist'},
|
||||||
</fieldset>
|
{name: 'Anonymous Artist'}];
|
||||||
</div>
|
|
||||||
|
const sex_checks = [
|
||||||
<div class="input">
|
{name: 'Male'},
|
||||||
<%= f.label :parent_id, "Parent ID" %>
|
{name: 'Female'},
|
||||||
<%= f.text_field :parent_id, :value => params[:parent_id] %>
|
{name: 'Cuntboy'},
|
||||||
</div>
|
{name: 'Dickgirl'},
|
||||||
|
{name: 'Hermaphrodite', tag: 'herm'},
|
||||||
<div class="input">
|
{name: 'Male-Herm', tag: 'maleherm'},
|
||||||
<strong>Commentary</strong>
|
{name: 'Ambiguous', tag: 'ambiguous_gender'}];
|
||||||
<a href="#" id="toggle-artist-commentary">show »</a>
|
|
||||||
|
const pairing_checks = [
|
||||||
<div class="artist-commentary" style="display: none;">
|
{name: 'Male/Male'},
|
||||||
<div class="input">
|
{name: 'Male/Female'},
|
||||||
<%= f.label :artist_commentary_title, "Title" %>
|
{name: 'Female/Female'},
|
||||||
<%= f.text_field :artist_commentary_title, :value => params[:artist_commentary_title] %>
|
{name: 'Intersex/Male'},
|
||||||
</div>
|
{name: 'Intersex/Female'},
|
||||||
|
{name: 'Intersex/Intersex'}
|
||||||
<div class="input">
|
];
|
||||||
<%= f.label :artist_commentary_desc, "Description" %>
|
|
||||||
<%= f.text_area :artist_commentary_desc, :size => "60x5", :value => params[:artist_commentary_desc] %>
|
const char_count_checks = [
|
||||||
</div>
|
{name: 'Solo'},
|
||||||
|
{name: 'Duo'},
|
||||||
<div class="input">
|
{name: 'Group'},
|
||||||
<label for="upload_include_artist_commentary">
|
{name: 'Zero Pictured'}];
|
||||||
<%= f.check_box :include_artist_commentary, :checked => params[:include_artist_commentary].present? %>
|
|
||||||
Include Commentary
|
const body_type_checks = [
|
||||||
</label>
|
{name: 'Anthro'},
|
||||||
</div>
|
{name: 'Feral'},
|
||||||
</div>
|
{name: 'Humanoid'},
|
||||||
</div>
|
{name: 'Human'},
|
||||||
|
{name: 'Taur'}];
|
||||||
<div class="input" id="tags-container">
|
|
||||||
<div class="header">
|
function updatePreviewDims(e) {
|
||||||
<%= f.label :tag_string, "Tags" %>
|
var img = e.target;
|
||||||
|
if (thumbURLs.filter(function (x) {
|
||||||
<span class="options">
|
return img.src.indexOf(x) !== -1;
|
||||||
<i id="face" class="fas"></i>
|
}).length !== 0)
|
||||||
<span class="count"></span>
|
return;
|
||||||
<a href="javascript:void(0)"><i id="open-edit-dialog" class="fas fa-arrows-alt" title="detach" data-shortcut="shift+e"></i></a>
|
this.previewHeight = img.naturalHeight;
|
||||||
</span>
|
this.previewWidth = img.naturalWidth;
|
||||||
</div>
|
this.overDims = (img.naturalHeight > 15000 || img.naturalWidth > 15000);
|
||||||
|
updateDimensionTag.call(this);
|
||||||
<div>
|
}
|
||||||
<%= f.text_area :tag_string, :size => "60x5", :spellcheck => false, :"data-autocomplete" => "tag-edit", :"data-shortcut" => "e", :value => params[:tag_string] %>
|
|
||||||
</div>
|
function previewError() {
|
||||||
<%= render "related_tags/buttons" %>
|
this.previewWidth = this.previewHeight = 0;
|
||||||
</div>
|
this.overDims = false;
|
||||||
|
if (this.uploadURL === '' && !this.$refs['post_file']) {
|
||||||
<div class="input">
|
this.previewURL = thumbs.none;
|
||||||
<%= submit_tag "Submit", :id => "submit-button", :class => "large ui-button ui-widget ui-corner-all", data: { disable_with: false } %>
|
} else {
|
||||||
</div>
|
this.previewURL = thumbs.notfound;
|
||||||
|
}
|
||||||
<%= render "related_tags/container" %>
|
}
|
||||||
<% end %>
|
|
||||||
<% else %>
|
function updatePreviewFile() {
|
||||||
<h2 style="margin-bottom: 1em;">You <%= CurrentUser.user.upload_limited_reason %></h2>
|
var self = this;
|
||||||
<% end %>
|
var reader = new FileReader();
|
||||||
</div>
|
var file = this.$refs['post_file'].files[0];
|
||||||
</div>
|
this.previewHeight = 0;
|
||||||
|
this.previewWidth = 0;
|
||||||
<% content_for(:page_title) do %>
|
reader.onload = function (e) {
|
||||||
Upload - <%= Danbooru.config.app_name %>
|
var src = e.target.result;
|
||||||
<% end %>
|
|
||||||
|
if (file.type.match('video/webm'))
|
||||||
<% content_for(:html_header) do %>
|
src = thumbs.webm;
|
||||||
<script async src="/vendor/spark-md5-3.0.min.js" integrity="sha384-5VJv9Bpdgn6Hi1U9X+oyrPZZ6vIihhKUi6Dc3DoCBGph3XbthcAH6va41dxo1KUO" crossorigin="anonymous"></script>
|
else if (file.type.match('application/x-shockwave-flash'))
|
||||||
<script>
|
src = thumbs.flash;
|
||||||
$(function() {
|
self.previewURL = src;
|
||||||
var enabled = true;
|
};
|
||||||
var maxFilesize = <%= Danbooru.config.max_file_size.to_json %> / (1024 * 1024);
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
if (!window.FileReader) {
|
this.disableURLUpload = true;
|
||||||
enabled = false;
|
}
|
||||||
}
|
|
||||||
|
function updatePreviewURL() {
|
||||||
// this.on("addedfile", function(file) {
|
var self = this;
|
||||||
// var reader = new FileReader();
|
if (this.uploadURL.length === 0 || (this.$refs['post_file'] && this.$refs['post_file'].files.length > 0)) {
|
||||||
// reader.addEventListener("loadend", function() {
|
this.disableFileUpload = false;
|
||||||
// var buf = new SparkMD5.ArrayBuffer();
|
this.oldDomain = '';
|
||||||
// buf.append(this.result);
|
return;
|
||||||
// var hash = buf.end();
|
}
|
||||||
// $("#upload_md5_confirmation").val(hash);
|
this.disableFileUpload = true;
|
||||||
// });
|
var domain = $j("<a>").prop("href", this.uploadURL).prop("hostname");
|
||||||
// reader.readAsArrayBuffer(file);
|
|
||||||
// });
|
if (domain && domain != this.oldDomain) {
|
||||||
});
|
$j.getJSON("/upload_whitelist/is_whitelisted", {url: this.uploadURL}, function (data) {
|
||||||
</script>
|
if (data.domain)
|
||||||
<% end %>
|
self.whitelistWarning(data.is_whitelisted, data.domain);
|
||||||
|
});
|
||||||
<%= render "uploads/secondary_links" %>
|
}
|
||||||
|
this.oldDomain = domain;
|
||||||
|
|
||||||
|
var src = thumbs.none;
|
||||||
|
if (this.uploadURL.match(/^(https?\:\/\/|www).*?\.(jpg|jpeg|gif|png)/))
|
||||||
|
src = this.uploadURL;
|
||||||
|
else if (this.uploadURL.match(/^(https?\:\/\/|www).*?\.(swf)$/))
|
||||||
|
src = thumbs.flash;
|
||||||
|
else if (this.uploadURL.match(/^(https?\:\/\/|www).*?\.(webm)$/))
|
||||||
|
src = thumbs.webm;
|
||||||
|
|
||||||
|
this.previewURL = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDimensionTag() {
|
||||||
|
var self = this;
|
||||||
|
if (!(self.previewHeight || self.previewWidth))
|
||||||
|
return;
|
||||||
|
var otherTags = ['low_res', 'hi_res', 'superabsurd_res', 'absurd_res'];
|
||||||
|
var ourTag = function (h, w) {
|
||||||
|
if (!(h && w)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ((h <= 500) && (w <= 500))
|
||||||
|
return 'low_res';
|
||||||
|
if ((h >= 10000) || (w >= 10000))
|
||||||
|
return 'superabsurb_res';
|
||||||
|
if ((h >= 2400) || (w >= 3200))
|
||||||
|
return 'absurd_res';
|
||||||
|
if ((h >= 1200) || (w >= 1600))
|
||||||
|
return 'hi_res';
|
||||||
|
return null;
|
||||||
|
}(self.previewHeight, self.previewWidth);
|
||||||
|
var tagIdx = otherTags.indexOf(ourTag);
|
||||||
|
if (tagIdx > 0)
|
||||||
|
otherTags.splice(tagIdx, 1);
|
||||||
|
if (ourTag)
|
||||||
|
self.pushTag(ourTag, true);
|
||||||
|
for(var i = 0; i < otherTags.length; i++) {
|
||||||
|
self.pushTag(otherTags[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePreview() {
|
||||||
|
if (this.$refs['post_file'] && this.$refs['post_file'].files[0])
|
||||||
|
updatePreviewFile.call(this);
|
||||||
|
else
|
||||||
|
updatePreviewURL.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function directURLCheck(url) {
|
||||||
|
var patterns = [{reason: 'Thumbnail URL', test: /[at]\.facdn\.net/gi},
|
||||||
|
{reason: 'Sample URL', test: /pximg\.net\/img-master/gi},
|
||||||
|
// {reason: 'Sample URL', test: /\d+\.media\.tumblr\.com/gi}, // Tumblr broke raws.
|
||||||
|
{reason: 'Sample URL', test: /d3gz42uwgl1r1y\.cloudfront\.net\/.*\/\d+x\d+\./gi},
|
||||||
|
{reason: 'Sample URL', test: /pbs\.twimg\.com\/media\/\w+\.(jpg|png)(:large)?$/gi},
|
||||||
|
{reason: 'Sample URL', test: /pbs\.twimg\.com\/media\/\w+\?format=/gi},
|
||||||
|
{reason: 'Sample URL', test: /derpicdn\.net\/.*\/large\./gi},
|
||||||
|
{reason: 'Sample URL', test: /metapix\.net\/files\/(preview|screen)\//gi},
|
||||||
|
{reason: 'Sample URL', test: /sofurryfiles\.com\/std\/preview/gi}];
|
||||||
|
for (var i = 0; i < patterns.length; ++i) {
|
||||||
|
var pattern = patterns[i];
|
||||||
|
if (pattern.test.test(url))
|
||||||
|
return pattern.reason;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearFileUpload() {
|
||||||
|
if (!(this.$refs['post_file'] && this.$refs['post_file'].files[0]))
|
||||||
|
return;
|
||||||
|
this.$refs['post_file'].value = null;
|
||||||
|
this.disableURLUpload = this.disableFileUpload = false;
|
||||||
|
this.previewURL = thumbs.none;
|
||||||
|
this.previewHeight = this.previewWidth = 0;
|
||||||
|
this.updatePreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = Vue.extend({
|
||||||
|
template: '#source-template',
|
||||||
|
props: ['value', 'index', 'last'],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
backendValue: this.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
'realValue': {
|
||||||
|
get: function () {
|
||||||
|
return this.backendValue;
|
||||||
|
},
|
||||||
|
set: function (v) {
|
||||||
|
this.backendValue = v;
|
||||||
|
this.$emit('input', v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.$emit('add');
|
||||||
|
},
|
||||||
|
remove: function () {
|
||||||
|
this.$emit('delete');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: function (v) {
|
||||||
|
this.backendValue = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var checkbox = Vue.extend({
|
||||||
|
template: '#checkbox-template',
|
||||||
|
props: ['check', 'checks'],
|
||||||
|
computed: {
|
||||||
|
value: {
|
||||||
|
get: function () {
|
||||||
|
if (this.checks[this.tagName] === undefined)
|
||||||
|
return false;
|
||||||
|
return this.checks[this.tagName];
|
||||||
|
},
|
||||||
|
set: function (v) {
|
||||||
|
this.$emit('set', this.tagName, v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tagName: function () {
|
||||||
|
return this.check.tag || this.check.name.toLowerCase().replace(/ /g, '_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var tagSorter = function (a, b) {
|
||||||
|
return a[0] > b[0] ? 1 : -1;
|
||||||
|
};
|
||||||
|
var relatedTags = Vue.extend({
|
||||||
|
template: '#related-tags',
|
||||||
|
props: ['tags', 'related', 'loading'],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
uploaded: (userUploadTags || []),
|
||||||
|
recent: (userRecentTags || []).sort(tagSorter),
|
||||||
|
artists: (userArtistTags || []).sort(tagSorter)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle: function (tag) {
|
||||||
|
this.$emit('tag-active', tag[0], !this.tagActive(tag));
|
||||||
|
},
|
||||||
|
tagLink: function (tag) {
|
||||||
|
return '/post/index?tags=' + encodeURIComponent(tag[0]);
|
||||||
|
},
|
||||||
|
tagActive: function (tag) {
|
||||||
|
return this.tags.indexOf(tag[0]) !== -1;
|
||||||
|
},
|
||||||
|
tagClasses: function (tag) {
|
||||||
|
var classes = {'tag-active': this.tagActive(tag)};
|
||||||
|
classes['tag-type-' + tag[2]] = true;
|
||||||
|
return classes;
|
||||||
|
},
|
||||||
|
splitTags: function (tags) {
|
||||||
|
var chunkArray = function (arr, size) {
|
||||||
|
var chunks = [];
|
||||||
|
for (var i = 0; i < arr.length; i += size) {
|
||||||
|
chunks.push(arr.slice(i, i + size));
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
};
|
||||||
|
return chunkArray(tags, 15);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tagGroups: {
|
||||||
|
get: function () {
|
||||||
|
var groups = [];
|
||||||
|
if (this.uploaded && this.uploaded.length) {
|
||||||
|
groups.push({
|
||||||
|
title: "Quick Tags",
|
||||||
|
tags: this.uploaded
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.recent && this.recent.length) {
|
||||||
|
groups.push({
|
||||||
|
title: "Recent",
|
||||||
|
tags: this.recent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.artists && this.artists.length) {
|
||||||
|
groups.push({
|
||||||
|
title: "Artists",
|
||||||
|
tags: this.artists
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.related && this.related.length) {
|
||||||
|
for (var i = 0; i < this.related.length; i++) {
|
||||||
|
groups.push(this.related[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.loading) {
|
||||||
|
groups.push({title: 'Loading Related Tags', tags: [['', '', '']]});
|
||||||
|
}
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var tagPreviewTag = Vue.extend({
|
||||||
|
functional: true,
|
||||||
|
props: ['tag'],
|
||||||
|
render: function (h, ctx) {
|
||||||
|
var tag = ctx.props.tag;
|
||||||
|
switch (tag.type) {
|
||||||
|
default:
|
||||||
|
case 'tag':
|
||||||
|
return h('a', {
|
||||||
|
staticClass: 'tag-preview tag-type-' + tag.tagType
|
||||||
|
}, tag.a);
|
||||||
|
case 'alias':
|
||||||
|
return h('span', {staticClass: 'tag-preview tag-preview-alias'}, [
|
||||||
|
h('del', undefined, [
|
||||||
|
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a)
|
||||||
|
]), ' → ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
|
||||||
|
]);
|
||||||
|
case 'implication':
|
||||||
|
return h('span', {staticClass: 'tag-preview tag-preview-implication'}, [
|
||||||
|
h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.a), ' ⇐ ', h('a', {staticClass: 'tag-type-' + tag.tagType}, tag.b)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var tagPreview = Vue.extend({
|
||||||
|
template: '#tag-preview',
|
||||||
|
props: ['tags', 'loading'],
|
||||||
|
components: {
|
||||||
|
'tag-preview': tagPreviewTag
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close: function () {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
splitTags: function () {
|
||||||
|
var newTags = this.tags.concat([]);
|
||||||
|
newTags.sort(function (a, b) {
|
||||||
|
return a.a === b.a ? 0 : (a.a < b.a ? -1 : 1);
|
||||||
|
});
|
||||||
|
var chunkArray = function (arr, size) {
|
||||||
|
var chunks = [];
|
||||||
|
for (var i = 0; i < arr.length; i += size) {
|
||||||
|
chunks.push(arr.slice(i, i + size));
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
};
|
||||||
|
return chunkArray(newTags, 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var editor = Vue.extend({
|
||||||
|
template: '#post-creator',
|
||||||
|
props: ['safe'],
|
||||||
|
components: {
|
||||||
|
'image-source': source,
|
||||||
|
'image-checkbox': checkbox,
|
||||||
|
'related-tags': relatedTags,
|
||||||
|
'tag-preview': tagPreview
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
var allChecks = {};
|
||||||
|
var addChecks = function (check) {
|
||||||
|
if (typeof check['tag'] !== "undefined") {
|
||||||
|
allChecks[check.tag] = true;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allChecks[check.name.toLowerCase().replace(' ', '_')] = true;
|
||||||
|
};
|
||||||
|
artist_checks.forEach(addChecks);
|
||||||
|
sex_checks.forEach(addChecks);
|
||||||
|
pairing_checks.forEach(addChecks);
|
||||||
|
char_count_checks.forEach(addChecks);
|
||||||
|
body_type_checks.forEach(addChecks);
|
||||||
|
return {
|
||||||
|
showErrors: false,
|
||||||
|
whitelist: {
|
||||||
|
visible: false,
|
||||||
|
allowed: false,
|
||||||
|
domain: ''
|
||||||
|
},
|
||||||
|
submitting: false,
|
||||||
|
disableFileUpload: false,
|
||||||
|
disableURLUpload: false,
|
||||||
|
|
||||||
|
previewHeight: 0,
|
||||||
|
previewWidth: 0,
|
||||||
|
overDims: false,
|
||||||
|
uploadURL: '',
|
||||||
|
previewURL: thumbs.none,
|
||||||
|
|
||||||
|
oldDomain: '',
|
||||||
|
|
||||||
|
noSource: false,
|
||||||
|
sources: [''],
|
||||||
|
normalMode: true,
|
||||||
|
|
||||||
|
checkboxes: {
|
||||||
|
artist: artist_checks,
|
||||||
|
sex: sex_checks,
|
||||||
|
pairing: pairing_checks,
|
||||||
|
count: char_count_checks,
|
||||||
|
body: body_type_checks,
|
||||||
|
selected: {},
|
||||||
|
all: allChecks
|
||||||
|
},
|
||||||
|
tagEntries: {
|
||||||
|
character: '',
|
||||||
|
sex: '',
|
||||||
|
bodyType: '',
|
||||||
|
theme: '',
|
||||||
|
other: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
preview: {
|
||||||
|
loading: false,
|
||||||
|
show: false,
|
||||||
|
tags: []
|
||||||
|
},
|
||||||
|
|
||||||
|
relatedTags: [],
|
||||||
|
loadingRelated: false,
|
||||||
|
|
||||||
|
parentID: '',
|
||||||
|
description: '',
|
||||||
|
rating: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updatePreview: updatePreview,
|
||||||
|
updatePreviewDims: updatePreviewDims,
|
||||||
|
previewError: previewError,
|
||||||
|
clearFile: clearFileUpload,
|
||||||
|
whitelistWarning: function (allowed, domain) {
|
||||||
|
this.whitelist.allowed = allowed;
|
||||||
|
this.whitelist.domain = domain;
|
||||||
|
this.whitelist.visible = true;
|
||||||
|
},
|
||||||
|
removeSource: function (i) {
|
||||||
|
this.sources.splice(i, 1);
|
||||||
|
},
|
||||||
|
addSource: function () {
|
||||||
|
if (this.sources.length < 5)
|
||||||
|
this.sources.push('');
|
||||||
|
},
|
||||||
|
setCheck: function (tag, value) {
|
||||||
|
Vue.set(this.checkboxes.selected, tag, value);
|
||||||
|
},
|
||||||
|
submit: function () {
|
||||||
|
this.showErrors = true;
|
||||||
|
if (this.preventUpload || this.submitting)
|
||||||
|
return;
|
||||||
|
var self = this;
|
||||||
|
this.submitting = true;
|
||||||
|
var data = new FormData();
|
||||||
|
var post_file = this.$refs['post_file'];
|
||||||
|
if (post_file && post_file.files && post_file.files.length) {
|
||||||
|
data.append('post[file]', this.$refs['post_file'].files[0]);
|
||||||
|
} else {
|
||||||
|
data.append('post[direct_url]', this.uploadURL);
|
||||||
|
}
|
||||||
|
data.append('upload[tag_string]', this.tags);
|
||||||
|
data.append('upload[rating]', this.rating);
|
||||||
|
data.append('upload[source]', this.sources.join('\n'));
|
||||||
|
// data.append('upload[description]', this.description);
|
||||||
|
data.append('upload[parent_id]', this.parentID);
|
||||||
|
jQuery.ajax('/uploads.json', {
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
method: 'POST',
|
||||||
|
type: 'POST',
|
||||||
|
data: data,
|
||||||
|
success: function (data) {
|
||||||
|
self.submitting = false;
|
||||||
|
notice('Post uploaded successfully.');
|
||||||
|
location.assign(data.location);
|
||||||
|
},
|
||||||
|
error: function (data) {
|
||||||
|
self.submitting = false;
|
||||||
|
try {
|
||||||
|
var data2 = JSON.parse(data.responseText);
|
||||||
|
if (data2 && data2.location) {
|
||||||
|
error('Error: Post already exists. <a href="' + data2.location + '">View it.</a>');
|
||||||
|
} else {
|
||||||
|
error('Error: ' + data2.reason);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
error('Error: Unknown error! ' + data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
pushTag: function (tag, add) {
|
||||||
|
this.preview.show = false;
|
||||||
|
var 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.
|
||||||
|
if (isCheck && this.normalMode) {
|
||||||
|
this.setCheck(tag, add);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tags = this.tagEntries.other ? this.tagEntries.other.trim().split(' ') : [];
|
||||||
|
var tagIdx = tags.indexOf(tag);
|
||||||
|
if (add) {
|
||||||
|
if (tagIdx === -1)
|
||||||
|
tags.push(tag);
|
||||||
|
} else {
|
||||||
|
if (tagIdx === -1)
|
||||||
|
return;
|
||||||
|
tags.splice(tagIdx, 1);
|
||||||
|
}
|
||||||
|
this.tagEntries.other = tags.join(' ') + ' ';
|
||||||
|
},
|
||||||
|
previewFinalTags: function () {
|
||||||
|
if (this.preview.loading)
|
||||||
|
return;
|
||||||
|
if (this.preview.show) {
|
||||||
|
this.preview.show = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.preview.loading = true;
|
||||||
|
this.preview.show = true;
|
||||||
|
this.preview.tags = [];
|
||||||
|
var self = this;
|
||||||
|
var data = {tags: this.tags};
|
||||||
|
jQuery.ajax("/tag/preview.json", {
|
||||||
|
method: 'POST',
|
||||||
|
type: 'POST',
|
||||||
|
data: data,
|
||||||
|
success: function (result) {
|
||||||
|
self.preview.loading = false;
|
||||||
|
self.preview.tags = result;
|
||||||
|
},
|
||||||
|
error: function (result) {
|
||||||
|
self.preview.loading = false;
|
||||||
|
self.preview.tags = [];
|
||||||
|
self.preview.show = false;
|
||||||
|
error('Error loading tag preview ' + result);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
findRelated: function (type) {
|
||||||
|
var self = this;
|
||||||
|
var convertResponse = function (respData) {
|
||||||
|
var sortedRelated = [];
|
||||||
|
for (var key in respData) {
|
||||||
|
if (!respData.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sortedRelated.push({title: 'Related: ' + key, tags: respData[key].sort(tagSorter)});
|
||||||
|
}
|
||||||
|
return sortedRelated;
|
||||||
|
};
|
||||||
|
var getSelectedTags = function () {
|
||||||
|
var field = self.$refs['otherTags'];
|
||||||
|
if (!field.hasOwnProperty('selectionStart'))
|
||||||
|
return null;
|
||||||
|
var length = field.selectionEnd - field.selectionStart;
|
||||||
|
if (length)
|
||||||
|
return field.value.substr(field.selectionStart, length);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
this.loadingRelated = true;
|
||||||
|
this.relatedTags = [];
|
||||||
|
var selectedTags = getSelectedTags();
|
||||||
|
var params = selectedTags ? {tags: selectedTags} : {tags: this.tags};
|
||||||
|
if (type)
|
||||||
|
params['type'] = type;
|
||||||
|
new Ajax.Request("/tag/related.json", {
|
||||||
|
method: 'POST',
|
||||||
|
parameters: params,
|
||||||
|
onComplete: function (resp) {
|
||||||
|
var respJ = resp.responseJSON;
|
||||||
|
self.relatedTags = convertResponse(respJ);
|
||||||
|
self.loadingRelated = false;
|
||||||
|
},
|
||||||
|
onError: function () {
|
||||||
|
self.loadingRelated = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tags: function () {
|
||||||
|
var self = this;
|
||||||
|
var checked = Object.keys(this.checkboxes.selected).filter(function (x) {
|
||||||
|
return self.checkboxes.selected[x] === true;
|
||||||
|
});
|
||||||
|
return checked.concat([this.tagEntries.other, this.tagEntries.sex, this.tagEntries.bodyType,
|
||||||
|
this.tagEntries.theme, this.tagEntries.character]).join(' ').replace(',', ' ').trim().replace(/ +/g, ' ');
|
||||||
|
},
|
||||||
|
tagsArray: function () {
|
||||||
|
return this.tags.toLowerCase().split(' ');
|
||||||
|
},
|
||||||
|
previewDimensions: function () {
|
||||||
|
if (this.previewWidth && this.previewHeight)
|
||||||
|
return this.previewHeight + '×' + this.previewWidth;
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
directURLProblem: function () {
|
||||||
|
return directURLCheck(this.uploadURL);
|
||||||
|
},
|
||||||
|
badDirectURL: function () {
|
||||||
|
return !!this.directURLProblem;
|
||||||
|
},
|
||||||
|
sourceWarning: function () {
|
||||||
|
var validSourceCount = this.sources.filter(function (i) {
|
||||||
|
return i.length > 0;
|
||||||
|
}).length;
|
||||||
|
return !this.noSource && (validSourceCount === 0);
|
||||||
|
},
|
||||||
|
tagCount: function () {
|
||||||
|
return this.tags.split(' ').filter(function (x) {
|
||||||
|
return x;
|
||||||
|
}).length;
|
||||||
|
},
|
||||||
|
notEnoughTags: function () {
|
||||||
|
return this.tagCount < 4;
|
||||||
|
},
|
||||||
|
invalidRating: function () {
|
||||||
|
return !this.rating;
|
||||||
|
},
|
||||||
|
preventUpload: function () {
|
||||||
|
return this.sourceWarning || this.badDirectURL || this.notEnoughTags
|
||||||
|
|| this.invalidRating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var main = new Vue({
|
||||||
|
el: '#post-add',
|
||||||
|
components: {
|
||||||
|
'post-creator': editor
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
178
app/views/uploads/upload_partials/_css.html.erb
Normal file
178
app/views/uploads/upload_partials/_css.html.erb
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<style>
|
||||||
|
.toggle-button {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: center;
|
||||||
|
user-select: none;
|
||||||
|
padding: .175em .5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-button.active {
|
||||||
|
background-color: #FDF5D9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-grid-outer {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_container.in-editor {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_container.in-sidebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-grid {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col2 {
|
||||||
|
flex: 2 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-bottom {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.come-together-now {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.over-me {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 0 1 10%;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0 -5px;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-item {
|
||||||
|
padding: 0 5px;
|
||||||
|
max-width: 140px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-title {
|
||||||
|
padding: 0 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-active {
|
||||||
|
background: rgb(0, 111, 250);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-preview {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
background: rgba(1, 1, 1, 0.15);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 3px;
|
||||||
|
margin-right: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-preview-alias {
|
||||||
|
background-color: rgba(150, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-preview-implication {
|
||||||
|
background-color: rgba(0, 150, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-textarea {
|
||||||
|
display: inline-block; /* Why were we even unsetting this? It breaks EVERYTHING. */
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to override this so it shows up at all. */
|
||||||
|
#whitelist-warning {
|
||||||
|
display: block;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (orientation: portrait), (max-width: 1100px) {
|
||||||
|
#preview-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_container.in-editor {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_container.in-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_dims {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload_preview_img {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.below-upload > .upload_preview_img {
|
||||||
|
max-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-section {
|
||||||
|
flex: 0 1 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-grid {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.the_secret_switch {
|
||||||
|
height: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
12
app/views/uploads/upload_partials/_related.html.erb
Normal file
12
app/views/uploads/upload_partials/_related.html.erb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template id="related-tags">
|
||||||
|
<div class="related-tags flex-wrap">
|
||||||
|
<div class="related-section" v-for="group in tagGroups" :key="group.title">
|
||||||
|
<div class="related-items" v-for="tags, i in splitTags(group.tags)" :key="i">
|
||||||
|
<div class="related-title" v-if="i === 0">{{group.title}}</div>
|
||||||
|
<div class="related-item" v-for="tag in tags" :key="tag[0]">
|
||||||
|
<a :class="tagClasses(tag)" :href="tagLink(tag)" @click.prevent="toggle(tag)">{{tag[0]}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
7
app/views/uploads/upload_partials/_source.html.erb
Normal file
7
app/views/uploads/upload_partials/_source.html.erb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template id="source-template">
|
||||||
|
<div>
|
||||||
|
<input type="text" size="50" v-model="realValue" @keyup.enter="add"/>
|
||||||
|
<button @click="remove" v-if="index !== 0">-</button>
|
||||||
|
<button @click="add" v-if="last && index < 4">+</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
13
app/views/uploads/upload_partials/_tag_preview.html.erb
Normal file
13
app/views/uploads/upload_partials/_tag_preview.html.erb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template id="tag-preview">
|
||||||
|
<div>
|
||||||
|
<div v-show="loading">Fetching tags...</div>
|
||||||
|
<div class="related-tags flex-wrap">
|
||||||
|
<div class="related-items" v-for="sTags, i in splitTags" :key="i">
|
||||||
|
<tag-preview v-for="tag, $idx in sTags" :key="$idx" :tag="tag"></tag-preview>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#" @click.prevent="close">Close Preview</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
228
app/views/uploads/upload_partials/_uploader.html.erb
Normal file
228
app/views/uploads/upload_partials/_uploader.html.erb
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<template id="checkbox-template">
|
||||||
|
<button class="toggle-button" :class="{active: value}" @click="value = !value">{{check.name}}</button>
|
||||||
|
</template>
|
||||||
|
<template id="post-creator">
|
||||||
|
<div class="flex-grid-outer">
|
||||||
|
<div class="col box-section" style="flex: 2 0 0;">
|
||||||
|
<div class="the_secret_switch" @click="normalMode = !normalMode"></div>
|
||||||
|
<% unless @upload.new_record? %>
|
||||||
|
<div class="box-section" style="margin-bottom: 1rem;">
|
||||||
|
<p>This post was already uploaded
|
||||||
|
(<%= link_to "post ##{@upload.id}", {action: "show", id: @upload.id}, target: "_blank" %>).</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_file">Image</label>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div v-if="!disableFileUpload">
|
||||||
|
<label>File:
|
||||||
|
<input type="file" ref="post_file" @change="updatePreview" :disabled="disableFileUpload"/>
|
||||||
|
</label>
|
||||||
|
<button @click="clearFile" v-show="disableURLUpload">Clear</button>
|
||||||
|
</div>
|
||||||
|
<div v-if="!disableURLUpload">
|
||||||
|
<div class="box-section sect_red" v-if="badDirectURL">
|
||||||
|
The direct URL entered has the following problem: {{ directURLProblem }}<br>
|
||||||
|
You should review <a href="/wiki/show/howto:sites_and_sources">the sourcing guide</a>.
|
||||||
|
</div>
|
||||||
|
<label>{{!disableFileUpload ? '(or) ' : '' }}URL:
|
||||||
|
<input type="text" size="50" v-model="uploadURL" @keyup="updatePreview" :disabled="disableURLUpload"/>
|
||||||
|
</label>
|
||||||
|
<div id="whitelist-warning" v-show="whitelist.visible" :class="{'whitelist-warning-allowed': whitelist.allowed, 'whitelist-warning-disallowed': !whitelist.allowed}">
|
||||||
|
<span v-if="whitelist.allowed">Uploads from <b>{{whitelist.domain}}</b> are permitted.</span>
|
||||||
|
<span v-if="!whitelist.allowed">Uploads from <b>{{whitelist.domain}}</b> are not permitted. (<a href='/upload_whitelist'>View whitelisted domains</a>)</span>
|
||||||
|
</div>
|
||||||
|
</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%;"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_sources">Sources</label>
|
||||||
|
<div>You should include: A link to the artists page where this was obtained, and a link to the submission page
|
||||||
|
where this image was obtained. No available source should ONLY be used if the content has never been posted
|
||||||
|
online anywhere else.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div class="box-section sect_red" v-show="showErrors && sourceWarning">A source must be provided or you must
|
||||||
|
select that there
|
||||||
|
is no available source.
|
||||||
|
</div>
|
||||||
|
<div v-if="!noSource">
|
||||||
|
<image-source :last="i === (sources.length-1)" :index="i" v-model="sources[i]" v-for="s, i in sources"
|
||||||
|
@delete="removeSource(i)" @add="addSource" :key="i"></image-source>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="section-label"><input type="checkbox" id="no_source" v-model="noSource"/> No available source
|
||||||
|
/ I am the source.</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-if="normalMode">
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="names">Artists</label>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div>
|
||||||
|
<textarea class="tag-textarea" v-model="tagEntries.character" id="post_characters" rows="2"
|
||||||
|
placeholder="Ex: artist_name etc."></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<image-checkbox :check="check" :checks="checkboxes.selected" v-for="check in checkboxes.artist" @set="setCheck"
|
||||||
|
:key="check.name"></image-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_sex_tags">Characters</label>
|
||||||
|
<div>Select (and write in) all that apply. Character sex is based only on what is visible in the image.
|
||||||
|
Outside information or other images should not be used when deciding what tags are used.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<image-checkbox :check="check" :checks="checkboxes.selected" v-for="check in checkboxes.sex" @set="setCheck"
|
||||||
|
:key="check.name"></image-checkbox>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<image-checkbox :check="check" :checks="checkboxes.selected" v-for="check in checkboxes.count" @set="setCheck"
|
||||||
|
:key="check.name"></image-checkbox>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<image-checkbox :check="check" :checks="checkboxes.selected" v-for="check in checkboxes.pairing" @set="setCheck"
|
||||||
|
:key="check.name"></image-checkbox>
|
||||||
|
</div>
|
||||||
|
<textarea class="tag-textarea" rows="2" v-model="tagEntries.sex" id="post_sexes"
|
||||||
|
placeholder="Ex: character_name solo_focus etc."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label">Body Types and Species</label>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div class="flex-wrap">
|
||||||
|
<image-checkbox :check="check" :checks="checkboxes.selected" v-for="check in checkboxes.body" @set="setCheck"
|
||||||
|
:key="check.name"></image-checkbox>
|
||||||
|
</div>
|
||||||
|
<textarea class="tag-textarea" rows="2" v-model="tagEntries.bodyType" id="post_bodyTypes"
|
||||||
|
placeholder="Ex: bear dragon hyena rat newt etc."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label">Contentious Content</label>
|
||||||
|
<div>
|
||||||
|
These allow users to find or blacklist content with ease. Make sure that you are tagging these upon
|
||||||
|
initial upload.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<textarea class="tag-textarea" v-model="tagEntries.theme" id="post_themes" rows="2"
|
||||||
|
placeholder="Ex: cub young gore scat watersports diaper my_little_pony vore not_furry rape etc."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_rating_questionable">Rating</label>
|
||||||
|
<div>Explicit tags include sex, pussy, penis, masturbation, fellatio, etc.
|
||||||
|
(<%= link_to "help", help_pages_path(title: 'ratings'), target: "_blank" %>)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<div class="box-section sect_red" v-if="showErrors && invalidRating">
|
||||||
|
You must select an appropriate rating for this image.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<template v-if="!safe">
|
||||||
|
<button class="toggle-button" :class="{active: rating==='e'}" @click="rating = 'e'">Explicit</button>
|
||||||
|
<button class="toggle-button" :class="{active: rating==='q'}" @click="rating = 'q'">Questionable</button>
|
||||||
|
</template>
|
||||||
|
<button class="toggle-button" :class="{active: rating==='s'}" @click="rating = 's'">Safe</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid come-together-now">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_tags">Other Tags</label>
|
||||||
|
<div>
|
||||||
|
Separate tags with spaces. (<%= link_to "help", help_pages_path(title: 'tags'), target: "_blank" %>)
|
||||||
|
</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%;"/>
|
||||||
|
</div>
|
||||||
|
<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">
|
||||||
|
<textarea class="tag-textarea" id="post_tags" v-model="tagEntries.other" rows="5" ref="otherTags"></textarea>
|
||||||
|
</div>
|
||||||
|
<div v-show="preview.show">
|
||||||
|
<tag-preview :tags="preview.tags" :loading="preview.loading" @close="previewFinalTags"></tag-preview>
|
||||||
|
</div>
|
||||||
|
<div class="related-tag-functions">
|
||||||
|
<a href="#" @click.prevent="findRelated">Related Tags</a> |
|
||||||
|
<a href="#" @click.prevent="findRelated('artist')">Related Artists</a> |
|
||||||
|
<a href="#" @click.prevent="findRelated('char')">Related Characters</a> |
|
||||||
|
<a href="#" @click.prevent="findRelated('copyright')">Related Copyrights</a> |
|
||||||
|
<a href="#" @click.prevent="previewFinalTags">Preview Final Tags</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom over-me">
|
||||||
|
<related-tags :tags="tagsArray" :related="relatedTags" :loading="loadingRelated" @tag-active="pushTag"></related-tags>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label">Parent Post ID</label>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<input type="number" v-model.number="parentID" placeholder="Ex. 12345"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid border-bottom">
|
||||||
|
<div class="col">
|
||||||
|
<label class="section-label" for="post_description">Description</label>
|
||||||
|
</div>
|
||||||
|
<div class="col2">
|
||||||
|
<textarea class="tag-textarea" id="post_description" v-model="description" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grid">
|
||||||
|
<div class="col"></div>
|
||||||
|
<div class="col2">
|
||||||
|
<div class="box-section sect_red" v-show="preventUpload && showErrors">
|
||||||
|
Unmet requirements above prevent the submission of the post.
|
||||||
|
</div>
|
||||||
|
<div class="box-section sect_green" v-show="submitting">
|
||||||
|
Submitting your post, please wait.
|
||||||
|
</div>
|
||||||
|
<button @click="submit" :disabled="(showErrors && preventUpload) || submitting" accesskey="s">{{ submitting ? 'Uploading...' :
|
||||||
|
'Upload' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -10,7 +10,8 @@
|
|||||||
"qtip2": "^3.0.3",
|
"qtip2": "^3.0.3",
|
||||||
"rails-erb-loader": "^5.4.2",
|
"rails-erb-loader": "^5.4.2",
|
||||||
"script-loader": "^0.7.2",
|
"script-loader": "^0.7.2",
|
||||||
"webpack-cli": "^3.0.8"
|
"webpack-cli": "^3.0.8",
|
||||||
|
"vue": "^2.6.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^5.3.0",
|
"eslint": "^5.3.0",
|
||||||
|
11944
public/vendor/vue.js
vendored
Normal file
11944
public/vendor/vue.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -6682,6 +6682,11 @@ vm-browserify@0.0.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
indexof "0.0.1"
|
indexof "0.0.1"
|
||||||
|
|
||||||
|
vue@^2.6.10:
|
||||||
|
version "2.6.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
|
||||||
|
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
|
||||||
|
|
||||||
watchpack@^1.4.0:
|
watchpack@^1.4.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
||||||
|
Loading…
Reference in New Issue
Block a user