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

Introduce ingredients as new content structure #2061

Merged
merged 57 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
5ac5be3
Add Alchemy::Ingredient model
tvdeyen Apr 8, 2021
cf15c5d
Add a Text Ingredient class
tvdeyen Apr 8, 2021
774568f
Add ingredient_attributes class methods to ingredient
tvdeyen Apr 8, 2021
c8a9408
Add more ingredient classes
tvdeyen Apr 8, 2021
1aac6f1
Add File ingredient
tvdeyen Apr 8, 2021
1172261
Add Node and Page ingredients
tvdeyen Apr 8, 2021
a17dfd7
Add Picture ingredient class
tvdeyen Apr 8, 2021
e85957d
Add Richtext ingredient
tvdeyen Apr 8, 2021
b71a93b
Typecast boolean and datetime ingredients
tvdeyen Apr 8, 2021
cd1bf39
Add preview_text to ingredient classes
tvdeyen Apr 8, 2021
d35e875
Return related object from ingredient if present
tvdeyen Apr 8, 2021
ca0e05e
Add has_many ingredients relation to element
tvdeyen Apr 9, 2021
5222d53
Add settings and partial name to Ingredient model
tvdeyen Apr 12, 2021
64320a7
Add predicate methods to ingredient class
tvdeyen Apr 12, 2021
add3f1b
Add hints to Ingredient class
tvdeyen Apr 12, 2021
b1ed76f
Add IngredientEditor
tvdeyen Apr 12, 2021
94f445e
Add ingredient views
tvdeyen Apr 12, 2021
3779b58
Add thumbnail_url to picture ingredient
tvdeyen Apr 14, 2021
2b06cc2
Allow translated ingredient default text
tvdeyen Apr 14, 2021
1e353b4
Update picture ingredient to latest essence picture changes
tvdeyen May 25, 2021
52ab28a
Rewrite ingredient_attributes to class attribute
tvdeyen May 25, 2021
69f2f2f
Adds admin ingredients controller
tvdeyen May 25, 2021
093de6f
Render ingredient editors
tvdeyen Apr 10, 2021
e6e1745
Add Headline ingredient
tvdeyen May 26, 2021
1ac49d7
Update headline partials
tvdeyen May 26, 2021
2ff6fca
Add audio and video ingredients
tvdeyen May 26, 2021
e241902
Add ingredients elements to page layout
tvdeyen May 26, 2021
61d345e
Add custom tinymce config feature to ingredients
tvdeyen May 26, 2021
cae0aad
Add ingredient scopes
tvdeyen May 26, 2021
fd0dd8c
Add has_tinymce? to ingredient
tvdeyen May 26, 2021
4ea76c6
Init tinymce editor for ingredients
tvdeyen May 26, 2021
54e5108
Add *_id methods for related_object_alias
tvdeyen May 28, 2021
4a0e93b
Use fields_for for ingredient editor partials
tvdeyen May 28, 2021
45f8e68
Set related object type when we set the id
tvdeyen May 28, 2021
0e4390e
Remove nonsense spec
tvdeyen Jun 7, 2021
79a9301
Autoformat elements controller spec
tvdeyen Jun 7, 2021
c3f5c9a
Update elements generator for ingredients
tvdeyen Jun 7, 2021
25015a9
Add templates for elements with ingredients
tvdeyen Jun 7, 2021
5e3dd08
Support ingredients in block level helpers
tvdeyen Jun 10, 2021
9efffd4
Make sure to persist ingredient values
tvdeyen Jun 10, 2021
172038e
Add ingredient validations
tvdeyen Jun 10, 2021
210e3c6
Display ingredient validation errors on element editor
tvdeyen Jun 10, 2021
6684d2f
Use CropAction concern in admin ingredients controller
tvdeyen Jun 25, 2021
4d2a437
Use "having picture thumbnails" on picture ingredient
tvdeyen Jun 25, 2021
ff5dffb
Make link dialog work with ingredients
tvdeyen Jun 27, 2021
373a30b
Do not create contents if ingredients are defined as well
tvdeyen Jun 28, 2021
796aec1
Add rake task to migrate elements to ingredients
tvdeyen Jun 28, 2021
c5ea77a
Show element editor if element has no contents but ingredients defined
tvdeyen Jun 28, 2021
c71efbe
Add ingredient generator
tvdeyen Jun 28, 2021
2eb7895
Touch element on changing ingredients
mamhoff Jun 29, 2021
c642161
Destroy contents in migrator
mamhoff Jun 29, 2021
228d73e
Duplicate ingredients with Elements
mamhoff Jun 29, 2021
eb38d58
Pick Ingredients first in ElementBlockHelper
mamhoff Jun 29, 2021
42c2e4d
Use Rails' store_accessor for ingredients data
tvdeyen Jun 29, 2021
c322280
Eager load ingredients in admin and API controllers
tvdeyen Jun 29, 2021
57dc0fb
Update brakeman ignores
tvdeyen Jun 29, 2021
9234ecd
Add an ingredient factory
tvdeyen Jun 30, 2021
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
Prev Previous commit
Next Next commit
Add Picture ingredient class
This will replace the EssencePicture essence
  • Loading branch information
