camaleon_cms 2.9.2 → 2.9.4
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/README.md +17 -4
- data/Rakefile +3 -16
- data/app/apps/plugins/attack/admin_controller.rb +9 -6
- data/app/apps/plugins/attack/attack_helper.rb +35 -25
- data/app/apps/plugins/authoring_post/authoring_post_helper.rb +23 -16
- data/app/apps/plugins/front_cache/admin_controller.rb +14 -10
- data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
- data/app/apps/plugins/front_cache/config/locales/translation.yml +0 -7
- data/app/apps/plugins/front_cache/front_cache_helper.rb +109 -37
- data/app/apps/plugins/front_cache/views/admin/settings.html.erb +0 -5
- data/app/apps/plugins/visibility_post/config/config.json +1 -0
- data/app/apps/plugins/visibility_post/config/routes_front.txt +1 -0
- data/app/apps/plugins/visibility_post/front_controller.rb +23 -0
- data/app/apps/plugins/visibility_post/visibility_post_helper.rb +141 -70
- data/app/apps/themes/camaleon_first/main_helper.rb +18 -12
- data/app/apps/themes/default/assets/css/style.css.scss +24 -0
- data/app/apps/themes/default/assets/genericons/genericons.css +3 -8
- data/app/apps/themes/default/default_helper.rb +2 -1
- data/app/apps/themes/default/views/layouts/index.html.erb +3 -1
- data/app/apps/themes/new/assets/css/styles.css.scss +24 -0
- data/app/apps/themes/new/custom_helper.rb +5 -9
- data/app/apps/themes/new/views/layouts/_header.html.erb +3 -1
- data/app/assets/javascripts/camaleon_cms/admin/_data.js +16 -0
- data/app/assets/javascripts/camaleon_cms/admin/_post.js +5 -2
- data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +14 -3
- data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js +5 -0
- data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +8 -6
- data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
- data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +7 -2
- data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +2 -1
- data/app/controllers/camaleon_cms/admin/categories_controller.rb +19 -4
- data/app/controllers/camaleon_cms/admin/comments_controller.rb +0 -1
- data/app/controllers/camaleon_cms/admin/installers_controller.rb +32 -1
- data/app/controllers/camaleon_cms/admin/media_controller.rb +66 -14
- data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
- data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +10 -4
- data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
- data/app/controllers/camaleon_cms/admin/posts_controller.rb +55 -22
- data/app/controllers/camaleon_cms/admin/sessions_controller.rb +237 -44
- data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +80 -13
- data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +5 -2
- data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +26 -3
- data/app/controllers/camaleon_cms/admin/settings_controller.rb +5 -3
- data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +7 -5
- data/app/controllers/camaleon_cms/admin/users_controller.rb +78 -11
- data/app/controllers/camaleon_cms/admin_controller.rb +136 -26
- data/app/controllers/camaleon_cms/camaleon_controller.rb +37 -92
- data/app/controllers/camaleon_cms/frontend_controller.rb +146 -74
- data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +20 -5
- data/app/controllers/concerns/camaleon_cms/frontend_concern.rb +46 -17
- data/app/controllers/concerns/camaleon_cms/frontend_visited_state_concern.rb +72 -0
- data/app/controllers/concerns/camaleon_cms/hook_lifecycle_concern.rb +104 -0
- data/app/controllers/concerns/camaleon_cms/request_context_concern.rb +113 -0
- data/app/controllers/concerns/camaleon_cms/runtime_admin_menu_concern.rb +237 -0
- data/app/controllers/concerns/camaleon_cms/runtime_captcha_image_concern.rb +13 -0
- data/app/controllers/concerns/camaleon_cms/runtime_html_content_concern.rb +143 -0
- data/app/controllers/concerns/camaleon_cms/runtime_shortcode_theme_concern.rb +246 -0
- data/app/controllers/concerns/camaleon_cms/runtime_state_concern.rb +13 -0
- data/app/controllers/concerns/camaleon_cms/runtime_uploader_concern.rb +54 -0
- data/app/controllers/concerns/camaleon_cms/session_captcha_runtime_concern.rb +19 -0
- data/app/controllers/concerns/camaleon_cms/session_runtime_concern.rb +40 -0
- data/app/decorators/camaleon_cms/application_decorator.rb +11 -8
- data/app/decorators/camaleon_cms/category_decorator.rb +3 -2
- data/app/decorators/camaleon_cms/post_comment_decorator.rb +13 -5
- data/app/decorators/camaleon_cms/post_decorator.rb +68 -50
- data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
- data/app/decorators/camaleon_cms/site_decorator.rb +33 -25
- data/app/decorators/camaleon_cms/term_taxonomy_decorator.rb +21 -10
- data/app/decorators/camaleon_cms/theme_decorator.rb +3 -3
- data/app/decorators/camaleon_cms/user_decorator.rb +26 -5
- data/app/helpers/camaleon_cms/admin/application_helper.rb +5 -8
- data/app/helpers/camaleon_cms/admin/breadcrumb_helper.rb +1 -1
- data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +24 -23
- data/app/helpers/camaleon_cms/admin/menus_helper.rb +249 -139
- data/app/helpers/camaleon_cms/admin/post_type_helper.rb +34 -17
- data/app/helpers/camaleon_cms/camaleon_helper.rb +31 -39
- data/app/helpers/camaleon_cms/captcha_helper.rb +73 -53
- data/app/helpers/camaleon_cms/comment_helper.rb +19 -7
- data/app/helpers/camaleon_cms/content_helper.rb +13 -6
- data/app/helpers/camaleon_cms/email_helper.rb +7 -3
- data/app/helpers/camaleon_cms/frontend/application_helper.rb +6 -1
- data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +34 -20
- data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +143 -66
- data/app/helpers/camaleon_cms/frontend/seo_helper.rb +39 -28
- data/app/helpers/camaleon_cms/frontend/site_helper.rb +32 -12
- data/app/helpers/camaleon_cms/hooks_helper.rb +14 -4
- data/app/helpers/camaleon_cms/html_helper.rb +58 -37
- data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
- data/app/helpers/camaleon_cms/session_helper.rb +188 -44
- data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
- data/app/helpers/camaleon_cms/site_helper.rb +34 -13
- data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
- data/app/helpers/camaleon_cms/uploader_helper.rb +19 -473
- data/app/helpers/camaleon_cms/user_roles_helper.rb +5 -4
- data/app/mailers/camaleon_cms/html_mailer.rb +4 -4
- data/app/models/camaleon_cms/ability.rb +15 -7
- data/app/models/camaleon_cms/category.rb +6 -6
- data/app/models/camaleon_cms/custom_field.rb +15 -6
- data/app/models/camaleon_cms/custom_field_group.rb +39 -22
- data/app/models/camaleon_cms/custom_fields_relationship.rb +140 -2
- data/app/models/camaleon_cms/media.rb +8 -2
- data/app/models/camaleon_cms/meta.rb +2 -2
- data/app/models/camaleon_cms/nav_menu.rb +5 -3
- data/app/models/camaleon_cms/nav_menu_item.rb +16 -8
- data/app/models/camaleon_cms/plugin.rb +3 -4
- data/app/models/camaleon_cms/post.rb +137 -27
- data/app/models/camaleon_cms/post_comment.rb +10 -6
- data/app/models/camaleon_cms/post_default.rb +42 -12
- data/app/models/camaleon_cms/post_relationship.rb +6 -4
- data/app/models/camaleon_cms/post_tag.rb +4 -5
- data/app/models/camaleon_cms/post_type.rb +21 -13
- data/app/models/camaleon_cms/site.rb +39 -29
- data/app/models/camaleon_cms/term_relationship.rb +10 -7
- data/app/models/camaleon_cms/term_taxonomy.rb +58 -4
- data/app/models/camaleon_cms/theme.rb +2 -4
- data/app/models/camaleon_cms/user.rb +17 -5
- data/app/models/camaleon_cms/user_role.rb +81 -6
- data/app/models/camaleon_cms/widget/assigned.rb +11 -6
- data/app/models/camaleon_cms/widget/main.rb +12 -8
- data/app/models/camaleon_cms/widget/sidebar.rb +3 -8
- data/app/models/camaleon_record.rb +89 -5
- data/app/models/concerns/camaleon_cms/categories_tags_for_posts.rb +36 -42
- data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
- data/app/models/concerns/camaleon_cms/content_shortcode_gate.rb +73 -0
- data/app/models/concerns/camaleon_cms/custom_fields_read.rb +111 -54
- data/app/models/concerns/camaleon_cms/metas.rb +31 -6
- data/app/models/concerns/camaleon_cms/normalize_attrs.rb +2 -8
- data/app/models/concerns/camaleon_cms/site_default_settings.rb +120 -16
- data/app/models/concerns/camaleon_cms/user_methods.rb +44 -19
- data/app/models/current_request.rb +8 -1
- data/app/uploaders/camaleon_cms_aws_uploader.rb +31 -10
- data/app/uploaders/camaleon_cms_local_uploader.rb +76 -19
- data/app/uploaders/camaleon_cms_uploader.rb +23 -10
- data/app/validators/camaleon_cms/post_uniq_validator.rb +5 -4
- data/app/validators/camaleon_cms/uniq_validator.rb +1 -1
- data/app/validators/camaleon_cms/user_url_validator.rb +215 -36
- data/app/views/camaleon_cms/admin/categories/index.html.erb +2 -2
- data/app/views/camaleon_cms/admin/installers/form.html.erb +5 -0
- data/app/views/camaleon_cms/admin/installers/welcome.html.erb +30 -6
- data/app/views/camaleon_cms/admin/plugins/_plugins_list.html.erb +2 -2
- data/app/views/camaleon_cms/admin/post_tags/index.html.erb +2 -2
- data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +1 -1
- data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
- data/app/views/camaleon_cms/admin/posts/index.html.erb +5 -5
- data/app/views/camaleon_cms/admin/sessions/back_to_parent.html.erb +39 -0
- data/app/views/camaleon_cms/admin/sessions/logout_confirm.html.erb +27 -0
- data/app/views/camaleon_cms/admin/settings/_email_settings.html.erb +4 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +19 -4
- data/app/views/camaleon_cms/admin/settings/custom_fields/_render_category_simple.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +4 -3
- data/app/views/camaleon_cms/admin/settings/shortcodes.html.erb +4 -4
- data/app/views/camaleon_cms/admin/settings/site.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/sites/form.html.erb +1 -1
- data/app/views/camaleon_cms/admin/user_roles/form.html.erb +24 -3
- data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
- data/app/views/camaleon_cms/admin/users/index.html.erb +1 -1
- data/app/views/camaleon_cms/default_theme/partials/_render_custom_field.html.erb +8 -2
- data/app/views/camaleon_cms/default_theme/sitemap.html.erb +1 -1
- data/app/views/camaleon_cms/default_theme/sitemap.xml.builder +1 -1
- data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
- data/config/initializers/action_view.rb +42 -5
- data/config/initializers/active_record_extension.rb +13 -27
- data/config/initializers/assets.rb +52 -23
- data/config/initializers/custom_initializers.rb +1 -1
- data/config/locales/camaleon_cms/admin/ar.yml +1 -0
- data/config/locales/camaleon_cms/admin/de.yml +1 -0
- data/config/locales/camaleon_cms/admin/en.yml +36 -0
- data/config/locales/camaleon_cms/admin/es.yml +1 -0
- data/config/locales/camaleon_cms/admin/fr.yml +1 -0
- data/config/locales/camaleon_cms/admin/it.yml +1 -0
- data/config/locales/camaleon_cms/admin/nl.yml +1 -0
- data/config/locales/camaleon_cms/admin/pt-BR.yml +1 -0
- data/config/locales/camaleon_cms/admin/pt.yml +1 -0
- data/config/locales/camaleon_cms/admin/ru.yml +1 -0
- data/config/locales/camaleon_cms/admin/uk.yml +1 -0
- data/config/locales/camaleon_cms/admin/zh-CH.yml +1 -0
- data/config/routes/admin.rb +33 -15
- data/config/routes/frontend.rb +21 -15
- data/lib/camaleon_cms/assets_precompile.rb +86 -0
- data/lib/camaleon_cms/captcha_image_generation.rb +65 -0
- data/lib/camaleon_cms/content_security.rb +158 -0
- data/lib/camaleon_cms/engine.rb +45 -21
- data/lib/camaleon_cms/media_security_headers.rb +27 -0
- data/lib/camaleon_cms/setup_token.rb +69 -0
- data/lib/camaleon_cms/shortcode_registry.rb +102 -0
- data/lib/camaleon_cms/svg_content_checker.rb +123 -0
- data/lib/camaleon_cms/task_reporter.rb +14 -0
- data/lib/camaleon_cms/unsafe_markup.rb +207 -0
- data/lib/camaleon_cms/uploader_content_security.rb +248 -0
- data/lib/camaleon_cms/uploader_image_processing.rb +166 -0
- data/lib/camaleon_cms/uploader_path_security.rb +146 -0
- data/lib/camaleon_cms/uploader_pipeline.rb +350 -0
- data/lib/camaleon_cms/uploader_support.rb +86 -0
- data/lib/camaleon_cms/version.rb +1 -1
- data/lib/camaleon_cms.rb +23 -0
- data/lib/ext/hash.rb +28 -2
- data/lib/ext/string.rb +10 -5
- data/lib/ext/translator.rb +10 -2
- data/lib/generators/camaleon_cms/gem_plugin_template/app/controllers/plugins/my_plugin/admin_controller.rb +5 -1
- data/lib/generators/camaleon_cms/install_generator.rb +7 -4
- data/lib/generators/camaleon_cms/install_template/plugin_routes.rb +5 -12
- data/lib/generators/camaleon_cms/theme_generator.rb +5 -10
- data/lib/generators/camaleon_cms/theme_template/views/layouts/index.html.erb +3 -1
- data/lib/plugin_routes.rb +412 -368
- data/lib/tasks/camaleon_cms/camaleon_tasks.rake +2 -1
- data/lib/tasks/cross_site_field_groups.rake +74 -0
- data/lib/tasks/custom_fields_roles.rake +15 -13
- data/lib/tasks/orphaned_comments.rake +42 -0
- data/lib/tasks/private_upload_acls.rake +31 -0
- data/lib/tasks/site_custom_field_groups.rake +36 -0
- data/lib/tasks/unsafe_stored_content.rake +42 -0
- data/lib/tasks/unsafe_stored_uploads.rake +70 -0
- data/lib/tasks/user_field_groups.rake +27 -0
- metadata +125 -4
|
@@ -2,96 +2,100 @@ module CamaleonCms
|
|
|
2
2
|
module ShortCodeHelper
|
|
3
3
|
# Internal method
|
|
4
4
|
def shortcodes_init
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
CurrentRequest.shortcodes = []
|
|
6
|
+
CurrentRequest.shortcodes_template = {}
|
|
7
|
+
CurrentRequest.shortcodes_descr = {}
|
|
8
8
|
|
|
9
9
|
shortcode_add('widget', nil, "Renderize the widget content in this place.
|
|
10
10
|
Don't forget to create and copy the shortcode of your widgets in appearance -> widgets
|
|
11
11
|
Sample: [widget widget_key]")
|
|
12
12
|
|
|
13
|
-
shortcode_add(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
13
|
+
shortcode_add(
|
|
14
|
+
'load_libraries',
|
|
15
|
+
lambda do |attrs, args|
|
|
16
|
+
return args[:shortcode] if attrs.blank?
|
|
17
|
+
|
|
18
|
+
cama_load_libraries(*attrs['data'].to_s.split(','))
|
|
19
|
+
''
|
|
20
|
+
end,
|
|
21
|
+
"Permit to load libraries on demand, sample: [load_libraries data='datepicker,tinymce']"
|
|
22
|
+
)
|
|
23
|
+
# rubocop:disable Layout/LineLength
|
|
24
|
+
shortcode_add(
|
|
25
|
+
'asset',
|
|
26
|
+
lambda do |attrs, args|
|
|
27
|
+
return args[:shortcode] if attrs.blank?
|
|
28
|
+
|
|
29
|
+
url = shortcode_asset_reference(attrs['file'], as_path: attrs['as_path'].present?)
|
|
30
|
+
if attrs['image'].present?
|
|
31
|
+
ActionController::Base.helpers.image_tag(url, class: attrs['class'], style: attrs['style'])
|
|
32
|
+
else
|
|
33
|
+
url
|
|
34
|
+
end
|
|
35
|
+
end,
|
|
36
|
+
"Permit to generate an asset url (
|
|
37
|
+
add file='' asset file path,
|
|
38
|
+
add as_path='true' to generate only the path and not the full url,
|
|
39
|
+
add class='my_class' to setup image class,
|
|
40
|
+
add style='height: 100px; width: 200px;...' to setup image style,
|
|
41
|
+
add image='true' to generate the image tag with this url),
|
|
42
|
+
sample: <img src=\"[asset as_path='true' file='themes/my_theme/assets/img/signature.png']\" /> or [asset image='true' file='themes/my_theme/assets/img/signature.png' style='height: 50px;']"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
shortcode_add(
|
|
46
|
+
'data',
|
|
47
|
+
->(attrs, args) { attrs.present? ? cama_shortcode_data(attrs, args) : args[:shortcode] },
|
|
48
|
+
"Permit to generate specific data of a post.
|
|
49
|
+
Attributes:
|
|
50
|
+
object: (String, defaut post) Model name: post | posttype | category | posttag | site | user |theme | navmenu
|
|
51
|
+
id: (Integer) Post id
|
|
52
|
+
key: (String) Post slug
|
|
53
|
+
field: (String) Custom field key, you can add render_field='true' to render field as html element, also you can add index=2 to indicate the value in position 2 for multitple values
|
|
54
|
+
attrs: (String) attribute name
|
|
55
|
+
post: title | created_at | excerpt | url | link | thumb | updated_at | author_name | author_url | content
|
|
56
|
+
posttype: title | created_at | excerpt | url | link | thumb | updated_at
|
|
57
|
+
category: title | created_at | excerpt | url | link | thumb | updated_at
|
|
58
|
+
posttag: title | created_at | excerpt | url | link | thumb | updated_at
|
|
59
|
+
site: title | created_at | excerpt | url | link | thumb | updated_at
|
|
60
|
+
user: title | created_at | excerpt | url | link | thumb | updated_at
|
|
61
|
+
theme: title | created_at | excerpt | url | link | thumb | updated_at
|
|
62
|
+
navmenu: title | created_at | excerpt | url | link | thumb | updated_at
|
|
63
|
+
Note: If id and key is not present, then will be rendered for current model
|
|
64
|
+
Sample:
|
|
65
|
+
[data id='122' attr='title'] ==> return the title of post with id = 122
|
|
66
|
+
[data key='contact' attr='url'] ==> return the url of post with slug = contact
|
|
67
|
+
[data key='contact' attr='link'] ==> return the link with title as text of the link of post with slug = contact
|
|
68
|
+
[data object='site' attr='url'] ==> return the url of currrent site
|
|
69
|
+
[data key='page' object='posttype' attr='url'] ==> return the url of post_type with slug = page
|
|
70
|
+
[data field=icon index=2] ==> return the second value (multiple values) for this custom field with key=icon of current object
|
|
71
|
+
[data key='contact' field='sub_title'] ==> return the value of the custom_field with key=sub_title registered for post.slug = contact
|
|
72
|
+
[data object='site' field='sub_title'] ==> return the value of the custom_field with key=sub_title registered for current_site"
|
|
73
|
+
)
|
|
71
74
|
end
|
|
75
|
+
# rubocop:enable Layout/LineLength
|
|
72
76
|
|
|
73
77
|
# add shortcode
|
|
74
78
|
# key: shortcode key
|
|
75
|
-
# template: template to render, if nil
|
|
76
|
-
# Also can be a function to execute that instead a render, sample: lambda{|attrs, args| return "my custom content"
|
|
79
|
+
# template: template to render, if nil renders "shortcode_templates/<key>"
|
|
80
|
+
# Also can be a function to execute that instead a render, sample: lambda{|attrs, args| return "my custom content" }
|
|
77
81
|
# descr: description for shortcode
|
|
78
82
|
def shortcode_add(key, template = nil, descr = '')
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
shortcode_keys << key
|
|
84
|
+
CurrentRequest.shortcodes_template = shortcode_templates.merge({ key.to_s => template }) if template.present?
|
|
85
|
+
shortcode_descriptions[key] = descr if descr.present?
|
|
82
86
|
end
|
|
83
87
|
|
|
84
88
|
# add or update shortcode template
|
|
85
89
|
# key: chortcode key to add or update
|
|
86
90
|
# template: template to render, if nil will render "shortcode_templates/<key>"
|
|
87
91
|
def shortcode_change_template(key, template = nil)
|
|
88
|
-
|
|
92
|
+
shortcode_templates[key] = template
|
|
89
93
|
end
|
|
90
94
|
|
|
91
|
-
#
|
|
95
|
+
# Delete the shortcode
|
|
92
96
|
# key: chortcode key to delete
|
|
93
97
|
def shortcode_delete(key)
|
|
94
|
-
|
|
98
|
+
shortcode_keys.delete(key)
|
|
95
99
|
end
|
|
96
100
|
|
|
97
101
|
# run all shortcodes in the content
|
|
@@ -122,8 +126,11 @@ module CamaleonCms
|
|
|
122
126
|
# text: text that contain the shortcode
|
|
123
127
|
# key: shortcode key
|
|
124
128
|
# template: template to render, if nil this will render default render file
|
|
125
|
-
# Also can be a function to execute that instead a render, sample: lambda{|attrs, args| return "my custom content"
|
|
126
|
-
# render_shortcode(
|
|
129
|
+
# Also can be a function to execute that instead a render, sample: lambda{|attrs, args| return "my custom content" }
|
|
130
|
+
# render_shortcode(
|
|
131
|
+
# "asda dasdasdas[owen a='1'] [bbb] sdasdas dasd as das[owen a=213]", "owen",
|
|
132
|
+
# lambda { |attrs, args| puts attrs; return "my test"; }
|
|
133
|
+
# )
|
|
127
134
|
def render_shortcode(text, key, template = nil)
|
|
128
135
|
text.scan(/#{cama_reg_shortcode(key)}/).each do |item|
|
|
129
136
|
text = _cama_replace_shortcode(text, item, {}, template)
|
|
@@ -131,6 +138,14 @@ module CamaleonCms
|
|
|
131
138
|
text
|
|
132
139
|
end
|
|
133
140
|
|
|
141
|
+
def shortcodes_list
|
|
142
|
+
shortcode_keys
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def shortcodes_descriptions
|
|
146
|
+
shortcode_descriptions
|
|
147
|
+
end
|
|
148
|
+
|
|
134
149
|
private
|
|
135
150
|
|
|
136
151
|
# helper to replace shortcodes adding support for closed shortcodes, sample: [title]my title[/title]
|
|
@@ -154,32 +169,113 @@ module CamaleonCms
|
|
|
154
169
|
# if empty, codes will be replaced with all registered shortcodes
|
|
155
170
|
# Return: (String) reg expression string
|
|
156
171
|
def cama_reg_shortcode(codes = nil)
|
|
157
|
-
#
|
|
158
|
-
"(\\[(#{codes || (@_shortcodes || []).join(
|
|
172
|
+
# doesn't support for similar names, like: [media] and [media_gallery]
|
|
173
|
+
# "(\\[(#{codes || (@_shortcodes || []).join("|")})(\s|\\]){0}(.*?)\\])"
|
|
174
|
+
"(\\[(#{codes || shortcode_keys.join('|')})((\s)((?!\\]).)*|)\\])"
|
|
159
175
|
end
|
|
160
176
|
|
|
161
177
|
# determine the content to replace instead the shortcode
|
|
162
178
|
# return string
|
|
163
179
|
def _eval_shortcode(code, attrs, args = {}, template = nil)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
180
|
+
templates = shortcode_templates
|
|
181
|
+
template ||= templates[code].presence || "camaleon_cms/shortcode_templates/#{code}"
|
|
182
|
+
if templates[code].instance_of?(::Proc)
|
|
183
|
+
templates[code].call(_shortcode_parse_attr(attrs), args)
|
|
167
184
|
else
|
|
168
185
|
render template: template, locals: { attributes: _shortcode_parse_attr(attrs), args: args }, formats: [:html]
|
|
169
186
|
end
|
|
170
187
|
end
|
|
171
188
|
|
|
189
|
+
def shortcode_keys
|
|
190
|
+
CurrentRequest.shortcodes ||= []
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def shortcode_templates
|
|
194
|
+
CurrentRequest.shortcodes_template ||= {}
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def shortcode_descriptions
|
|
198
|
+
CurrentRequest.shortcodes_descr ||= {}
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def shortcode_asset_reference(file, as_path: false)
|
|
202
|
+
return if file.blank?
|
|
203
|
+
|
|
204
|
+
# Defensive ordering: assign the locals the rescue branch uses before
|
|
205
|
+
# everything else, so it can never see them nil. The only call that raises
|
|
206
|
+
# AssetNotFound is the asset helper below — resolve_shortcode_theme_asset
|
|
207
|
+
# never does (regex, string interpolation and File.exist? only).
|
|
208
|
+
helper = ActionController::Base.helpers
|
|
209
|
+
method_name = as_path ? :asset_path : :asset_url
|
|
210
|
+
file = resolve_shortcode_theme_asset(file)
|
|
211
|
+
helper.public_send(method_name, file)
|
|
212
|
+
rescue Sprockets::Rails::Helper::AssetNotFound
|
|
213
|
+
helper.public_send(method_name, file, skip_pipeline: true)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def resolve_shortcode_theme_asset(file)
|
|
217
|
+
# Tolerate both `themes/<slug>/assets/...` and `/themes/<slug>/assets/...`
|
|
218
|
+
# — the latter is what Rails' asset helpers typically emit.
|
|
219
|
+
match = file.to_s.match(%r{\A/?themes/[^/]+/assets/(?<asset>.+)\z})
|
|
220
|
+
return file unless match
|
|
221
|
+
|
|
222
|
+
can_resolve_theme_assets = respond_to?(:current_theme) &&
|
|
223
|
+
respond_to?(:theme_asset_path) &&
|
|
224
|
+
respond_to?(:theme_asset_file_path)
|
|
225
|
+
return file unless can_resolve_theme_assets
|
|
226
|
+
|
|
227
|
+
return file if current_theme.blank?
|
|
228
|
+
|
|
229
|
+
asset = match[:asset]
|
|
230
|
+
remapped_file = theme_asset_path(asset)
|
|
231
|
+
return file unless remapped_file.present? && remapped_file != file
|
|
232
|
+
return file unless File.exist?(theme_asset_file_path(asset))
|
|
233
|
+
|
|
234
|
+
remapped_file
|
|
235
|
+
end
|
|
236
|
+
|
|
172
237
|
# parse the attributes of a shortcode
|
|
173
238
|
def _shortcode_parse_attr(text)
|
|
174
239
|
res = {}
|
|
175
|
-
return res
|
|
240
|
+
return res if text.blank?
|
|
176
241
|
|
|
177
|
-
text
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
242
|
+
# StringScanner tokenizes the text by moving through it sequentially,
|
|
243
|
+
# matching patterns and advancing the scan pointer with each successful scan.
|
|
244
|
+
scanner = StringScanner.new(text)
|
|
245
|
+
|
|
246
|
+
# Continue parsing until we reach the end of the string.
|
|
247
|
+
until scanner.eos?
|
|
248
|
+
# Skip any leading whitespace before attempting to match a token.
|
|
249
|
+
scanner.skip(/\s+/)
|
|
250
|
+
break if scanner.eos?
|
|
251
|
+
|
|
252
|
+
# Attempt to match a key=value attribute (e.g., width="100", class='foo', height=200).
|
|
253
|
+
# Capture group 1 extracts the attribute name (word characters before =).
|
|
254
|
+
if scanner.scan(/(\w+)\s*=\s*/)
|
|
255
|
+
key = scanner[1]
|
|
256
|
+
|
|
257
|
+
# Determine the attribute value based on its quoting style:
|
|
258
|
+
# 1. Double-quoted string: "value" → extract content between quotes
|
|
259
|
+
# 2. Single-quoted string: 'value' → extract content between quotes
|
|
260
|
+
# 3. Unquoted value: any characters except whitespace or quotes
|
|
261
|
+
val = if scanner.scan(/"([^"]*)"/)
|
|
262
|
+
scanner[1]
|
|
263
|
+
elsif scanner.scan(/'([^']*)'/)
|
|
264
|
+
scanner[1]
|
|
265
|
+
elsif scanner.scan(/([^\s'"]+)/)
|
|
266
|
+
scanner[1]
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Store the parsed key-value pair in the result hash.
|
|
270
|
+
res[key] = val
|
|
271
|
+
|
|
272
|
+
# If no key=value pattern matched, this is a standalone value (no assignment).
|
|
273
|
+
# Match either a double-quoted string or a bare unquoted token.
|
|
274
|
+
elsif scanner.scan(/"([^"]*)"|(\S+)/)
|
|
275
|
+
# Use the appropriate capture group: group 1 for quoted, group 2 for unquoted.
|
|
276
|
+
val = scanner[1] || scanner[2]
|
|
277
|
+
# Standalone values are stored with a nil key reference.
|
|
278
|
+
res[val] = nil
|
|
183
279
|
end
|
|
184
280
|
end
|
|
185
281
|
res
|
|
@@ -195,7 +291,7 @@ module CamaleonCms
|
|
|
195
291
|
else
|
|
196
292
|
args[:owner]
|
|
197
293
|
end
|
|
198
|
-
return res
|
|
294
|
+
return res if model.blank?
|
|
199
295
|
|
|
200
296
|
if attrs['field'].present? # model custom fields
|
|
201
297
|
field = model.get_field_object(attrs['field'])
|
|
@@ -295,7 +391,7 @@ module CamaleonCms
|
|
|
295
391
|
|
|
296
392
|
when 'navmenu'
|
|
297
393
|
model = current_site.nav_menu_items.find(attrs['id']) if attrs['id'].present?
|
|
298
|
-
model = current_site.nav_menu_items.find_by_slug(attrs['key']) if attrs['key'].present?
|
|
394
|
+
model = current_site.nav_menu_items.find_by_slug(attrs['key']) if attrs['key'].present? # rubocop:disable Rails/DynamicFindBy
|
|
299
395
|
|
|
300
396
|
when 'user'
|
|
301
397
|
model = current_site.the_user(attrs['id'].to_i) if attrs['id'].present?
|
|
@@ -3,9 +3,9 @@ module CamaleonCms
|
|
|
3
3
|
# return current site or assign a site as a current site
|
|
4
4
|
def current_site(site = nil)
|
|
5
5
|
if site.present?
|
|
6
|
-
|
|
7
|
-
CurrentRequest.
|
|
8
|
-
return
|
|
6
|
+
CurrentRequest.site = site.decorate
|
|
7
|
+
CurrentRequest.frontend_current_theme = nil
|
|
8
|
+
return CurrentRequest.site
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
if defined?($current_site)
|
|
@@ -13,11 +13,19 @@ module CamaleonCms
|
|
|
13
13
|
return $current_site
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
# Honor a caller-set @current_site (HtmlMailer and other background senders assign it) before the
|
|
17
|
+
# memoized CurrentRequest.site, so a delivery for another site resolves against that site rather
|
|
18
|
+
# than the request's. Restores 2.9.2; without it, multisite/background mail resolves the wrong site
|
|
19
|
+
# or raises NameError on `request` in a job. See regression audit M21. Read via
|
|
20
|
+
# instance_variable_get to match #current_theme and avoid Rails/HelperInstanceVariable.
|
|
21
|
+
caller_site = (instance_variable_get(:@current_site) if instance_variable_defined?(:@current_site))
|
|
22
|
+
if caller_site.present?
|
|
23
|
+
CurrentRequest.site = caller_site
|
|
24
|
+
return caller_site
|
|
19
25
|
end
|
|
20
26
|
|
|
27
|
+
return CurrentRequest.site if CurrentRequest.site.present?
|
|
28
|
+
|
|
21
29
|
if PluginRoutes.get_sites.size == 1
|
|
22
30
|
site = begin
|
|
23
31
|
CamaleonCms::Site.first.decorate
|
|
@@ -43,16 +51,28 @@ module CamaleonCms
|
|
|
43
51
|
rescue StandardError
|
|
44
52
|
nil
|
|
45
53
|
end
|
|
46
|
-
|
|
47
|
-
Rails.logger.error
|
|
54
|
+
if r[:site].blank?
|
|
55
|
+
Rails.logger.error(
|
|
56
|
+
'Camaleon CMS - Please define your current site: $current_site = CamaleonCms::Site.first.decorate or ' \
|
|
57
|
+
'map your domains: https://camaleon.website/documentation/category/139779-examples/how.html'
|
|
58
|
+
.cama_log_style(:red)
|
|
59
|
+
)
|
|
48
60
|
end
|
|
49
|
-
|
|
50
|
-
CurrentRequest.
|
|
61
|
+
CurrentRequest.site = r[:site]
|
|
62
|
+
CurrentRequest.frontend_current_theme = nil
|
|
63
|
+
CurrentRequest.site
|
|
51
64
|
end
|
|
52
65
|
|
|
53
66
|
# return current theme model for current site
|
|
54
67
|
def current_theme
|
|
55
|
-
|
|
68
|
+
preview_theme = (instance_variable_get(:@_current_theme) if instance_variable_defined?(:@_current_theme))
|
|
69
|
+
return CurrentRequest.frontend_current_theme = preview_theme if preview_theme.present?
|
|
70
|
+
|
|
71
|
+
theme = CurrentRequest.frontend_current_theme
|
|
72
|
+
return theme if theme.present?
|
|
73
|
+
|
|
74
|
+
theme = current_site.get_theme.decorate
|
|
75
|
+
CurrentRequest.frontend_current_theme = theme
|
|
56
76
|
end
|
|
57
77
|
|
|
58
78
|
# get list templates files of current theme
|
|
@@ -105,7 +125,7 @@ module CamaleonCms
|
|
|
105
125
|
# new theme
|
|
106
126
|
current_site.set_option('_theme', key)
|
|
107
127
|
theme = PluginRoutes.theme_info(key)
|
|
108
|
-
current_site.themes.update_all(status: 'inactive')
|
|
128
|
+
current_site.themes.update_all(status: 'inactive') # rubocop:disable Rails/SkipsModelValidations
|
|
109
129
|
theme_model = current_site.themes.where(slug: key).first_or_create! { |t| t.name = theme[:name] }
|
|
110
130
|
theme_model.update(status: nil)
|
|
111
131
|
hook_run(theme, 'on_active', theme_model)
|
|
@@ -121,7 +141,8 @@ module CamaleonCms
|
|
|
121
141
|
# theme_model.destroy
|
|
122
142
|
end
|
|
123
143
|
|
|
124
|
-
# add host
|
|
144
|
+
# add host and port to args of the current site visited
|
|
145
|
+
# (only if the request is coming from console or tasks i.e. not web browser)
|
|
125
146
|
# args: Hash
|
|
126
147
|
# sample: {} will return {host: 'localhost', port: 3000}
|
|
127
148
|
def cama_current_site_host_port(args)
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
module CamaleonCms
|
|
2
2
|
module ThemeHelper
|
|
3
3
|
def theme_init
|
|
4
|
-
|
|
4
|
+
camaleon_theme_state[:front_breadcrumb] = []
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
# return theme full asset path
|
|
8
8
|
# theme_name: theme name, if nil, then will use current theme
|
|
9
|
-
# asset: asset file name, if asset is present return full path to this asset
|
|
10
|
-
# sample: <script src="<%= theme_asset_path("js/admin.js") %>"></script> =>
|
|
9
|
+
# asset: asset file name, if asset is present return the full path to this asset
|
|
10
|
+
# sample: <script src="<%= theme_asset_path("js/admin.js") %>"></script> =>
|
|
11
|
+
# return: /assets/themes/my_theme/assets/js/admin-54505620f.js
|
|
11
12
|
def theme_asset_path(asset = nil, theme_name = nil)
|
|
12
13
|
return theme_asset_url(theme_name, current_theme.slug) if theme_name.present? && theme_name.include?('/')
|
|
13
14
|
|
|
@@ -22,11 +23,12 @@ module CamaleonCms
|
|
|
22
23
|
alias theme_asset theme_asset_path
|
|
23
24
|
alias theme_gem_asset theme_asset_path
|
|
24
25
|
|
|
25
|
-
# return the full url for asset of current theme:
|
|
26
|
+
# return the full url for asset of the current theme:
|
|
26
27
|
# asset: (String) asset name
|
|
27
28
|
# theme_name: (optional) theme name, default (current theme caller to this function)
|
|
28
29
|
# sample:
|
|
29
|
-
# theme_asset_url("css/main.css") =>
|
|
30
|
+
# theme_asset_url("css/main.css") =>
|
|
31
|
+
# return: https://myhost.com/assets/themes/my_theme/assets/css/main-54505620f.css
|
|
30
32
|
def theme_asset_url(asset, theme_name = nil)
|
|
31
33
|
p = theme_asset_path(asset, theme_name)
|
|
32
34
|
begin
|
|
@@ -36,11 +38,17 @@ module CamaleonCms
|
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
# return theme view path including the path of current theme
|
|
41
|
+
# return the theme view path including the path of current theme
|
|
40
42
|
# view_name: name of the view or template
|
|
41
43
|
# sample: theme_view("index") => "themes/my_theme/index"
|
|
42
44
|
def theme_view(view_name, deprecated_attr = '')
|
|
43
|
-
|
|
45
|
+
if deprecated_attr.present?
|
|
46
|
+
ActiveSupport::Deprecation._instance.warn(
|
|
47
|
+
'Passing theme view name as the second argument to #theme_view is deprecated. ' \
|
|
48
|
+
'Pass the view name as the first argument instead.'
|
|
49
|
+
)
|
|
50
|
+
view_name = deprecated_attr
|
|
51
|
+
end
|
|
44
52
|
if current_theme.settings['gem_mode']
|
|
45
53
|
"themes/#{current_theme.slug}/#{view_name}"
|
|
46
54
|
else
|
|
@@ -49,7 +57,7 @@ module CamaleonCms
|
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
# assign the layout for this request
|
|
52
|
-
# asset: asset file name, if asset is present return full path to this asset
|
|
60
|
+
# asset: asset file name, if asset is present return the full path to this asset
|
|
53
61
|
# layout_name: layout name
|
|
54
62
|
def theme_layout(layout_name, _theme_name = nil)
|
|
55
63
|
if current_theme.settings['gem_mode']
|
|
@@ -70,15 +78,19 @@ module CamaleonCms
|
|
|
70
78
|
f.split(k).last.split('/').first
|
|
71
79
|
end
|
|
72
80
|
|
|
73
|
-
# returns
|
|
74
|
-
# theme_name: theme name, if nil, then will use current theme
|
|
75
|
-
# asset: asset file name, if asset is present return full path to this asset
|
|
76
|
-
# sample:
|
|
81
|
+
# returns the filesystem path to theme asset
|
|
82
|
+
# theme_name: theme name, if nil, then will use the current theme
|
|
83
|
+
# asset: asset file name, if asset is present, return the full path to this asset
|
|
84
|
+
# sample:
|
|
85
|
+
# theme_asset_file_path('images/foo.jpg') =>
|
|
86
|
+
# return: /home/camaleon/my-site/app/apps/themes/default/assets/images/foo.jpg
|
|
77
87
|
def theme_asset_file_path(asset = nil, theme_name = nil)
|
|
78
|
-
theme_path =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
theme_path = if theme_name && (theme = Theme.where(name: theme_name).first)
|
|
89
|
+
theme.settings['path']
|
|
90
|
+
else
|
|
91
|
+
current_theme.settings['path']
|
|
92
|
+
end
|
|
93
|
+
|
|
82
94
|
"#{theme_path}/assets/#{asset}"
|
|
83
95
|
end
|
|
84
96
|
|
|
@@ -86,9 +98,13 @@ module CamaleonCms
|
|
|
86
98
|
def theme_home_page
|
|
87
99
|
current_site.the_post(current_theme.get_field('home_page')) ||
|
|
88
100
|
current_site.the_posts('page').first ||
|
|
89
|
-
CamaleonCms::Post.new(title: 'Hello World!',
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
CamaleonCms::Post.new(title: 'Hello World!', content: 'Please add a page.', status: 'published')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def camaleon_theme_state
|
|
107
|
+
CurrentRequest.theme_helper_state ||= {}
|
|
92
108
|
end
|
|
93
109
|
end
|
|
94
110
|
end
|