alchemy_cms 6.0.14 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of alchemy_cms might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +0 -3
- data/.github/workflows/stale.yml +2 -0
- data/CHANGELOG.md +34 -5
- data/Gemfile +2 -2
- data/alchemy_cms.gemspec +2 -1
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +13 -11
- data/app/assets/stylesheets/alchemy/_variables.scss +9 -4
- data/app/assets/stylesheets/alchemy/elements.scss +96 -4
- data/app/assets/stylesheets/alchemy/forms.scss +59 -17
- data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +3 -3
- data/app/controllers/alchemy/admin/ingredients_controller.rb +1 -1
- data/app/controllers/alchemy/admin/pages_controller.rb +3 -3
- data/app/controllers/alchemy/api/ingredients_controller.rb +22 -0
- data/app/controllers/alchemy/messages_controller.rb +1 -1
- data/app/controllers/alchemy/pages_controller.rb +19 -5
- data/app/decorators/alchemy/ingredient_editor.rb +4 -0
- data/app/helpers/alchemy/elements_helper.rb +0 -8
- data/app/helpers/alchemy/url_helper.rb +0 -8
- data/app/models/alchemy/element/definitions.rb +16 -2
- data/app/models/alchemy/element/dom_id.rb +30 -0
- data/app/models/alchemy/element/presenters.rb +1 -1
- data/app/models/alchemy/element.rb +12 -3
- data/app/models/alchemy/ingredients/headline.rb +4 -1
- data/app/models/alchemy/ingredients/text.rb +3 -0
- data/app/models/alchemy/page/page_layouts.rb +128 -0
- data/app/models/alchemy/page.rb +4 -2
- data/app/models/alchemy/picture_thumb/create.rb +1 -1
- data/app/models/concerns/alchemy/dom_ids.rb +32 -0
- data/app/serializers/alchemy/ingredient_serializer.rb +11 -0
- data/app/views/alchemy/admin/elements/update.js.erb +3 -0
- data/app/views/alchemy/admin/ingredients/_dom_id_fields.html.erb +4 -0
- data/app/views/alchemy/admin/ingredients/_headline_fields.html.erb +3 -0
- data/app/views/alchemy/admin/ingredients/_text_fields.html.erb +3 -0
- data/app/views/alchemy/admin/ingredients/update.js.erb +7 -0
- data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
- data/app/views/alchemy/admin/languages/_language.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
- data/app/views/alchemy/admin/partials/_routes.html.erb +2 -1
- data/app/views/alchemy/ingredients/_headline_editor.html.erb +22 -20
- data/app/views/alchemy/ingredients/_headline_view.html.erb +1 -0
- data/app/views/alchemy/ingredients/_text_editor.html.erb +3 -0
- data/app/views/alchemy/ingredients/_text_view.html.erb +7 -3
- data/app/views/alchemy/ingredients/shared/_anchor.html.erb +9 -0
- data/app/views/alchemy/messages_mailer/contact_form_mail.de.text.erb +2 -0
- data/app/views/alchemy/messages_mailer/contact_form_mail.en.text.erb +2 -0
- data/app/views/alchemy/messages_mailer/contact_form_mail.es.text.erb +2 -0
- data/config/locales/alchemy.en.yml +5 -2
- data/config/routes.rb +1 -0
- data/lib/alchemy/error_tracking/error_logger.rb +13 -0
- data/lib/alchemy/error_tracking.rb +3 -1
- data/lib/alchemy/install/tasks.rb +1 -7
- data/lib/alchemy/page_layout.rb +0 -113
- data/lib/alchemy/test_support/shared_dom_ids_examples.rb +119 -0
- data/lib/alchemy/upgrader/tasks/add_page_versions.rb +2 -2
- data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +7 -5
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +4 -0
- data/lib/alchemy_cms.rb +1 -1
- data/lib/generators/alchemy/elements/templates/view.html.erb +1 -1
- data/lib/generators/alchemy/elements/templates/view.html.haml +1 -1
- data/lib/generators/alchemy/elements/templates/view.html.slim +1 -1
- data/lib/tasks/alchemy/thumbnails.rake +1 -1
- data/package/admin.js +2 -0
- data/package/src/ingredient_anchor_link.js +17 -0
- data/package.json +2 -2
- data/vendor/assets/javascripts/tinymce/tinymce.min.js +2 -2
- metadata +32 -6
- data/lib/non_stupid_digest_assets.rb +0 -55
@@ -8,19 +8,33 @@ module Alchemy
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
+
# Register a custom element definitions repository
|
12
|
+
#
|
13
|
+
# The default repository is Alchemy::ElementDefinition
|
14
|
+
#
|
15
|
+
def definitions_repository=(klass)
|
16
|
+
@_definitions_repository = klass
|
17
|
+
end
|
18
|
+
|
11
19
|
# Returns the definitions from elements.yml file.
|
12
20
|
#
|
13
21
|
# Place a +elements.yml+ file inside your apps +config/alchemy+ folder to define
|
14
22
|
# your own set of elements
|
15
23
|
#
|
16
24
|
def definitions
|
17
|
-
|
25
|
+
definitions_repository.all
|
18
26
|
end
|
19
27
|
|
20
28
|
# Returns one element definition by given name.
|
21
29
|
#
|
22
30
|
def definition_by_name(name)
|
23
|
-
|
31
|
+
definitions_repository.get(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def definitions_repository
|
37
|
+
@_definitions_repository ||= ElementDefinition
|
24
38
|
end
|
25
39
|
end
|
26
40
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
# Returns a dom id used for elements html id tag.
|
5
|
+
#
|
6
|
+
# Uses the elements name and its position on the page.
|
7
|
+
# If the element is nested in a parent element it prefixes
|
8
|
+
# the id with the parent elements dom_id.
|
9
|
+
#
|
10
|
+
# Register your own dom id class with
|
11
|
+
#
|
12
|
+
# Alchemy::Element.dom_id_class = MyDomIdClass
|
13
|
+
#
|
14
|
+
class Element < BaseRecord
|
15
|
+
class DomId
|
16
|
+
def initialize(element)
|
17
|
+
@element = element
|
18
|
+
@parent_element = element.parent_element
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
[parent_element&.dom_id, element.name, element.position].compact.join("-")
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :element, :parent_element
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -103,7 +103,6 @@ module Alchemy
|
|
103
103
|
scope :published, -> { where(public: true) }
|
104
104
|
scope :hidden, -> { where(public: false) }
|
105
105
|
scope :not_restricted, -> { joins(:page).merge(Page.not_restricted) }
|
106
|
-
scope :available, -> { published }
|
107
106
|
scope :named, ->(names) { where(name: names) }
|
108
107
|
scope :excluded, ->(names) { where.not(name: names) }
|
109
108
|
scope :fixed, -> { where(fixed: true) }
|
@@ -143,6 +142,18 @@ module Alchemy
|
|
143
142
|
super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES))
|
144
143
|
end
|
145
144
|
|
145
|
+
# The class responsible for the +dom_id+ of elements.
|
146
|
+
# Defaults to +Alchemy::Element::DomId+.
|
147
|
+
def dom_id_class
|
148
|
+
@_dom_id_class || DomId
|
149
|
+
end
|
150
|
+
|
151
|
+
# Register a custom +DomId+ class responsible for the +dom_id+ of elements.
|
152
|
+
# Defaults to +Alchemy::Element::DomId+.
|
153
|
+
def dom_id_class=(klass)
|
154
|
+
@_dom_id_class = klass
|
155
|
+
end
|
156
|
+
|
146
157
|
# This methods does a copy of source and all depending contents and all of their depending essences.
|
147
158
|
#
|
148
159
|
# == Options
|
@@ -178,8 +189,6 @@ module Alchemy
|
|
178
189
|
|
179
190
|
all_from_clipboard(clipboard).where(name: parent_element.definition["nestable_elements"])
|
180
191
|
end
|
181
|
-
|
182
|
-
deprecate available: :published, deprecator: Alchemy::Deprecation
|
183
192
|
end
|
184
193
|
|
185
194
|
# Returns next public element from same page.
|
@@ -5,7 +5,10 @@ module Alchemy
|
|
5
5
|
# A text headline
|
6
6
|
#
|
7
7
|
class Headline < Alchemy::Ingredient
|
8
|
+
include DomIds
|
9
|
+
|
8
10
|
store_accessor :data,
|
11
|
+
:dom_id,
|
9
12
|
:level,
|
10
13
|
:size
|
11
14
|
|
@@ -20,7 +23,7 @@ module Alchemy
|
|
20
23
|
end
|
21
24
|
|
22
25
|
def size_options
|
23
|
-
sizes.map { |size| ["
|
26
|
+
sizes.map { |size| [".h#{size}", size] }
|
24
27
|
end
|
25
28
|
|
26
29
|
private
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
class Page < BaseRecord
|
5
|
+
# Module concerning page layouts
|
6
|
+
#
|
7
|
+
module PageLayouts
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# Register a custom page layouts repository
|
12
|
+
#
|
13
|
+
# The default repository is Alchemy::PageLayout
|
14
|
+
#
|
15
|
+
def layouts_repository=(klass)
|
16
|
+
@_layouts_repository = klass
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns page layouts ready for Rails' select form helper.
|
20
|
+
#
|
21
|
+
def layouts_for_select(language_id, layoutpages: false)
|
22
|
+
@map_array = []
|
23
|
+
mapped_layouts_for_select(selectable_layouts(language_id, layoutpages: layoutpages))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns page layouts including given layout ready for Rails' select form helper.
|
27
|
+
#
|
28
|
+
def layouts_with_own_for_select(page_layout_name, language_id, layoutpages: false)
|
29
|
+
layouts = selectable_layouts(language_id, layoutpages: layoutpages)
|
30
|
+
if layouts.detect { |l| l["name"] == page_layout_name }.nil?
|
31
|
+
@map_array = [[human_layout_name(page_layout_name), page_layout_name]]
|
32
|
+
else
|
33
|
+
@map_array = []
|
34
|
+
end
|
35
|
+
mapped_layouts_for_select(layouts)
|
36
|
+
end
|
37
|
+
|
38
|
+
deprecate :layouts_with_own_for_select, deprecator: Alchemy::Deprecation
|
39
|
+
|
40
|
+
# Returns all layouts that can be used for creating a new page.
|
41
|
+
#
|
42
|
+
# It removes all layouts from available layouts that are unique and already taken and that are marked as hide.
|
43
|
+
#
|
44
|
+
# @param [Fixnum]
|
45
|
+
# language_id of current used Language.
|
46
|
+
# @param [Boolean] (false)
|
47
|
+
# Pass true to only select layouts for global/layout pages.
|
48
|
+
#
|
49
|
+
def selectable_layouts(language_id, layoutpages: false)
|
50
|
+
@language_id = language_id
|
51
|
+
layouts_repository.all.select do |layout|
|
52
|
+
if layoutpages
|
53
|
+
layout["layoutpage"] && layout_available?(layout)
|
54
|
+
else
|
55
|
+
!layout["layoutpage"] && layout_available?(layout)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Translates name for given layout
|
61
|
+
#
|
62
|
+
# === Translation example
|
63
|
+
#
|
64
|
+
# en:
|
65
|
+
# alchemy:
|
66
|
+
# page_layout_names:
|
67
|
+
# products_overview: Products Overview
|
68
|
+
#
|
69
|
+
# @param [String]
|
70
|
+
# The layout name
|
71
|
+
#
|
72
|
+
def human_layout_name(layout)
|
73
|
+
Alchemy.t(layout, scope: "page_layout_names", default: layout.to_s.humanize)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def layouts_repository
|
79
|
+
@_layouts_repository ||= PageLayout
|
80
|
+
end
|
81
|
+
|
82
|
+
# Maps given layouts for Rails select form helper.
|
83
|
+
#
|
84
|
+
def mapped_layouts_for_select(layouts)
|
85
|
+
layouts.each do |layout|
|
86
|
+
@map_array << [human_layout_name(layout["name"]), layout["name"]]
|
87
|
+
end
|
88
|
+
@map_array
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns true if the given layout is unique and not already taken or it should be hidden.
|
92
|
+
#
|
93
|
+
def layout_available?(layout)
|
94
|
+
!layout["hide"] && !already_taken?(layout) && available_on_site?(layout)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns true if this layout is unique and already taken by another page.
|
98
|
+
#
|
99
|
+
def already_taken?(layout)
|
100
|
+
layout["unique"] && page_with_layout_existing?(layout["name"])
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns true if one page already has the given layout
|
104
|
+
#
|
105
|
+
def page_with_layout_existing?(layout)
|
106
|
+
Alchemy::Page.where(page_layout: layout, language_id: @language_id).pluck(:id).any?
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns true if given layout is available for current site.
|
110
|
+
#
|
111
|
+
# If no site layouts are defined it always returns true.
|
112
|
+
#
|
113
|
+
# == Example
|
114
|
+
#
|
115
|
+
# # config/alchemy/site_layouts.yml
|
116
|
+
# - name: default_site
|
117
|
+
# page_layouts: [default_intro]
|
118
|
+
#
|
119
|
+
def available_on_site?(layout)
|
120
|
+
return false unless Alchemy::Site.current
|
121
|
+
|
122
|
+
Alchemy::Site.current.definition.blank? ||
|
123
|
+
Alchemy::Site.current.definition.fetch("page_layouts", []).include?(layout["name"])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/app/models/alchemy/page.rb
CHANGED
@@ -36,6 +36,7 @@
|
|
36
36
|
#
|
37
37
|
|
38
38
|
require_dependency "alchemy/page/fixed_attributes"
|
39
|
+
require_dependency "alchemy/page/page_layouts"
|
39
40
|
require_dependency "alchemy/page/page_scopes"
|
40
41
|
require_dependency "alchemy/page/page_natures"
|
41
42
|
require_dependency "alchemy/page/page_naming"
|
@@ -152,6 +153,7 @@ module Alchemy
|
|
152
153
|
after_update :touch_nodes
|
153
154
|
|
154
155
|
# Concerns
|
156
|
+
include PageLayouts
|
155
157
|
include PageScopes
|
156
158
|
include PageNatures
|
157
159
|
include PageNaming
|
@@ -267,11 +269,11 @@ module Alchemy
|
|
267
269
|
where(id: clipboard.collect { |p| p["id"] })
|
268
270
|
end
|
269
271
|
|
270
|
-
def all_from_clipboard_for_select(clipboard, language_id,
|
272
|
+
def all_from_clipboard_for_select(clipboard, language_id, layoutpages: false)
|
271
273
|
return [] if clipboard.blank?
|
272
274
|
|
273
275
|
clipboard_pages = all_from_clipboard(clipboard)
|
274
|
-
allowed_page_layouts = Alchemy::
|
276
|
+
allowed_page_layouts = Alchemy::Page.selectable_layouts(language_id, layoutpages: layoutpages)
|
275
277
|
allowed_page_layout_names = allowed_page_layouts.collect { |p| p["name"] }
|
276
278
|
clipboard_pages.select { |cp| allowed_page_layout_names.include?(cp.page_layout) }
|
277
279
|
end
|
@@ -30,7 +30,7 @@ module Alchemy
|
|
30
30
|
# store the processed image
|
31
31
|
image.to_file(server_path(uid)).close
|
32
32
|
rescue RuntimeError => e
|
33
|
-
|
33
|
+
ErrorTracking.notification_handler.call(e)
|
34
34
|
# destroy the thumb if processing or storing fails
|
35
35
|
thumb&.destroy
|
36
36
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module DomIds
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
RESERVED_ANCHOR_SETTING_VALUES = %w[false from_value true]
|
8
|
+
|
9
|
+
included do
|
10
|
+
before_validation :parameterize_dom_id,
|
11
|
+
if: -> { settings[:anchor].to_s == "true" }
|
12
|
+
before_validation :set_dom_id_from_value,
|
13
|
+
if: -> { settings[:anchor].to_s == "from_value" }
|
14
|
+
before_validation :set_dom_id_to_fixed_value,
|
15
|
+
if: -> { !RESERVED_ANCHOR_SETTING_VALUES.include? settings[:anchor].to_s }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def parameterize_dom_id
|
21
|
+
self.dom_id = dom_id&.parameterize
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_dom_id_from_value
|
25
|
+
self.dom_id = value&.parameterize
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_dom_id_to_fixed_value
|
29
|
+
self.dom_id = settings[:anchor]&.parameterize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -7,6 +7,9 @@
|
|
7
7
|
|
8
8
|
$errors.hide();
|
9
9
|
$el.trigger('SaveElement.Alchemy', {previewText: '<%= j sanitize(@element.preview_text) %>'});
|
10
|
+
<% @element.ingredients.select { |i| i.settings[:anchor] }.each do |ingredient| %>
|
11
|
+
Alchemy.IngredientAnchorLink.updateIcon(<%= ingredient.id %>, <%= ingredient.dom_id.present? %>);
|
12
|
+
<% end %>
|
10
13
|
Alchemy.growl('<%= Alchemy.t(:element_saved) %>');
|
11
14
|
Alchemy.PreviewWindow.refresh(function() {
|
12
15
|
Alchemy.ElementEditors.focusElementPreview(<%= @element.id %>);
|
@@ -14,7 +14,7 @@
|
|
14
14
|
<%= f.input :frontpage_name %>
|
15
15
|
<%= f.input :page_layout,
|
16
16
|
collection: Alchemy::PageLayout.all,
|
17
|
-
label_method: ->(p) { Alchemy::
|
17
|
+
label_method: ->(p) { Alchemy::Page.human_layout_name(p['name']) },
|
18
18
|
value_method: ->(p) { p['name'] },
|
19
19
|
input_html: {class: 'alchemy_selectbox'} %>
|
20
20
|
<%= f.input :public %>
|
@@ -18,7 +18,7 @@
|
|
18
18
|
<%= language.frontpage_name %>
|
19
19
|
</td>
|
20
20
|
<td>
|
21
|
-
<%= Alchemy::
|
21
|
+
<%= Alchemy::Page.human_layout_name(language.page_layout) %>
|
22
22
|
</td>
|
23
23
|
<td class="center">
|
24
24
|
<%= language.public? ? render_icon(:check) : nil %>
|
@@ -34,6 +34,7 @@
|
|
34
34
|
order_admin_elements_path: '<%= alchemy.order_admin_elements_path %>',
|
35
35
|
link_admin_pages_path: '<%= alchemy.link_admin_pages_path %>',
|
36
36
|
api_pages_path: '<%= alchemy.api_pages_path %>',
|
37
|
-
api_elements_path: '<%= alchemy.api_elements_path %>'
|
37
|
+
api_elements_path: '<%= alchemy.api_elements_path %>',
|
38
|
+
api_ingredients_path: '<%= alchemy.api_ingredients_path %>'
|
38
39
|
};
|
39
40
|
</script>
|
@@ -1,3 +1,6 @@
|
|
1
|
+
<% has_level_select = headline_editor.level_options.many? %>
|
2
|
+
<% has_size_select = headline_editor.size_options.many? %>
|
3
|
+
|
1
4
|
<%= content_tag :div,
|
2
5
|
class: headline_editor.css_classes,
|
3
6
|
data: headline_editor.data_attributes do %>
|
@@ -5,26 +8,25 @@
|
|
5
8
|
<%= ingredient_label(headline_editor) %>
|
6
9
|
<%= f.text_field :value, id: nil %>
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
<% if headline_editor.settings[:anchor] %>
|
12
|
+
<%= render "alchemy/ingredients/shared/anchor", ingredient_editor: headline_editor %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<% if has_level_select %>
|
16
|
+
<div class="input-addon right<%= " second" if has_size_select %>">
|
17
|
+
<%= f.select :level,
|
18
|
+
options_for_select(headline_editor.level_options, headline_editor.level),
|
19
|
+
{},
|
20
|
+
{ class: "custom-select", title: f.object.class.human_attribute_name(:level) } %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
</div>
|
27
|
-
<% end %>
|
28
|
-
</div>
|
24
|
+
<% if has_size_select %>
|
25
|
+
<div class="input-addon right">
|
26
|
+
<%= f.select :size, options_for_select(headline_editor.size_options, headline_editor.size),
|
27
|
+
{},
|
28
|
+
{ class: "custom-select", title: f.object.class.human_attribute_name(:size) } %>
|
29
|
+
</div>
|
30
|
+
<% end %>
|
29
31
|
<% end %>
|
30
32
|
<% end %>
|
@@ -9,6 +9,9 @@
|
|
9
9
|
class: text_editor.settings[:linkable] ? "text_with_icon" : "",
|
10
10
|
id: nil,
|
11
11
|
type: text_editor.settings[:input_type] || "text" %>
|
12
|
+
<% if text_editor.settings[:anchor] %>
|
13
|
+
<%= render "alchemy/ingredients/shared/anchor", ingredient_editor: text_editor %>
|
14
|
+
<% end %>
|
12
15
|
<% if text_editor.settings[:linkable] %>
|
13
16
|
<%= f.hidden_field :link, "data-link-value": true, id: nil %>
|
14
17
|
<%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
|
@@ -1,13 +1,17 @@
|
|
1
1
|
<%- options = local_assigns.fetch(:options, {}) -%>
|
2
2
|
<%- html_options = local_assigns.fetch(:html_options, {}) -%>
|
3
|
-
<%- if text_view.link.blank? ||
|
4
|
-
|
5
|
-
<%= text_view.value
|
3
|
+
<%- if text_view.link.blank? || text_view.settings_value(:disable_link, options) -%>
|
4
|
+
<%- if text_view.dom_id.present? -%>
|
5
|
+
<%= content_tag :a, text_view.value, id: text_view.dom_id %>
|
6
|
+
<% else %>
|
7
|
+
<%= text_view.value -%>
|
8
|
+
<%- end -%>
|
6
9
|
<%- else -%>
|
7
10
|
<%= link_to(
|
8
11
|
text_view.value,
|
9
12
|
url_for(text_view.link),
|
10
13
|
{
|
14
|
+
id: text_view.dom_id.presence,
|
11
15
|
title: text_view.link_title,
|
12
16
|
target: (text_view.link_target == "blank" ? "_blank" : nil),
|
13
17
|
'data-link-target' => text_view.link_target
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<span class="edit-ingredient-anchor-link">
|
2
|
+
<%= link_to_dialog render_icon(:bookmark, { style: ingredient_editor.dom_id.present? ? "solid" : "regular" }),
|
3
|
+
alchemy.edit_admin_ingredient_path(id: ingredient_editor.id),
|
4
|
+
{
|
5
|
+
title: Alchemy.t(:edit_anchor),
|
6
|
+
size: "380x125"
|
7
|
+
},
|
8
|
+
title: Alchemy.t(:edit_anchor) %>
|
9
|
+
</span>
|
@@ -228,7 +228,8 @@ en:
|
|
228
228
|
|
229
229
|
add_nested_element: "Add %{name}"
|
230
230
|
anchor: 'Anchor'
|
231
|
-
anchor_link_headline:
|
231
|
+
anchor_link_headline: You can link to an anchor from the current page.
|
232
|
+
automatic_anchor_notice: The anchor is generated automatically.
|
232
233
|
attribute_fixed: Value can't be changed for this page type
|
233
234
|
back: 'back'
|
234
235
|
locked_pages: "Active pages"
|
@@ -467,7 +468,7 @@ en:
|
|
467
468
|
image_name: "Name: %{name}"
|
468
469
|
image_title: "Title-tag"
|
469
470
|
internal_link_headline: "Search for a page to link to by entering its name into the Page select."
|
470
|
-
internal_link_page_elements_explanation: "Additionally you can choose an anchor to
|
471
|
+
internal_link_page_elements_explanation: "Additionally you can choose an anchor to link to from selected page."
|
471
472
|
"item copied to clipboard": "Copied %{name} to clipboard"
|
472
473
|
"item moved to clipboard": "Moved %{name} to clipboard"
|
473
474
|
"item removed from clipboard": "Removed %{name} from clipboard"
|
@@ -845,6 +846,8 @@ en:
|
|
845
846
|
crop_from: Crop from
|
846
847
|
crop_size: Crop size
|
847
848
|
picture_id: Bild
|
849
|
+
alchemy/ingredient:
|
850
|
+
dom_id: Anchor
|
848
851
|
alchemy/language:
|
849
852
|
country_code: "Country code"
|
850
853
|
language_code: "Language code"
|
data/config/routes.rb
CHANGED
@@ -126,6 +126,7 @@ Alchemy::Engine.routes.draw do
|
|
126
126
|
|
127
127
|
namespace :api, defaults: { format: "json" } do
|
128
128
|
resources :contents, only: [:index, :show]
|
129
|
+
resources :ingredients, only: [:index]
|
129
130
|
|
130
131
|
resources :elements, only: [:index, :show] do
|
131
132
|
get "/contents" => "contents#index", as: "contents"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module ErrorTracking
|
5
|
+
class ErrorLogger < BaseHandler
|
6
|
+
def self.call(exception)
|
7
|
+
::Rails.logger.tagged("alchemy_cms") do
|
8
|
+
::Rails.logger.error("#{exception.class.name}: #{exception.message} in #{exception.backtrace.first}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -31,13 +31,7 @@ module Alchemy
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def inject_seeder
|
34
|
-
|
35
|
-
args = [seed_file, "Alchemy::Seeder.seed!\n"]
|
36
|
-
if File.exist?(seed_file)
|
37
|
-
append_file(*args)
|
38
|
-
else
|
39
|
-
add_file(*args)
|
40
|
-
end
|
34
|
+
append_file "./db/seeds.rb", "Alchemy::Seeder.seed!\n"
|
41
35
|
end
|
42
36
|
end
|
43
37
|
end
|