alchemy_cms 2.4.beta2 → 2.4.rc1

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 (168) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +3 -1
  3. data/.yardopts +1 -1
  4. data/Gemfile +2 -1
  5. data/alchemy_cms.gemspec +18 -17
  6. data/app/assets/images/alchemy/ajax_loader.gif +0 -0
  7. data/app/assets/images/alchemy/alchemy-logo.png +0 -0
  8. data/app/assets/images/alchemy/icons.png +0 -0
  9. data/app/assets/images/alchemy/image_loader.gif +0 -0
  10. data/app/assets/images/alchemy/placeholder.png +0 -0
  11. data/app/assets/images/alchemy/shading.png +0 -0
  12. data/app/assets/images/alchemy/swfupload/browse_button.png +0 -0
  13. data/app/assets/images/alchemy/tabs.gif +0 -0
  14. data/app/assets/images/alchemy/ui-icons_666666_256x240.png +0 -0
  15. data/app/assets/images/sassy-ie-overlay.png +0 -0
  16. data/app/assets/javascripts/alchemy/alchemy.base.js +1 -3
  17. data/app/assets/javascripts/alchemy/alchemy.browser.js.coffee +28 -0
  18. data/app/assets/javascripts/alchemy/alchemy.jquery_loader.js +2 -2
  19. data/app/assets/javascripts/alchemy/alchemy.js +2 -0
  20. data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +79 -47
  21. data/app/assets/javascripts/alchemy/alchemy.menubar.js +12 -4
  22. data/app/assets/javascripts/alchemy/alchemy.onload.js.coffee +1 -1
  23. data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +103 -0
  24. data/app/assets/javascripts/alchemy/alchemy.swf_upload.js +1 -1
  25. data/app/assets/javascripts/alchemy/alchemy.uploader.js +4 -6
  26. data/app/assets/javascripts/alchemy/preview.js +1 -0
  27. data/app/assets/stylesheets/alchemy/admin.css.scss +25 -0
  28. data/app/assets/stylesheets/alchemy/{archive.css.scss → archive.scss} +0 -2
  29. data/app/assets/stylesheets/alchemy/{base.css.scss → base.scss} +1 -57
  30. data/app/assets/stylesheets/alchemy/{custom.css → custom.scss} +0 -0
  31. data/app/assets/stylesheets/alchemy/{dashboard.css.scss → dashboard.scss} +0 -2
  32. data/app/assets/stylesheets/alchemy/defaults.scss +5 -0
  33. data/app/assets/stylesheets/alchemy/{elements.css.scss → elements.scss} +24 -37
  34. data/app/assets/stylesheets/alchemy/{errors.css.scss → errors.scss} +0 -2
  35. data/app/assets/stylesheets/alchemy/{flash.css.scss → flash.scss} +0 -2
  36. data/app/assets/stylesheets/alchemy/{form_elements.css.scss → form_elements.scss} +39 -12
  37. data/app/assets/stylesheets/alchemy/{frame.css.scss → frame.scss} +0 -2
  38. data/app/assets/stylesheets/alchemy/{icons.css.scss → icons.scss} +20 -2
  39. data/app/assets/stylesheets/alchemy/{jquery-ui.alchemy.css.scss → jquery-ui.scss} +6 -3
  40. data/app/assets/stylesheets/alchemy/{login.css.scss → login.scss} +3 -3
  41. data/app/assets/stylesheets/alchemy/menubar.css.scss +0 -1
  42. data/app/assets/stylesheets/alchemy/{_defaults.scss → mixins.scss} +2 -39
  43. data/app/assets/stylesheets/alchemy/{modules.css.scss → modules.scss} +4 -2
  44. data/app/assets/stylesheets/alchemy/notices.scss +51 -0
  45. data/app/assets/stylesheets/alchemy/{pagination.css.scss → pagination.scss} +0 -2
  46. data/app/assets/stylesheets/alchemy/{print.css → print.css.scss} +3 -3
  47. data/app/assets/stylesheets/alchemy/search.scss +63 -0
  48. data/app/assets/stylesheets/alchemy/{sitemap.css.scss → sitemap.scss} +1 -2
  49. data/app/assets/stylesheets/alchemy/{tables.css.scss → tables.scss} +16 -3
  50. data/app/assets/stylesheets/alchemy/tinymce_content.css.scss +3 -0
  51. data/app/assets/stylesheets/alchemy/tinymce_dialog.css.scss +3 -0
  52. data/app/assets/stylesheets/alchemy/{upload.css.scss → upload.scss} +0 -2
  53. data/app/assets/stylesheets/alchemy/variables.scss +33 -0
  54. data/app/controllers/alchemy/admin/elements_controller.rb +1 -2
  55. data/app/controllers/alchemy/admin/tags_controller.rb +64 -0
  56. data/app/controllers/alchemy/base_controller.rb +8 -23
  57. data/app/controllers/alchemy/pages_controller.rb +5 -18
  58. data/app/helpers/alchemy/admin/base_helper.rb +1 -1
  59. data/app/helpers/alchemy/admin/elements_helper.rb +1 -0
  60. data/app/helpers/alchemy/elements_block_helper.rb +162 -0
  61. data/app/helpers/alchemy/elements_helper.rb +41 -3
  62. data/app/helpers/alchemy/pages_helper.rb +2 -1
  63. data/app/models/alchemy/attachment.rb +2 -1
  64. data/app/models/alchemy/element.rb +13 -10
  65. data/app/models/alchemy/essence_link.rb +11 -0
  66. data/app/models/alchemy/essence_picture.rb +15 -4
  67. data/app/models/alchemy/page.rb +23 -25
  68. data/app/models/alchemy/picture.rb +2 -2
  69. data/app/models/alchemy/tag.rb +16 -0
  70. data/app/models/alchemy/user.rb +3 -1
  71. data/app/views/alchemy/admin/attachments/_attachment.html.erb +12 -12
  72. data/app/views/alchemy/admin/attachments/edit.html.erb +10 -4
  73. data/app/views/alchemy/admin/elements/_element.html.erb +10 -13
  74. data/app/views/alchemy/admin/elements/_element_foot.html.erb +1 -1
  75. data/app/views/alchemy/admin/essence_files/edit.html.erb +12 -76
  76. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +9 -4
  77. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +1 -1
  78. data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -1
  79. data/app/views/alchemy/admin/pages/_external_link.html.erb +9 -4
  80. data/app/views/alchemy/admin/pages/configure.html.erb +22 -12
  81. data/app/views/alchemy/admin/pages/edit.html.erb +40 -40
  82. data/app/views/alchemy/admin/partials/_autocomplete_tag_list.html.erb +9 -0
  83. data/app/views/alchemy/admin/pictures/edit.html.erb +1 -1
  84. data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +11 -2
  85. data/app/views/alchemy/admin/tags/_radio_tag.html.erb +6 -0
  86. data/app/views/alchemy/admin/tags/_tag.html.erb +29 -0
  87. data/app/views/alchemy/admin/tags/edit.html.erb +41 -0
  88. data/app/views/alchemy/admin/tags/index.html.erb +46 -0
  89. data/app/views/alchemy/admin/tags/new.html.erb +16 -0
  90. data/app/views/alchemy/admin/users/_table.html.erb +18 -10
  91. data/app/views/alchemy/admin/users/_user.html.erb +2 -1
  92. data/app/views/alchemy/admin/users/index.html.erb +2 -1
  93. data/app/views/alchemy/elements/_article_view.html.erb +1 -1
  94. data/app/views/alchemy/essences/_essence_link_editor.html.erb +23 -0
  95. data/app/views/alchemy/essences/_essence_link_view.html.erb +0 -0
  96. data/app/views/alchemy/essences/_essence_picture_tools.html.erb +1 -1
  97. data/app/views/alchemy/essences/_essence_text_editor.html.erb +1 -9
  98. data/app/views/alchemy/essences/_linkable_essence_tools.html.erb +19 -0
  99. data/app/views/layouts/alchemy/admin.html.erb +1 -1
  100. data/config/alchemy/elements.yml +2 -0
  101. data/config/alchemy/modules.yml +12 -0
  102. data/config/alchemy/page_layouts.yml +2 -0
  103. data/config/authorization_rules.rb +2 -0
  104. data/config/locales/alchemy.de.yml +36 -5
  105. data/config/locales/alchemy.en.yml +3 -0
  106. data/config/routes.rb +6 -4
  107. data/db/migrate/20121026100815_alchemy_two_point_three.rb +0 -36
  108. data/db/migrate/20121113115120_create_alchemy_essence_links.rb +13 -0
  109. data/db/migrate/20121115100736_add_cached_tag_list_to_elements_pages_and_users.rb +7 -0
  110. data/db/migrate/20121116140636_add_cached_tag_list_to_alchemy_attachments.rb +5 -0
  111. data/db/migrate/20121116141016_change_alchemy_pictures_tag_list_column.rb +9 -0
  112. data/lib/alchemy/engine.rb +1 -1
  113. data/lib/alchemy/resource.rb +1 -1
  114. data/lib/alchemy/resources_helper.rb +1 -1
  115. data/lib/alchemy/upgrader.rb +17 -0
  116. data/lib/alchemy/version.rb +1 -1
  117. data/lib/alchemy_cms.rb +1 -0
  118. data/lib/rails/generators/alchemy/base.rb +41 -0
  119. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +10 -3
  120. data/lib/rails/generators/alchemy/elements/elements_generator.rb +6 -14
  121. data/lib/rails/generators/alchemy/elements/templates/editor.html.erb +8 -6
  122. data/lib/rails/generators/alchemy/elements/templates/editor.html.haml +13 -0
  123. data/lib/rails/generators/alchemy/elements/templates/editor.html.slim +13 -0
  124. data/lib/rails/generators/alchemy/elements/templates/view.html.erb +4 -4
  125. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +15 -0
  126. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +15 -0
  127. data/lib/rails/generators/alchemy/essence/essence_generator.rb +1 -1
  128. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +2 -3
  129. data/lib/rails/generators/alchemy/page_layouts/page_layouts_generator.rb +4 -13
  130. data/lib/rails/generators/alchemy/page_layouts/templates/layout.html.haml +1 -0
  131. data/lib/rails/generators/alchemy/page_layouts/templates/layout.html.slim +1 -0
  132. data/spec/controllers/pages_controller_spec.rb +41 -34
  133. data/spec/dummy/app/views/layouts/application.html.erb +51 -0
  134. data/spec/dummy/db/migrate/20121026100815_alchemy_two_point_three.rb +0 -36
  135. data/spec/dummy/db/migrate/20121113115120_create_alchemy_essence_links.rb +13 -0
  136. data/spec/dummy/db/migrate/20121115100736_add_cached_tag_list_to_elements_pages_and_users.rb +7 -0
  137. data/spec/dummy/db/migrate/20121116140636_add_cached_tag_list_to_alchemy_attachments.rb +5 -0
  138. data/spec/dummy/db/migrate/20121116141016_change_alchemy_pictures_tag_list_column.rb +9 -0
  139. data/spec/dummy/db/schema.rb +24 -45
  140. data/spec/helpers/elements_block_helper_spec.rb +135 -0
  141. data/spec/helpers/elements_helper_spec.rb +43 -5
  142. data/spec/integration/pages_controller_spec.rb +22 -18
  143. data/spec/integration/translation_integration_spec.rb +0 -15
  144. data/spec/models/element_spec.rb +44 -36
  145. data/spec/models/essence_picture_spec.rb +22 -6
  146. data/spec/models/page_spec.rb +28 -0
  147. data/spec/spec_helper.rb +8 -3
  148. data/spec/support/ci/install_phantomjs +6 -0
  149. metadata +82 -40
  150. data/app/assets/images/alchemy/gui/navi-tab.png +0 -0
  151. data/app/assets/images/alchemy/gui/shading_90.png +0 -0
  152. data/app/assets/images/alchemy/jquery-sb/select_arrow.gif +0 -0
  153. data/app/assets/images/alchemy/jquery-sb/select_arrow_bg.gif +0 -0
  154. data/app/assets/images/alchemy/jquery-sb/select_arrow_bg_hover.gif +0 -0
  155. data/app/assets/javascripts/alchemy/alchemy.preview.js +0 -98
  156. data/app/assets/stylesheets/alchemy/alchemy.css +0 -21
  157. data/app/controllers/alchemy/admin/essence_audios_controller.rb +0 -12
  158. data/app/controllers/alchemy/admin/essence_flashes_controller.rb +0 -12
  159. data/app/controllers/alchemy/admin/essence_videos_controller.rb +0 -12
  160. data/app/models/alchemy/essence_audio.rb +0 -14
  161. data/app/models/alchemy/essence_flash.rb +0 -12
  162. data/app/models/alchemy/essence_video.rb +0 -20
  163. data/app/views/alchemy/essences/_essence_audio_editor.html.erb +0 -1
  164. data/app/views/alchemy/essences/_essence_audio_view.html.erb +0 -33
  165. data/app/views/alchemy/essences/_essence_flash_editor.html.erb +0 -1
  166. data/app/views/alchemy/essences/_essence_flash_view.html.erb +0 -26
  167. data/app/views/alchemy/essences/_essence_video_editor.html.erb +0 -1
  168. data/app/views/alchemy/essences/_essence_video_view.html.erb +0 -35
