alchemy_cms 2.2.4 → 2.3.rc5
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 +1 -1
- data/.travis.yml +3 -4
- data/Gemfile +1 -0
- data/README.md +10 -6
- data/alchemy_cms.gemspec +5 -2
- data/app/assets/images/alchemy/icons.png +0 -0
- data/app/assets/images/sassy-ie-overlay.png +0 -0
- data/app/assets/javascripts/alchemy/alchemy.base.js +50 -59
- data/app/assets/javascripts/alchemy/alchemy.buttons.js +14 -4
- data/app/assets/javascripts/alchemy/alchemy.datepicker.js +8 -2
- data/app/assets/javascripts/alchemy/alchemy.elements_window.js +11 -3
- data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +1 -1
- data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +14 -1
- data/app/assets/javascripts/alchemy/alchemy.preview.js +1 -1
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js +12 -4
- data/app/assets/javascripts/alchemy/alchemy.uploader.js +4 -1
- data/app/assets/javascripts/alchemy/alchemy.windows.js +18 -8
- data/app/assets/stylesheets/alchemy/_defaults.scss +84 -120
- data/app/assets/stylesheets/alchemy/alchemy.css +2 -2
- data/app/assets/stylesheets/alchemy/archive.css.scss +288 -0
- data/app/assets/stylesheets/alchemy/base.css.scss +95 -390
- data/app/assets/stylesheets/alchemy/dashboard.css.scss +4 -4
- data/app/assets/stylesheets/alchemy/elements.css.scss +83 -118
- data/app/assets/stylesheets/alchemy/flash.css.scss +1 -1
- data/app/assets/stylesheets/alchemy/form_elements.css.scss +528 -0
- data/app/assets/stylesheets/alchemy/frame.css.scss +13 -39
- data/app/assets/stylesheets/alchemy/icons.css.scss +217 -228
- data/app/assets/stylesheets/alchemy/jquery-ui.alchemy.css.scss +48 -50
- data/app/assets/stylesheets/alchemy/jquery.Jcrop.css.scss +1 -1
- data/app/assets/stylesheets/alchemy/login.css.scss +1 -5
- data/app/assets/stylesheets/alchemy/menubar.css.scss +19 -29
- data/app/assets/stylesheets/alchemy/pagination.css.scss +3 -4
- data/app/assets/stylesheets/alchemy/sitemap.css.scss +81 -81
- data/app/assets/stylesheets/alchemy/tables.css.scss +63 -57
- data/app/assets/stylesheets/alchemy/tinymce_dialog.css.scss +57 -57
- data/app/assets/stylesheets/alchemy/upload.css.scss +6 -6
- data/app/assets/stylesheets/tiny_mce/plugins/inlinepopups/skins/alchemy/window.css.scss +6 -10
- data/app/controllers/alchemy/admin/attachments_controller.rb +5 -4
- data/app/controllers/alchemy/admin/base_controller.rb +1 -9
- data/app/controllers/alchemy/admin/contents_controller.rb +4 -6
- data/app/controllers/alchemy/admin/elements_controller.rb +2 -2
- data/app/controllers/alchemy/admin/pages_controller.rb +2 -2
- data/app/controllers/alchemy/admin/pictures_controller.rb +74 -15
- data/app/controllers/alchemy/attachments_controller.rb +8 -2
- data/app/controllers/alchemy/base_controller.rb +47 -5
- data/app/controllers/alchemy/elements_controller.rb +1 -1
- data/app/controllers/alchemy/messages_controller.rb +12 -12
- data/app/controllers/alchemy/pages_controller.rb +5 -1
- data/app/controllers/alchemy/pictures_controller.rb +9 -4
- data/app/controllers/alchemy/user_sessions_controller.rb +2 -4
- data/app/helpers/alchemy/admin/base_helper.rb +98 -19
- data/app/helpers/alchemy/admin/contents_helper.rb +2 -2
- data/app/helpers/alchemy/admin/elements_helper.rb +2 -3
- data/app/helpers/alchemy/base_helper.rb +6 -5
- data/app/helpers/alchemy/elements_helper.rb +2 -2
- data/app/helpers/alchemy/essences_helper.rb +4 -5
- data/app/helpers/alchemy/pages_helper.rb +15 -79
- data/app/helpers/alchemy/url_helper.rb +67 -0
- data/app/mailers/alchemy/messages.rb +1 -1
- data/app/mailers/alchemy/notifications.rb +1 -1
- data/app/models/alchemy/attachment.rb +11 -2
- data/app/models/alchemy/cell.rb +20 -10
- data/app/models/alchemy/content.rb +4 -3
- data/app/models/alchemy/element.rb +170 -178
- data/app/models/alchemy/language/code.rb +4 -1
- data/app/models/alchemy/message.rb +19 -3
- data/app/models/alchemy/page.rb +45 -40
- data/app/models/alchemy/picture.rb +24 -2
- data/app/models/alchemy/user.rb +2 -3
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +12 -12
- data/app/views/alchemy/admin/attachments/_attachment.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/create.js.erb +1 -0
- data/app/views/alchemy/admin/attachments/edit.html.erb +9 -3
- data/app/views/alchemy/admin/attachments/index.html.erb +3 -2
- data/app/views/alchemy/admin/contents/_missing.html.erb +1 -1
- data/app/views/alchemy/admin/contents/create.js.erb +54 -0
- data/app/views/alchemy/admin/contents/new.html.erb +9 -4
- data/app/views/alchemy/admin/elements/{_add_content.html.erb → _add_picture.html.erb} +4 -4
- data/app/views/alchemy/admin/elements/_elements_select.html.erb +2 -1
- data/app/views/alchemy/admin/elements/_new_element_form.html.erb +1 -1
- data/app/views/alchemy/admin/elements/{_picture_editor.html.erb → _picture_gallery_editor.html.erb} +7 -11
- data/app/views/alchemy/admin/elements/fold.js.erb +46 -0
- data/app/views/alchemy/admin/elements/index.html.erb +24 -24
- data/app/views/alchemy/admin/elements/list.js.erb +11 -9
- data/app/views/alchemy/admin/essence_files/assign.js.erb +3 -1
- data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +28 -0
- data/app/views/alchemy/admin/pages/_contactform_links.html.erb +8 -6
- data/app/views/alchemy/admin/pages/_external_link.html.erb +11 -9
- data/app/views/alchemy/admin/pages/_file_link.html.erb +10 -8
- data/app/views/alchemy/admin/pages/_internal_link.html.erb +14 -10
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_page_for_links.html.erb +32 -21
- data/app/views/alchemy/admin/pages/configure.html.erb +2 -2
- data/app/views/alchemy/admin/pages/configure_external.html.erb +13 -13
- data/app/views/alchemy/admin/pages/edit.html.erb +2 -2
- data/app/views/alchemy/admin/pages/index.html.erb +26 -24
- data/app/views/alchemy/admin/pages/link.html.erb +2 -5
- data/app/views/alchemy/admin/partials/_upload_form.html.erb +28 -12
- data/app/views/alchemy/admin/pictures/_archive.html.erb +54 -0
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +10 -7
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +21 -22
- data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +31 -0
- data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +9 -0
- data/app/views/alchemy/admin/pictures/_picture.html.erb +36 -6
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +27 -0
- data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +3 -1
- data/app/views/alchemy/admin/pictures/create.js.erb +4 -5
- data/app/views/alchemy/admin/pictures/edit.html.erb +26 -0
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +39 -0
- data/app/views/alchemy/admin/pictures/index.html.erb +81 -70
- data/app/views/alchemy/admin/pictures/index.js.erb +3 -0
- data/app/views/alchemy/admin/pictures/new.html.erb +1 -0
- data/app/views/alchemy/admin/resources/index.html.erb +3 -1
- data/app/views/alchemy/admin/users/_table.html.erb +1 -1
- data/app/views/alchemy/admin/users/index.html.erb +27 -23
- data/app/views/alchemy/elements/_article_editor.html.erb +7 -2
- data/app/views/alchemy/elements/_bild_editor.html.erb +1 -1
- data/app/views/alchemy/elements/_bild_text_editor.html.erb +6 -1
- data/app/views/alchemy/elements/_bild_text_view.html.erb +3 -3
- data/app/views/alchemy/elements/_image_mosaic_editor.html.erb +1 -1
- data/app/views/alchemy/elements/_image_mosaic_view.html.erb +2 -2
- data/app/views/alchemy/elements/_intro_image_text_view.html.erb +4 -4
- data/app/views/alchemy/elements/_searchresult_editor.html.erb +4 -1
- data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +1 -1
- data/app/views/alchemy/essences/_essence_picture_editor.html.erb +2 -3
- data/app/views/alchemy/essences/_essence_picture_tools.html.erb +1 -1
- data/app/views/alchemy/search/_form.html.erb +8 -0
- data/app/views/alchemy/search/_result.html.erb +3 -2
- data/app/views/alchemy/search/_results.html.erb +28 -0
- data/app/views/alchemy/user_sessions/leave.html.erb +4 -4
- data/app/views/alchemy/user_sessions/login.html.erb +1 -2
- data/app/views/layouts/alchemy/admin.html.erb +30 -10
- data/app/views/layouts/alchemy/login.html.erb +2 -39
- data/config/alchemy/elements.yml +1 -2
- data/config/alchemy/page_layouts.yml +8 -5
- data/config/authorization_rules.rb +27 -18
- data/config/initializers/localeapp.rb +9 -0
- data/config/locales/alchemy.de.yml +93 -56
- data/config/locales/alchemy.en.yml +73 -50
- data/config/routes.rb +3 -1
- data/db/migrate/20120704181529_add_upload_hash_to_alchemy_picture.rb +5 -0
- data/db/migrate/20120705214247_acts_as_taggable_on_migration.rb +28 -0
- data/db/migrate/20120728185830_add_cached_tag_list_to_alchemy_pictures.rb +5 -0
- data/db/migrate/20120831135441_set_alchemy_languages_country_code_default_to_empty_string.rb +9 -0
- data/lib/alchemy/capistrano.rb +2 -2
- data/lib/alchemy/essence.rb +14 -0
- data/lib/alchemy/page_layout.rb +0 -6
- data/lib/alchemy/resource.rb +9 -15
- data/lib/alchemy/upgrader.rb +18 -3
- data/lib/alchemy/version.rb +5 -1
- data/lib/alchemy_cms.rb +4 -1
- data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +16 -6
- data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +17 -3
- data/lib/rails/generators/alchemy/elements/elements_generator.rb +6 -1
- data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +10 -1
- data/lib/rails/generators/alchemy/elements/templates/view.html.erb +17 -18
- data/lib/rails/generators/alchemy/scaffold/files/pages.html.erb +4 -2
- data/lib/tasks/fleximage.rake +2 -2
- data/spec/controllers/admin/contents_controller_spec.rb +2 -2
- data/spec/controllers/admin/elements_controller_spec.rb +30 -1
- data/spec/controllers/admin/pages_controller_spec.rb +35 -18
- data/spec/controllers/admin/trash_controller_spec.rb +40 -16
- data/spec/controllers/attachments_controller_spec.rb +62 -0
- data/spec/controllers/base_controller_spec.rb +43 -42
- data/spec/controllers/elements_controller_spec.rb +30 -0
- data/spec/controllers/pages_controller_spec.rb +22 -5
- data/spec/controllers/pictures_controller_spec.rb +82 -0
- data/spec/dummy/app/models/event.rb +2 -1
- data/spec/dummy/config/database.yml +3 -2
- data/spec/dummy/db/schema.rb +51 -27
- data/spec/factories.rb +29 -8
- data/spec/helpers/admin/base_helper_spec.rb +134 -21
- data/spec/helpers/admin/contents_helper_spec.rb +2 -2
- data/spec/helpers/admin/elements_helper_spec.rb +17 -9
- data/spec/helpers/admin/essences_helper_spec.rb +7 -6
- data/spec/helpers/essences_helper_spec.rb +8 -7
- data/spec/helpers/pages_helper_spec.rb +208 -325
- data/spec/helpers/url_helper_spec.rb +171 -0
- data/spec/integration/admin/link_overlay_spec.rb +53 -0
- data/spec/integration/admin/modules_integration_spec.rb +22 -26
- data/spec/integration/admin/pages_controller_spec.rb +10 -19
- data/spec/integration/admin/picture_library_integration_spec.rb +52 -0
- data/spec/integration/admin/resources_integration_spec.rb +68 -75
- data/spec/integration/pages_controller_spec.rb +70 -61
- data/spec/integration/security_spec.rb +3 -5
- data/spec/integration/translation_integration_spec.rb +56 -0
- data/spec/libraries/essence_spec.rb +18 -0
- data/spec/libraries/resource_spec.rb +101 -79
- data/spec/libraries/resources_helper_spec.rb +3 -0
- data/spec/models/content_spec.rb +63 -60
- data/spec/models/element_spec.rb +203 -93
- data/spec/models/language_spec.rb +90 -65
- data/spec/models/page_layout_spec.rb +37 -0
- data/spec/models/page_spec.rb +181 -113
- data/spec/models/picture_spec.rb +73 -26
- data/spec/models/resource_spec.rb +52 -23
- data/spec/support/alchemy/specs_helpers.rb +2 -0
- data/spec/support/image.png +0 -0
- data/spec/{helpers/url_helpers_spec.rb → url_helpers_spec.rb} +0 -0
- data/vendor/assets/javascripts/jquery_plugins/jquery.selectBoxIt.js +1909 -0
- data/vendor/assets/javascripts/jquery_plugins/preloadCssImages.jQuery_v5.js +152 -0
- metadata +106 -33
- data/app/assets/stylesheets/alchemy/buttons.css.scss +0 -361
- data/app/assets/stylesheets/alchemy/jquery.sb.css.scss +0 -260
- data/app/views/alchemy/admin/contents/create.js.coffee +0 -49
- data/app/views/alchemy/admin/elements/fold.js.coffee +0 -37
- data/app/views/alchemy/admin/essence_pictures/destroy.js.coffee +0 -19
- data/app/views/alchemy/admin/pictures/_pictures_list.html.erb +0 -16
- data/app/views/alchemy/admin/pictures/update.js.erb +0 -3
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/locales/fo.yml +0 -5
- data/spec/page_layout_spec.rb +0 -35
- data/vendor/assets/javascripts/jquery_plugins/jquery.in-place-edit.js +0 -172
- data/vendor/assets/javascripts/jquery_plugins/jquery.sb.min.js +0 -14
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
module Alchemy
|
|
2
2
|
class Attachment < ActiveRecord::Base
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
has_many :essence_files, :class_name => 'Alchemy::EssenceFile', :foreign_key => 'attachment_id'
|
|
5
|
+
has_many :contents, :through => :essence_files
|
|
6
|
+
has_many :elements, :through => :contents
|
|
7
|
+
has_many :pages, :through => :elements
|
|
8
|
+
|
|
9
|
+
attr_accessible :uploaded_data, :name, :filename
|
|
5
10
|
|
|
6
11
|
stampable(:stamper_class_name => 'Alchemy::User')
|
|
7
12
|
|
|
@@ -22,10 +27,14 @@ module Alchemy
|
|
|
22
27
|
::CGI.escape(read_attribute(:filename).split('.').first)
|
|
23
28
|
end
|
|
24
29
|
|
|
30
|
+
# Checks if the attachment is restricted, because it is attached on restricted pages only
|
|
31
|
+
def restricted?
|
|
32
|
+
pages.any? && pages.not_restricted.blank?
|
|
33
|
+
end
|
|
34
|
+
|
|
25
35
|
def extension
|
|
26
36
|
filename.split(".").last
|
|
27
37
|
end
|
|
28
|
-
|
|
29
38
|
alias_method :suffix, :extension
|
|
30
39
|
|
|
31
40
|
def icon_css_class
|
data/app/models/alchemy/cell.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# A cell is a group of elements that are rendered inside a specific area on your page_layout.
|
|
2
2
|
# Think of it like a column, or section in your layout. I.e. a header or right column.
|
|
3
|
-
#
|
|
3
|
+
#
|
|
4
4
|
# Elements are displayed in tabs inside the elements window in page edit view.
|
|
5
5
|
# Every cell is a list of elements with the position scoped to +cell_id+ and +page_id+.
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
# Define cells inside a +cells.yml+ file located in the +config/alchermy+ folder of your project.
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# Render cells with the +render_cell+ helper
|
|
10
|
-
#
|
|
10
|
+
#
|
|
11
11
|
# Views for cells are inside the +app/views/cells+ folder in you project.
|
|
12
|
-
#
|
|
12
|
+
#
|
|
13
13
|
module Alchemy
|
|
14
14
|
class Cell < ActiveRecord::Base
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ module Alchemy
|
|
|
21
21
|
|
|
22
22
|
def self.definitions
|
|
23
23
|
cell_yml = ::File.join(::Rails.root, 'config', 'alchemy', 'cells.yml')
|
|
24
|
-
::YAML.load_file(cell_yml)
|
|
24
|
+
::YAML.load_file(cell_yml)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def self.definition_for(cellname)
|
|
@@ -52,13 +52,23 @@ module Alchemy
|
|
|
52
52
|
definitions.collect { |d| d['name'] }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def name_for_label
|
|
56
|
-
self.class.translated_label_for(self.name)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
55
|
def self.translated_label_for(cell_name)
|
|
60
56
|
I18n.t(cell_name, :scope => :cell_names)
|
|
61
57
|
end
|
|
62
58
|
|
|
59
|
+
# Returns the cell definition defined in +config/alchemy/cells.yml+
|
|
60
|
+
def definition
|
|
61
|
+
self.class.definition_for(self.name)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns all elements that can be placed in this cell
|
|
65
|
+
def available_elements
|
|
66
|
+
definition['elements']
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def name_for_label
|
|
70
|
+
self.class.translated_label_for(self.name)
|
|
71
|
+
end
|
|
72
|
+
|
|
63
73
|
end
|
|
64
74
|
end
|
|
@@ -25,6 +25,7 @@ module Alchemy
|
|
|
25
25
|
validates_uniqueness_of :position, :scope => [:element_id, :essence_type]
|
|
26
26
|
|
|
27
27
|
scope :essence_pictures, where(:essence_type => "Alchemy::EssencePicture")
|
|
28
|
+
scope :gallery_pictures, essence_pictures.where("#{self.table_name}.name LIKE 'essence_picture_%'")
|
|
28
29
|
scope :essence_texts, where(:essence_type => "Alchemy::EssenceText")
|
|
29
30
|
scope :essence_richtexts, where(:essence_type => "Alchemy::EssenceRichtext")
|
|
30
31
|
scope :essence_selects, where(:essence_type => "Alchemy::EssenceSelect")
|
|
@@ -49,6 +50,7 @@ module Alchemy
|
|
|
49
50
|
raise "No description found in elements.yml for #{essences_hash.inspect} and #{element.inspect}" if description.blank?
|
|
50
51
|
content = new(:name => description['name'], :element_id => element.id)
|
|
51
52
|
content.create_essence!(description)
|
|
53
|
+
content
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
# Makes a copy of source and also copies the associated essence.
|
|
@@ -79,7 +81,7 @@ module Alchemy
|
|
|
79
81
|
))
|
|
80
82
|
new_essence.save!
|
|
81
83
|
raise "Essence not cloned" if new_essence.id == content.essence_id
|
|
82
|
-
content.
|
|
84
|
+
content.update_attributes(:essence_id => new_essence.id)
|
|
83
85
|
content
|
|
84
86
|
end
|
|
85
87
|
|
|
@@ -238,9 +240,8 @@ module Alchemy
|
|
|
238
240
|
if essence
|
|
239
241
|
self.essence = essence
|
|
240
242
|
save!
|
|
241
|
-
self
|
|
242
243
|
else
|
|
243
|
-
|
|
244
|
+
false
|
|
244
245
|
end
|
|
245
246
|
end
|
|
246
247
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Alchemy
|
|
2
2
|
class Element < ActiveRecord::Base
|
|
3
3
|
|
|
4
|
+
FORBIDDEN_DEFINITION_ATTRIBUTES = %w(contents available_contents display_name amount picture_gallery)
|
|
5
|
+
|
|
4
6
|
attr_accessible(
|
|
5
7
|
:cell_id,
|
|
6
8
|
:create_contents_after_create,
|
|
@@ -35,6 +37,165 @@ module Alchemy
|
|
|
35
37
|
scope :named, lambda { |names| where(:name => names) }
|
|
36
38
|
scope :excluded, lambda { |names| where(arel_table[:name].not_in(names)) }
|
|
37
39
|
scope :not_in_cell, where(:cell_id => nil)
|
|
40
|
+
scope :in_cell, where("#{self.table_name}.cell_id IS NOT NULL")
|
|
41
|
+
|
|
42
|
+
# class methods
|
|
43
|
+
class << self
|
|
44
|
+
|
|
45
|
+
# Builds a new element as described in +/config/alchemy/elements.yml+
|
|
46
|
+
def new_from_scratch(attributes)
|
|
47
|
+
attributes.stringify_keys!
|
|
48
|
+
return new if attributes['name'].blank?
|
|
49
|
+
return nil if descriptions.blank?
|
|
50
|
+
# clean the name from cell name
|
|
51
|
+
attributes['name'] = attributes['name'].split('#').first
|
|
52
|
+
element_scratch = descriptions.detect { |m| m["name"] == attributes['name'] }
|
|
53
|
+
if element_scratch
|
|
54
|
+
new(element_scratch.except(*FORBIDDEN_DEFINITION_ATTRIBUTES).merge(attributes))
|
|
55
|
+
else
|
|
56
|
+
raise "Element description for #{attributes['name']} not found. Please check your elements.yml"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Builds a new element as described in +/config/alchemy/elements.yml+ and saves it
|
|
61
|
+
def create_from_scratch(attributes)
|
|
62
|
+
element = new_from_scratch(attributes)
|
|
63
|
+
element.save if element
|
|
64
|
+
return element
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the descriptions from elements.yml file.
|
|
68
|
+
# Alchemy comes with its own elements.yml file. As so called standard set.
|
|
69
|
+
# Place a elements.yml file inside your apps config/alchemy folder to define
|
|
70
|
+
# your own set of elements
|
|
71
|
+
def descriptions
|
|
72
|
+
if ::File.exists? "#{::Rails.root}/config/alchemy/elements.yml"
|
|
73
|
+
element_definitions = ::YAML.load_file("#{::Rails.root}/config/alchemy/elements.yml")
|
|
74
|
+
end
|
|
75
|
+
if !element_definitions
|
|
76
|
+
if ::File.exists?(::File.join(::File.dirname(__FILE__), "../../../config/alchemy/elements.yml"))
|
|
77
|
+
element_definitions = ::YAML.load_file(::File.join(::File.dirname(__FILE__), "../../../config/alchemy/elements.yml"))
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
if !element_definitions
|
|
81
|
+
raise LoadError, "Could not find elements.yml file! Please run: rails generate alchemy:scaffold"
|
|
82
|
+
end
|
|
83
|
+
element_definitions
|
|
84
|
+
end
|
|
85
|
+
alias_method :definitions, :descriptions
|
|
86
|
+
|
|
87
|
+
# pastes a element from the clipboard in the session to page
|
|
88
|
+
def paste_from_clipboard(page_id, element, method, position)
|
|
89
|
+
element_copy = copy(element, :page_id => page_id)
|
|
90
|
+
element_copy.insert_at(position)
|
|
91
|
+
if method == "move" && element_copy.valid?
|
|
92
|
+
element.destroy
|
|
93
|
+
end
|
|
94
|
+
element_copy
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# List all element definitions for +self.page#page_layout+
|
|
98
|
+
def all_for_page(page)
|
|
99
|
+
raise TypeError if page.class.name != "Alchemy::Page"
|
|
100
|
+
# if page_layout has cells, collect elements from cells and group them by cellname
|
|
101
|
+
page_layout = PageLayout.get(page.page_layout)
|
|
102
|
+
if page_layout.blank?
|
|
103
|
+
logger.warn "\n++++++\nWARNING! Could not find page_layout description for page: #{page.name}\n++++++++\n"
|
|
104
|
+
return []
|
|
105
|
+
end
|
|
106
|
+
elements_for_layout = []
|
|
107
|
+
elements_for_layout += all_definitions_for(page_layout['elements'])
|
|
108
|
+
return [] if elements_for_layout.blank?
|
|
109
|
+
# all unique and limited elements from this layout
|
|
110
|
+
limited_elements = elements_for_layout.select{ |m| m["unique"] == true || (m["amount"] > 0 unless m["amount"].nil?) }
|
|
111
|
+
elements_already_on_the_page = page.elements.not_trashed
|
|
112
|
+
# delete all elements from the elements that could be placed that are unique or limited and already and the page
|
|
113
|
+
elements_counts = Hash.new(0)
|
|
114
|
+
elements_already_on_the_page.each { |e| elements_counts[e.name] += 1 }
|
|
115
|
+
limited_elements.each do |limited_element|
|
|
116
|
+
next if elements_counts[limited_element["name"]] == 0
|
|
117
|
+
if limited_element["unique"]
|
|
118
|
+
elements_for_layout.delete(limited_element) if elements_counts[limited_element["name"]] > 0
|
|
119
|
+
next
|
|
120
|
+
end
|
|
121
|
+
unless limited_element["amount"].nil?
|
|
122
|
+
elements_for_layout.delete(limited_element) if elements_counts[limited_element["name"]] >= limited_element["amount"]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
elements_for_layout
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def all_definitions_for(element_names)
|
|
129
|
+
return [] if element_names.blank?
|
|
130
|
+
if element_names.to_s == "all"
|
|
131
|
+
definitions
|
|
132
|
+
else
|
|
133
|
+
definitions.select { |e| element_names.include? e['name'] }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# This methods does a copy of source and all depending contents and all of their depending essences.
|
|
138
|
+
#
|
|
139
|
+
# == Options
|
|
140
|
+
#
|
|
141
|
+
# You can pass a differences Hash as second option to update attributes for the copy.
|
|
142
|
+
#
|
|
143
|
+
# == Example
|
|
144
|
+
#
|
|
145
|
+
# @copy = Alchemy::Element.copy(@element, {:public => false})
|
|
146
|
+
# @copy.public? # => false
|
|
147
|
+
#
|
|
148
|
+
def copy(source, differences = {})
|
|
149
|
+
attributes = source.attributes.except(
|
|
150
|
+
"id",
|
|
151
|
+
"position",
|
|
152
|
+
"folded",
|
|
153
|
+
"created_at",
|
|
154
|
+
"updated_at",
|
|
155
|
+
"creator_id",
|
|
156
|
+
"updater_id",
|
|
157
|
+
"cell_id"
|
|
158
|
+
).merge(differences.stringify_keys)
|
|
159
|
+
element = self.create!(attributes.merge(:create_contents_after_create => false))
|
|
160
|
+
source.contents.each do |content|
|
|
161
|
+
new_content = Content.copy(content, :element_id => element.id)
|
|
162
|
+
new_content.move_to_bottom
|
|
163
|
+
end
|
|
164
|
+
element
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# List all elements from page_layout
|
|
168
|
+
def elements_for_layout(layout)
|
|
169
|
+
elements = []
|
|
170
|
+
layout_elements = PageLayout.get(layout)["elements"]
|
|
171
|
+
return Element.descriptions if layout_elements == "all"
|
|
172
|
+
Element.descriptions.each do |element|
|
|
173
|
+
if layout_elements.include?(element["name"])
|
|
174
|
+
elements << element
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
elements
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def get_from_clipboard(clipboard)
|
|
181
|
+
return nil if clipboard.blank?
|
|
182
|
+
find_by_id(clipboard[:element_id])
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def all_from_clipboard(clipboard)
|
|
186
|
+
return [] if clipboard.nil?
|
|
187
|
+
find_all_by_id(clipboard.collect { |i| i[:id] })
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def all_from_clipboard_for_page(clipboard, page)
|
|
191
|
+
return [] if clipboard.nil? || page.nil?
|
|
192
|
+
allowed_elements = all_for_page(page)
|
|
193
|
+
clipboard_elements = all_from_clipboard(clipboard)
|
|
194
|
+
allowed_element_names = allowed_elements.collect { |e| e['name'] }
|
|
195
|
+
clipboard_elements.select { |ce| allowed_element_names.include?(ce.name) }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
38
199
|
|
|
39
200
|
# Returns next public element from same page.
|
|
40
201
|
# Pass an element name to get next of this kind.
|
|
@@ -61,9 +222,10 @@ module Alchemy
|
|
|
61
222
|
end
|
|
62
223
|
end
|
|
63
224
|
|
|
64
|
-
# Trashing an element means nullifying its position and unpublishing it.
|
|
225
|
+
# Trashing an element means nullifying its position, folding and unpublishing it.
|
|
65
226
|
def trash
|
|
66
227
|
self.update_column(:public, false)
|
|
228
|
+
self.update_column(:folded, true)
|
|
67
229
|
self.remove_from_list
|
|
68
230
|
end
|
|
69
231
|
|
|
@@ -71,10 +233,6 @@ module Alchemy
|
|
|
71
233
|
self.position.nil?
|
|
72
234
|
end
|
|
73
235
|
|
|
74
|
-
def folded?
|
|
75
|
-
self.trashed? || self.read_attribute(:folded)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
236
|
def content_by_name(name)
|
|
79
237
|
self.contents.find_by_name(name)
|
|
80
238
|
end
|
|
@@ -121,135 +279,6 @@ module Alchemy
|
|
|
121
279
|
contents.find_by_name(rss_title['name'])
|
|
122
280
|
end
|
|
123
281
|
|
|
124
|
-
# Builds a new element as described in +/config/alchemy/elements.yml+
|
|
125
|
-
def self.new_from_scratch(attributes)
|
|
126
|
-
attributes.stringify_keys!
|
|
127
|
-
return Element.new if attributes['name'].blank?
|
|
128
|
-
element_descriptions = Element.descriptions
|
|
129
|
-
return if element_descriptions.blank?
|
|
130
|
-
element_name = attributes['name'].split('#').first
|
|
131
|
-
element_scratch = element_descriptions.detect { |m| m["name"] == element_name }
|
|
132
|
-
if element_scratch
|
|
133
|
-
Element.new(
|
|
134
|
-
element_scratch.except('contents', 'available_contents', 'display_name', 'amount').merge({
|
|
135
|
-
:page_id => attributes['page_id']
|
|
136
|
-
})
|
|
137
|
-
)
|
|
138
|
-
else
|
|
139
|
-
raise "Element description for #{element_name} not found. Please check your elements.yml"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# Builds a new element as described in +/config/alchemy/elements.yml+ and saves it
|
|
144
|
-
def self.create_from_scratch(attributes)
|
|
145
|
-
element = Element.new_from_scratch(attributes)
|
|
146
|
-
element.save if element
|
|
147
|
-
return element
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# pastes a element from the clipboard in the session to page
|
|
151
|
-
def self.paste_from_clipboard(page_id, element, method, position)
|
|
152
|
-
copy = self.copy(element, :page_id => page_id)
|
|
153
|
-
copy.insert_at(position)
|
|
154
|
-
if method == "move" && copy.valid?
|
|
155
|
-
element.destroy
|
|
156
|
-
end
|
|
157
|
-
copy
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# Returns the descriptions from elements.yml file.
|
|
161
|
-
# Alchemy comes with its own elements.yml file. As so called standard set.
|
|
162
|
-
# Place a elements.yml file inside your apps config/alchemy folder to define
|
|
163
|
-
# your own set of elements
|
|
164
|
-
def self.descriptions
|
|
165
|
-
if ::File.exists? "#{::Rails.root}/config/alchemy/elements.yml"
|
|
166
|
-
element_definitions = ::YAML.load_file("#{::Rails.root}/config/alchemy/elements.yml")
|
|
167
|
-
end
|
|
168
|
-
if !element_definitions
|
|
169
|
-
if ::File.exists?(::File.join(::File.dirname(__FILE__), "../../../config/alchemy/elements.yml"))
|
|
170
|
-
element_definitions = ::YAML.load_file(::File.join(::File.dirname(__FILE__), "../../../config/alchemy/elements.yml"))
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
if !element_definitions
|
|
174
|
-
raise LoadError, "Could not find elements.yml file! Please run: rails generate alchemy:scaffold"
|
|
175
|
-
end
|
|
176
|
-
element_definitions
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# List all elements for page_layout
|
|
180
|
-
def self.all_for_page(page)
|
|
181
|
-
raise TypeError if page.class.name != "Alchemy::Page"
|
|
182
|
-
# if page_layout has cells, collect elements from cells and group them by cellname
|
|
183
|
-
page_layout = PageLayout.get(page.page_layout)
|
|
184
|
-
if page_layout.blank?
|
|
185
|
-
logger.warn "\n++++++\nWARNING! Could not find page_layout description for page: #{page.name}\n++++++++\n"
|
|
186
|
-
return []
|
|
187
|
-
end
|
|
188
|
-
elements_for_layout = []
|
|
189
|
-
elements_for_layout += all_definitions_for(page_layout['elements'])
|
|
190
|
-
return [] if elements_for_layout.blank?
|
|
191
|
-
# all unique and limited elements from this layout
|
|
192
|
-
limited_elements = elements_for_layout.select{ |m| m["unique"] == true || (m["amount"] > 0 unless m["amount"].nil?) }
|
|
193
|
-
elements_already_on_the_page = page.elements
|
|
194
|
-
# delete all elements from the elements that could be placed that are unique or limited and already and the page
|
|
195
|
-
elements_counts = Hash.new(0)
|
|
196
|
-
elements_already_on_the_page.each { |e| elements_counts[e.name] += 1 }
|
|
197
|
-
limited_elements.each do |limited_element|
|
|
198
|
-
next if elements_counts[limited_element["name"]] == 0
|
|
199
|
-
if limited_element["unique"]
|
|
200
|
-
elements_for_layout.delete(limited_element) if elements_counts[limited_element["name"]] > 0
|
|
201
|
-
next
|
|
202
|
-
end
|
|
203
|
-
unless limited_element["amount"].nil?
|
|
204
|
-
elements_for_layout.delete(limited_element) if elements_counts[limited_element["name"]] >= limited_element["amount"]
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
elements_for_layout
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def self.all_definitions_for(element_names)
|
|
211
|
-
return [] if element_names.blank?
|
|
212
|
-
if element_names.to_s == "all"
|
|
213
|
-
return element_descriptions
|
|
214
|
-
else
|
|
215
|
-
return definitions.select { |e| element_names.include? e['name'] }
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
# This methods does a copy of source and all depending contents and all of their depending essences.
|
|
220
|
-
#
|
|
221
|
-
# == Options
|
|
222
|
-
#
|
|
223
|
-
# You can pass a differences Hash as second option to update attributes for the copy.
|
|
224
|
-
#
|
|
225
|
-
# == Example
|
|
226
|
-
#
|
|
227
|
-
# @copy = Alchemy::Element.copy(@element, {:public => false})
|
|
228
|
-
# @copy.public? # => false
|
|
229
|
-
#
|
|
230
|
-
def self.copy(source, differences = {})
|
|
231
|
-
attributes = source.attributes.except(
|
|
232
|
-
"id",
|
|
233
|
-
"position",
|
|
234
|
-
"folded",
|
|
235
|
-
"created_at",
|
|
236
|
-
"updated_at",
|
|
237
|
-
"creator_id",
|
|
238
|
-
"updater_id",
|
|
239
|
-
"cell_id"
|
|
240
|
-
).merge(differences.stringify_keys)
|
|
241
|
-
element = self.create!(attributes.merge(:create_contents_after_create => false))
|
|
242
|
-
source.contents.each do |content|
|
|
243
|
-
new_content = Content.copy(content, :element_id => element.id)
|
|
244
|
-
new_content.move_to_bottom
|
|
245
|
-
end
|
|
246
|
-
element
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def self.definitions
|
|
250
|
-
self.descriptions
|
|
251
|
-
end
|
|
252
|
-
|
|
253
282
|
# Returns the array with the hashes for all element contents in the elements.yml file
|
|
254
283
|
def content_descriptions
|
|
255
284
|
return nil if description.blank?
|
|
@@ -282,7 +311,6 @@ module Alchemy
|
|
|
282
311
|
def description
|
|
283
312
|
self.class.descriptions.detect { |d| d['name'] == self.name }
|
|
284
313
|
end
|
|
285
|
-
|
|
286
314
|
alias_method :definition, :description
|
|
287
315
|
|
|
288
316
|
# Human name for displaying in selectboxes and element editor views.
|
|
@@ -351,39 +379,6 @@ module Alchemy
|
|
|
351
379
|
"#{name}_#{id}"
|
|
352
380
|
end
|
|
353
381
|
|
|
354
|
-
# List all elements by from page_layout
|
|
355
|
-
def self.elements_for_layout(layout)
|
|
356
|
-
element_descriptions = Element.descriptions
|
|
357
|
-
elements = []
|
|
358
|
-
page_layout = PageLayout.get(layout)
|
|
359
|
-
layout_elements = page_layout["elements"]
|
|
360
|
-
return element_descriptions if layout_elements == "all"
|
|
361
|
-
element_descriptions.each do |element|
|
|
362
|
-
if layout_elements.include?(element["name"])
|
|
363
|
-
elements << element
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
return elements
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def self.get_from_clipboard(clipboard)
|
|
370
|
-
return nil if clipboard.blank?
|
|
371
|
-
self.find_by_id(clipboard[:element_id])
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
def self.all_from_clipboard(clipboard)
|
|
375
|
-
return [] if clipboard.nil?
|
|
376
|
-
self.find_all_by_id(clipboard.collect { |i| i[:id] })
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
def self.all_from_clipboard_for_page(clipboard, page)
|
|
380
|
-
return [] if clipboard.nil? || page.nil?
|
|
381
|
-
allowed_elements = self.all_for_page(page)
|
|
382
|
-
clipboard_elements = self.all_from_clipboard(clipboard)
|
|
383
|
-
allowed_element_names = allowed_elements.collect { |e| e['name'] }
|
|
384
|
-
clipboard_elements.select { |ce| allowed_element_names.include?(ce.name) }
|
|
385
|
-
end
|
|
386
|
-
|
|
387
382
|
# returns the collection of available essence_types that can be created for this element depending on its description in elements.yml
|
|
388
383
|
def available_contents
|
|
389
384
|
description['available_contents']
|
|
@@ -489,22 +484,19 @@ module Alchemy
|
|
|
489
484
|
end
|
|
490
485
|
alias_method :richtext_contents, :rtf_contents
|
|
491
486
|
|
|
492
|
-
# The
|
|
487
|
+
# The names of all cells from given page this element could be placed in.
|
|
493
488
|
def belonging_cellnames(page)
|
|
494
|
-
cellnames =
|
|
489
|
+
cellnames = page.cells.select { |c| c.available_elements.include?(self.name) }.collect(&:name).flatten.uniq
|
|
495
490
|
if cellnames.blank? || !page.has_cells?
|
|
496
|
-
|
|
491
|
+
['for_other_elements']
|
|
497
492
|
else
|
|
498
|
-
|
|
493
|
+
cellnames
|
|
499
494
|
end
|
|
500
495
|
end
|
|
501
496
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
def self.which_class
|
|
507
|
-
'original'
|
|
497
|
+
# returns true if the page this element is displayed on is restricted?
|
|
498
|
+
def restricted?
|
|
499
|
+
page.restricted?
|
|
508
500
|
end
|
|
509
501
|
|
|
510
502
|
private
|