Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi language image descriptions #2792

Merged
merged 1 commit into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class window.Alchemy.ImageOverlay extends Alchemy.Dialog
@$previous = $('.previous-picture')
@$next = $('.next-picture')
@$document.keydown (e) =>
return true if e.target.nodeName == 'INPUT'
if e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA'
return true
switch e.which
when 37
@previous()
Expand Down
6 changes: 6 additions & 0 deletions app/assets/stylesheets/alchemy/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ form {
@include form-label;
}

.inline-label {
display: inline-flex;
align-items: center;
gap: var(--spacing-1);
}

.input {
padding: $default-padding 0;
@include clearfix;
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/alchemy/admin/ingredients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class IngredientsController < Alchemy::Admin::BaseController
helper "Alchemy::Admin::Ingredients"

def edit
@language = Alchemy::Language.find_by(id: params[:language_id]) ||
Alchemy::Current.language
end

def update
Expand Down
1 change: 1 addition & 0 deletions app/controllers/alchemy/admin/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def edit
end
@preview_url = @preview_urls.first.last
@layoutpage = @page.layoutpage?
Alchemy::Current.language = @page.language
end

# Set page configuration like page names, meta tags and states.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Alchemy
module Admin
class PictureDescriptionsController < Alchemy::Admin::ResourcesController
def edit
@picture_description = @picture.descriptions.find_or_initialize_by(language_id: params[:language_id])
end

private

def load_resource
@picture = Alchemy::Picture.find(params[:picture_id])
end
end
end
end
19 changes: 18 additions & 1 deletion app/controllers/alchemy/admin/pictures_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Admin
class PicturesController < Alchemy::Admin::ResourcesController
include UploaderResponses
include ArchiveOverlay
include CurrentLanguage

helper "alchemy/admin/tags"

Expand Down Expand Up @@ -33,6 +34,9 @@ def show
@previous = filtered_pictures.where("name < ?", @picture.name).last
@next = filtered_pictures.where("name > ?", @picture.name).first
@assignments = @picture.picture_ingredients.joins(element: :page)
@picture_description = @picture.descriptions.find_or_initialize_by(
language_id: Alchemy::Current.language.id
)

render action: "show"
end
Expand Down Expand Up @@ -193,7 +197,20 @@ def search_filter_params
end

def picture_params
params.require(:picture).permit(:image_file, :upload_hash, :name, :description, :tag_list)
params.require(:picture).permit(
:image_file,
:upload_hash,
:name,
{
descriptions_attributes: [
:id,
:text,
:language_id,
:picture_id
]
},
:tag_list
)
end

def picture_url_params
Expand Down
6 changes: 4 additions & 2 deletions app/models/alchemy/ingredients/picture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class Picture < Alchemy::Ingredient
upsample
]

def alt_text
alt_tag.presence || picture&.description || picture&.name&.humanize
def alt_text(language: Alchemy::Current.language)
alt_tag.presence ||
picture&.description_for(language) ||
picture&.name&.humanize
end

# The first 30 characters of the pictures name
Expand Down
8 changes: 8 additions & 0 deletions app/models/alchemy/picture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Picture < BaseRecord
has_many :elements, through: :picture_ingredients
has_many :pages, through: :elements
has_many :thumbs, class_name: "Alchemy::PictureThumb", dependent: :destroy
has_many :descriptions, class_name: "Alchemy::PictureDescription", dependent: :destroy

accepts_nested_attributes_for :descriptions, allow_destroy: true, reject_if: ->(attr) { attr[:text].blank? }

# Raise error, if picture is in use (aka. assigned to an Picture ingredient)
#
Expand Down Expand Up @@ -231,6 +234,11 @@ def to_jq_upload
}
end

# Returns the picture description for a given language.
def description_for(language)
descriptions.find_by(language: language)&.text
end

# Returns an uri escaped name.
#
def urlname
Expand Down
8 changes: 8 additions & 0 deletions app/models/alchemy/picture_description.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Alchemy
class PictureDescription < ActiveRecord::Base
belongs_to :picture, class_name: "Alchemy::Picture"
belongs_to :language, class_name: "Alchemy::Language"