@@ -125,33 +125,19 @@ module Alchemy
125
125
  end
126
126
  end
127
127
 
128
- # Handles the layout rendering
128
+ # Returns the layout to be used by the current page. This method is being
129
+ # used in PageController#show's invocation of #render.
129
130
  #
130
- # Can be used inside the controller´s +layout+ class method
131
- #
132
- # === Example:
133
- # layout :layout_for_page
134
- #
135
- # === Usage:
136
- # 1. You can pass none or false as url parameter to avoid any layout rendering.
137
- # 2. You can pass a layout name of any existing layout file in +app/views/layouts+ folder.
138
- #
139
- # If no layout name is given, Alchemy tries to render +app/views/layouts/application/+ layout.
140
- # If that is not present, Alchemy tries to render +app/views/layouts/alchemy/pages+ layout.
131
+ # It allows you to request a specific page layout by passing a 'layout' parameter
132
+ # in a request. If this parameter is set to 'none' or 'false', no layout whatsoever
133
+ # will be used to render the page; otherwise, a layout by the given name
134
+ # will be applied.
141
135
  #
142
136
  def layout_for_page
143
137
  if params[:layout] == 'none' || params[:layout] == 'false'
144
138
  false
145
- elsif !params[:layout].blank?
146
- if File.exist?(Rails.root.join('app/views/layouts', "#{params[:layout]}.html.erb"))
147
- params[:layout]
148
- else
149
- raise_not_found_error
150
- end
151
- elsif File.exist?(Rails.root.join('app/views/layouts', 'application.html.erb'))
152
- 'application'
153
139
  else
