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 56 commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Alchemy.ElementEditors =
# private

_shouldUpdateTitle: (element, event) ->
editors = element.find('> .element-content .element-content-editors').children()
editors = element.find('> .element-content .element-content-editors, > .element-content .element-ingredient-editors').children()
if @_hasParents(element)
editors.length != 0
else if @_isParent(element) && @_isFirstChild $(event.target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ Alchemy.ElementsWindow =
$.get @url, (data) =>
@element_area.html data
Alchemy.GUI.init(@element_area)
Alchemy.fileEditors(@element_area.find(".essence_file, .essence_video, .essence_audio").selector)
Alchemy.pictureEditors(@element_area.find(".essence_picture").selector)
Alchemy.fileEditors(@element_area.find(".essence_file, .essence_video, .essence_audio, .ingredient-editor.file, .ingredient-editor.audio, .ingredient-editor.video").selector)
Alchemy.pictureEditors(@element_area.find(".essence_picture, .ingredient-editor.picture").selector)
if @callback
@callback.call()
.fail (xhr, status, error) =>
Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/alchemy/alchemy.gui.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ Alchemy.GUI =
Alchemy.ElementDirtyObserver($el)
Alchemy.GUI.init($el)
Alchemy.ImageLoader($el[0])
Alchemy.fileEditors($el.find(".essence_file, .essence_video, .essence_audio").selector)
Alchemy.pictureEditors($el.find(".essence_picture").selector)
Alchemy.fileEditors($el.find(".essence_file, .essence_video, .essence_audio, .ingredient-editor.file, .ingredient-editor.audio, .ingredient-editor.video").selector)
Alchemy.pictureEditors($el.find(".essence_picture, .ingredient-editor.picture").selector)
65 changes: 39 additions & 26 deletions app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
class window.Alchemy.LinkDialog extends Alchemy.Dialog

constructor: (@link_object) ->
parent_selector = @link_object.dataset.parentSelector
parent = document.querySelector(parent_selector)
@link_value_field = parent.querySelector("[data-link-value]")
@link_title_field = parent.querySelector("[data-link-title]")
@link_target_field = parent.querySelector("[data-link-target]")
@link_class_field = parent.querySelector("[data-link-class]")
@url = Alchemy.routes.link_admin_pages_path
@$link_object = $(@link_object)
@options =
Expand Down Expand Up @@ -136,7 +142,7 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
if @link_object.editor
@setTinyMCELink(url, title, target)
else
@setEssenceLink(url, title, target)
@setLinkFields(url, title, target)

# Sets a link in TinyMCE editor.
setTinyMCELink: (url, title, target) ->
Expand All @@ -151,14 +157,16 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
true

# Sets a link on an Essence (e.g. EssencePicture).
setEssenceLink: (url, title, target) ->
content_id = @$link_object.data('content-id')
$("#contents_#{content_id}_link").val(url).change()
$("#contents_#{content_id}_link_title").val(title)
$("#contents_#{content_id}_link_class_name").val(@link_type)
$("#contents_#{content_id}_link_target").val(target)
@$link_object.addClass('linked')
@$link_object.next().addClass('linked').removeClass('disabled').removeAttr('tabindex')
setLinkFields: (url, title, target) ->
@link_value_field.value = url
@link_value_field.dispatchEvent(new Event("change"))
@link_title_field.value = title
@link_class_field.value = @link_type
@link_target_field.value = target
@link_object.classList.add("linked")
@link_object.nextElementSibling.classList.replace("disabled", "linked")
@link_object.nextElementSibling.removeAttribute("tabindex")
return

# Selects the correct tab for link type and fills all fields.
selectTab: ->
Expand Down Expand Up @@ -205,12 +213,11 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
# Creates a temporay $('a') object that holds all values on it.
createTempLink: ->
@$tmp_link = $('<a/>')
content_id = @$link_object.data('content-id')
@$tmp_link.attr 'href', $("#contents_#{content_id}_link").val()
@$tmp_link.attr 'title', $("#contents_#{content_id}_link_title").val()
@$tmp_link.attr 'data-link-target', $("#contents_#{content_id}_link_target").val()
@$tmp_link.attr 'target', if $("#contents_#{content_id}_link_target").val() == 'blank' then '_blank' else null
@$tmp_link.addClass $("#contents_#{content_id}_link_class_name").val()
@$tmp_link.attr('href', @link_value_field.value)
@$tmp_link.attr('title', @link_title_field.value)
@$tmp_link.attr('data-link-target', @link_target_field.value)
@$tmp_link.attr('target', if @link_target_field.value == 'blank' then '_blank' else null)
@$tmp_link.addClass(@link_class_field.value)
@$tmp_link

# Validates url for beginning with an protocol.
Expand Down Expand Up @@ -240,15 +247,21 @@ class window.Alchemy.LinkDialog extends Alchemy.Dialog
# Public class methods

# Removes link from Essence.
@removeLink = (link, content_id) ->
$link = $(link)
$("#contents_#{content_id}_link").val('').change()
$("#contents_#{content_id}_link_title").val('')
$("#contents_#{content_id}_link_class_name").val('')
$("#contents_#{content_id}_link_target").val('')
if $link.hasClass('linked')
Alchemy.setElementDirty $(link).closest('.element-editor')
$link.removeClass('linked').addClass('disabled').attr('tabindex', '-1')
$link.blur()
$('#edit_link_' + content_id).removeClass('linked')
@removeLink = (link, parent_selector) ->
parent = document.querySelector(parent_selector)
link_value_field = parent.querySelector("[data-link-value]")
link_title_field = parent.querySelector("[data-link-title]")
link_target_field = parent.querySelector("[data-link-target]")
link_class_field = parent.querySelector("[data-link-class]")
link_value_field.value = ""
link_value_field.dispatchEvent(new Event("change"))
link_title_field.value = ""
link_class_field.value = ""
link_target_field.value = ""
if link.classList.contains('linked')
Alchemy.setElementDirty link.closest('.element-editor')
link.classList.replace('linked', 'disabled')
link.setAttribute('tabindex', '-1')
link.blur()
link.previousElementSibling.classList.remove("linked")
false
93 changes: 53 additions & 40 deletions app/assets/stylesheets/alchemy/elements.scss
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@
}

