alchemy_cms 2.2.4 → 2.3.rc5

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