154
- 'alchemy/pages'
140
+ params[:layout] || 'application'
155
141
  end
156
142
  end
157
143
 
@@ -159,8 +145,7 @@ module Alchemy
159
145
  if exception
160
146
  logger.info "Rendering 404: #{exception.message}"
161
147
  end
162
- @page = Page.language_root_for(session[:language_id])
163
- render :file => Rails.root.join("public/404.html"), :status => 404, :layout => !@page.nil?
148
+ render :file => Rails.root.join("public/404.html"), :status => 404, :layout => false
164
149
  end
165
150
 
166
151
  # Enforce ssl for login and all admin modules.
@@ -53,7 +53,7 @@ module Alchemy
53
53
  end
54
54
  end
55
55
 
56
- protected
56
+ private
57
57
 
58
58
  def load_page
59
59
  # we need this, because of a dec_auth bug (it calls this method after the before_filter again).
@@ -136,25 +136,12 @@ module Alchemy
136
136
  end
137
137
  end
138
138
 
139
- def find_first_public(page)
140
- if page.public == true
141
- return page
142
- end
143
- page.children.each do |child|
144
- result = find_first_public(child)
145
- if result != nil
146
- return result
147
- end
148
- end
149
- return nil
150
- end
151
-
152
139
  def redirect_to_public_child
