Merge pull request #4586 from consul/attach_with_keyboard

Allow attaching files using the keyboard
This commit is contained in:
Javi Martín
2021-07-15 00:19:27 +02:00
committed by GitHub
40 changed files with 324 additions and 450 deletions

View File

@@ -17,11 +17,11 @@
App.Documentable.lockUploads();
}
});
App.Documentable.initializeRemoveCachedDocumentLinks();
},
initializeDirectUploadInput: function(input) {
var inputData;
inputData = this.buildData([], input);
this.initializeRemoveCachedDocumentLink(input, inputData);
$(input).fileupload({
paramName: "attachment",
formData: null,
@@ -45,7 +45,6 @@
App.Documentable.setInputErrors(data);
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove();
$(data.addAttachmentLabel).addClass("error");
$(data.addAttachmentLabel).show();
},
done: function(e, data) {
var destroyAttachmentLink;
@@ -54,16 +53,8 @@
App.Documentable.setProgressBar(data, "complete");
App.Documentable.setFilename(data, data.result.filename);
App.Documentable.clearInputErrors(data);
$(data.addAttachmentLabel).hide();
$(data.wrapper).find(".attachment-actions").removeClass("small-12").addClass("small-6 float-right");
$(data.wrapper).find(".attachment-actions .action-remove").removeClass("small-3").addClass("small-12");
destroyAttachmentLink = $(data.result.destroy_link);
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink);
$(destroyAttachmentLink).on("click", function(event) {
event.preventDefault();
event.stopPropagation();
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data);
});
if (input.lockUpload) {
App.Documentable.showNotice();
}
@@ -78,8 +69,6 @@
buildData: function(data, input) {
var wrapper;
wrapper = $(input).closest(".direct-upload");
data.input = input;
data.wrapper = wrapper;
data.progressBar = $(wrapper).find(".progress-bar-placeholder");
data.errorContainer = $(wrapper).find(".attachment-errors");
data.fileNameContainer = $(wrapper).find("p.file-name");
@@ -92,7 +81,6 @@
},
clearFilename: function(data) {
$(data.fileNameContainer).text("");
$(data.fileNameContainer).hide();
},
clearInputErrors: function(data) {
$(data.errorContainer).find("small.error").remove();
@@ -102,7 +90,6 @@
},
setFilename: function(data, file_name) {
$(data.fileNameContainer).text(file_name);
$(data.fileNameContainer).show();
},
setProgressBar: function(data, klass) {
$(data.progressBar).find(".loading-bar").addClass(klass);
@@ -127,39 +114,10 @@
showNotice: function() {
$("#max-documents-notice").removeClass("hide");
},
doDeleteCachedAttachmentRequest: function(url, data) {
$.ajax({
type: "POST",
url: url,
dataType: "json",
data: {
"_method": "delete"
},
complete: function() {
$(data.cachedAttachmentField).val("");
$(data.addAttachmentLabel).show();
App.Documentable.clearFilename(data);
App.Documentable.clearInputErrors(data);
App.Documentable.clearProgressBar(data);
App.Documentable.unlockUploads();
$(data.wrapper).find(".attachment-actions").addClass("small-12").removeClass("small-6 float-right");
$(data.wrapper).find(".attachment-actions .action-remove").addClass("small-3").removeClass("small-12");
if ($(data.input).data("nested-document") === true) {
$(data.wrapper).remove();
} else {
$(data.wrapper).find("a.remove-cached-attachment").remove();
}
}
});
},
initializeRemoveCachedDocumentLink: function(input, data) {
var remove_document_link, wrapper;
wrapper = $(input).closest(".direct-upload");
remove_document_link = $(wrapper).find("a.remove-cached-attachment");
$(remove_document_link).on("click", function(e) {
e.preventDefault();
e.stopPropagation();
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data);
initializeRemoveCachedDocumentLinks: function() {
$("#nested-documents").on("ajax:complete", "a.remove-cached-attachment", function() {
App.Documentable.unlockUploads();
$(this).closest(".direct-upload").remove();
});
},
removeDocument: function(id) {

View File

@@ -8,20 +8,17 @@
$("#nested-image").on("cocoon:after-remove", function() {
$("#new_image_link").removeClass("hide");
});
$("#nested-image").on("cocoon:before-insert", function() {
$(".js-image-attachment").closest(".image").remove();
});
$("#nested-image").on("cocoon:after-insert", function(e, nested_image) {
var input;
$("#new_image_link").addClass("hide");
input = $(nested_image).find(".js-image-attachment");
App.Imageable.initializeDirectUploadInput(input);
});
App.Imageable.initializeRemoveCachedImageLinks();
},
initializeDirectUploadInput: function(input) {
var inputData;
inputData = this.buildData([], input);
this.initializeRemoveCachedImageLink(input, inputData);
$(input).fileupload({
paramName: "attachment",
formData: null,
@@ -46,7 +43,6 @@
App.Imageable.clearPreview(data);
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove();
$(data.addAttachmentLabel).addClass("error");
$(data.addAttachmentLabel).show();
},
done: function(e, data) {
var destroyAttachmentLink;
@@ -55,17 +51,9 @@
App.Imageable.setProgressBar(data, "complete");
App.Imageable.setFilename(data, data.result.filename);
App.Imageable.clearInputErrors(data);
$(data.addAttachmentLabel).hide();
$(data.wrapper).find(".attachment-actions").removeClass("small-12").addClass("small-6 float-right");
$(data.wrapper).find(".attachment-actions .action-remove").removeClass("small-3").addClass("small-12");
App.Imageable.setPreview(data);
destroyAttachmentLink = $(data.result.destroy_link);
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink);
$(destroyAttachmentLink).on("click", function(event) {
event.preventDefault();
event.stopPropagation();
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data);
});
},
progress: function(e, data) {
var progress;
@@ -77,7 +65,6 @@
buildData: function(data, input) {
var wrapper;
wrapper = $(input).closest(".direct-upload");
data.input = input;
data.wrapper = wrapper;
data.progressBar = $(wrapper).find(".progress-bar-placeholder");
data.preview = $(wrapper).find(".image-preview");
@@ -92,7 +79,6 @@
},
clearFilename: function(data) {
$(data.fileNameContainer).text("");
$(data.fileNameContainer).hide();
},
clearInputErrors: function(data) {
$(data.errorContainer).find("small.error").remove();
@@ -105,7 +91,6 @@
},
setFilename: function(data, file_name) {
$(data.fileNameContainer).text(file_name);
$(data.fileNameContainer).show();
},
setProgressBar: function(data, klass) {
$(data.progressBar).find(".loading-bar").addClass(klass);
@@ -130,40 +115,10 @@
data.preview = $(data.wrapper).find(".image-preview");
}
},
doDeleteCachedAttachmentRequest: function(url, data) {
$.ajax({
type: "POST",
url: url,
dataType: "json",
data: {
"_method": "delete"
},
complete: function() {
$(data.cachedAttachmentField).val("");
$(data.addAttachmentLabel).show();
App.Imageable.clearFilename(data);
App.Imageable.clearInputErrors(data);
App.Imageable.clearProgressBar(data);
App.Imageable.clearPreview(data);
$("#new_image_link").removeClass("hide");
$(data.wrapper).find(".attachment-actions").addClass("small-12").removeClass("small-6 float-right");
$(data.wrapper).find(".attachment-actions .action-remove").addClass("small-3").removeClass("small-12");
if ($(data.input).data("nested-image") === true) {
$(data.wrapper).remove();
} else {
$(data.wrapper).find("a.remove-cached-attachment").remove();
}
}
});
},
initializeRemoveCachedImageLink: function(input, data) {
var remove_image_link, wrapper;
wrapper = $(input).closest(".direct-upload");
remove_image_link = $(wrapper).find("a.remove-cached-attachment");
$(remove_image_link).on("click", function(e) {
e.preventDefault();
e.stopPropagation();
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data);
initializeRemoveCachedImageLinks: function() {
$("#nested-image").on("ajax:complete", "a.remove-cached-attachment", function() {
$("#new_image_link").removeClass("hide");
$(this).closest(".direct-upload").remove();
});
},
removeImage: function(id) {

View File

@@ -20,13 +20,17 @@
p {
margin-bottom: 0;
}
&:focus-within label {
outline: $outline-focus;
}
}
.attachment-errors {
> .js-image-attachment,
> .js-document-attachment {
display: none;
@include element-invisible;
~ .error {
display: inline-block;
@@ -41,7 +45,17 @@
}
.file-name {
padding-left: 0;
margin-top: 0;
&:empty {
display: none;
}
&:not(:empty) + .document-attachment,
&:not(:empty) + .image-attachment {
display: none;
}
}
.loading-bar {

View File

@@ -57,7 +57,7 @@
<% if feature?(:allow_images) %>
<div class="images small-12 column">
<%= render "images/nested_image", imageable: @phase, f: f %>
<%= render "images/nested_image", f: f %>
<p class="help-text"><%= t("admin.budget_phases.edit.image_description") %></p>
</div>
<% end %>

View File

@@ -41,7 +41,7 @@
<% if feature?(:allow_images) %>
<div class="images small-12 column">
<%= render "/images/nested_image", imageable: budget, f: f %>
<%= render "/images/nested_image", f: f %>
<p class="help-text"><%= t("admin.budgets.edit.image_description") %></p>
</div>
<% end %>

View File

@@ -38,13 +38,13 @@
<% if feature?(:allow_images) %>
<div class="images">
<%= render "images/nested_image", imageable: investment, f: f %>
<%= render "images/nested_image", f: f %>
</div>
<% end %>
<% if feature?(:allow_attached_documents) %>
<div class="documents">
<%= render "documents/nested_documents", documentable: investment, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<% end %>

View File

@@ -0,0 +1,28 @@
<div class="document direct-upload document-fields nested-fields">
<%= f.hidden_field :id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :cached_attachment %>
<div class="small-12 column title">
<%= f.text_field :title, placeholder: t("documents.form.title_placeholder") %>
</div>
<div class="small-12 column attachment-actions">
<p class="file-name small-9 column"><%= file_name %></p>
<div class="small-9 column action-add attachment-errors document-attachment">
<%= file_field %>
</div>
<div class="small-3 column action-remove text-right">
<%= destroy_link %>
</div>
</div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
<hr>
</div>

View File

@@ -0,0 +1,54 @@
class Documents::FieldsComponent < ApplicationComponent
attr_reader :f
delegate :current_user, to: :helpers
def initialize(f)
@f = f
end
private
def document
f.object
end
def file_name
document.attachment_file_name
end
def destroy_link
if !document.persisted? && document.cached_attachment.present?
link_to t("documents.form.delete_button"),
direct_upload_destroy_path(
"direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents",
"direct_upload[cached_attachment]": document.cached_attachment
),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to_remove_association document.new_record? ? t("documents.form.cancel_button") : t("documents.form.delete_button"), f, class: "delete remove-document"
end
end
def file_field
klass = document.persisted? || document.cached_attachment.present? ? " hide" : ""
f.file_field :attachment,
label_options: { class: "button hollow #{klass}" },
accept: accepted_content_types_extensions,
class: "js-document-attachment",
data: { url: direct_upload_path }
end
def direct_upload_path
direct_uploads_path("direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents")
end
def accepted_content_types_extensions
Setting.accepted_content_types_for("documents").map { |content_type| ".#{content_type}" }.join(",")
end
end

View File

@@ -0,0 +1,24 @@
<fieldset class="documents-list">
<legend><%= t("documents.form.title") %></legend>
<p class="help-text"><%= note %></p>
<div id="nested-documents" data-max-documents-allowed="<%= max_documents_allowed %>">
<%= f.fields_for :documents do |documents_builder| %>
<%= render Documents::FieldsComponent.new(documents_builder) %>
<% end %>
</div>
<%= link_to_add_association t("documents.form.add_new_document"), f, :documents,
partial: "documents/document_fields",
id: "new_document_link",
class: "button upload-document
#{"hide" if max_documents_allowed?}",
data: {
association_insertion_node: "#nested-documents",
association_insertion_method: "append"
} %>
<div id="max-documents-notice" class="max-documents-notice callout primary text-center <%= "hide" unless max_documents_allowed? %>">
<%= sanitize(t("documents.max_documents_allowed_reached")) %>
</div>
</fieldset>

View File

@@ -0,0 +1,28 @@
class Documents::NestedComponent < ApplicationComponent
attr_reader :f
delegate :documentable_humanized_accepted_content_types, :max_file_size, to: :helpers
def initialize(f)
@f = f
end
private
def documentable
f.object
end
def max_documents_allowed
documentable.class.max_documents_allowed
end
def note
t "documents.form.note", max_documents_allowed: max_documents_allowed,
accepted_content_types: documentable_humanized_accepted_content_types(documentable.class),
max_file_size: max_file_size(documentable.class)
end
def max_documents_allowed?
documentable.documents.count >= max_documents_allowed
end
end

View File

@@ -0,0 +1,29 @@
<div class="image direct-upload nested-fields">
<%= f.hidden_field :id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :cached_attachment %>
<div class="small-12 margin-top title">
<%= f.text_field :title, placeholder: t("images.form.title_placeholder") %>
</div>
<%= render_image(image, :thumb, false) if image.attachment.exists? %>
<div class="small-12 column attachment-actions">
<p class="file-name small-9 column"><%= file_name %></p>
<div class="small-9 column action-add attachment-errors image-attachment">
<%= file_field %>
</div>
<div class="small-3 column action-remove text-right">
<%= destroy_link %>
</div>
</div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
<hr>
</div>

View File

@@ -0,0 +1,61 @@
class Images::FieldsComponent < ApplicationComponent
attr_reader :f, :imageable
delegate :current_user, :render_image, to: :helpers
def initialize(f, imageable:)
@f = f
@imageable = imageable
end
private
def image
f.object
end
def file_name
image.attachment_file_name
end
def destroy_link
if !image.persisted? && image.cached_attachment.present?
link_to t("images.form.delete_button"),
direct_upload_destroy_path(
"direct_upload[resource_type]": image.imageable_type,
"direct_upload[resource_id]": image.imageable_id,
"direct_upload[resource_relation]": "image",
"direct_upload[cached_attachment]": image.cached_attachment
),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to_remove_association t("images.form.delete_button"), f, class: "delete remove-image"
end
end
def file_field
klass = image.persisted? || image.cached_attachment.present? ? " hide" : ""
f.file_field :attachment,
label_options: { class: "button hollow #{klass}" },
accept: accepted_content_types_extensions,
class: "js-image-attachment",
data: { url: direct_upload_path }
end
def direct_upload_path
direct_uploads_path("direct_upload[resource_type]": imageable.class.name,
"direct_upload[resource_id]": imageable.id,
"direct_upload[resource_relation]": "image")
end
def accepted_content_types_extensions
Setting.accepted_content_types_for("images").map do |content_type|
if content_type == "jpg"
".jpg,.jpeg"
else
".#{content_type}"
end
end.join(",")
end
end

View File

@@ -0,0 +1,24 @@
<fieldset>
<legend><%= t("images.form.title") %></legend>
<p class="help-text"><%= note %></p>
<div id="nested-image">
<%= f.fields_for image_fields do |image_builder| %>
<%= render Images::FieldsComponent.new(image_builder, imageable: imageable) %>
<% end %>
</div>
<%= link_to_add_association t("images.form.add_new_image"), f, image_fields,
force_non_association_create: true,
partial: "images/image_fields",
id: "new_image_link",
class: "button upload-image
#{"hide" if image_fields == :image && imageable.image.present?}",
render_options: {
locals: { imageable: imageable }
},
data: {
association_insertion_node: "#nested-image",
association_insertion_method: "append"
} %>
</fieldset>

View File

@@ -0,0 +1,20 @@
class Images::NestedComponent < ApplicationComponent
attr_reader :f, :image_fields
delegate :imageable_humanized_accepted_content_types, :imageable_max_file_size, to: :helpers
def initialize(f, image_fields: :image)
@f = f
@image_fields = image_fields
end
private
def imageable
f.object
end
def note
t "images.form.note", accepted_content_types: imageable_humanized_accepted_content_types,
max_file_size: imageable_max_file_size
end
end

View File

@@ -39,13 +39,13 @@
<% if feature?(:allow_images) %>
<div class="images">
<%= render "images/nested_image", imageable: proposal, f: f %>
<%= render "images/nested_image", f: f %>
</div>
<% end %>
<% if feature?(:allow_attached_documents) %>
<div class="documents">
<%= render "documents/nested_documents", documentable: proposal, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<% end %>

View File

@@ -7,11 +7,9 @@ class Admin::Poll::Questions::Answers::ImagesController < Admin::Poll::BaseContr
end
def new
@answer = ::Poll::Question::Answer.find(params[:answer_id])
end
def create
@answer = ::Poll::Question::Answer.find(params[:answer_id])
@answer.attributes = images_params
if @answer.save

View File

@@ -1,12 +1,4 @@
module DocumentablesHelper
def documentable_class(documentable)
documentable.class.name.parameterize(separator: "_")
end
def max_documents_allowed(documentable)
documentable.class.max_documents_allowed
end
def max_file_size(documentable_class)
documentable_class.max_file_size / Numeric::MEGABYTE
end
@@ -15,21 +7,7 @@ module DocumentablesHelper
documentable_class.accepted_content_types
end
def accepted_content_types_extensions(documentable_class)
Setting.accepted_content_types_for("documents").map { |content_type| ".#{content_type}" }.join(",")
end
def documentable_humanized_accepted_content_types(documentable_class)
Setting.accepted_content_types_for("documents").join(", ")
end
def documentables_note(documentable)
t "documents.form.note", max_documents_allowed: max_documents_allowed(documentable),
accepted_content_types: documentable_humanized_accepted_content_types(documentable.class),
max_file_size: max_file_size(documentable.class)
end
def max_documents_allowed?(documentable)
documentable.documents.count >= documentable.class.max_documents_allowed
end
end

View File

@@ -1,47 +1,4 @@
module DocumentsHelper
def document_attachment_file_name(document)
document.attachment_file_name
end
def document_errors_on_attachment(document)
document.errors[:attachment].join(", ") if document.errors.key?(:attachment)
end
def render_destroy_document_link(builder, document)
if !document.persisted? && document.cached_attachment.present?
link_to t("documents.form.delete_button"),
direct_upload_destroy_path(
"direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents",
"direct_upload[cached_attachment]": document.cached_attachment
),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to_remove_association document.new_record? ? t("documents.form.cancel_button") : t("documents.form.delete_button"), builder, class: "delete remove-document"
end
end
def render_attachment(builder, document)
klass = document.persisted? || document.cached_attachment.present? ? " hide" : ""
builder.file_field :attachment,
label_options: { class: "button hollow #{klass}" },
accept: accepted_content_types_extensions(document.documentable_type.constantize),
class: "js-document-attachment",
data: {
url: document_direct_upload_path(document),
nested_document: true
}
end
def document_direct_upload_path(document)
direct_uploads_path("direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents")
end
def document_item_link(document)
info_text = "#{document.humanized_content_type} | #{number_to_human_size(document.attachment_file_size)}"

View File

@@ -11,22 +11,7 @@ module ImageablesHelper
Setting["uploads.images.content_types"]&.split(" ") || ["image/jpeg"]
end
def imageable_accepted_content_types_extensions
Setting.accepted_content_types_for("images").map do |content_type|
if content_type == "jpg"
".jpg,.jpeg"
else
".#{content_type}"
end
end.join(",")
end
def imageable_humanized_accepted_content_types
Setting.accepted_content_types_for("images").join(", ")
end
def imageables_note(_imageable)
t "images.form.note", accepted_content_types: imageable_humanized_accepted_content_types,
max_file_size: imageable_max_file_size
end
end

View File

@@ -9,57 +9,14 @@ module ImagesHelper
end
end
def image_attachment_file_name(image)
image.attachment_file_name
end
def image_errors_on_attachment(image)
image.errors[:attachment].join(", ") if image.errors.key?(:attachment)
end
def image_class(image)
image.persisted? ? "persisted-image" : "cached-image"
end
def render_destroy_image_link(builder, image)
if !image.persisted? && image.cached_attachment.present?
link_to t("images.form.delete_button"),
direct_upload_destroy_path(
"direct_upload[resource_type]": image.imageable_type,
"direct_upload[resource_id]": image.imageable_id,
"direct_upload[resource_relation]": "image",
"direct_upload[cached_attachment]": image.cached_attachment
),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to_remove_association t("images.form.delete_button"), builder, class: "delete remove-image"
end
end
def render_image_attachment(builder, imageable, image)
klass = image.persisted? || image.cached_attachment.present? ? " hide" : ""
builder.file_field :attachment,
label_options: { class: "button hollow #{klass}" },
accept: imageable_accepted_content_types_extensions,
class: "js-image-attachment",
data: {
url: image_direct_upload_path(imageable),
nested_image: true
}
end
def render_image(image, version, show_caption = true)
version = image.persisted? ? version : :original
render "images/image", image: image,
version: version,
show_caption: show_caption
end
def image_direct_upload_path(imageable)
direct_uploads_path("direct_upload[resource_type]": imageable.class.name,
"direct_upload[resource_id]": imageable.id,
"direct_upload[resource_relation]": "image")
end
end

View File

@@ -62,7 +62,7 @@
<% if feature?(:allow_attached_documents) %>
<div class="documents small-12 column">
<hr>
<%= render "documents/nested_documents", documentable: dashboard_action, f: f %>
<%= render "documents/nested_documents", f: f %>
<hr>
</div>
<% end %>

View File

@@ -110,7 +110,7 @@
<div class="row">
<div class="documents small-12 column">
<%= render "documents/nested_documents", documentable: @process, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<div class="small-12 column">
@@ -118,7 +118,7 @@
</div>
<div class="images small-12 column">
<%= render "images/nested_image", imageable: @process, f: f %>
<%= render "images/nested_image", f: f %>
</div>
<div class="small-12 column">

View File

@@ -27,10 +27,10 @@
<div class="column">
<%= f.date_field :publication_date %>
<%= render "images/admin_image", imageable: @milestone, f: f %>
<%= render "images/nested_image", f: f %>
<div class="documents">
<%= render "documents/nested_documents", documentable: @milestone, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<%= f.submit nil, class: "button success" %>

View File

@@ -32,8 +32,8 @@
</div>
<div class="row">
<div class="small-12 column">
<%= render "images/admin_image", imageable: @poll, f: f %>
<div class="images small-12 column">
<%= render "images/nested_image", f: f %>
</div>
<div class="clear">

View File

@@ -15,7 +15,7 @@
<%= render "shared/errors", resource: @answer %>
<div class="documents">
<%= render "documents/nested_documents", documentable: @answer, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<div class="small-12 medium-6 large-2">

View File

@@ -5,7 +5,7 @@
<%= render "shared/errors", resource: @answer %>
<div class="images">
<%= render "images/nested_image", imageable: @answer, f: f, image_fields: :images %>
<%= render Images::NestedComponent.new(f, image_fields: :images) %>
</div>
<%= f.submit t("admin.questions.answers.images.save_image"), class: "button success" %>

View File

@@ -45,7 +45,7 @@
<div class="row">
<div class="image-form">
<div class="image small-12 column">
<%= render "images/nested_image", imageable: card, f: f %>
<%= render "images/nested_image", f: f %>
</div>
</div>
<div class="column">

View File

@@ -1,31 +1 @@
<div id="<%= dom_id(f.object) %>" class="document direct-upload document-fields nested-fields">
<%= f.hidden_field :id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :cached_attachment %>
<div class="small-12 column title">
<%= f.text_field :title, placeholder: t("documents.form.title_placeholder") %>
</div>
<div class="small-12 column attachment-actions">
<div class="small-9 column action-add attachment-errors document-attachment">
<%= render_attachment(f, f.object) %>
</div>
<div class="small-3 column action-remove text-right">
<%= render_destroy_document_link(f, f.object) %>
</div>
</div>
<div class="small-6 column">
<p class="file-name">
<%= document_attachment_file_name(f.object) %>
</p>
</div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
<hr>
</div>
<%= render Documents::FieldsComponent.new(f) %>

View File

@@ -1,24 +1 @@
<div class="documents-list">
<%= f.label :documents, t("documents.form.title") %>
<p class="help-text"><%= documentables_note(documentable) %></p>
<div id="nested-documents" data-max-documents-allowed="<%= documentable.class.max_documents_allowed %>">
<%= f.fields_for :documents do |documents_builder| %>
<%= render "documents/document_fields", f: documents_builder %>
<% end %>
</div>
<%= link_to_add_association t("documents.form.add_new_document"), f, :documents,
partial: "documents/document_fields",
id: "new_document_link",
class: "button upload-document
#{"hide" if max_documents_allowed?(documentable)}",
data: {
association_insertion_node: "#nested-documents",
association_insertion_method: "append"
} %>
<div id="max-documents-notice" class="max-documents-notice callout primary text-center <%= "hide" unless max_documents_allowed?(documentable) %>">
<%= sanitize(t("documents.max_documents_allowed_reached")) %>
</div>
</div>
<%= render Documents::NestedComponent.new(f) %>

View File

@@ -1,40 +0,0 @@
<div class="images">
<div>
<%= f.label :image, t("images.form.admin_title") %>
<%= link_to_add_association t("images.form.add_new_image"), f, :image,
force_non_association_create: true,
partial: "images/image_fields",
id: "new_image_link",
class: "button hollow",
render_options: {
locals: { imageable: imageable }
},
data: {
association_insertion_node: "#nested-image",
association_insertion_method: "append"
} %>
<%= render_image(f.object.image, :thumb, false) if f.object.image %>
<div id="nested-image">
<%= f.fields_for :image do |image_builder| %>
<div id="<%= dom_id(image_builder.object) %>" class="image direct-upload nested-fields">
<%= image_builder.hidden_field :id %>
<%= image_builder.hidden_field :user_id, value: current_user.id %>
<%= image_builder.hidden_field :cached_attachment %>
<%= image_builder.text_field :title, placeholder: t("images.form.title_placeholder"), label: "#{t("images.form.admin_alt_text")}" %>
<div class="attachment-actions">
<div class="small-12 column action-add attachment-errors image-attachment">
<%= render_image_attachment(image_builder, imageable, image_builder.object) %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -1,32 +1 @@
<div id="<%= dom_id(f.object) %>" class="image direct-upload nested-fields">
<%= f.hidden_field :id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :cached_attachment %>
<div class="small-12 margin-top title">
<%= f.text_field :title, placeholder: t("images.form.title_placeholder") %>
</div>
<%= render_image(f.object, :thumb, false) if f.object.attachment.exists? %>
<div class="small-12 column attachment-actions">
<div class="small-9 column action-add attachment-errors image-attachment">
<%= render_image_attachment(f, imageable, f.object) %>
</div>
<div class="small-3 column action-remove text-right">
<%= render_destroy_image_link(f, f.object) %>
</div>
</div>
<div class="small-6 column">
<p class="file-name">
<%= image_attachment_file_name(f.object) %>
</p>
</div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
<hr>
</div>
<%= render Images::FieldsComponent.new(f, imageable: imageable) %>

View File

@@ -1,24 +1 @@
<% image_fields ||= :image %>
<%= f.label image_fields, t("images.form.title") %>
<p class="help-text"><%= imageables_note(imageable) %></p>
<div id="nested-image">
<%= f.fields_for image_fields do |image_builder| %>
<%= render "images/image_fields", f: image_builder, imageable: imageable %>
<% end %>
</div>
<%= link_to_add_association t("images.form.add_new_image"), f, image_fields,
force_non_association_create: true,
partial: "images/image_fields",
id: "new_image_link",
class: "button upload-image
#{"hide" if image_fields == :image && imageable.image.present?}",
render_options: {
locals: { imageable: imageable }
},
data: {
association_insertion_node: "#nested-image",
association_insertion_method: "append"
} %>
<%= render Images::NestedComponent.new(f) %>

View File

@@ -28,12 +28,12 @@
<% if feature?(:allow_images) %>
<div class="images small-12 column">
<%= render "images/nested_image", imageable: @proposal, f: f %>
<%= render "images/nested_image", f: f %>
</div>
<% end %>
<div class="documents small-12 column" data-max-documents="<%= Legislation::Proposal.max_documents_allowed %>">
<%= render "documents/nested_documents", documentable: @proposal, f: f %>
<%= render "documents/nested_documents", f: f %>
</div>
<div class="small-12 medium-6 column">

View File

@@ -8,8 +8,6 @@ en:
note: "You can upload one image of following content types: %{accepted_content_types}, up to %{max_file_size} MB."
add_new_image: Add image
title_placeholder: Add a descriptive title for the image
admin_title: "Image"
admin_alt_text: "Alternative text for the image"
actions:
destroy:
notice: Image was deleted successfully.

View File

@@ -7,8 +7,6 @@ es:
delete_button: Eliminar imagen
note: "Puedes subir una imagen en los formatos: %{accepted_content_types}, y de hasta %{max_file_size} MB por archivo."
add_new_image: Añadir imagen
admin_title: "Imagen"
admin_alt_text: "Texto alternativo para la imagen"
actions:
destroy:
notice: La imagen se ha eliminado correctamente.

View File

@@ -134,12 +134,3 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path,
end
end
end
def attach_document(path, success = true)
attach_file :document_attachment, path, make_visible: true
if success
expect(page).to have_css ".loading-bar.complete"
else
expect(page).to have_css ".loading-bar.errors"
end
end

View File

@@ -30,14 +30,3 @@ shared_examples "imageable" do |imageable_factory_name, imageable_path, imageabl
end
end
end
def attach_image(path, success = true)
image = find(".image")
image_input = image.find("input[type=file]", visible: false)
attach_file image_input[:id], path, make_visible: true
if success
expect(page).to have_css ".loading-bar.complete"
else
expect(page).to have_css ".loading-bar.errors"
end
end

View File

@@ -77,12 +77,7 @@ shared_examples "nested documentable" do |login_as_name, documentable_factory_na
click_link "Add new document"
within "#nested-documents" do
document = find(".document input[type=file]", visible: :hidden)
attach_file(
document[:id],
Rails.root.join("spec/fixtures/files/empty.pdf"),
make_visible: true
)
attach_file "Choose document", Rails.root.join("spec/fixtures/files/empty.pdf")
expect(page).to have_css ".loading-bar.complete"
end
@@ -109,12 +104,7 @@ shared_examples "nested documentable" do |login_as_name, documentable_factory_na
within "#nested-documents" do
input = find("input[name$='[title]']")
fill_in input[:id], with: "My Title"
document_input = find("input[type=file]", visible: :hidden)
attach_file(
document_input[:id],
Rails.root.join("spec/fixtures/files/empty.pdf"),
make_visible: true
)
attach_file "Choose document", Rails.root.join("spec/fixtures/files/empty.pdf")
expect(page).to have_css ".loading-bar.complete"
end
@@ -320,9 +310,8 @@ end
def documentable_attach_new_file(path, success = true)
click_link "Add new document"
document = all("#new_document").last
document_input = document.find("input[type=file]", visible: :hidden)
attach_file(document_input[:id], path, make_visible: true)
document = all(".document").last
attach_file "Choose document", path
within document do
if success

View File

@@ -38,12 +38,7 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
visit send(path, arguments)
click_link "Add image"
image_input = find(".image").find("input[type=file]", visible: :hidden)
attach_file(
image_input[:id],
Rails.root.join("spec/fixtures/files/clippy.jpg"),
make_visible: true
)
attach_file "Choose image", Rails.root.join("spec/fixtures/files/clippy.jpg")
expect(page).to have_selector ".file-name", text: "clippy.jpg"
end
@@ -67,12 +62,7 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
click_link "Add image"
input_title = find(".image input[name$='[title]']")
fill_in input_title[:id], with: "Title"
image_input = find(".image").find("input[type=file]", visible: :hidden)
attach_file(
image_input[:id],
Rails.root.join("spec/fixtures/files/clippy.jpg"),
make_visible: true
)
attach_file "Choose image", Rails.root.join("spec/fixtures/files/clippy.jpg")
if has_many_images
expect(find("input[id$='_title']").value).to eq "Title"
@@ -271,8 +261,7 @@ def imageable_attach_new_file(_imageable_factory_name, path, success = true)
click_link "Add image"
within "#nested-image" do
image = find(".image")
image_input = image.find("input[type=file]", visible: :hidden)
attach_file(image_input[:id], path, make_visible: true)
attach_file "Choose image", path
within image do
if success
expect(page).to have_css(".loading-bar.complete")

View File

@@ -252,11 +252,8 @@ describe "Cards", :admin do
def attach_image_to_card
click_link "Add image"
image_input = all(".image").last.find("input[type=file]", visible: false)
attach_file(
image_input[:id],
Rails.root.join("spec/fixtures/files/clippy.jpg"),
make_visible: true)
attach_file "Choose image", Rails.root.join("spec/fixtures/files/clippy.jpg")
expect(page).to have_field("widget_card_image_attributes_title", with: "clippy.jpg")
end
end