validates_uniqueness_of :picture_id, scope: :language_id
end
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= f.input :caption, as: ingredient.settings[:caption_as_textarea] ? 'text' : 'string' %>
<%= f.input :title %>
<%= f.input :alt_tag, as: :text, placeholder: ingredient.alt_text %>
<%= f.input :alt_tag, as: :text, placeholder: ingredient.alt_text(language: @language) %>
<%- if ingredient.settings[:sizes].present? && ingredient.settings[:srcset].blank? -%>
<%= f.input :render_size,
collection: [
Expand Down
11 changes: 11 additions & 0 deletions app/views/alchemy/admin/picture_descriptions/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% field_name_prefix = "picture[descriptions_attributes][#{picture_description_counter}]" %>

<% if picture_description.persisted? %>
<%= hidden_field field_name_prefix, :id, value: picture_description.id %>
<% else %>
<%= hidden_field field_name_prefix, :language_id, value: picture_description.language_id %>
<%= hidden_field field_name_prefix, :picture_id, value: picture_description.picture_id %>
<% end %>

<%= label field_name_prefix, :text, Alchemy::PictureDescription.human_attribute_name(:text), class: "control-label" %>
<%= text_area field_name_prefix, :text, value: picture_description.text, rows: 3 %>
6 changes: 6 additions & 0 deletions app/views/alchemy/admin/picture_descriptions/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<turbo-frame id="picture_descriptions">
<%= render "form", {
picture_description: @picture_description,
picture_description_counter: @picture.descriptions.index(@picture_description)
} %>
</turbo-frame>
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
<%= f.input :description %>
<div class="input">
<% if Alchemy::Language.many? %>
<label class="inline-label" style="float: right">
<%= Alchemy::Language.model_name.human %>
<%= select_tag :language_id, options_from_collection_for_select(
Alchemy::Language.published, :id, ->(l) { l.code.upcase },
selected: @picture_description.language_id,
), data: {
url: alchemy.edit_admin_picture_description_url(id: "__ID__", picture_id: @picture)
} %>
</label>
<% end %>

<turbo-frame id="picture_descriptions">
<%= render "alchemy/admin/picture_descriptions/form",
picture_description_counter: @picture.descriptions.index(@picture_description),
picture_description: @picture_description %>
</turbo-frame>
</div>

<script type="module">
const select = document.querySelector("#language_id")

select.addEventListener("change", () => {
const url = new URL(select.dataset.url)
url.searchParams.set("language_id", select.value)
Turbo.visit(url, { frame: "picture_descriptions" })
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

<%= content_tag "sl-tooltip", content: Alchemy.t(:edit_image_properties), placement: "top-end" do %>
<%= link_to_dialog render_icon(:edit),
alchemy.edit_admin_ingredient_path(id: picture_editor.id),
alchemy.edit_admin_ingredient_path(id: picture_editor.id, language_id: @page.language_id),
{
title: Alchemy.t(:edit_image_properties),
size: "380x255"
Expand Down
5 changes: 5 additions & 0 deletions config/locales/alchemy.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,9 @@ en:
alchemy/picture:
one: Picture
other: Pictures
alchemy/picture_description:
one: Picture Description
other: Picture Descriptions
alchemy/user:
one: User
other: User
Expand Down Expand Up @@ -902,6 +905,8 @@ en:
image_file_size: "Filesize"
name: "Name"
tag_list: Tags
alchemy/picture_description:
text: "Description"
alchemy/site:
name: "Name"
host: "Primary Host"
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
end
end

resources :picture_descriptions, only: [:index, :edit]

resources :attachments, except: [:new] do
member do
get :download
Expand Down
5 changes: 0 additions & 5 deletions db/migrate/20240208101342_add_description_to_picture.rb

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateAlchemyPictureDescriptions < ActiveRecord::Migration[7.0]
def change
create_table :alchemy_picture_descriptions do |t|
t.belongs_to :picture, null: false, foreign_key: {to_table: :alchemy_pictures}
t.belongs_to :language, null: false, foreign_key: {to_table: :alchemy_languages}
t.text :text

t.timestamps
end
end
end
1 change: 1 addition & 0 deletions lib/alchemy/permissions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ def alchemy_editor_rules
end

can :manage, Alchemy::Picture
can :manage, Alchemy::PictureDescription
can :manage, Alchemy::Attachment
can :manage, Alchemy::Tag
can :index, Alchemy::Language
Expand Down
17 changes: 15 additions & 2 deletions spec/controllers/alchemy/admin/pictures_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module Alchemy
authorize_user(:as_admin)
end

let!(:language) { create(:alchemy_language) }

describe "#index" do
context "with search params" do
let!(:picture_1) { create(:alchemy_picture, name: "cute kitten") }
Expand Down Expand Up @@ -250,12 +252,23 @@ module Alchemy
let(:picture) { create(:alchemy_picture) }

subject do
put :update, params: {id: 1, picture: {name: "", description: "foo bar"}}, xhr: true
put :update, params: {
id: 1,
picture: {
name: "",
descriptions_attributes: {
0 => {
text: "foo bar",
language_id: language.id
}
}
}
}, xhr: true
end

it "sets the description" do
subject
expect(picture.description).to eq("foo bar")
expect(picture.description_for(language)).to eq("foo bar")
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/config/locales/alchemy.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ de:
richtext: Dieser Inhaltstyp stellt formatierbaren Text dar
select: Dieser Inhaltstyp stellt Werte dar aus denen der Redakteur wählen kann
text: Dieser Inhaltstyp stellt eine einfache Zeile Text dar

activerecord:
attributes:
alchemy/picture_description:
text: "Bildbeschreibung"

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This migration comes from alchemy (originally 20240314105244)
class CreateAlchemyPictureDescriptions < ActiveRecord::Migration[7.0]
def change
create_table :alchemy_picture_descriptions do |t|
t.belongs_to :picture, null: false, foreign_key: {to_table: :alchemy_pictures}
t.belongs_to :language, null: false, foreign_key: {to_table: :alchemy_languages}
t.text :text

t.timestamps
end
end
end
17 changes: 14 additions & 3 deletions spec/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2024_02_08_101342) do
ActiveRecord::Schema[7.1].define(version: 2024_04_11_155901) do
create_table "alchemy_attachments", force: :cascade do |t|
t.string "name"
t.string "file_name"
Expand Down Expand Up @@ -136,7 +136,7 @@

create_table "alchemy_page_mutexes", force: :cascade do |t|
t.integer "page_id", null: false
t.datetime "created_at"
t.datetime "created_at", precision: nil
t.index ["page_id"], name: "index_alchemy_page_mutexes_on_page_id", unique: true
end

Expand Down Expand Up @@ -186,6 +186,16 @@
t.index ["urlname"], name: "index_pages_on_urlname"
end

create_table "alchemy_picture_descriptions", force: :cascade do |t|
t.integer "picture_id", null: false
t.integer "language_id", null: false
t.text "text"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["language_id"], name: "index_alchemy_picture_descriptions_on_language_id"
t.index ["picture_id"], name: "index_alchemy_picture_descriptions_on_picture_id"
end

create_table "alchemy_picture_thumbs", force: :cascade do |t|
t.integer "picture_id", null: false
t.string "signature", null: false
Expand All @@ -207,7 +217,6 @@
t.string "image_file_uid"
t.integer "image_file_size"
t.string "image_file_format"
t.text "description"
t.index ["creator_id"], name: "index_alchemy_pictures_on_creator_id"
t.index ["image_file_name"], name: "index_alchemy_pictures_on_image_file_name"
t.index ["name"], name: "index_alchemy_pictures_on_name"
Expand Down Expand Up @@ -293,5 +302,7 @@
add_foreign_key "alchemy_page_mutexes", "alchemy_pages", column: "page_id"
add_foreign_key "alchemy_page_versions", "alchemy_pages", column: "page_id", on_delete: :cascade
add_foreign_key "alchemy_pages", "alchemy_languages", column: "language_id"
add_foreign_key "alchemy_picture_descriptions", "alchemy_languages", column: "language_id"
add_foreign_key "alchemy_picture_descriptions", "alchemy_pictures", column: "picture_id"
add_foreign_key "alchemy_picture_thumbs", "alchemy_pictures", column: "picture_id"
end
20 changes: 20 additions & 0 deletions spec/features/admin/ingredient_pictures_feature_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "rails_helper"

RSpec.feature "Ingredient Pictures admin feature", type: :system do
before do
authorize_user(:as_editor)
end

let(:language) { create(:alchemy_language) }
let(:picture) { create(:alchemy_picture) }
let(:ingredient_picture) { create(:alchemy_ingredient_picture, picture: picture) }

let!(:picture_description) do
Alchemy::PictureDescription.create!(picture: picture, language: language, text: "A nice picture")
end

scenario "Picture description is used as default for ingredient picture alt text" do
visit alchemy.edit_admin_ingredient_path(ingredient_picture)
expect(page).to have_field("Alternative text", placeholder: "A nice picture")
end
end
Loading