153
- @page = find_first_public(@page)
154
- if @page.blank?
155
- raise_not_found_error
156
- else
140
+ @page = @page.self_and_descendants.published.not_restricted.first
141
+ if @page
157
142
  redirect_page
143
+ else
144
+ raise_not_found_error
158
145
  end
159
146
  end
160
147
 
@@ -292,7 +292,7 @@ module Alchemy
292
292
  if content_for?(:title)
293
293
  title = content_for(:title)
294
294
  else
295
- title = t(controller_name, :scope => :libraries)
295
+ title = t(controller_name, :scope => :modules)
296
296
  end
297
297
  "Alchemy CMS - #{title}"
298
298
  end
@@ -3,6 +3,7 @@ module Alchemy
3
3
  module ElementsHelper
4
4
 
5
5
  include Alchemy::ElementsHelper
6
+ include Alchemy::ElementsBlockHelper
6
7
  include Alchemy::Admin::BaseHelper
7
8
  include Alchemy::Admin::ContentsHelper
8
9
  include Alchemy::Admin::EssencesHelper
@@ -0,0 +1,162 @@
1
+ module Alchemy
2
+ # Provides a collection of block-level helpers, allowing for a much more
3
+ # concise way of writing element view/editor partials.
4
+ #
5
+ module ElementsBlockHelper
6
+ # Base class for our block-level helpers.
7
+ #
8
+ class BlockHelper
9
+ def initialize(helpers, opts = {})
10
+ @helpers = helpers
11
+ @opts = opts
12
+ end
13
+
14
+ def opts
15
+ @opts
16
+ end
17
+
18
+ def element
19
+ opts[:element]
20
+ end
21
+
22
+ def helpers
23
+ @helpers
24
+ end
25
+ end
26
+
27
+ # Block-level helper class for element views.
28
+ #
29
+ class ElementViewHelper < BlockHelper
30
+ # Renders one of the element's contents.
31
+ #
32
+ def render(name, *args)
33
+ helpers.render_essence_view_by_name(element, name.to_s, *args)
34
+ end
35
+
36
+ # Returns one of the element's contents (ie. essence instances).
37
+ #
38
+ def content(name)
39
+ element.content_by_name(name)
40
+ end
41
+
42
+ # Returns the ingredient of one of the element's contents.
43
+ #
44
+ def ingredient(name)
45
+ element.ingredient(name)
46
+ end
47
+
48
+ # Returns true if the given content has been filled by the user.
49
+ #
50
+ def has?(name)
51
+ element.has_ingredient?(name)
52
+ end
53
+
54
+ # Return's the given content's essence.
55
+ #
56
+ def essence(name)
57
+ content(name).try(:essence)
58
+ end
59
+ end
60
+
61
+ # Block-level helper class for element editors.
62
+ #
63
+ class ElementEditorHelper < BlockHelper
64
+ def edit(name, *args)
65
+ helpers.render_essence_editor_by_name(element, name.to_s, *args)
66
+ end
67
+ end
68
+
69
+ # Block-level helper for element views. Constructs a DOM element wrapping
70
+ # your content element and provides a block helper object you can use for
71
+ # concise access to Alchemy's various helpers.
72
+ #
73
+ # === Example:
74
+ #
75
+ # <%= element_view_for(element) do |el| %>
76
+ # <%= el.render :title %>
77
+ # <%= el.render :body %>
78
+ # <%= link_to "Go!", el.ingredient(:target_url) %>
79
+ # <% end %>
80
+ #
81
+ # You can override the tag, ID and class used for the generated DOM
82
+ # element:
83
+ #
84
+ # <%= element_view_for(element, tag: 'span', id: 'my_id', class: 'thing') do |el| %>
85
+ # <%- ... %>
86
+ # <% end %>
87
+ #
88
+ # If you don't want your view to be wrapped into an extra element, simply set
89
+ # `tag` to `false`:
90
+ #
91
+ # <%= element_view_for(element, tag: false) do |el| %>
92
+ # <%- ... %>
93
+ # <% end %>
94
+ #
95
+ # @param [Alchemy::Element] element
96
+ # The element to display.
97
+ # @param [Hash] options
98
+ # Additional options.
99
+ #
100
+ # @option options :tag (:div)
101
+ # The HTML tag to be used for the wrapping element.
102
+ # @option options :id (the element's ID)
103
+ # The wrapper tag's DOM ID.
104
+ # @option options :class (the element's essence name)
105
+ # The wrapper tag's DOM class.
106
+ # @option options :tags_formatter
107
+ # A lambda used for formatting the element's tags (see Alchemy::ElementsHelper::element_tags_attributes). Set to +false+ to not include tags in the wrapper element.
108
+ #
109
+ def element_view_for(element, options = {})
110
+ options = {
111
+ :tag => :div,
112
+ :id => element_dom_id(element),
113
+ :class => element.name,
114
+ :tags_formatter => lambda { |tags| tags.join(" ") }
115
+ }.merge(options)
116
+
117
+ # capture inner template block
118
+ output = capture do
119
+ yield ElementViewHelper.new(self, :element => element) if block_given?
120
+ end
121
+
122
+ # wrap output in a useful DOM element
123
+ if tag = options.delete(:tag)
124
+ # add preview attributes
125
+ options.merge!(element_preview_code_attributes(element))
126
+
127
+ # add tags
128
+ if tags_formatter = options.delete(:tags_formatter)
129
+ options.merge!(element_tags_attributes(element, formatter: tags_formatter))
130
+ end
131
+
132
+ output = content_tag(tag, output, options)
133
+ end
134
+
135
+ # that's it!
136
+ output
137
+ end
138
+ # Block-level helper for element editors. Provides a block helper object
139
+ # you can use for concise access to Alchemy's various helpers.
140
+ #
141
+ # === Example:
142
+ #
143
+ # <%= element_editor_for(element) do |el| %>
144
+ # <%= el.edit :title %>
145
+ # <%= el.edit :body %>
146
+ # <%= el.edit :target_url %>
147
+ # <% end %>
148
+ #
149
+ # @param [Alchemy::Element] element
150
+ # The element to display.
151
+ #
152
+ def element_editor_for(element, options = {})
153
+ options = {
154
+ # nothing here yet.
155
+ }.merge(options)
156
+
157
+ capture do
158
+ yield ElementEditorHelper.new(self, :element => element)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -160,10 +160,15 @@ module Alchemy
160
160
  "#{element.name}_#{element.id}".html_safe