tvdeyen committed Jun 28, 2021
commit a17dfd7c2907a4a9a3bf015f0f58604b5b212dd5
86 changes: 86 additions & 0 deletions app/models/alchemy/ingredients/picture.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

module Alchemy
module Ingredients
# A picture assignment
#
# Assign Alchemy::Picture to this ingredient
#
# Optionally you can add a link
# As well as set the alt tag, a caption and title
#
class Picture < Alchemy::Ingredient
ingredient_attributes(
:alt_tag,
:caption,
:crop_from,
:crop_size,
:css_class,
:link_class_name,
:link_target,
:link_title,
:link,
:render_size,
:title,
)

related_object_alias :picture

# The url to show the picture.
#
# Takes all values like +name+ and crop sizes (+crop_from+, +crop_size+ from the build in graphical image cropper)
# and also adds the security token.
#
# You typically want to set the size the picture should be resized to.
#
# === Example:
#
# ingredient.picture_url(size: '200x300', crop: true, format: 'gif')
# # '/pictures/1/show/200x300/crop/cats.gif?sh=765rfghj'
#
# @option options size [String]
# The size the picture should be resized to.
#
# @option options format [String]
# The format the picture should be rendered in.
# Defaults to the +image_output_format+ from the +Alchemy::Config+.
#
# @option options crop [Boolean]
# If set to true the picture will be cropped to fit the size value.
#
# @return [String]
def picture_url(options = {})
return if picture.nil?

picture.url(picture_url_options.merge(options)) || "missing-image.png"
end

# Picture rendering options
#
# Returns the +default_render_format+ of the associated +Alchemy::Picture+
# together with the +crop_from+ and +crop_size+ values
#
# @return [HashWithIndifferentAccess]
def picture_url_options
return {} if picture.nil?

{
format: picture.default_render_format,
crop_from: crop_from.presence,
crop_size: crop_size.presence,
size: settings[:size],
}.with_indifferent_access
end

# Enable image cropping in ingredient editor
# @return [Boolean]
def allow_image_cropping?
settings[:crop] && picture &&
picture.can_be_cropped_to?(
settings[:size],
settings[:upsample],
) && !!picture.image_file
end
end
end
end
224 changes: 224 additions & 0 deletions spec/models/alchemy/ingredients/picture_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Alchemy::Ingredients::Picture do
it_behaves_like "an alchemy ingredient"

let(:element) { build(:alchemy_element) }
let(:picture) { build(:alchemy_picture) }

let(:picture_ingredient) do
described_class.new(
element: element,
type: described_class.name,
role: "image",
related_object: picture,
)
end

describe "alt_tag" do
before { picture_ingredient.alt_tag = "A cute kitten" }
subject { picture_ingredient.alt_tag }

it { is_expected.to eq("A cute kitten") }
end

describe "css_class" do
before { picture_ingredient.css_class = "download" }
subject { picture_ingredient.css_class }

it { is_expected.to eq("download") }
end

describe "link_title" do
before { picture_ingredient.link_title = "Nice picture" }
subject { picture_ingredient.link_title }

