alchemy_cms 2.4.rc2 → 2.4.rc4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|