161
161
  end
162
162
 
163
- # Renders the data-alchemy-element HTML attribut used for the preview window hover effect.
163
+ # Renders the HTML tag attributes required for preview mode.
164
164
  def element_preview_code(element)
165
- return "" if element.nil?
166
- " data-alchemy-element='#{element.id}'".html_safe if @preview_mode && element.page == @page
165
+ tag_options(element_preview_code_attributes(element))
166
+ end
167
+
168
+ # Returns a hash containing the HTML tag attributes required for preview mode.
169
+ def element_preview_code_attributes(element)
170
+ return {} unless element.present? && @preview_mode && element.page == @page
171
+ { :'data-alchemy-element' => element.id }
167
172
  end
168
173
 
169
174
  # Returns the full url containing host, page and anchor for the given element
@@ -171,5 +176,38 @@ module Alchemy
171
176
  "#{current_server}/#{element.page.urlname}##{element_dom_id(element)}"
172
177
  end
173
178
 
179
+ # Returns the element's tags information as a string. Parameters and options
180
+ # are equivalent to {#element_tags_attributes}.
181
+ #
182
+ # @see #element_tags_attributes
183
+ #
184
+ # @return [String]
185
+ # HTML tag attributes containing the element's tag information.
186
+ #
187
+ def element_tags(element, options = {})
188
+ tag_options(element_tags_attributes(element, options))
189
+ end
190
+
191
+
192
+ # Returns the element's tags information as an attribute hash.
193
+ #
194
+ # @param [Alchemy::Element] element The element.
195
+ #
196
+ # @option options [Proc] :formatter
197
+ # ('lambda { |tags| tags.join(' ') }')
198
+ # Lambda converting array of tags to a string.
199
+ #
200
+ # @return [Hash]
201
+ # HTML tag attributes containing the element's tag information.
202
+ #
203
+ def element_tags_attributes(element, options = {})
204
+ options = {
205
+ formatter: lambda { |tags| tags.join(' ') }
206
+ }.merge(options)
207
+
208
+ return {} if !element.taggable? || element.tag_list.blank?
209
+ { :'data-element-tags' => options[:formatter].call(element.tag_list) }
210
+ end
211
+
174
212
  end