it { is_expected.to eq("Nice picture") }
end

describe "title" do
before { picture_ingredient.title = "Click to view" }
subject { picture_ingredient.title }

it { is_expected.to eq("Click to view") }
end

describe "picture" do
subject { picture_ingredient.picture }

it { is_expected.to be_an(Alchemy::Picture) }
end

describe "picture=" do
let(:picture) { Alchemy::Picture.new }

subject { picture_ingredient.picture = picture }

it { is_expected.to be(picture) }
end

describe "#picture_url" do
subject(:picture_url) { picture_ingredient.picture_url(options) }

let(:options) { {} }

context "with no picture present" do
let(:picture) { nil }

it { is_expected.to be_nil }
end

context "with picture present" do
let(:picture) { create(:alchemy_picture) }

it "reads url from picture" do
is_expected.to match(/\/pictures\/.+\/image\.png/)
end

context "with crop sizes in the options" do
let(:options) do
{ crop_from: "30x30", crop_size: "75x75" }
end

it "passes these crop sizes to picture url." do
expect(picture).to receive(:url).with(
hash_including(crop_from: "30x30", crop_size: "75x75"),
)
picture_url
end
end

context "with format in the options" do
let(:options) { { format: "gif" } }

it "takes this as format." do
is_expected.to match(/\.gif/)
end
end

context "with other options given" do
let(:options) { { foo: "baz" } }

it "adds them to the url" do
is_expected.to match(/\?foo=baz/)
end
end

context "if picture.url returns nil" do
before do
expect(picture).to receive(:url) { nil }
end

it "returns missing image url" do
is_expected.to eq "missing-image.png"
end
end
end
end

describe "#picture_url_options" do
subject(:picture_url_options) { picture_ingredient.picture_url_options }

let(:picture) { build_stubbed(:alchemy_picture) }

it { is_expected.to be_a(HashWithIndifferentAccess) }

it "includes the pictures default render format." do
expect(picture).to receive(:default_render_format) { "img" }
expect(picture_url_options[:format]).to eq("img")
end

context "with crop sizes present" do
before do
expect(picture_ingredient).to receive(:crop_size) { "200x200" }
expect(picture_ingredient).to receive(:crop_from) { "10x10" }
end

it "includes these crop sizes.", :aggregate_failures do
expect(picture_url_options[:crop_from]).to eq "10x10"
expect(picture_url_options[:crop_size]).to eq "200x200"
end
end

# Regression spec for issue #1279
context "with crop sizes being empty strings" do
before do
expect(picture_ingredient).to receive(:crop_size) { "" }
expect(picture_ingredient).to receive(:crop_from) { "" }
end

it "does not include these crop sizes.", :aggregate_failures do
expect(picture_url_options[:crop_from]).to be_nil
expect(picture_url_options[:crop_size]).to be_nil
end
end

context "with ingredient having size setting" do
before do
expect(picture_ingredient).to receive(:settings) { { size: "30x70" } }
end

it "includes this size." do
expect(picture_url_options[:size]).to eq "30x70"
end
end

context "without picture assigned" do
let(:picture) { nil }

it { is_expected.to be_a(Hash) }
end
end

describe "#allow_image_cropping?" do
subject { picture_ingredient.allow_image_cropping? }

context "if disabled in the settings" do
it { is_expected.to be_falsy }
end

context "if enabled in settings" do
before do
expect(picture_ingredient).to receive(:settings).at_least(:once) { { crop: true } }
end

context "but with no picture assigned" do
let(:picture) { nil }

it { is_expected.to be_falsy }
end

context "with picture assigned" do
context "and with image smaller than desired size" do
before do
expect(picture).to receive(:can_be_cropped_to?) { false }
end

it { is_expected.to be_falsy }
end

context "and with image larger than desired size" do
before do
expect(picture).to receive(:can_be_cropped_to?) { true }
end

context "if picture has no image attached" do
before do
expect(picture).to receive(:image_file) { nil }
end

it { is_expected.to be_falsy }
end

context "if picture.image_file is present" do
let(:picture) { build_stubbed(:alchemy_picture) }

it { is_expected.to be(true) }
end
end
end
end
end
end