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.
Files changed (215) hide show
  1. data/.gitignore +1 -1
  2. data/.travis.yml +3 -4
  3. data/Gemfile +1 -0
  4. data/README.md +10 -6
  5. data/alchemy_cms.gemspec +5 -2
  6. data/app/assets/images/alchemy/icons.png +0 -0
  7. data/app/assets/images/sassy-ie-overlay.png +0 -0
  8. data/app/assets/javascripts/alchemy/alchemy.base.js +50 -59
  9. data/app/assets/javascripts/alchemy/alchemy.buttons.js +14 -4
  10. data/app/assets/javascripts/alchemy/alchemy.datepicker.js +8 -2
  11. data/app/assets/javascripts/alchemy/alchemy.elements_window.js +11 -3
  12. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +1 -1
  13. data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +14 -1
  14. data/app/assets/javascripts/alchemy/alchemy.preview.js +1 -1
  15. data/app/assets/javascripts/alchemy/alchemy.preview_window.js +12 -4
  16. data/app/assets/javascripts/alchemy/alchemy.uploader.js +4 -1
  17. data/app/assets/javascripts/alchemy/alchemy.windows.js +18 -8
  18. data/app/assets/stylesheets/alchemy/_defaults.scss +84 -120
  19. data/app/assets/stylesheets/alchemy/alchemy.css +2 -2
  20. data/app/assets/stylesheets/alchemy/archive.css.scss +288 -0
  21. data/app/assets/stylesheets/alchemy/base.css.scss +95 -390
  22. data/app/assets/stylesheets/alchemy/dashboard.css.scss +4 -4
  23. data/app/assets/stylesheets/alchemy/elements.css.scss +83 -118
  24. data/app/assets/stylesheets/alchemy/flash.css.scss +1 -1
  25. data/app/assets/stylesheets/alchemy/form_elements.css.scss +528 -0
  26. data/app/assets/stylesheets/alchemy/frame.css.scss +13 -39
  27. data/app/assets/stylesheets/alchemy/icons.css.scss +217 -228
  28. data/app/assets/stylesheets/alchemy/jquery-ui.alchemy.css.scss +48 -50
  29. data/app/assets/stylesheets/alchemy/jquery.Jcrop.css.scss +1 -1
  30. data/app/assets/stylesheets/alchemy/login.css.scss +1 -5
  31. data/app/assets/stylesheets/alchemy/menubar.css.scss +19 -29
  32. data/app/assets/stylesheets/alchemy/pagination.css.scss +3 -4
  33. data/app/assets/stylesheets/alchemy/sitemap.css.scss +81 -81
  34. data/app/assets/stylesheets/alchemy/tables.css.scss +63 -57
  35. data/app/assets/stylesheets/alchemy/tinymce_dialog.css.scss +57 -57
  36. data/app/assets/stylesheets/alchemy/upload.css.scss +6 -6
  37. data/app/assets/stylesheets/tiny_mce/plugins/inlinepopups/skins/alchemy/window.css.scss +6 -10
  38. data/app/controllers/alchemy/admin/attachments_controller.rb +5 -4
  39. data/app/controllers/alchemy/admin/base_controller.rb +1 -9
  40. data/app/controllers/alchemy/admin/contents_controller.rb +4 -6
  41. data/app/controllers/alchemy/admin/elements_controller.rb +2 -2
  42. data/app/controllers/alchemy/admin/pages_controller.rb +2 -2
  43. data/app/controllers/alchemy/admin/pictures_controller.rb +74 -15
  44. data/app/controllers/alchemy/attachments_controller.rb +8 -2
  45. data/app/controllers/alchemy/base_controller.rb +47 -5
  46. data/app/controllers/alchemy/elements_controller.rb +1 -1
  47. data/app/controllers/alchemy/messages_controller.rb +12 -12
  48. data/app/controllers/alchemy/pages_controller.rb +5 -1
  49. data/app/controllers/alchemy/pictures_controller.rb +9 -4
  50. data/app/controllers/alchemy/user_sessions_controller.rb +2 -4
  51. data/app/helpers/alchemy/admin/base_helper.rb +98 -19
  52. data/app/helpers/alchemy/admin/contents_helper.rb +2 -2
  53. data/app/helpers/alchemy/admin/elements_helper.rb +2 -3
  54. data/app/helpers/alchemy/base_helper.rb +6 -5
  55. data/app/helpers/alchemy/elements_helper.rb +2 -2
  56. data/app/helpers/alchemy/essences_helper.rb +4 -5
  57. data/app/helpers/alchemy/pages_helper.rb +15 -79
  58. data/app/helpers/alchemy/url_helper.rb +67 -0
  59. data/app/mailers/alchemy/messages.rb +1 -1
  60. data/app/mailers/alchemy/notifications.rb +1 -1
  61. data/app/models/alchemy/attachment.rb +11 -2
  62. data/app/models/alchemy/cell.rb +20 -10
  63. data/app/models/alchemy/content.rb +4 -3
  64. data/app/models/alchemy/element.rb +170 -178
  65. data/app/models/alchemy/language/code.rb +4 -1
  66. data/app/models/alchemy/message.rb +19 -3
  67. data/app/models/alchemy/page.rb +45 -40
  68. data/app/models/alchemy/picture.rb +24 -2
  69. data/app/models/alchemy/user.rb +2 -3
  70. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +12 -12
  71. data/app/views/alchemy/admin/attachments/_attachment.html.erb +1 -1
  72. data/app/views/alchemy/admin/attachments/create.js.erb +1 -0
  73. data/app/views/alchemy/admin/attachments/edit.html.erb +9 -3
  74. data/app/views/alchemy/admin/attachments/index.html.erb +3 -2
  75. data/app/views/alchemy/admin/contents/_missing.html.erb +1 -1
  76. data/app/views/alchemy/admin/contents/create.js.erb +54 -0
  77. data/app/views/alchemy/admin/contents/new.html.erb +9 -4
  78. data/app/views/alchemy/admin/elements/{_add_content.html.erb → _add_picture.html.erb} +4 -4
  79. data/app/views/alchemy/admin/elements/_elements_select.html.erb +2 -1
  80. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +1 -1
  81. data/app/views/alchemy/admin/elements/{_picture_editor.html.erb → _picture_gallery_editor.html.erb} +7 -11
  82. data/app/views/alchemy/admin/elements/fold.js.erb +46 -0
  83. data/app/views/alchemy/admin/elements/index.html.erb +24 -24
  84. data/app/views/alchemy/admin/elements/list.js.erb +11 -9
  85. data/app/views/alchemy/admin/essence_files/assign.js.erb +3 -1
  86. data/app/views/alchemy/admin/essence_pictures/destroy.js.erb +28 -0
  87. data/app/views/alchemy/admin/pages/_contactform_links.html.erb +8 -6
  88. data/app/views/alchemy/admin/pages/_external_link.html.erb +11 -9
  89. data/app/views/alchemy/admin/pages/_file_link.html.erb +10 -8
  90. data/app/views/alchemy/admin/pages/_internal_link.html.erb +14 -10
  91. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -1
  92. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  93. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +32 -21
  94. data/app/views/alchemy/admin/pages/configure.html.erb +2 -2
  95. data/app/views/alchemy/admin/pages/configure_external.html.erb +13 -13
  96. data/app/views/alchemy/admin/pages/edit.html.erb +2 -2
  97. data/app/views/alchemy/admin/pages/index.html.erb +26 -24
  98. data/app/views/alchemy/admin/pages/link.html.erb +2 -5
  99. data/app/views/alchemy/admin/partials/_upload_form.html.erb +28 -12
  100. data/app/views/alchemy/admin/pictures/_archive.html.erb +54 -0
  101. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +10 -7
  102. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +21 -22
  103. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +31 -0
  104. data/app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb +9 -0
  105. data/app/views/alchemy/admin/pictures/_picture.html.erb +36 -6
  106. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +27 -0
  107. data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +3 -1
  108. data/app/views/alchemy/admin/pictures/create.js.erb +4 -5
  109. data/app/views/alchemy/admin/pictures/edit.html.erb +26 -0
  110. data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +39 -0
  111. data/app/views/alchemy/admin/pictures/index.html.erb +81 -70
  112. data/app/views/alchemy/admin/pictures/index.js.erb +3 -0
  113. data/app/views/alchemy/admin/pictures/new.html.erb +1 -0
  114. data/app/views/alchemy/admin/resources/index.html.erb +3 -1
  115. data/app/views/alchemy/admin/users/_table.html.erb +1 -1
  116. data/app/views/alchemy/admin/users/index.html.erb +27 -23
  117. data/app/views/alchemy/elements/_article_editor.html.erb +7 -2
  118. data/app/views/alchemy/elements/_bild_editor.html.erb +1 -1
  119. data/app/views/alchemy/elements/_bild_text_editor.html.erb +6 -1
  120. data/app/views/alchemy/elements/_bild_text_view.html.erb +3 -3
  121. data/app/views/alchemy/elements/_image_mosaic_editor.html.erb +1 -1
  122. data/app/views/alchemy/elements/_image_mosaic_view.html.erb +2 -2
  123. data/app/views/alchemy/elements/_intro_image_text_view.html.erb +4 -4
  124. data/app/views/alchemy/elements/_searchresult_editor.html.erb +4 -1
  125. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +1 -1
  126. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +2 -3
  127. data/app/views/alchemy/essences/_essence_picture_tools.html.erb +1 -1
  128. data/app/views/alchemy/search/_form.html.erb +8 -0
  129. data/app/views/alchemy/search/_result.html.erb +3 -2
  130. data/app/views/alchemy/search/_results.html.erb +28 -0
  131. data/app/views/alchemy/user_sessions/leave.html.erb +4 -4
  132. data/app/views/alchemy/user_sessions/login.html.erb +1 -2
  133. data/app/views/layouts/alchemy/admin.html.erb +30 -10
  134. data/app/views/layouts/alchemy/login.html.erb +2 -39
  135. data/config/alchemy/elements.yml +1 -2
  136. data/config/alchemy/page_layouts.yml +8 -5
  137. data/config/authorization_rules.rb +27 -18
  138. data/config/initializers/localeapp.rb +9 -0
  139. data/config/locales/alchemy.de.yml +93 -56
  140. data/config/locales/alchemy.en.yml +73 -50
  141. data/config/routes.rb +3 -1
  142. data/db/migrate/20120704181529_add_upload_hash_to_alchemy_picture.rb +5 -0
  143. data/db/migrate/20120705214247_acts_as_taggable_on_migration.rb +28 -0
  144. data/db/migrate/20120728185830_add_cached_tag_list_to_alchemy_pictures.rb +5 -0
  145. data/db/migrate/20120831135441_set_alchemy_languages_country_code_default_to_empty_string.rb +9 -0
  146. data/lib/alchemy/capistrano.rb +2 -2
  147. data/lib/alchemy/essence.rb +14 -0
  148. data/lib/alchemy/page_layout.rb +0 -6
  149. data/lib/alchemy/resource.rb +9 -15
  150. data/lib/alchemy/upgrader.rb +18 -3
  151. data/lib/alchemy/version.rb +5 -1
  152. data/lib/alchemy_cms.rb +4 -1
  153. data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +16 -6
  154. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +17 -3
  155. data/lib/rails/generators/alchemy/elements/elements_generator.rb +6 -1
  156. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +10 -1
  157. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +17 -18
  158. data/lib/rails/generators/alchemy/scaffold/files/pages.html.erb +4 -2
  159. data/lib/tasks/fleximage.rake +2 -2
  160. data/spec/controllers/admin/contents_controller_spec.rb +2 -2
  161. data/spec/controllers/admin/elements_controller_spec.rb +30 -1
  162. data/spec/controllers/admin/pages_controller_spec.rb +35 -18
  163. data/spec/controllers/admin/trash_controller_spec.rb +40 -16
  164. data/spec/controllers/attachments_controller_spec.rb +62 -0
  165. data/spec/controllers/base_controller_spec.rb +43 -42
  166. data/spec/controllers/elements_controller_spec.rb +30 -0
  167. data/spec/controllers/pages_controller_spec.rb +22 -5
  168. data/spec/controllers/pictures_controller_spec.rb +82 -0
  169. data/spec/dummy/app/models/event.rb +2 -1
  170. data/spec/dummy/config/database.yml +3 -2
  171. data/spec/dummy/db/schema.rb +51 -27
  172. data/spec/factories.rb +29 -8
  173. data/spec/helpers/admin/base_helper_spec.rb +134 -21
  174. data/spec/helpers/admin/contents_helper_spec.rb +2 -2
  175. data/spec/helpers/admin/elements_helper_spec.rb +17 -9
  176. data/spec/helpers/admin/essences_helper_spec.rb +7 -6
  177. data/spec/helpers/essences_helper_spec.rb +8 -7
  178. data/spec/helpers/pages_helper_spec.rb +208 -325
  179. data/spec/helpers/url_helper_spec.rb +171 -0
  180. data/spec/integration/admin/link_overlay_spec.rb +53 -0
  181. data/spec/integration/admin/modules_integration_spec.rb +22 -26
  182. data/spec/integration/admin/pages_controller_spec.rb +10 -19
  183. data/spec/integration/admin/picture_library_integration_spec.rb +52 -0
  184. data/spec/integration/admin/resources_integration_spec.rb +68 -75
  185. data/spec/integration/pages_controller_spec.rb +70 -61
  186. data/spec/integration/security_spec.rb +3 -5
  187. data/spec/integration/translation_integration_spec.rb +56 -0
  188. data/spec/libraries/essence_spec.rb +18 -0
  189. data/spec/libraries/resource_spec.rb +101 -79
  190. data/spec/libraries/resources_helper_spec.rb +3 -0
  191. data/spec/models/content_spec.rb +63 -60
  192. data/spec/models/element_spec.rb +203 -93
  193. data/spec/models/language_spec.rb +90 -65
  194. data/spec/models/page_layout_spec.rb +37 -0
  195. data/spec/models/page_spec.rb +181 -113
  196. data/spec/models/picture_spec.rb +73 -26
  197. data/spec/models/resource_spec.rb +52 -23
  198. data/spec/support/alchemy/specs_helpers.rb +2 -0
  199. data/spec/support/image.png +0 -0
  200. data/spec/{helpers/url_helpers_spec.rb → url_helpers_spec.rb} +0 -0
  201. data/vendor/assets/javascripts/jquery_plugins/jquery.selectBoxIt.js +1909 -0
  202. data/vendor/assets/javascripts/jquery_plugins/preloadCssImages.jQuery_v5.js +152 -0
  203. metadata +106 -33
  204. data/app/assets/stylesheets/alchemy/buttons.css.scss +0 -361
  205. data/app/assets/stylesheets/alchemy/jquery.sb.css.scss +0 -260
  206. data/app/views/alchemy/admin/contents/create.js.coffee +0 -49
  207. data/app/views/alchemy/admin/elements/fold.js.coffee +0 -37
  208. data/app/views/alchemy/admin/essence_pictures/destroy.js.coffee +0 -19
  209. data/app/views/alchemy/admin/pictures/_pictures_list.html.erb +0 -16
  210. data/app/views/alchemy/admin/pictures/update.js.erb +0 -3
  211. data/spec/dummy/config/locales/en.yml +0 -5
  212. data/spec/dummy/config/locales/fo.yml +0 -5
  213. data/spec/page_layout_spec.rb +0 -35
  214. data/vendor/assets/javascripts/jquery_plugins/jquery.in-place-edit.js +0 -172
  215. data/vendor/assets/javascripts/jquery_plugins/jquery.sb.min.js +0 -14
