alchemy_cms 2.4.rc2 → 2.4.rc4
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.
- data/.gitignore +2 -1
- data/.travis.yml +7 -4
- data/README.md +1 -0
- data/alchemy_cms.gemspec +19 -1
- data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +5 -2
- data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js +4 -21
- data/app/assets/javascripts/alchemy/alchemy.windows.js +0 -1
- data/app/assets/stylesheets/alchemy/base.scss +4 -0
- data/app/assets/stylesheets/alchemy/elements.scss +59 -60
- data/app/assets/stylesheets/alchemy/flash.scss +3 -3
- data/app/assets/stylesheets/alchemy/form_elements.scss +15 -2
- data/app/assets/stylesheets/alchemy/jquery-ui.scss +11 -3
- data/app/assets/stylesheets/alchemy/mixins.scss +9 -0
- data/app/assets/stylesheets/alchemy/tinymce_content.css.scss +1 -1
- data/app/assets/stylesheets/alchemy/tinymce_dialog.css.scss +4 -0
- data/app/assets/stylesheets/alchemy/variables.scss +5 -1
- data/app/controllers/alchemy/admin/base_controller.rb +18 -3
- data/app/controllers/alchemy/admin/elements_controller.rb +4 -7
- data/app/controllers/alchemy/admin/pages_controller.rb +3 -4
- data/app/controllers/alchemy/admin/resources_controller.rb +1 -18
- data/app/controllers/alchemy/admin/users_controller.rb +8 -5
- data/app/helpers/alchemy/admin/pages_helper.rb +6 -1
- data/app/models/alchemy/content.rb +26 -5
- data/app/models/alchemy/element.rb +1 -0
- data/app/models/alchemy/essence_richtext.rb +1 -1
- data/app/models/alchemy/page.rb +131 -88
- data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
- data/app/views/alchemy/admin/elements/create.js.erb +6 -1
- data/app/views/alchemy/admin/elements/trash.js.erb +1 -3
- data/app/views/alchemy/admin/resources/_form.html.erb +13 -1
- data/app/views/alchemy/admin/trash/index.html.erb +1 -1
- data/app/views/alchemy/base/remote_errors.js.erb +5 -1
- data/app/views/alchemy/essences/_essence_link_view.html.erb +2 -0
- data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +1 -1
- data/config/locales/alchemy.de.yml +11 -4
- data/lib/alchemy/capistrano.rb +59 -1
- data/lib/alchemy/essence.rb +1 -0
- data/lib/alchemy/seeder.rb +39 -49
- data/lib/alchemy/tinymce.rb +1 -1
- data/lib/alchemy/version.rb +1 -1
- data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +1 -1
- data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +3 -0
- data/lib/rails/generators/alchemy/elements/templates/view.html.haml +2 -2
- data/lib/rails/generators/alchemy/elements/templates/view.html.slim +2 -2
- data/lib/tasks/database.rake +25 -0
- data/lib/tasks/install.rake +5 -14
- data/spec/factories.rb +10 -0
- data/spec/integration/admin/resources_integration_spec.rb +64 -23
- data/spec/integration/pages_controller_spec.rb +0 -2
- data/spec/libraries/resources_helper_spec.rb +6 -2
- data/spec/models/content_spec.rb +31 -0
- data/spec/models/element_spec.rb +7 -2
- data/spec/models/page_spec.rb +36 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.dialogextend.1_0_1.js +676 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +298 -238
- data/vendor/assets/javascripts/tiny_mce/langs/de.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/langs/en.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/license.txt +6 -6
- data/vendor/assets/javascripts/tiny_mce/plugins/fullscreen/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/plugins/fullscreen/fullscreen.htm +97 -97
- data/vendor/assets/javascripts/tiny_mce/plugins/inlinepopups/template.htm +376 -386
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/js/pastetext.js +30 -30
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/js/pasteword.js +45 -45
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/langs/de_dlg.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/pastetext.htm +17 -20
- data/vendor/assets/javascripts/tiny_mce/plugins/paste/pasteword.htm +12 -12
- data/vendor/assets/javascripts/tiny_mce/plugins/table/cell.htm +173 -183
- data/vendor/assets/javascripts/tiny_mce/plugins/table/css/cell.css +4 -4
- data/vendor/assets/javascripts/tiny_mce/plugins/table/css/row.css +7 -7
- data/vendor/assets/javascripts/tiny_mce/plugins/table/css/table.css +3 -3
- data/vendor/assets/javascripts/tiny_mce/plugins/table/editor_plugin.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/plugins/table/js/cell.js +280 -282
- data/vendor/assets/javascripts/tiny_mce/plugins/table/js/merge_cells.js +15 -15
- data/vendor/assets/javascripts/tiny_mce/plugins/table/js/row.js +221 -204
- data/vendor/assets/javascripts/tiny_mce/plugins/table/js/table.js +448 -435
- data/vendor/assets/javascripts/tiny_mce/plugins/table/langs/de_dlg.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/plugins/table/merge_cells.htm +22 -24
- data/vendor/assets/javascripts/tiny_mce/plugins/table/row.htm +136 -144
- data/vendor/assets/javascripts/tiny_mce/plugins/table/table.htm +168 -184
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/about.htm +46 -62
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/anchor.htm +16 -17
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/charmap.htm +47 -56
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/color_picker.htm +52 -69
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/editor_template.js +1 -852
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/image.htm +69 -79
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/img/icons.gif +0 -0
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/about.js +48 -48
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/anchor.js +50 -37
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/charmap.js +317 -317
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/color_picker.js +345 -331
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/image.js +248 -246
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/link.js +152 -146
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/source_editor.js +53 -31
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/de.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/de_dlg.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/en.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/en_dlg.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/link.htm +46 -53
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/shortcuts.htm +45 -57
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/content.css +47 -182
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/dialog.css +93 -399
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/ui.css +191 -890
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/content.css +24 -102
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/dialog.css +79 -377
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/ui.css +80 -451
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/content.css +45 -167
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/dialog.css +93 -399
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui.css +194 -889
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui_black.css +7 -33
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css +4 -15
- data/vendor/assets/javascripts/tiny_mce/themes/advanced/source_editor.htm +16 -19
- data/vendor/assets/javascripts/tiny_mce/tiny_mce.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/tiny_mce_popup.js +1 -1
- data/vendor/assets/javascripts/tiny_mce/utils/editable_selects.js +46 -46
- data/vendor/assets/javascripts/tiny_mce/utils/form_utils.js +124 -124
- data/vendor/assets/javascripts/tiny_mce/utils/mctabs.js +112 -112
- data/vendor/assets/javascripts/tiny_mce/utils/validate.js +213 -213
- metadata +11 -6
- data/spec/dummy/public/404.html.bak +0 -26
- data/vendor/assets/javascripts/jquery_plugins/jquery.dialogextend.min.js +0 -8
|
@@ -50,6 +50,13 @@
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
@mixin field_with_error {
|
|
54
|
+
border-color: $error_border_color;
|
|
55
|
+
color: $error_text_color;
|
|
56
|
+
background-color: lighten($error_background_color, 8%);
|
|
57
|
+
@include box-shadow(inset 1px 1px 4px rgba($error_border_color, 0.5));
|
|
58
|
+
}
|
|
59
|
+
|
|
53
60
|
@mixin default-input-style {
|
|
54
61
|
@include box-sizing(border-box);
|
|
55
62
|
$border-inset-color: lighten($default-border-color, 20%);
|
|
@@ -72,6 +79,8 @@
|
|
|
72
79
|
&:focus {
|
|
73
80
|
@include default-focus-style;
|
|
74
81
|
}
|
|
82
|
+
|
|
83
|
+
&.with_error { @include field_with_error }
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
@mixin text-overflow($prop: ellipsis) {
|
|
@@ -30,4 +30,8 @@ $sb-border-radius: $default-border-radius;
|
|
|
30
30
|
$sb-font-size: $default-font-size;
|
|
31
31
|
$sb-text-color: $text-color;
|
|
32
32
|
$sb-ie-support: true;
|
|
33
|
-
$default-form-field-margin:
|
|
33
|
+
$default-form-field-margin: $default-padding 0;
|
|
34
|
+
|
|
35
|
+
$error_border_color: #c49c9c;
|
|
36
|
+
$error_text_color: #592e2e;
|
|
37
|
+
$error_background_color: #efd3d3;
|
|
@@ -85,17 +85,28 @@ module Alchemy
|
|
|
85
85
|
|
|
86
86
|
# Displays errors in a #errors div if any errors are present on the object.
|
|
87
87
|
# Or redirects to the given redirect url.
|
|
88
|
+
#
|
|
89
|
+
# @param object [ActiveRecord::Base]
|
|
90
|
+
# @param redirect_url [String]
|
|
91
|
+
# @param flash_notice [String]
|
|
92
|
+
#
|
|
88
93
|
def render_errors_or_redirect(object, redirect_url, flash_notice)
|
|
89
94
|
if object.errors.empty?
|
|
90
95
|
@redirect_url = redirect_url
|
|
91
96
|
flash[:notice] = t(flash_notice)
|
|
92
|
-
|
|
97
|
+
respond_to do |format|
|
|
98
|
+
format.js { render :action => :redirect }
|
|
99
|
+
format.html { redirect_to @redirect_url }
|
|
100
|
+
end
|
|
93
101
|
else
|
|
94
|
-
|
|
102
|
+
respond_to do |format|
|
|
103
|
+
format.js { render_remote_errors(object) }
|
|
104
|
+
format.html { render :action => (params[:action] == "update" ? :edit : :new) }
|
|
105
|
+
end
|
|
95
106
|
end
|
|
96
107
|
end
|
|
97
108
|
|
|
98
|
-
#
|
|
109
|
+
# Renders an unordered list of objects errors in an errors div via javascript.
|
|
99
110
|
#
|
|
100
111
|
# Note: You have to have a hidden div with the id +#errors+ in your form, to make this work.
|
|
101
112
|
#
|
|
@@ -103,8 +114,12 @@ module Alchemy
|
|
|
103
114
|
#
|
|
104
115
|
# Hint: If you use an alternative div, please use the +errors+ css class to get the correct styling.
|
|
105
116
|
#
|
|
117
|
+
# @param object [ActiveRecord::Base]
|
|
118
|
+
# @param error_div_id [String]
|
|
119
|
+
#
|
|
106
120
|
def render_remote_errors(object, error_div_id = nil)
|
|
107
121
|
@error_div_id = error_div_id || '#errors'
|
|
122
|
+
@error_fields = object.errors.messages.keys.map { |f| "#{object.class.model_name.demodulize.underscore}_#{f}" }
|
|
108
123
|
@errors = ("<ul>" + object.errors.full_messages.map { |e| "<li>#{e}</li>" }.join + "</ul>").html_safe
|
|
109
124
|
render :action => :remote_errors
|
|
110
125
|
end
|
|
@@ -40,13 +40,14 @@ module Alchemy
|
|
|
40
40
|
Element.transaction do
|
|
41
41
|
if @paste_from_clipboard = params[:paste_from_clipboard].present?
|
|
42
42
|
@element = paste_element_from_clipboard
|
|
43
|
+
@cell = @element.cell
|
|
43
44
|
else
|
|
44
45
|
@element = Element.new_from_scratch(params[:element])
|
|
45
46
|
if @page.can_have_cells?
|
|
46
47
|
@cell = find_or_create_cell
|
|
47
48
|
@element.cell = @cell
|
|
48
49
|
end
|
|
49
|
-
@element.save
|
|
50
|
+
@element.save
|
|
50
51
|
end
|
|
51
52
|
if @insert_at_top = @page.definition['insert_elements_at'] == 'top'
|
|
52
53
|
@element.move_to_top
|
|
@@ -110,12 +111,8 @@ module Alchemy
|
|
|
110
111
|
else
|
|
111
112
|
element_with_cell_name = params[:element][:name]
|
|
112
113
|
end
|
|
113
|
-
if element_with_cell_name.blank?
|
|
114
|
-
|
|
115
|
-
end
|
|
116
|
-
unless element_with_cell_name.include?('#')
|
|
117
|
-
return nil
|
|
118
|
-
end
|
|
114
|
+
return nil if element_with_cell_name.blank?
|
|
115
|
+
return nil unless element_with_cell_name.include?('#')
|
|
119
116
|
cell_name = element_with_cell_name.split('#').last
|
|
120
117
|
cell_definition = Cell.definition_for(cell_name)
|
|
121
118
|
if cell_definition.blank?
|
|
@@ -53,13 +53,12 @@ module Alchemy
|
|
|
53
53
|
if !params[:paste_from_clipboard].blank?
|
|
54
54
|
source_page = Page.find(params[:paste_from_clipboard])
|
|
55
55
|
@page = Page.copy(source_page, {
|
|
56
|
-
:name => params[:page][:name].blank? ? source_page.name + ' (' + t('Copy') + ')' : params[:page][:name],
|
|
57
|
-
:urlname => '',
|
|
58
|
-
:title => '',
|
|
59
56
|
:parent_id => params[:page][:parent_id],
|
|
60
57
|
:language => parent.language
|
|
61
58
|
})
|
|
62
|
-
|
|
59
|
+
if source_page.children.any?
|
|
60
|
+
source_page.copy_children_to(@page)
|
|
61
|
+
end
|
|
63
62
|
else
|
|
64
63
|
@page = Page.create(params[:page])
|
|
65
64
|
end
|
|
@@ -6,8 +6,6 @@ module Alchemy
|
|
|
6
6
|
helper Alchemy::ResourcesHelper
|
|
7
7
|
helper_method :resource_handler
|
|
8
8
|
|
|
9
|
-
rescue_from Exception, :with => :exception_handler
|
|
10
|
-
|
|
11
9
|
before_filter :load_resource, :only => [:show, :edit, :update, :destroy]
|
|
12
10
|
|
|
13
11
|
def index
|
|
@@ -65,25 +63,10 @@ module Alchemy
|
|
|
65
63
|
|
|
66
64
|
protected
|
|
67
65
|
|
|
68
|
-
def render_errors_or_redirect(object, redirect_url, flash_notice)
|
|
69
|
-
if object.errors.empty?
|
|
70
|
-
@redirect_url = redirect_url
|
|
71
|
-
flash[:notice] = t(flash_notice)
|
|
72
|
-
respond_to do |format|
|
|
73
|
-
format.js { render :action => :redirect }
|
|
74
|
-
format.html { redirect_to @redirect_url }
|
|
75
|
-
end
|
|
76
|
-
else
|
|
77
|
-
respond_to do |format|
|
|
78
|
-
format.js { render_remote_errors(object) }
|
|
79
|
-
format.html { render :action => :new }
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
66
|
# Returns a translated +flash[:notice]+.
|
|
85
67
|
# The key should look like "Modelname successfully created|updated|destroyed."
|
|
86
68
|
def flash_notice_for_resource_action(action = params[:action])
|
|
69
|
+
return if resource_instance_variable.errors.any?
|
|
87
70
|
case action.to_sym
|
|
88
71
|
when :create
|
|
89
72
|
verb = "created"
|
|
@@ -5,6 +5,8 @@ module Alchemy
|
|
|
5
5
|
filter_access_to [:edit, :update, :destroy], :attribute_check => true, :load_method => :load_user, :model => Alchemy::User
|
|
6
6
|
filter_access_to [:index, :new, :create], :attribute_check => false
|
|
7
7
|
|
|
8
|
+
before_filter :set_roles_and_genders, :except => [:index, :destroy]
|
|
9
|
+
|
|
8
10
|
def index
|
|
9
11
|
if !params[:query].blank?
|
|
10
12
|
users = User.where([
|
|
@@ -22,8 +24,6 @@ module Alchemy
|
|
|
22
24
|
|
|
23
25
|
def new
|
|
24
26
|
@user = User.new
|
|
25
|
-
@user_roles = User::ROLES.map { |role| [User.human_rolename(role), role] }
|
|
26
|
-
@user_genders = User.genders_for_select
|
|
27
27
|
render :layout => false
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -44,8 +44,6 @@ module Alchemy
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def edit
|
|
47
|
-
@user_roles = User::ROLES.map { |role| [User.human_rolename(role), role] }
|
|
48
|
-
@user_genders = User.genders_for_select
|
|
49
47
|
render :layout => false
|
|
50
48
|
end
|
|
51
49
|
|
|
@@ -71,12 +69,17 @@ module Alchemy
|
|
|
71
69
|
render :action => :redirect
|
|
72
70
|
end
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
private
|
|
75
73
|
|
|
76
74
|
def load_user
|
|
77
75
|
@user = User.find(params[:id])
|
|
78
76
|
end
|
|
79
77
|
|
|
78
|
+
def set_roles_and_genders
|
|
79
|
+
@user_roles = User::ROLES.map { |role| [User.human_rolename(role), role] }
|
|
80
|
+
@user_genders = User.genders_for_select
|
|
81
|
+
end
|
|
82
|
+
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
end
|
|
@@ -49,7 +49,12 @@ module Alchemy
|
|
|
49
49
|
<script type='text/javascript'>
|
|
50
50
|
jQuery(function($) {
|
|
51
51
|
Alchemy.Tinymce.customInits = [];"
|
|
52
|
-
Alchemy::Tinymce.custom_config_contents
|
|
52
|
+
custom_config_contents = Alchemy::Tinymce.custom_config_contents
|
|
53
|
+
content_names = custom_config_contents.collect{ |c| c['name'] }
|
|
54
|
+
if content_names.uniq.length != content_names.length
|
|
55
|
+
raise "Duplicated content names with tinymce setting in elements.yml found. Please rename these contents."
|
|
56
|
+
end
|
|
57
|
+
custom_config_contents.each do |content|
|
|
53
58
|
next unless content['settings']['tinymce']
|
|
54
59
|
config = Alchemy::Tinymce.init.merge(content['settings']['tinymce'].symbolize_keys)
|
|
55
60
|
config = config.collect { |key, value| "#{key} : #{value.to_json}" }.join(', ')
|
|
@@ -6,6 +6,7 @@ module Alchemy
|
|
|
6
6
|
:element_id,
|
|
7
7
|
:essence_id,
|
|
8
8
|
:essence_type,
|
|
9
|
+
:ingredient,
|
|
9
10
|
:name,
|
|
10
11
|
:position
|
|
11
12
|
)
|
|
@@ -35,6 +36,8 @@ module Alchemy
|
|
|
35
36
|
|
|
36
37
|
# Creates a new Content as descriped in the elements.yml file
|
|
37
38
|
def create_from_scratch(element, essences_hash)
|
|
39
|
+
# If no name given, we can create the content from essence type.
|
|
40
|
+
# Used in picture gallery
|
|
38
41
|
if essences_hash[:name].blank? && !essences_hash[:essence_type].blank?
|
|
39
42
|
essences_of_same_type = element.contents.where(
|
|
40
43
|
:essence_type => Content.normalize_essence_type(essences_hash[:essence_type])
|
|
@@ -43,6 +46,7 @@ module Alchemy
|
|
|
43
46
|
'type' => essences_hash[:essence_type],
|
|
44
47
|
'name' => "#{essences_hash[:essence_type].classify.demodulize.underscore}_#{essences_of_same_type.count + 1}"
|
|
45
48
|
}
|
|
49
|
+
# Normal way to create
|
|
46
50
|
else
|
|
47
51
|
description = element.content_description_for(essences_hash[:name])
|
|
48
52
|
description = element.available_content_description_for(essences_hash[:name]) if description.blank?
|
|
@@ -151,8 +155,14 @@ module Alchemy
|
|
|
151
155
|
|
|
152
156
|
# Gets the ingredient from essence
|
|
153
157
|
def ingredient
|
|
154
|
-
return nil if
|
|
155
|
-
|
|
158
|
+
return nil if essence.nil?
|
|
159
|
+
essence.ingredient
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Sets the ingredient from essence
|
|
163
|
+
def ingredient=(value)
|
|
164
|
+
raise "No essence found" if essence.nil?
|
|
165
|
+
essence.ingredient = value
|
|
156
166
|
end
|
|
157
167
|
|
|
158
168
|
# Calls essence.update_attributes. Called from +Alchemy::Element#save_contents+
|
|
@@ -232,11 +242,13 @@ module Alchemy
|
|
|
232
242
|
# Creates self.essence from description.
|
|
233
243
|
def create_essence!(description)
|
|
234
244
|
essence_class = self.class.normalize_essence_type(description['type']).constantize
|
|
245
|
+
attributes = {
|
|
246
|
+
:ingredient => default_or_lorem_ipsum(description['default'])
|
|
247
|
+
}
|
|
235
248
|
if description['type'] == "EssenceRichtext" || description['type'] == "EssenceText"
|
|
236
|
-
|
|
237
|
-
else
|
|
238
|
-
essence = essence_class.create
|
|
249
|
+
attributes.merge!(:do_not_index => !description['do_not_index'].nil?)
|
|
239
250
|
end
|
|
251
|
+
essence = essence_class.create(attributes)
|
|
240
252
|
if essence
|
|
241
253
|
self.essence = essence
|
|
242
254
|
save!
|
|
@@ -245,5 +257,14 @@ module Alchemy
|
|
|
245
257
|
end
|
|
246
258
|
end
|
|
247
259
|
|
|
260
|
+
def default_or_lorem_ipsum(default)
|
|
261
|
+
return if default.nil?
|
|
262
|
+
if default.is_a? Symbol
|
|
263
|
+
I18n.t(default, :scope => :default_content_texts)
|
|
264
|
+
else
|
|
265
|
+
default
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
248
269
|
end
|
|
249
270
|
end
|
|
@@ -157,6 +157,7 @@ module Alchemy
|
|
|
157
157
|
differences.stringify_keys!
|
|
158
158
|
attributes = source.attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY).merge(differences)
|
|
159
159
|
element = self.create!(attributes.merge(:create_contents_after_create => false))
|
|
160
|
+
element.tag_list = source.tag_list
|
|
160
161
|
source.contents.each do |content|
|
|
161
162
|
new_content = Content.copy(content, :element_id => element.id)
|
|
162
163
|
new_content.move_to_bottom
|
data/app/models/alchemy/page.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Alchemy
|
|
|
11
11
|
:locked => false,
|
|
12
12
|
:locked_by => nil
|
|
13
13
|
}
|
|
14
|
-
SKIPPED_ATTRIBUTES_ON_COPY = %w(id updated_at created_at creator_id updater_id lft rgt depth cached_tag_list)
|
|
14
|
+
SKIPPED_ATTRIBUTES_ON_COPY = %w(id updated_at created_at creator_id updater_id lft rgt depth urlname cached_tag_list)
|
|
15
15
|
|
|
16
16
|
attr_accessible(
|
|
17
17
|
:do_not_autogenerate,
|
|
@@ -94,6 +94,135 @@ module Alchemy
|
|
|
94
94
|
scope :flushables, not_locked.published.contentpages
|
|
95
95
|
scope :searchables, not_restricted.published.contentpages
|
|
96
96
|
|
|
97
|
+
# Class methods
|
|
98
|
+
#
|
|
99
|
+
class << self
|
|
100
|
+
|
|
101
|
+
alias_method :rootpage, :root
|
|
102
|
+
|
|
103
|
+
# @return the language root page for given language id.
|
|
104
|
+
# @param language_id [Fixnum]
|
|
105
|
+
#
|
|
106
|
+
def language_root_for(language_id)
|
|
107
|
+
self.language_roots.find_by_language_id(language_id)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Creates a copy of source
|
|
111
|
+
#
|
|
112
|
+
# Also copies all elements included in source.
|
|
113
|
+
#
|
|
114
|
+
# === Note:
|
|
115
|
+
# It prevents the element auto generator from running.
|
|
116
|
+
#
|
|
117
|
+
# @param source [Alchemy::Page]
|
|
118
|
+
# @param differences [Hash]
|
|
119
|
+
#
|
|
120
|
+
# @return [Alchemy::Page]
|
|
121
|
+
#
|
|
122
|
+
def copy(source, differences = {})
|
|
123
|
+
source.attributes.stringify_keys!
|
|
124
|
+
differences.stringify_keys!
|
|
125
|
+
attributes = source.attributes.merge(differences)
|
|
126
|
+
attributes.merge!(DEFAULT_ATTRIBUTES_FOR_COPY)
|
|
127
|
+
attributes.merge!('name' => "#{source.name} (#{I18n.t('Copy')})")
|
|
128
|
+
page = self.new(attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY))
|
|
129
|
+
page.tag_list = source.tag_list
|
|
130
|
+
if page.save!
|
|
131
|
+
copy_cells(source, page)
|
|
132
|
+
copy_elements(source, page)
|
|
133
|
+
page
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Copy page cells
|
|
138
|
+
#
|
|
139
|
+
# @param source [Alchemy::Page]
|
|
140
|
+
# @param target [Alchemy::Page]
|
|
141
|
+
# @return [Array]
|
|
142
|
+
#
|
|
143
|
+
def copy_cells(source, target)
|
|
144
|
+
new_cells = []
|
|
145
|
+
source.cells.each do |cell|
|
|
146
|
+
new_cells << Cell.create(:name => cell.name, :page_id => target.id)
|
|
147
|
+
end
|
|
148
|
+
new_cells
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Copy page elements
|
|
152
|
+
#
|
|
153
|
+
# @param source [Alchemy::Page]
|
|
154
|
+
# @param target [Alchemy::Page]
|
|
155
|
+
# @return [Array]
|
|
156
|
+
#
|
|
157
|
+
def copy_elements(source, target)
|
|
158
|
+
new_elements = []
|
|
159
|
+
source.elements.each do |element|
|
|
160
|
+
# detect cell for element
|
|
161
|
+
if element.cell
|
|
162
|
+
cell = target.cells.detect { |c| c.name == element.cell.name }
|
|
163
|
+
else
|
|
164
|
+
cell = nil
|
|
165
|
+
end
|
|
166
|
+
# if cell is nil also pass nil to element.cell_id
|
|
167
|
+
new_element = Element.copy(element, :page_id => target.id, :cell_id => (cell.blank? ? nil : cell.id))
|
|
168
|
+
# move element to bottom of the list
|
|
169
|
+
new_element.move_to_bottom
|
|
170
|
+
new_elements << new_element
|
|
171
|
+
end
|
|
172
|
+
new_elements
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def layout_root_for(language_id)
|
|
176
|
+
where({:parent_id => Page.root.id, :layoutpage => true, :language_id => language_id}).limit(1).first
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def find_or_create_layout_root_for(language_id)
|
|
180
|
+
layoutroot = layout_root_for(language_id)
|
|
181
|
+
return layoutroot if layoutroot
|
|
182
|
+
language = Language.find(language_id)
|
|
183
|
+
layoutroot = Page.new({
|
|
184
|
+
:name => "Layoutroot for #{language.name}",
|
|
185
|
+
:layoutpage => true,
|
|
186
|
+
:language => language,
|
|
187
|
+
:do_not_autogenerate => true
|
|
188
|
+
})
|
|
189
|
+
if layoutroot.save(:validate => false)
|
|
190
|
+
layoutroot.move_to_child_of(Page.root)
|
|
191
|
+
return layoutroot
|
|
192
|
+
else
|
|
193
|
+
raise "Layout root for #{language.name} could not be created"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def all_from_clipboard(clipboard)
|
|
198
|
+
return [] if clipboard.blank?
|
|
199
|
+
self.find_all_by_id(clipboard.collect { |i| i[:id] })
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def all_from_clipboard_for_select(clipboard, language_id, layoutpage = false)
|
|
203
|
+
return [] if clipboard.blank?
|
|
204
|
+
clipboard_pages = self.all_from_clipboard(clipboard)
|
|
205
|
+
allowed_page_layouts = Alchemy::PageLayout.selectable_layouts(language_id, layoutpage)
|
|
206
|
+
allowed_page_layout_names = allowed_page_layouts.collect { |p| p['name'] }
|
|
207
|
+
clipboard_pages.select { |cp| allowed_page_layout_names.include?(cp.page_layout) }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def link_target_options
|
|
211
|
+
options = [
|
|
212
|
+
[I18n.t('default', :scope => :link_target_options), '']
|
|
213
|
+
]
|
|
214
|
+
link_target_options = Config.get(:link_target_options)
|
|
215
|
+
link_target_options.each do |option|
|
|
216
|
+
options << [I18n.t(option, :scope => :link_target_options), option]
|
|
217
|
+
end
|
|
218
|
+
options
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Instance methods
|
|
224
|
+
#
|
|
225
|
+
|
|
97
226
|
# Finds selected elements from page.
|
|
98
227
|
#
|
|
99
228
|
# Options are:
|
|
@@ -385,39 +514,6 @@ module Alchemy
|
|
|
385
514
|
self.children.where(:public => true).limit(1).first
|
|
386
515
|
end
|
|
387
516
|
|
|
388
|
-
def self.language_root_for(language_id)
|
|
389
|
-
self.language_roots.find_by_language_id(language_id)
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
# Creates a copy of source (a Page object) and does a copy of all elements depending to source.
|
|
393
|
-
# You can pass any kind of Page#attributes as a difference to source.
|
|
394
|
-
# Notice: It prevents the element auto_generator from running.
|
|
395
|
-
def self.copy(source, differences = {})
|
|
396
|
-
source.attributes.stringify_keys!
|
|
397
|
-
differences.stringify_keys!
|
|
398
|
-
attributes = source.attributes.merge(differences)
|
|
399
|
-
attributes.merge!(DEFAULT_ATTRIBUTES_FOR_COPY)
|
|
400
|
-
page = self.new(attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY))
|
|
401
|
-
if page.save
|
|
402
|
-
# copy the page´s cells
|
|
403
|
-
source.cells.each do |cell|
|
|
404
|
-
new_cell = Cell.create(:name => cell.name, :page_id => page.id)
|
|
405
|
-
end
|
|
406
|
-
# copy the page´s elements
|
|
407
|
-
source.elements.each do |element|
|
|
408
|
-
# detect cell for element
|
|
409
|
-
# if cell is nil also pass nil to element.cell_id
|
|
410
|
-
cell = nil
|
|
411
|
-
cell = page.cells.detect { |c| c.name == element.cell.name } if element.cell
|
|
412
|
-
new_element = Element.copy(element, :page_id => page.id, :cell_id => (cell.blank? ? nil : cell.id))
|
|
413
|
-
new_element.move_to_bottom
|
|
414
|
-
end
|
|
415
|
-
return page
|
|
416
|
-
else
|
|
417
|
-
raise "`#{page.name}`: #{page.errors.full_messages}"
|
|
418
|
-
end
|
|
419
|
-
end
|
|
420
|
-
|
|
421
517
|
# Gets the language_root page for page
|
|
422
518
|
def get_language_root
|
|
423
519
|
return self if self.language_root
|
|
@@ -429,50 +525,12 @@ module Alchemy
|
|
|
429
525
|
return page
|
|
430
526
|
end
|
|
431
527
|
|
|
432
|
-
def self.layout_root_for(language_id)
|
|
433
|
-
where({:parent_id => Page.root.id, :layoutpage => true, :language_id => language_id}).limit(1).first
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
def self.find_or_create_layout_root_for(language_id)
|
|
437
|
-
layoutroot = layout_root_for(language_id)
|
|
438
|
-
return layoutroot if layoutroot
|
|
439
|
-
language = Language.find(language_id)
|
|
440
|
-
layoutroot = Page.new({
|
|
441
|
-
:name => "Layoutroot for #{language.name}",
|
|
442
|
-
:layoutpage => true,
|
|
443
|
-
:language => language,
|
|
444
|
-
:do_not_autogenerate => true
|
|
445
|
-
})
|
|
446
|
-
if layoutroot.save(:validate => false)
|
|
447
|
-
layoutroot.move_to_child_of(Page.root)
|
|
448
|
-
return layoutroot
|
|
449
|
-
else
|
|
450
|
-
raise "Layout root for #{language.name} could not be created"
|
|
451
|
-
end
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def self.all_from_clipboard(clipboard)
|
|
455
|
-
return [] if clipboard.blank?
|
|
456
|
-
self.find_all_by_id(clipboard.collect { |i| i[:id] })
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def self.all_from_clipboard_for_select(clipboard, language_id, layoutpage = false)
|
|
460
|
-
return [] if clipboard.blank?
|
|
461
|
-
clipboard_pages = self.all_from_clipboard(clipboard)
|
|
462
|
-
allowed_page_layouts = Alchemy::PageLayout.selectable_layouts(language_id, layoutpage)
|
|
463
|
-
allowed_page_layout_names = allowed_page_layouts.collect { |p| p['name'] }
|
|
464
|
-
clipboard_pages.select { |cp| allowed_page_layout_names.include?(cp.page_layout) }
|
|
465
|
-
end
|
|
466
|
-
|
|
467
528
|
def copy_children_to(new_parent)
|
|
468
529
|
self.children.each do |child|
|
|
469
530
|
next if child == new_parent
|
|
470
531
|
new_child = Page.copy(child, {
|
|
471
532
|
:language_id => new_parent.language_id,
|
|
472
|
-
:language_code => new_parent.language_code
|
|
473
|
-
:name => child.name + ' (' + I18n.t('Copy') + ')',
|
|
474
|
-
:urlname => child.redirects_to_external? ? child.urlname : '',
|
|
475
|
-
:title => ''
|
|
533
|
+
:language_code => new_parent.language_code
|
|
476
534
|
})
|
|
477
535
|
new_child.move_to_child_of(new_parent)
|
|
478
536
|
child.copy_children_to(new_child) unless child.children.blank?
|
|
@@ -488,17 +546,6 @@ module Alchemy
|
|
|
488
546
|
cells.any?
|
|
489
547
|
end
|
|
490
548
|
|
|
491
|
-
def self.link_target_options
|
|
492
|
-
options = [
|
|
493
|
-
[I18n.t('default', :scope => :link_target_options), '']
|
|
494
|
-
]
|
|
495
|
-
link_target_options = Config.get(:link_target_options)
|
|
496
|
-
link_target_options.each do |option|
|
|
497
|
-
options << [I18n.t(option, :scope => :link_target_options), option]
|
|
498
|
-
end
|
|
499
|
-
options
|
|
500
|
-
end
|
|
501
|
-
|
|
502
549
|
def locker_name
|
|
503
550
|
return I18n.t('unknown') if self.locker.nil?
|
|
504
551
|
self.locker.name
|
|
@@ -513,10 +560,6 @@ module Alchemy
|
|
|
513
560
|
rootpage? || (self.parent_id == Page.root.id && !self.language_root?)
|
|
514
561
|
end
|
|
515
562
|
|
|
516
|
-
def self.rootpage
|
|
517
|
-
self.root
|
|
518
|
-
end
|
|
519
|
-
|
|
520
563
|
def cache_key(request = nil)
|
|
521
564
|
"alchemy/#{language_code}/#{urlname}"
|
|
522
565
|
end
|