.content_editor,
.ingredient-editor,
.picture_thumbnail {
width: 100%;
}
Expand Down Expand Up @@ -413,7 +414,8 @@
}
}

.element-content-editors {
.element-content-editors,
.element-ingredient-editors {
display: flex;
flex-wrap: wrap;
}
Expand Down Expand Up @@ -524,7 +526,8 @@
}
}

.essence_picture {
.essence_picture,
.ingredient-editor.picture {
position: relative;

.picture_thumbnail {
Expand Down Expand Up @@ -559,47 +562,49 @@
}
}

.content_editor {
&.essence_audio,
&.essence_file,
&.essence_video {
.file {
display: flex;
align-items: center;
margin: 6px 0 $default-margin;
border: $default-border;
background-color: $white;
border-radius: $default-border-radius;
height: $form-field-height;
.content_editor.essence_audio,
.content_editor.essence_file,
.content_editor.essence_video,
.ingredient-editor.audio,
.ingredient-editor.file,
.ingredient-editor.video {
.file {
display: flex;
align-items: center;
margin: 6px 0 $default-margin;
border: $default-border;
background-color: $white;
border-radius: $default-border-radius;
height: $form-field-height;

.validation_failed & {
color: $error_text_color;
border-color: $error_border_color;
}
.validation_failed & {
color: $error_text_color;
border-color: $error_border_color;
}
}

.file_icon {
text-align: center;
width: 24px;
padding: $default-padding;
}
.file_icon {
text-align: center;
width: 24px;
padding: $default-padding;
}

.file_name {
white-space: nowrap;
overflow: hidden;
max-width: 80%;
font-size: $small-font-size;
text-overflow: ellipsis;
padding: $default-padding;
}
.file_name {
white-space: nowrap;
overflow: hidden;
max-width: 80%;
font-size: $small-font-size;
text-overflow: ellipsis;
padding: $default-padding;
}

.remove_file_link {
width: 24px;
padding: $default-padding;
}
.remove_file_link {
width: 24px;
padding: $default-padding;
}
}

.file_tools,
.essence_file_tools {
display: flex;
align-items: center;
Expand Down Expand Up @@ -635,7 +640,8 @@ select.long {
padding: 0;
}

.content_editor {
.content_editor,
.ingredient-editor {
width: 100%;
padding: $default-padding 0;
position: relative;
Expand Down Expand Up @@ -676,7 +682,7 @@ select.long {
}

&.validation_failed {
label {
> label {
color: $error_text_color;
}

Expand Down Expand Up @@ -727,7 +733,8 @@ select.long {
}
}

&.essence_select {
&.essence_select,
&.select {
label {
margin-bottom: 2 * $default-margin;
}
Expand All @@ -741,6 +748,7 @@ select.long {
}
}

select.ingredient-editor-select,
select.essence_editor_select {
border-radius: $default-border-radius;
background: white;
Expand Down Expand Up @@ -768,12 +776,14 @@ select.long {
}
}

&.essence_picture {
&.essence_picture,
&.picture {
width: 50%;
padding-left: 1px; // Compensate the box shadow
padding-right: $default-padding;

+ .essence_picture {
+ .essence_picture,
+ .picture {
padding-left: $default-padding;
padding-right: 1px; // Compensate the box shadow
}
Expand Down Expand Up @@ -825,6 +835,8 @@ textarea.has_tinymce {

.content_editor .hint-with-icon,
.content_editor .with-hint,
.ingredient-editor .hint-with-icon,
.ingredient-editor .with-hint,
.element-handle .hint-with-icon {
margin: 0;

Expand Down Expand Up @@ -884,6 +896,7 @@ textarea.has_tinymce {
}
}

.ingredient-date--label,
.essence_date--label {
position: absolute;
right: 7px;
Expand Down
43 changes: 32 additions & 11 deletions app/controllers/alchemy/admin/elements_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ def create
# And update all contents in the elements by calling update_contents.
#
def update
if @element.update_contents(contents_params)
@page = @element.page
@element_validated = @element.update(element_params)
@page = @element.page

if element_params.key?(:ingredients_attributes)
update_element_with_ingredients
else
@element_validated = false
@notice = Alchemy.t("Validation failed")
@error_message = "<h2>#{@notice}</h2><p>#{Alchemy.t(:content_validations_headline)}</p>".html_safe
update_element_with_contents
end
end

Expand Down Expand Up @@ -105,6 +104,7 @@ def element_includes
contents: {
essence: :ingredient_association,
},
ingredients: :related_object,
},
:tags,
{
Expand All @@ -113,6 +113,7 @@ def element_includes
contents: {
essence: :ingredient_association,
},
ingredients: :related_object,
},
:tags,
],
Expand Down Expand Up @@ -150,16 +151,36 @@ def contents_params
end

def element_params
if @element.taggable?
params.fetch(:element, {}).permit(:tag_list)
else
params.fetch(:element, {})
end
params.fetch(:element).permit(:tag_list, ingredients_attributes: {})
end

def create_element_params
params.require(:element).permit(:name, :page_version_id, :parent_element_id)
end

def update_element_with_ingredients
if @element.update(element_params)
@element_validated = true
else
element_update_error
@error_messages = @element.ingredient_error_messages
end
end

def update_element_with_contents
if @element.update_contents(contents_params)
@element_validated = @element.update(element_params)
else
element_update_error
@error_messages = @element.essence_error_messages
end
end

def element_update_error
@element_validated = false
@notice = Alchemy.t("Validation failed")
@error_message = "<h2>#{@notice}</h2><p>#{Alchemy.t(:content_validations_headline)}</p>".html_safe
end
end
end
end
Loading