alchemy_cms 3.0.4 → 3.1.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -6
- data/Gemfile +4 -7
- data/README.md +207 -115
- data/alchemy_cms.gemspec +10 -9
- data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.js +6 -7
- data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +1 -43
- data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +1 -1
- data/app/assets/stylesheets/alchemy/_mixins.scss +2 -1
- data/app/assets/stylesheets/alchemy/buttons.scss +0 -5
- data/app/assets/stylesheets/alchemy/dialogs.scss +1 -0
- data/app/assets/stylesheets/alchemy/frame.scss +9 -12
- data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +11 -2
- data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +9 -1
- data/app/controllers/alchemy/admin/attachments_controller.rb +2 -4
- data/app/controllers/alchemy/admin/essence_pictures_controller.rb +34 -38
- data/app/controllers/alchemy/api/base_controller.rb +19 -0
- data/app/controllers/alchemy/api/contents_controller.rb +35 -0
- data/app/controllers/alchemy/api/elements_controller.rb +29 -0
- data/app/controllers/alchemy/api/pages_controller.rb +32 -0
- data/app/controllers/alchemy/contents_controller.rb +1 -0
- data/app/controllers/alchemy/elements_controller.rb +5 -2
- data/app/controllers/alchemy/pages_controller.rb +4 -1
- data/app/controllers/alchemy/pictures_controller.rb +4 -36
- data/app/helpers/alchemy/admin/essences_helper.rb +5 -2
- data/app/helpers/alchemy/essences_helper.rb +14 -1
- data/app/models/alchemy/content.rb +32 -4
- data/app/models/alchemy/element.rb +2 -16
- data/app/models/alchemy/element/presenters.rb +2 -2
- data/app/models/alchemy/essence_file.rb +5 -0
- data/app/models/alchemy/essence_picture.rb +12 -8
- data/app/models/alchemy/picture.rb +1 -74
- data/app/models/alchemy/picture/transformations.rb +249 -0
- data/app/serializers/alchemy/content_serializer.rb +3 -10
- data/app/serializers/alchemy/element_serializer.rb +6 -3
- data/app/serializers/alchemy/legacy_element_serializer.rb +17 -0
- data/app/views/alchemy/admin/dashboard/_sites.html.erb +14 -4
- data/app/views/alchemy/admin/essence_pictures/crop.html.erb +8 -5
- data/app/views/alchemy/admin/pages/edit.html.erb +9 -9
- data/app/views/alchemy/admin/pictures/info.html.erb +2 -3
- data/app/views/alchemy/admin/tags/edit.html.erb +1 -1
- data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +8 -7
- data/app/views/alchemy/essences/_essence_boolean_view.html.erb +3 -3
- data/app/views/alchemy/essences/_essence_date_editor.html.erb +8 -2
- data/app/views/alchemy/essences/_essence_date_view.html.erb +10 -8
- data/app/views/alchemy/essences/_essence_file_editor.html.erb +48 -53
- data/app/views/alchemy/essences/_essence_file_view.html.erb +5 -5
- data/app/views/alchemy/essences/_essence_html_editor.html.erb +5 -4
- data/app/views/alchemy/essences/_essence_link_editor.html.erb +17 -15
- data/app/views/alchemy/essences/_essence_link_view.html.erb +11 -7
- data/app/views/alchemy/essences/_essence_picture_editor.html.erb +4 -2
- data/app/views/alchemy/essences/_essence_picture_view.html.erb +4 -2
- data/app/views/alchemy/essences/_essence_richtext_view.html.erb +5 -4
- data/app/views/alchemy/essences/_essence_select_editor.html.erb +22 -32
- data/app/views/alchemy/essences/_essence_text_view.html.erb +7 -6
- data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +1 -1
- data/app/views/layouts/alchemy/admin.html.erb +5 -3
- data/config/initializers/inflections.rb +3 -0
- data/config/initializers/simple_form.rb +1 -1
- data/config/locales/alchemy.en.yml +0 -1
- data/config/routes.rb +14 -0
- data/lib/alchemy/capistrano.rb +71 -0
- data/lib/alchemy/engine.rb +0 -3
- data/lib/alchemy/essence.rb +1 -1
- data/lib/alchemy/permissions.rb +19 -5
- data/lib/alchemy/picture_attributes.rb +1 -1
- data/lib/alchemy/test_support/auth_helpers.rb +1 -1
- data/lib/alchemy/test_support/essence_shared_examples.rb +37 -22
- data/lib/alchemy/test_support/integration_helpers.rb +1 -1
- data/lib/alchemy/tinymce.rb +21 -4
- data/lib/alchemy/upgrader/three_point_one.rb +43 -0
- data/lib/alchemy/upgrader/three_point_zero.rb +13 -0
- data/lib/alchemy/version.rb +2 -1
- data/lib/rails/generators/alchemy/module/module_generator.rb +30 -0
- data/lib/rails/generators/alchemy/module/templates/ability.rb.tt +11 -0
- data/lib/rails/generators/alchemy/module/templates/controller.rb.tt +2 -0
- data/lib/rails/generators/alchemy/module/templates/module_config.rb.tt +15 -0
- data/lib/rails/generators/alchemy/scaffold/scaffold_generator.rb +0 -1
- data/lib/rails/templates/alchemy.rb +2 -2
- data/lib/tasks/alchemy/db.rake +7 -1
- data/spec/controllers/admin/attachments_controller_spec.rb +38 -38
- data/spec/controllers/admin/base_controller_spec.rb +18 -18
- data/spec/controllers/admin/clipboard_controller_spec.rb +23 -18
- data/spec/controllers/admin/contents_controller_spec.rb +33 -27
- data/spec/controllers/admin/dashboard_controller_spec.rb +14 -14
- data/spec/controllers/admin/elements_controller_spec.rb +125 -105
- data/spec/controllers/admin/essence_files_controller_spec.rb +6 -7
- data/spec/controllers/admin/essence_pictures_controller_spec.rb +52 -42
- data/spec/controllers/admin/languages_controller_spec.rb +3 -3
- data/spec/controllers/admin/pages_controller_spec.rb +81 -71
- data/spec/controllers/admin/pictures_controller_spec.rb +69 -72
- data/spec/controllers/admin/resources_controller_spec.rb +5 -5
- data/spec/controllers/admin/trash_controller_spec.rb +15 -12
- data/spec/controllers/alchemy/admin/tags_controller_spec.rb +8 -8
- data/spec/controllers/alchemy/api/contents_controller_spec.rb +73 -0
- data/spec/controllers/alchemy/api/elements_controller_spec.rb +69 -0
- data/spec/controllers/alchemy/api/pages_controller_spec.rb +86 -0
- data/spec/controllers/attachments_controller_spec.rb +8 -8
- data/spec/controllers/contents_controller_spec.rb +22 -0
- data/spec/controllers/elements_controller_spec.rb +10 -4
- data/spec/controllers/messages_controller_spec.rb +35 -34
- data/spec/controllers/pages_controller_spec.rb +37 -28
- data/spec/controllers/pictures_controller_spec.rb +90 -23
- data/spec/dummy/app/models/dummy_user.rb +0 -4
- data/spec/dummy/app/views/alchemy/elements/_all_you_can_eat_editor.html.erb +11 -0
- data/spec/dummy/config/alchemy/elements.yml +22 -1
- data/spec/dummy/config/alchemy/page_layouts.yml +4 -0
- data/spec/dummy/config/application.rb +2 -1
- data/spec/dummy/config/environments/test.rb +3 -1
- data/spec/features/admin/dashboard_spec.rb +41 -6
- data/spec/features/admin/language_tree_feature_spec.rb +3 -3
- data/spec/features/admin/legacy_page_url_management_spec.rb +1 -1
- data/spec/features/admin/link_overlay_spec.rb +7 -7
- data/spec/features/admin/locale_select_feature_spec.rb +5 -2
- data/spec/features/admin/modules_integration_spec.rb +1 -1
- data/spec/features/admin/page_creation_feature_spec.rb +3 -2
- data/spec/features/admin/page_editing_feature_spec.rb +66 -79
- data/spec/features/admin/picture_library_integration_spec.rb +8 -8
- data/spec/features/admin/resources_integration_spec.rb +21 -21
- data/spec/features/admin/tinymce_feature_spec.rb +36 -0
- data/spec/features/navigation_spec.rb +1 -1
- data/spec/features/page_feature_spec.rb +34 -34
- data/spec/features/picture_security_spec.rb +4 -4
- data/spec/features/security_spec.rb +1 -1
- data/spec/features/translation_integration_spec.rb +7 -7
- data/spec/helpers/admin/base_helper_spec.rb +51 -49
- data/spec/helpers/admin/contents_helper_spec.rb +11 -11
- data/spec/helpers/admin/elements_helper_spec.rb +20 -17
- data/spec/helpers/admin/essences_helper_spec.rb +42 -11
- data/spec/helpers/admin/navigation_helper_spec.rb +64 -54
- data/spec/helpers/admin/pages_helper_spec.rb +10 -10
- data/spec/helpers/admin/tags_helper_spec.rb +16 -16
- data/spec/helpers/base_helper_spec.rb +11 -11
- data/spec/helpers/elements_block_helper_spec.rb +24 -24
- data/spec/helpers/elements_helper_spec.rb +46 -46
- data/spec/helpers/essences_helper_spec.rb +90 -17
- data/spec/helpers/pages_helper_spec.rb +53 -53
- data/spec/helpers/picture_url_helpers_spec.rb +6 -6
- data/spec/helpers/url_helper_spec.rb +32 -32
- data/spec/libraries/config_spec.rb +9 -9
- data/spec/libraries/controller_actions_spec.rb +14 -14
- data/spec/libraries/i18n_spec.rb +6 -6
- data/spec/libraries/kaminari/scoped_pagination_url_helper_spec.rb +4 -4
- data/spec/libraries/modules_spec.rb +4 -4
- data/spec/libraries/mount_point_spec.rb +13 -13
- data/spec/libraries/page_layout_spec.rb +24 -24
- data/spec/libraries/permissions_spec.rb +97 -80
- data/spec/libraries/resource_spec.rb +37 -37
- data/spec/libraries/resources_helper_spec.rb +19 -19
- data/spec/libraries/shell_spec.rb +17 -17
- data/spec/libraries/template_tracker_spec.rb +14 -14
- data/spec/libraries/tinymce_spec.rb +8 -8
- data/spec/libraries/userstamp_spec.rb +2 -2
- data/spec/mailers/messages_spec.rb +4 -4
- data/spec/models/attachment_spec.rb +86 -30
- data/spec/models/cell_spec.rb +10 -10
- data/spec/models/content_spec.rb +106 -46
- data/spec/models/element_spec.rb +94 -115
- data/spec/models/essence_date_spec.rb +1 -1
- data/spec/models/essence_file_spec.rb +4 -4
- data/spec/models/essence_picture_spec.rb +56 -25
- data/spec/models/essence_richtext_spec.rb +1 -1
- data/spec/models/essence_text_spec.rb +7 -7
- data/spec/models/language_spec.rb +12 -12
- data/spec/models/legacy_page_url_spec.rb +2 -2
- data/spec/models/message_spec.rb +12 -5
- data/spec/models/page_spec.rb +259 -235
- data/spec/models/picture_spec.rb +72 -166
- data/spec/models/site_spec.rb +41 -41
- data/spec/models/tag_spec.rb +7 -7
- data/spec/routing/api_routing_spec.rb +150 -0
- data/spec/routing/routing_spec.rb +28 -28
- data/spec/spec_helper.rb +6 -5
- data/spec/support/hint_examples.rb +5 -5
- data/spec/support/transformation_examples.rb +173 -0
- data/spec/tasks/helpers_spec.rb +29 -29
- data/spec/views/essences/essence_boolean_editor_spec.rb +32 -0
- data/spec/views/essences/essence_boolean_view_spec.rb +2 -2
- data/spec/views/essences/essence_date_view_spec.rb +1 -1
- data/spec/views/essences/essence_link_view_spec.rb +11 -0
- data/spec/views/essences/essence_picture_view_spec.rb +56 -11
- data/spec/views/essences/essence_richtext_view_spec.rb +12 -0
- data/spec/views/essences/essence_text_view_spec.rb +12 -0
- data/vendor/assets/javascripts/tinymce/langs/de.js +20 -2
- data/vendor/assets/javascripts/tinymce/langs/fr.js +14 -1
- data/vendor/assets/javascripts/tinymce/langs/nl.js +22 -4
- data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/code/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/link/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/tabfocus/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/themes/modern/theme.min.js +1 -1
- data/vendor/assets/javascripts/tinymce/tinymce.min.js +11 -10
- metadata +72 -42
- data/app/views/alchemy/messages/contact_form_mail.es.text.erb +0 -12
- data/config/locales/alchemy.es.yml +0 -958
- data/config/locales/alchemy.ru.yml +0 -837
- data/config/locales/simple_form.es.yml +0 -6
- data/config/locales/simple_form.ru.yml +0 -25
- data/lib/rails/generators/alchemy/scaffold/files/alchemy.es.yml +0 -31
- data/vendor/assets/javascripts/tinymce/langs/es.js +0 -197
- data/vendor/assets/javascripts/tinymce/langs/ru.js +0 -197
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Alchemy
|
|
2
|
+
class API::BaseController < Alchemy::BaseController
|
|
3
|
+
layout false
|
|
4
|
+
respond_to :json
|
|
5
|
+
|
|
6
|
+
rescue_from CanCan::AccessDenied, with: :render_not_authorized
|
|
7
|
+
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def render_not_authorized
|
|
12
|
+
render json: {error: 'Not authorized'}, status: 403
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render_not_found
|
|
16
|
+
render json: {error: 'Record not found'}, status: 404
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Alchemy
|
|
2
|
+
class API::ContentsController < API::BaseController
|
|
3
|
+
|
|
4
|
+
# Returns all contents as json object
|
|
5
|
+
#
|
|
6
|
+
# You can either load all or only these for :element_id param
|
|
7
|
+
#
|
|
8
|
+
def index
|
|
9
|
+
@contents = Content.accessible_by(current_ability, :index)
|
|
10
|
+
if params[:element_id]
|
|
11
|
+
@contents = @contents.where(element_id: params[:element_id])
|
|
12
|
+
end
|
|
13
|
+
respond_with @contents
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns a json object for content
|
|
17
|
+
#
|
|
18
|
+
# You can either load it from :id param
|
|
19
|
+
# or even more useful via passing the element id and the name of the content
|
|
20
|
+
#
|
|
21
|
+
# $ bin/rake routes
|
|
22
|
+
#
|
|
23
|
+
# for more infos on how the url looks like.
|
|
24
|
+
#
|
|
25
|
+
def show
|
|
26
|
+
if params[:id]
|
|
27
|
+
@content = Content.find(params[:id])
|
|
28
|
+
elsif params[:element_id] && params[:name]
|
|
29
|
+
@content = Content.find_by!(element_id: params[:element_id], name: params[:name])
|
|
30
|
+
end
|
|
31
|
+
authorize! :show, @content
|
|
32
|
+
respond_with @content
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Alchemy
|
|
2
|
+
class API::ElementsController < API::BaseController
|
|
3
|
+
|
|
4
|
+
# Returns all elements as json object
|
|
5
|
+
#
|
|
6
|
+
# You can either load all or only these for :page_id param
|
|
7
|
+
#
|
|
8
|
+
# If you want to only load a specific type of element pass ?named=an_element_name
|
|
9
|
+
#
|
|
10
|
+
def index
|
|
11
|
+
@elements = Element.accessible_by(current_ability, :index)
|
|
12
|
+
if params[:page_id]
|
|
13
|
+
@elements = @elements.where(page_id: params[:page_id])
|
|
14
|
+
end
|
|
15
|
+
if params[:named]
|
|
16
|
+
@elements = @elements.named(params[:named])
|
|
17
|
+
end
|
|
18
|
+
respond_with @elements
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns a json object for element
|
|
22
|
+
#
|
|
23
|
+
def show
|
|
24
|
+
@element = Element.find(params[:id])
|
|
25
|
+
authorize! :show, @element
|
|
26
|
+
respond_with @element
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Alchemy
|
|
2
|
+
class API::PagesController < API::BaseController
|
|
3
|
+
before_action :load_page, only: [:show]
|
|
4
|
+
|
|
5
|
+
# Returns all pages as json object
|
|
6
|
+
#
|
|
7
|
+
def index
|
|
8
|
+
@pages = Page.accessible_by(current_ability, :index)
|
|
9
|
+
if params[:page_layout]
|
|
10
|
+
@pages = @pages.where(page_layout: params[:page_layout])
|
|
11
|
+
end
|
|
12
|
+
respond_with @pages
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns a json object for page
|
|
16
|
+
#
|
|
17
|
+
# You can either load the page via id or its urlname
|
|
18
|
+
#
|
|
19
|
+
def show
|
|
20
|
+
authorize! :show, @page
|
|
21
|
+
respond_with @page
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def load_page
|
|
27
|
+
@page = Page.find_by(id: params[:id]) ||
|
|
28
|
+
Page.find_by(urlname: params[:urlname]) ||
|
|
29
|
+
raise(ActiveRecord::RecordNotFound)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -21,8 +21,11 @@ module Alchemy
|
|
|
21
21
|
|
|
22
22
|
respond_to do |format|
|
|
23
23
|
format.html
|
|
24
|
-
format.js
|
|
25
|
-
format.json
|
|
24
|
+
format.js { @container_id = params[:container_id] }
|
|
25
|
+
format.json do
|
|
26
|
+
ActiveSupport::Deprecation.warn("The Alchemy elements json API moved to `api` namespace. Please use `/api/elements` for json requests instead.")
|
|
27
|
+
render json: @element, serializer: LegacyElementSerializer
|
|
28
|
+
end
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
31
|
|
|
@@ -26,7 +26,10 @@ module Alchemy
|
|
|
26
26
|
render xml: {error: 'Not found'}, status: 404
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
|
-
format.json
|
|
29
|
+
format.json do
|
|
30
|
+
ActiveSupport::Deprecation.warn('The Alchemy pages json API moved to `api` namespace. Please use `/api/pages` for json requests instead.')
|
|
31
|
+
render json: @page
|
|
32
|
+
end
|
|
30
33
|
end
|
|
31
34
|
end
|
|
32
35
|
end
|
|
@@ -62,52 +62,20 @@ module Alchemy
|
|
|
62
62
|
# Return the processed image dependent of size and cropping parameters
|
|
63
63
|
def processed_image
|
|
64
64
|
@image = @picture.image_file
|
|
65
|
+
@upsample = params[:upsample] == 'true' ? true : false
|
|
65
66
|
if @image.nil?
|
|
66
67
|
raise MissingImageFileError, "Missing image file for #{@picture.inspect}"
|
|
67
68
|
end
|
|
68
69
|
if @size.present?
|
|
69
|
-
if params[:crop_size].present? && params[:crop_from].present?
|
|
70
|
-
@
|
|
71
|
-
@image.thumb(resize_geometry_string)
|
|
72
|
-
elsif params[:crop]
|
|
73
|
-
@image.thumb(center_crop_geometry_string)
|
|
70
|
+
if params[:crop_size].present? && params[:crop_from].present? || params[:crop].present?
|
|
71
|
+
@picture.crop(@size, params[:crop_from], params[:crop_size], @upsample)
|
|
74
72
|
else
|
|
75
|
-
@
|
|
73
|
+
@picture.resize(@size, @upsample)
|
|
76
74
|
end
|
|
77
75
|
else
|
|
78
76
|
@image
|
|
79
77
|
end
|
|
80
78
|
end
|
|
81
79
|
|
|
82
|
-
# Returns the Imagemagick geometry string for cropping the image.
|
|
83
|
-
def xy_crop_geometry_string(params)
|
|
84
|
-
crop_from_x, crop_from_y = params[:crop_from].split('x')
|
|
85
|
-
"#{params[:crop_size]}+#{crop_from_x}+#{crop_from_y}"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Returns the Imagemagick geometry string used to resize the image.
|
|
89
|
-
#
|
|
90
|
-
# Prevents upscaling unless :upsample param is true.
|
|
91
|
-
def resize_geometry_string
|
|
92
|
-
params[:upsample] == 'true' ? @size : "#{@size}>"
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Returns the Imagemagick geometry string used to crop the image.
|
|
96
|
-
#
|
|
97
|
-
# Prevents upscaling unless :upsample param is true
|
|
98
|
-
def center_crop_geometry_string
|
|
99
|
-
params[:upsample] == 'true' ? "#{@size}#" : "#{normalized_sizes(*@size.split('x'))}#"
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Ensure we're not trying to scale the image up. Used only for cropping.
|
|
103
|
-
def normalized_sizes(width, height)
|
|
104
|
-
if width.to_i > @image.width
|
|
105
|
-
width = @image.width
|
|
106
|
-
end
|
|
107
|
-
if height.to_i > @image.height
|
|
108
|
-
height = @image.height
|
|
109
|
-
end
|
|
110
|
-
"#{width}x#{height}"
|
|
111
|
-
end
|
|
112
80
|
end
|
|
113
81
|
end
|
|
@@ -59,11 +59,14 @@ module Alchemy
|
|
|
59
59
|
|
|
60
60
|
def essence_picture_thumbnail(content, options)
|
|
61
61
|
return if content.ingredient.blank?
|
|
62
|
+
crop = !(content.essence.crop_size.blank? && content.essence.crop_from.blank?) ||
|
|
63
|
+
(content_settings_value(content, :crop, options) == true || content_settings_value(content, :crop, options) == "true")
|
|
62
64
|
image_options = {
|
|
63
|
-
size: content.
|
|
65
|
+
size: content.essence.thumbnail_size(content.essence.render_size.blank? ? content_settings_value(content, :size, options) : content.essence.render_size, crop),
|
|
64
66
|
crop_from: content.essence.crop_from.blank? ? nil : content.essence.crop_from,
|
|
65
67
|
crop_size: content.essence.crop_size.blank? ? nil : content.essence.crop_size,
|
|
66
|
-
crop:
|
|
68
|
+
crop: crop ? 'crop' : nil,
|
|
69
|
+
upsample: content_settings_value(content, :upsample, options)
|
|
67
70
|
}
|
|
68
71
|
image_tag(
|
|
69
72
|
alchemy.thumbnail_path({
|
|
@@ -92,7 +92,10 @@ module Alchemy
|
|
|
92
92
|
# Renders a essence picture
|
|
93
93
|
#
|
|
94
94
|
def render_essence_picture_view(content, options, html_options)
|
|
95
|
-
options = {
|
|
95
|
+
options = {
|
|
96
|
+
show_caption: true,
|
|
97
|
+
disable_link: false
|
|
98
|
+
}.update(content.settings).update(options)
|
|
96
99
|
return if content.ingredient.blank?
|
|
97
100
|
if content.essence.caption.present? && options[:show_caption]
|
|
98
101
|
caption = content_tag(:figcaption, content.essence.caption, id: "#{dom_id(content.ingredient)}_caption", class: "image_caption")
|
|
@@ -121,5 +124,15 @@ module Alchemy
|
|
|
121
124
|
end
|
|
122
125
|
end
|
|
123
126
|
|
|
127
|
+
# Fetches value from settings of given content
|
|
128
|
+
#
|
|
129
|
+
# @param content [Alchemy::Content] - The content that settings should be taken
|
|
130
|
+
# @param key [Symbol] - The hash key you want to fetch the value from
|
|
131
|
+
# @param options [Hash] - An optional Hash that can override the settings.
|
|
132
|
+
# Normally passed as options hash into the content editor view
|
|
133
|
+
def content_settings_value(content, key, options = {})
|
|
134
|
+
content.settings.update(options || {}).symbolize_keys[key.to_sym]
|
|
135
|
+
end
|
|
136
|
+
|
|
124
137
|
end
|
|
125
138
|
end
|
|
@@ -51,6 +51,14 @@ module Alchemy
|
|
|
51
51
|
scope :essence_selects, -> { where(essence_type: "Alchemy::EssenceSelect") }
|
|
52
52
|
scope :essence_texts, -> { where(essence_type: "Alchemy::EssenceText") }
|
|
53
53
|
scope :named, ->(name) { where(name: name) }
|
|
54
|
+
scope :available, -> { published.not_trashed }
|
|
55
|
+
scope :published, -> { joins(:element).merge(Element.published) }
|
|
56
|
+
scope :not_trashed, -> { joins(:element).merge(Element.not_trashed) }
|
|
57
|
+
scope :not_restricted, -> { joins(:element).merge(Element.not_restricted) }
|
|
58
|
+
|
|
59
|
+
delegate :restricted?, to: :element, allow_nil: true
|
|
60
|
+
delegate :trashed?, to: :element, allow_nil: true
|
|
61
|
+
delegate :public?, to: :element, allow_nil: true
|
|
54
62
|
|
|
55
63
|
class << self
|
|
56
64
|
# Returns the translated label for a content name.
|
|
@@ -99,9 +107,7 @@ module Alchemy
|
|
|
99
107
|
# Settings from the elements.yml definition
|
|
100
108
|
def settings
|
|
101
109
|
return {} if description.blank?
|
|
102
|
-
@settings ||= description
|
|
103
|
-
return {} if @settings.blank?
|
|
104
|
-
@settings.symbolize_keys
|
|
110
|
+
@settings ||= description.fetch('settings', {}).symbolize_keys
|
|
105
111
|
end
|
|
106
112
|
|
|
107
113
|
def siblings
|
|
@@ -115,6 +121,25 @@ module Alchemy
|
|
|
115
121
|
essence.ingredient
|
|
116
122
|
end
|
|
117
123
|
|
|
124
|
+
# Serialized object representation for json api
|
|
125
|
+
#
|
|
126
|
+
def serialize
|
|
127
|
+
{
|
|
128
|
+
name: name,
|
|
129
|
+
value: serialized_ingredient,
|
|
130
|
+
link: essence.try(:link)
|
|
131
|
+
}.delete_if { |_k, v| v.blank? }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Ingredient value from essence for json api
|
|
135
|
+
#
|
|
136
|
+
# If the essence responds to +serialized_ingredient+ method it takes this
|
|
137
|
+
# otherwise it uses the ingredient column.
|
|
138
|
+
#
|
|
139
|
+
def serialized_ingredient
|
|
140
|
+
essence.try(:serialized_ingredient) || ingredient
|
|
141
|
+
end
|
|
142
|
+
|
|
118
143
|
# Sets the ingredient from essence
|
|
119
144
|
def ingredient=(value)
|
|
120
145
|
raise EssenceMissingError if essence.nil?
|
|
@@ -184,7 +209,10 @@ module Alchemy
|
|
|
184
209
|
|
|
185
210
|
# Returns true if this content should be taken for element preview.
|
|
186
211
|
def preview_content?
|
|
187
|
-
|
|
212
|
+
if description['take_me_for_preview']
|
|
213
|
+
ActiveSupport::Deprecation.warn("Content definition's `take_me_for_preview` key is deprecated. Please use `as_element_title` instead.")
|
|
214
|
+
end
|
|
215
|
+
!!description['take_me_for_preview'] || !!description['as_element_title']
|
|
188
216
|
end
|
|
189
217
|
|
|
190
218
|
# Proxy method that returns the preview text from essence.
|
|
@@ -52,7 +52,7 @@ module Alchemy
|
|
|
52
52
|
scope :trashed, -> { where(position: nil).order('updated_at DESC') }
|
|
53
53
|
scope :not_trashed, -> { where(Element.arel_table[:position].not_eq(nil)) }
|
|
54
54
|
scope :published, -> { where(public: true) }
|
|
55
|
-
scope :not_restricted, -> { joins(:page).
|
|
55
|
+
scope :not_restricted, -> { joins(:page).merge(Page.not_restricted) }
|
|
56
56
|
scope :available, -> { published.not_trashed }
|
|
57
57
|
scope :named, ->(names) { where(name: names) }
|
|
58
58
|
scope :excluded, ->(names) { where(arel_table[:name].not_in(names)) }
|
|
@@ -361,7 +361,7 @@ module Alchemy
|
|
|
361
361
|
"fields.#{content_name}.#{error}".to_sym,
|
|
362
362
|
"errors.#{error}".to_sym
|
|
363
363
|
],
|
|
364
|
-
field: Content.translated_label_for(content_name
|
|
364
|
+
field: Content.translated_label_for(content_name)
|
|
365
365
|
)
|
|
366
366
|
end
|
|
367
367
|
end
|
|
@@ -421,20 +421,6 @@ module Alchemy
|
|
|
421
421
|
"alchemy/elements/#{name}_view"
|
|
422
422
|
end
|
|
423
423
|
|
|
424
|
-
# Returns the key that's taken for cache path.
|
|
425
|
-
#
|
|
426
|
-
# Uses the page's +published_at+ value that's updated when the user publishes the page.
|
|
427
|
-
#
|
|
428
|
-
# If the page is the current preview it uses the element's updated_at value as cache key.
|
|
429
|
-
#
|
|
430
|
-
def cache_key
|
|
431
|
-
if Page.current_preview == self.page
|
|
432
|
-
"alchemy/elements/#{id}-#{updated_at}"
|
|
433
|
-
else
|
|
434
|
-
"alchemy/elements/#{id}-#{page.published_at}"
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
|
|
438
424
|
private
|
|
439
425
|
|
|
440
426
|
# creates the contents for this element as described in the elements.yml
|
|
@@ -39,7 +39,7 @@ module Alchemy
|
|
|
39
39
|
#
|
|
40
40
|
# It's taken from the first Content found in the +elements.yml+ description file.
|
|
41
41
|
#
|
|
42
|
-
# You can flag a Content as +
|
|
42
|
+
# You can flag a Content as +as_element_title+ to take this as preview.
|
|
43
43
|
#
|
|
44
44
|
# @param maxlength [Fixnum] (30)
|
|
45
45
|
# Length of characters after the text will be cut off.
|
|
@@ -63,7 +63,7 @@ module Alchemy
|
|
|
63
63
|
# type: EssenceText
|
|
64
64
|
# - name: text
|
|
65
65
|
# type EssenceRichtext
|
|
66
|
-
#
|
|
66
|
+
# as_element_title: true
|
|
67
67
|
#
|
|
68
68
|
# With "I want to tell you a funky story" as stripped_body for the EssenceRichtext Content produces:
|
|
69
69
|
#
|
|
@@ -26,9 +26,12 @@ module Alchemy
|
|
|
26
26
|
acts_as_essence ingredient_column: 'picture'
|
|
27
27
|
|
|
28
28
|
belongs_to :picture
|
|
29
|
+
delegate :image_file_width, :image_file_height, :image_file, to: :picture
|
|
29
30
|
before_save :fix_crop_values
|
|
30
31
|
before_save :replace_newlines
|
|
31
32
|
|
|
33
|
+
include Alchemy::Picture::Transformations
|
|
34
|
+
|
|
32
35
|
# The url to show the picture.
|
|
33
36
|
#
|
|
34
37
|
# Takes all values like +name+ and crop sizes (+crop_from+, +crop_size+ from the build in graphical image cropper)
|
|
@@ -70,14 +73,15 @@ module Alchemy
|
|
|
70
73
|
#
|
|
71
74
|
def cropping_mask
|
|
72
75
|
return if crop_from.blank? || crop_size.blank?
|
|
73
|
-
crop_from = read_attribute(:crop_from)
|
|
74
|
-
crop_size = read_attribute(:crop_size)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
crop_from = point_from_string(read_attribute(:crop_from))
|
|
77
|
+
crop_size = sizes_from_string(read_attribute(:crop_size))
|
|
78
|
+
|
|
79
|
+
point_and_mask_to_points(crop_from, crop_size)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns a serialized ingredient value for json api
|
|
83
|
+
def serialized_ingredient
|
|
84
|
+
picture_url(content.settings)
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
private
|
|
@@ -22,6 +22,7 @@ module Alchemy
|
|
|
22
22
|
include Alchemy::NameConversions
|
|
23
23
|
include Alchemy::Touching
|
|
24
24
|
include Alchemy::Picture::Sweeping
|
|
25
|
+
include Alchemy::Picture::Transformations
|
|
25
26
|
|
|
26
27
|
has_many :essence_pictures, class_name: 'Alchemy::EssencePicture', foreign_key: 'picture_id'
|
|
27
28
|
has_many :contents, through: :essence_pictures
|
|
@@ -143,80 +144,6 @@ module Alchemy
|
|
|
143
144
|
convert_to_humanized_name(image_file_name, suffix)
|
|
144
145
|
end
|
|
145
146
|
|
|
146
|
-
# Returns true if picture's width is greater than it's height
|
|
147
|
-
#
|
|
148
|
-
def landscape_format?
|
|
149
|
-
image_file.landscape?
|
|
150
|
-
end
|
|
151
|
-
alias_method :landscape?, :landscape_format?
|
|
152
|
-
|
|
153
|
-
# Returns true if picture's width is smaller than it's height
|
|
154
|
-
#
|
|
155
|
-
def portrait_format?
|
|
156
|
-
image_file.portrait?
|
|
157
|
-
end
|
|
158
|
-
alias_method :portrait?, :portrait_format?
|
|
159
|
-
|
|
160
|
-
# Returns true if picture's width and height is equal
|
|
161
|
-
#
|
|
162
|
-
def square_format?
|
|
163
|
-
image_file.aspect_ratio == 1.0
|
|
164
|
-
end
|
|
165
|
-
alias_method :square?, :square_format?
|
|
166
|
-
|
|
167
|
-
# Returns the default centered image mask for a given size.
|
|
168
|
-
#
|
|
169
|
-
def default_mask(size)
|
|
170
|
-
raise "No size given" if size.blank?
|
|
171
|
-
width = size.split('x')[0].to_i
|
|
172
|
-
height = size.split('x')[1].to_i
|
|
173
|
-
if (width > height)
|
|
174
|
-
zoom_factor = image_file_width.to_f / width
|
|
175
|
-
mask_height = (height * zoom_factor).round
|
|
176
|
-
x1 = 0
|
|
177
|
-
x2 = image_file_width
|
|
178
|
-
y1 = (image_file_height - mask_height) / 2
|
|
179
|
-
y2 = y1 + mask_height
|
|
180
|
-
elsif (width == 0 && height == 0)
|
|
181
|
-
x1 = 0
|
|
182
|
-
x2 = image_file_width
|
|
183
|
-
y1 = 0
|
|
184
|
-
y2 = image_file_height
|
|
185
|
-
else
|
|
186
|
-
zoom_factor = image_file_height.to_f / height
|
|
187
|
-
mask_width = (width * zoom_factor).round
|
|
188
|
-
x1 = (image_file_width - mask_width) / 2
|
|
189
|
-
x2 = x1 + mask_width
|
|
190
|
-
y1 = 0
|
|
191
|
-
y2 = image_file_height
|
|
192
|
-
end
|
|
193
|
-
{
|
|
194
|
-
x1: x1,
|
|
195
|
-
y1: y1,
|
|
196
|
-
x2: x2,
|
|
197
|
-
y2: y2
|
|
198
|
-
}
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Returns a size value String for the thumbnail used in essence picture editors.
|
|
202
|
-
#
|
|
203
|
-
def cropped_thumbnail_size(size)
|
|
204
|
-
return "111x93" if size == "111x93" || size.blank?
|
|
205
|
-
x = size.split('x')[0].to_i
|
|
206
|
-
y = size.split('x')[1].to_i
|
|
207
|
-
return "111x93" if x.zero? || y.zero?
|
|
208
|
-
if (x > y)
|
|
209
|
-
zoom_factor = 111.0 / x
|
|
210
|
-
new_x = 111
|
|
211
|
-
new_y = y * zoom_factor
|
|
212
|
-
else
|
|
213
|
-
zoom_factor = 93.0 / y
|
|
214
|
-
new_x = x * zoom_factor
|
|
215
|
-
new_y = 93
|
|
216
|
-
end
|
|
217
|
-
"#{new_x.round}x#{new_y.round}"
|
|
218
|
-
end
|
|
219
|
-
|
|
220
147
|
# Checks if the picture is restricted.
|
|
221
148
|
#
|
|
222
149
|
# A picture is only restricted if it's assigned on restricted pages only.
|