@@ -1,7 +1,7 @@
1
1
  module Alchemy
2
2
  class Messages < ActionMailer::Base
3
3
 
4
- default :from => Alchemy::Config.get(:mailer)[:mail_from]
4
+ default :from => Alchemy::Config.get(:mailer)['mail_from']
5
5
 
6
6
  def contact_form_mail(message, mail_to, mail_from, subject)
7
7
  @message = message
@@ -1,7 +1,7 @@
1
1
  module Alchemy
2
2
  class Notifications < ActionMailer::Base
3
3
 
4
- default :from => Alchemy::Config.get(:mailer)[:mail_from]
4
+ default :from => Alchemy::Config.get(:mailer)['mail_from']
5
5
 
6
6
  def registered_user_created(user)
7
7
  @user = user
@@ -1,7 +1,12 @@
1
1
  module Alchemy
2
2
  class Attachment < ActiveRecord::Base
3
3
 
4
- attr_accessible :uploaded_data, :name
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
@@ -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) if ::File.exist?(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.update_attribute(:essence_id, new_essence.id)
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
- nil
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 name of the cell the element could be placed in.
487
+ # The names of all cells from given page this element could be placed in.
493
488
  def belonging_cellnames(page)
494
- cellnames = Cell.names_for_element(name)
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
- return ['for_other_elements']
491
+ ['for_other_elements']
497
492
  else
498
- return cellnames
493
+ cellnames
499
494
  end
500
495
  end
501
496
 
502
- def which_instance
503
- 'original'
504
- end
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