175
213
  end
@@ -3,6 +3,7 @@ module Alchemy
3
3
 
4
4
  include Alchemy::BaseHelper
5
5
  include Alchemy::ElementsHelper
6
+ include Alchemy::ElementsBlockHelper
6
7
  include Alchemy::UrlHelper
7
8
 
8
9
  def render_classes(classes=[])
@@ -478,7 +479,7 @@ module Alchemy
478
479
  Alchemy.loadAlchemyMenuBar({
479
480
  page_id: #{@page.id},
480
481
  route: '#{Alchemy.mount_point}',
481
- locale: '#{current_user.language}'
482
+ locale: '#{current_user.language || ::I18n.default_locale}'
482
483
  });
483
484
  } catch(e) {
484
485
  if(console){console.log(e)}
@@ -6,10 +6,11 @@ module Alchemy
6
6
  has_many :elements, :through => :contents
7
7
  has_many :pages, :through => :elements
8
8
 
9
- attr_accessible :uploaded_data, :name, :filename
9
+ attr_accessible :uploaded_data, :name, :filename, :tag_list
10
10
 
11
11
  stampable(:stamper_class_name => 'Alchemy::User')
12
12
 
13
+ acts_as_taggable
13
14
  has_attachment(
14
15
  :storage => :file_system,
15
16
  :file_system_path => 'uploads/attachments',
@@ -1,7 +1,10 @@
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)
4
+ FORBIDDEN_DEFINITION_ATTRIBUTES = %w(contents available_contents amount picture_gallery taggable)
5
+ SKIPPED_ATTRIBUTES_ON_COPY = %w(id position folded created_at updated_at creator_id updater_id cached_tag_list)
6
+
7
+ acts_as_taggable
5
8
 
6
9
  attr_accessible(
7
10
  :cell_id,
@@ -11,6 +14,7 @@ module Alchemy
11
14
  :page_id,
12
15
  :position,
13
16
  :public,
17
+ :tag_list,
14
18
  :unique
15
19
  )
16
20
 
@@ -149,15 +153,9 @@ module Alchemy
149
153
  # @copy.public? # => false
150
154
  #
151
155
  def copy(source, differences = {})
152
- attributes = source.attributes.except(
153
- "id",
154
- "position",
155
- "folded",
156
- "created_at",
157
- "updated_at",
158
- "creator_id",
159
- "updater_id"
160
- ).merge(differences.stringify_keys)
156
+ source.attributes.stringify_keys!
157
+ differences.stringify_keys!
158
+ attributes = source.attributes.except(*SKIPPED_ATTRIBUTES_ON_COPY).merge(differences)
161
159
  element = self.create!(attributes.merge(:create_contents_after_create => false))
162
160
  source.contents.each do |content|
163
161
  new_content = Content.copy(content, :element_id => element.id)
@@ -506,6 +504,11 @@ module Alchemy
506
504
  page.restricted?
507
505
  end
508
506
 
507
+ # Returns true if the definition of this element has a taggable true value.
508
+ def taggable?
509
+ description['taggable'] == true
510
+ end
511
+
509
512
  private
510
513
 
511
514
  # creates the contents for this element as described in the elements.yml
@@ -0,0 +1,11 @@
1
+ module Alchemy
2
+ class EssenceLink < ActiveRecord::Base
3
+
4
+ acts_as_essence(
5
+ :ingredient_column => :link
6
+ )
7
+
8
+ attr_accessible :link, :link_title, :link_class_name, :link_target
9
+
10
+ end
11
+ end
@@ -22,13 +22,24 @@ module Alchemy
22
22
  )
23
23
 
24
24
  belongs_to :picture
25
+ before_save :fix_crop_values
25
26
  before_save :replace_newlines
26
- before_save :fix_crop_from
27
27
 
28
- private
28
+ private
29
29
 
30
- def fix_crop_from
31
- write_attribute(:crop_from, self.crop_from.to_s.split('x').map { |number| number.to_i < 0 ? "0" : number }.join('x'))
30
+ def fix_crop_values
31
+ %w(crop_from crop_size).each do |crop_value|
32
+ write_attribute crop_value, normalize_crop_value(crop_value)
33
+ end
34
+ end
35
+
36
+ def normalize_crop_value(crop_value)
37
+ self.send(crop_value).to_s.split('x').map { |n| normalize_number(n) }.join('x')
38
+ end
39
+
40
+ def normalize_number(number)
41
+ number = number.to_f.round
42
+ number < 0 ? 0 : number
32
43
  end
33
44
 
34
45
  def replace_newlines