alchemy_cms 2.6.0.rc5 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/.travis.yml +1 -1
  2. data/Gemfile +2 -1
  3. data/README.md +2 -4
  4. data/alchemy_cms.gemspec +1 -1
  5. data/app/assets/fonts/alchemy/icons.eot +0 -0
  6. data/app/assets/fonts/alchemy/icons.svg +71 -0
  7. data/app/assets/fonts/alchemy/icons.ttf +0 -0
  8. data/app/assets/fonts/alchemy/icons.woff +0 -0
  9. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +6 -8
  10. data/app/assets/javascripts/alchemy/alchemy.hotkeys.js.coffee +2 -3
  11. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +3 -8
  12. data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +3 -3
  13. data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +19 -9
  14. data/app/assets/javascripts/tiny_mce/plugins/alchemy_link/editor_plugin.js +6 -7
  15. data/app/assets/stylesheets/alchemy/admin.css.scss +0 -1
  16. data/app/assets/stylesheets/alchemy/archive.scss +55 -7
  17. data/app/assets/stylesheets/alchemy/base.scss +8 -144
  18. data/app/assets/stylesheets/alchemy/defaults.scss +1 -1
  19. data/app/assets/stylesheets/alchemy/elements.scss +20 -16
  20. data/app/assets/stylesheets/alchemy/flash.scss +1 -1
  21. data/app/assets/stylesheets/alchemy/form_elements.scss +49 -42
  22. data/app/assets/stylesheets/alchemy/icon-font.css.scss +67 -0
  23. data/app/assets/stylesheets/alchemy/icons.scss +16 -4
  24. data/app/assets/stylesheets/alchemy/jquery-ui.scss +40 -26
  25. data/app/assets/stylesheets/alchemy/menubar.css.scss +1 -1
  26. data/app/assets/stylesheets/alchemy/notices.scss +6 -1
  27. data/app/assets/stylesheets/alchemy/search.scss +3 -2
  28. data/app/assets/stylesheets/alchemy/sitemap.scss +72 -13
  29. data/app/assets/stylesheets/alchemy/tables.scss +31 -24
  30. data/app/assets/stylesheets/alchemy/upload.scss +1 -1
  31. data/app/assets/stylesheets/alchemy/variables.scss +2 -1
  32. data/app/assets/stylesheets/tiny_mce/plugins/inlinepopups/skins/{alchemy → alchemy-tinymce-dialog}/window.css.scss +70 -65
  33. data/app/controllers/alchemy/admin/base_controller.rb +7 -4
  34. data/app/controllers/alchemy/admin/pictures_controller.rb +2 -0
  35. data/app/controllers/alchemy/admin/users_controller.rb +1 -1
  36. data/app/controllers/alchemy/user_sessions_controller.rb +1 -1
  37. data/app/helpers/alchemy/admin/base_helper.rb +161 -60
  38. data/app/helpers/alchemy/admin/pages_helper.rb +4 -1
  39. data/app/helpers/alchemy/elements_block_helper.rb +1 -1
  40. data/app/helpers/alchemy/elements_helper.rb +119 -31
  41. data/app/helpers/alchemy/pages_helper.rb +29 -72
  42. data/app/models/alchemy/attachment.rb +0 -2
  43. data/app/models/alchemy/content.rb +1 -1
  44. data/app/models/alchemy/language.rb +1 -0
  45. data/app/models/alchemy/page.rb +8 -8
  46. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +3 -1
  47. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  48. data/app/views/alchemy/admin/attachments/_tag_list.html.erb +25 -27
  49. data/app/views/alchemy/admin/attachments/index.html.erb +4 -1
  50. data/app/views/alchemy/admin/elements/_elements_select.html.erb +6 -6
  51. data/app/views/alchemy/admin/elements/list.js.erb +1 -1
  52. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  53. data/app/views/alchemy/admin/pages/_page_for_links.html.erb +1 -1
  54. data/app/views/alchemy/admin/pages/edit.html.erb +4 -2
  55. data/app/views/alchemy/admin/pictures/_archive.html.erb +0 -1
  56. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +2 -1
  57. data/app/views/alchemy/admin/pictures/_picture.html.erb +5 -0
  58. data/app/views/alchemy/admin/pictures/index.html.erb +1 -0
  59. data/app/views/alchemy/base/500.html.erb +26 -5
  60. data/app/views/alchemy/essences/_essence_picture_tools.html.erb +1 -1
  61. data/app/views/alchemy/essences/_linkable_essence_tools.html.erb +1 -1
  62. data/app/views/alchemy/language_links/_language.html.erb +12 -0
  63. data/app/views/alchemy/language_links/_spacer.html.erb +1 -0
  64. data/config/locales/alchemy.de.yml +7 -3
  65. data/config/locales/alchemy.en.yml +8 -3
  66. data/lib/alchemy/page_layout.rb +1 -1
  67. data/lib/alchemy/tinymce.rb +1 -1
  68. data/lib/alchemy/upgrader.rb +26 -0
  69. data/lib/alchemy/version.rb +1 -1
  70. data/lib/rails/generators/alchemy/scaffold/scaffold_generator.rb +4 -1
  71. data/lib/tasks/ferret.rake +1 -0
  72. data/spec/controllers/admin/users_controller_spec.rb +5 -5
  73. data/spec/features/admin/pages_controller_spec.rb +1 -1
  74. data/spec/helpers/admin/pages_helper_spec.rb +31 -0
  75. data/spec/helpers/pages_helper_spec.rb +60 -72
  76. data/spec/models/content_spec.rb +2 -1
  77. data/spec/models/page_layout_spec.rb +29 -0
  78. data/spec/models/page_spec.rb +33 -1
  79. data/spec/support/alchemy/test_tweaks.rb +2 -6
  80. metadata +34 -12
  81. data/app/assets/fonts/alchemy-icons.eot +0 -0
  82. data/app/assets/fonts/alchemy-icons.svg +0 -54
  83. data/app/assets/fonts/alchemy-icons.ttf +0 -0
  84. data/app/assets/fonts/alchemy-icons.woff +0 -0
  85. data/app/assets/images/alchemy/placeholder.png +0 -0
  86. data/app/assets/stylesheets/alchemy/fonts.scss +0 -46
@@ -20,17 +20,20 @@ module Alchemy
20
20
  def exception_handler(e)
21
21
  exception_logger(e)
22
22
  show_error_notice(e)
23
+ if defined?(Airbrake)
24
+ notify_airbrake(e) unless Rails.env.development? || Rails.env.test?
25
+ end
23
26
  end
24
27
 
25
28
  # Displays an error notice in the Alchemy backend.
26
29
  def show_error_notice(e)
27
- # truncate the message, because very long error messages (i.e from mysql2) causes cookie oveflow errors
28
- @notice = "Error: #{e.message[0..255]}"
29
- @trace = e.backtrace
30
+ @error = e
31
+ # truncate the message, because very long error messages (i.e from mysql2) causes cookie overflow errors
32
+ @notice = e.message[0..255]
33
+ @trace = e.backtrace[0..35]
30
34
  if request.xhr?
31
35
  render :action => "error_notice", :layout => false
32
36
  else
33
- flash.now[:error] = @notice
34
37
  render '500', :status => 500
35
38
  end
36
39
  end
@@ -17,6 +17,8 @@ module Alchemy
17
17
  @pictures = @pictures.recent
18
18
  when 'last_upload'
19
19
  @pictures = @pictures.last_upload
20
+ when 'without_tag'
21
+ @pictures = @pictures.where("cached_tag_list IS NULL OR cached_tag_list = ''")
20
22
  end
21
23
  @pictures = @pictures.find_paginated(params, pictures_per_page_for_size(@size))
22
24
  if in_overlay?
@@ -44,7 +44,7 @@ module Alchemy
44
44
 
45
45
  def update
46
46
  # User is fetched via before filter
47
- params[:user].delete(:role) unless permitted_to?(:update_role)
47
+ params[:user].delete(:roles) unless permitted_to?(:update_roles)
48
48
  if params[:user][:password].present?
49
49
  @user.update_attributes(params[:user])
50
50
  else
@@ -4,7 +4,7 @@ module Alchemy
4
4
  include Alchemy::FerretSearch
5
5
  helper 'Alchemy::Admin::Base', 'Alchemy::Pages'
6
6
 
7
- before_filter { enforce_ssl if ssl_required? && !request.ssl? }
7
+ before_filter(except: 'destroy') { enforce_ssl if ssl_required? && !request.ssl? }
8
8
  before_filter :set_translation
9
9
  before_filter :check_user_count, :only => :new
10
10
 
@@ -5,26 +5,43 @@ module Alchemy
5
5
  #
6
6
  # The most important helpers for module developers are:
7
7
  #
8
- # * toolbar
9
- # * toolbar_button
10
- # * link_to_overlay_window
11
- # * link_to_confirmation_window
8
+ # * {#toolbar}
9
+ # * {#toolbar_button}
10
+ # * {#link_to_overlay_window}
11
+ # * {#link_to_confirmation_window}
12
12
  #
13
13
  module BaseHelper
14
14
  include Alchemy::BaseHelper
15
15
 
16
- # This helper renders the link for an overlay window.
16
+ # This helper renders the link to an overlay window.
17
17
  #
18
18
  # We use this for our fancy modal overlay windows in the Alchemy cockpit.
19
19
  #
20
- # === Options:
20
+ # == Example
21
21
  #
22
- # :size [String] # String with format of "WidthxHeight". I.E. ("420x280")
23
- # :title [String] # Text for the overlay title bar.
24
- # :overflow [Boolean] # Should the dialog have overlapping content. If not, it shows scrollbars. Good for select boxes. Default false.
25
- # :resizable [Boolean] # Is the dialog window resizable? Default false.
26
- # :modal [Boolean] # Show as modal window. Default true.
27
- # :overflow [Boolean] # Should the window show overflowing content? Default true.
22
+ # <%= link_to_overlay_window('Edit', edit_product_path, {size: '200x300'}, {class: 'icon_button'}) %>
23
+ #
24
+ # @param [String] content
25
+ # The string inside the link tag
26
+ # @param [String or Hash] url
27
+ # The url of the action displayed inside the overlay window.
28
+ # @param [Hash] options
29
+ # options for the overlay window.
30
+ # @param [Hash] html_options
31
+ # HTML options passed to the <tt>link_to</tt> helper
32
+ #
33
+ # @option options [String] :size
34
+ # String with format of "WidthxHeight". I.E. ("420x280")
35
+ # @option options [String] :title
36
+ # Text for the overlay title bar.
37
+ # @option options [Boolean] :overflow (false)
38
+ # Should the dialog have overlapping content. If not, it shows scrollbars. Good for select boxes.
39
+ # @option options [Boolean] :resizable (false)
40
+ # Is the dialog window resizable?
41
+ # @option options [Boolean] :modal (true)
42
+ # Show as modal window.
43
+ # @option options [Boolean] :overflow (true)
44
+ # Should the window show overflowing content?
28
45
  #
29
46
  def link_to_overlay_window(content, url, options={}, html_options={})
30
47
  default_options = {
@@ -79,10 +96,30 @@ module Alchemy
79
96
  end
80
97
  end
81
98
 
82
- # Used by Alchemy to display a javascript driven filter for lists.
99
+ # Returns a javascript driven live filter for lists.
100
+ #
101
+ # The items must have a html +name+ attribute that holds the filterable value.
102
+ #
103
+ # == Example
104
+ #
105
+ # Given a list of items:
106
+ #
107
+ # <%= js_filter_field('#products .product') %>
83
108
  #
84
- # @param [String] a jquery compatible selector string that represents the items to filter
85
- # @param [Hash] html options passed to the input field
109
+ # <ul id="products">
110
+ # <li class="product" name="kat litter">Kat Litter</li>
111
+ # <li class="product" name="milk">Milk</li>
112
+ # </ul>
113
+ #
114
+ # @param [String] items
115
+ # A jquery compatible selector string that represents the items to filter
116
+ # @param [Hash] options
117
+ # HTML options passed to the input field
118
+ #
119
+ # @option options [String] :class ('js_filter_field')
120
+ # The css class of the <input> tag
121
+ # @option options [String or Hash] :data ({'alchemy-list-filter' => items})
122
+ # A HTML data attribute that holds the jQuery selector that represents the list to be filtered
86
123
  #
87
124
  def js_filter_field(items, options = {})
88
125
  options = {
@@ -99,17 +136,28 @@ module Alchemy
99
136
 
100
137
  # Returns a link that opens a modal confirmation to delete window.
101
138
  #
102
- # === Parameters:
103
- #
104
- # 1. The content inside the <a> tag
105
- # 2. The message that is displayed in the overlay window
106
- # 3. The url that gets opened after confirmation (Note: This is an Ajax request with a method of DELETE!)
107
- # 4. html options get passed to the link
108
- #
109
139
  # === Example:
110
140
  #
111
141
  # <%= link_to_confirmation_window('delete', 'Do you really want to delete this comment?', '/admin/comments/1') %>
112
142
  #
143
+ # @param [String] link_string
144
+ # The content inside the <a> tag
145
+ # @param [String] message
146
+ # The message that is displayed in the overlay window
147
+ # @param [String] url
148
+ # The url that gets opened after confirmation (Note: This is an Ajax request with a method of DELETE!)
149
+ # @param [Hash] html_options
150
+ # HTML options get passed to the link
151
+ #
152
+ # @option html_options [String] :title (_t(:please_confirm))
153
+ # The overlay title
154
+ # @option html_options [String] :message (message)
155
+ # The message displayed in the overlay
156
+ # @option html_options [String] :ok_label (_t("Yes"))
157
+ # The label for the ok button
158
+ # @option html_options [String] :cancel_label (_t("No"))
159
+ # The label for the cancel button
160
+ #
113
161
  def link_to_confirmation_window(link_string = "", message = "", url = "", html_options = {})
114
162
  link_to(link_string, url,
115
163
  html_options.merge(
@@ -127,19 +175,21 @@ module Alchemy
127
175
  #
128
176
  # After confirmation it proceeds to send the form's action.
129
177
  #
130
- # === Parameters:
131
- #
132
- # 1. The content inside the <a> tag
133
- # 2. The url that gets opened after confirmation
134
- # 3. Options for the Alchemy confirm overlay (See: app/assets/javascripts/alchemy/alchemy.window.js#openConfirmWindow)
135
- # 4. HTML options that get passed to the button_tag helper.
136
- #
137
- # NOTE: The method option in the html_options hash gets passed to the form_tag helper!
138
- #
139
178
  # === Example:
140
179
  #
141
180
  # <%= button_with_confirm('pay', '/admin/orders/1/pay', message: 'Do you really want to mark this order as payed?') %>
142
181
  #
182
+ # @param [String] value
183
+ # The content inside the <tt><a></tt> tag
184
+ # @param [String] url
185
+ # The url that gets opened after confirmation
186
+ # @param [Hash] options
187
+ # Options for the Alchemy confirm overlay (see also +app/assets/javascripts/alchemy/alchemy.window.js#openConfirmWindow+)
188
+ # @param [Hash] html_options
189
+ # HTML options that get passed to the +button_tag+ helper.
190
+ #
191
+ # @note The method option in the <tt>html_options</tt> hash gets passed to the <tt>form_tag</tt> helper!
192
+ #
143
193
  def button_with_confirm(value = "", url = "", options = {}, html_options = {})
144
194
  options = {
145
195
  message: _t(:confirm_to_proceed),
@@ -153,12 +203,15 @@ module Alchemy
153
203
  end
154
204
 
155
205
  # Returns an Array build for passing it to the options_for_select helper inside an essence editor partial.
156
- # Usefull for the select_values options from the render_essence_editor helpers.
157
206
  #
158
- # == Options:
207
+ # Useful for the <tt>select_values</tt> options from the {Alchemy::Admin::EssencesHelper#render_essence_editor} helpers.
159
208
  #
160
- # :from_page [String, Page] # Return only elements from this page. You can either pass a Page instance, or a page_layout name
161
- # :elements_with_name [Array, String] # Return only elements with this name(s).
209
+ # @option options [String or Page] :from_page (nil)
210
+ # Return only elements from this page. You can either pass a Page instance, or a page_layout name
211
+ # @option options [Array or String] :elements_with_name (nil)
212
+ # Return only elements with this name(s).
213
+ # @option options [String] :prompt (_t('Please choose'))
214
+ # Prompt inside the select tag.
162
215
  #
163
216
  def elements_for_essence_editor_select(options={})
164
217
  defaults = {
@@ -184,12 +237,14 @@ module Alchemy
184
237
 
185
238
  # Returns all public pages from current language as an option tags string suitable or the Rails +select_tag+ helper.
186
239
  #
187
- # === Parameters
188
- #
189
- # 1. A collection of pages so it only returns these pages and does not query the database.
190
- # 2. Pass a +Page#name+ or +Page#id+ as second parameter to be passed as selected item to the +options_for_select+ helper.
191
- # 3. The third parameter is used as prompt message in the select tag
192
- # 4. The fourth parameter is the method that is called on the page object to get the value that is passed with the params of the form.
240
+ # @param [Array]
241
+ # A collection of pages so it only returns these pages and does not query the database.
242
+ # @param [String]
243
+ # Pass a +Page#name+ or +Page#id+ as selected item to the +options_for_select+ helper.
244
+ # @param [String]
245
+ # Used as prompt message in the select tag
246
+ # @param [Symbol]
247
+ # Method that is called on the page object to get the value that is passed with the params of the form.
193
248
  #
194
249
  def pages_for_select(pages = nil, selected = nil, prompt = "", page_attribute = :id)
195
250
  result = [[prompt.blank? ? _t('Choose page') : prompt, ""]]
@@ -223,6 +278,7 @@ module Alchemy
223
278
  )
224
279
  end
225
280
 
281
+ # Renders the admin main navigation
226
282
  def admin_main_navigation
227
283
  entries = ""
228
284
  alchemy_modules.each do |alchemy_module|
@@ -231,10 +287,16 @@ module Alchemy
231
287
  entries.html_safe
232
288
  end
233
289
 
290
+ # Renders one admin main navigation entry
291
+ #
292
+ # @param [Hash] alchemy_module
293
+ # The Hash representing a Alchemy module
294
+ #
234
295
  def alchemy_main_navigation_entry(alchemy_module)
235
296
  render 'alchemy/admin/partials/main_navigation_entry', :alchemy_module => alchemy_module.stringify_keys, :navigation => alchemy_module['navigation'].stringify_keys
236
297
  end
237
298
 
299
+ # Renders the subnavigation in the admin areas
238
300
  def admin_subnavigation
239
301
  alchemy_module = module_definition_for(:controller => params[:controller], :action => 'index')
240
302
  unless alchemy_module.nil?
@@ -268,6 +330,7 @@ module Alchemy
268
330
  end
269
331
  end
270
332
 
333
+ # Returns true if the subnavigation entry is in the current params
271
334
  def admin_sub_navigation_entry_active?(entry)
272
335
  params[:controller] == entry["controller"].gsub(/^\//, '') && (params[:action] == entry["action"] || entry["nested_actions"] && entry["nested_actions"].include?(params[:action]))
273
336
  end
@@ -351,18 +414,26 @@ module Alchemy
351
414
 
352
415
  # Renders a toolbar button for the Alchemy toolbar
353
416
  #
354
- # == Options:
355
- #
356
- # :icon [String] # Icon class. See base.css.sccs for available icons, or make your own.
357
- # :label [String] # Text for button label.
358
- # :url [String] # Url for link.
359
- # :title [String] # Text for title tag.
360
- # :hotkey [String] # Keyboard shortcut for this button. I.E 'alt-n'
361
- # :overlay [Boolean] # Pass true to open the link in a modal overlay window.
362
- # :overlay_options [Hash] # Overlay options. See link_to_overlay_window helper.
363
- # :if_permitted_to [Array] # Check permission for button. [:action, :controller]. Exactly how you defined the permission in your +authorization_rules.rb+. Defaults to controller and action from button url.
364
- # :skip_permission_check [Boolean] # Skip the permission check. Default false. NOT RECOMMENDED!
365
- # :loading_indicator [Boolean] # Shows the please wait overlay while loading. Only for buttons not opening an overlay window. Default true.
417
+ # @option options [String] :icon
418
+ # Icon class. See +app/assets/stylesheets/alchemy/icons.css.sccs+ for available icons, or make your own.
419
+ # @option options [String] :label
420
+ # Text for button label.
421
+ # @option options [String] :url
422
+ # Url for link.
423
+ # @option options [String] :title
424
+ # Text for title tag.
425
+ # @option options [String] :hotkey
426
+ # Keyboard shortcut for this button. I.E +alt-n+
427
+ # @option options [Boolean] :overlay (true)
428
+ # Open the link in a modal overlay window.
429
+ # @option options [Hash] :overlay_options
430
+ # Overlay options. See link_to_overlay_window helper.
431
+ # @option options [Array] :if_permitted_to ([:action, :controller])
432
+ # Check permission for button. Exactly how you defined the permission in your +authorization_rules.rb+. Defaults to controller and action from button url.
433
+ # @option options [Boolean] :skip_permission_check (false)
434
+ # Skip the permission check. NOT RECOMMENDED!
435
+ # @option options [Boolean] :loading_indicator (true)
436
+ # Shows the please wait overlay while loading. Only for buttons not opening an overlay window.
366
437
  #
367
438
  def toolbar_button(options = {})
368
439
  options.symbolize_keys!
@@ -409,12 +480,32 @@ module Alchemy
409
480
  end
410
481
  end
411
482
 
412
- # Renders the Alchemy backend toolbar
483
+ # Renders the toolbar shown on top of the records.
413
484
  #
414
- # == Options
485
+ # == Example
415
486
  #
416
- # :buttons [Array] # Pass an Array with button options. They will be passed to toolbar_button helper. For options see toolbar_button
417
- # :search [Boolean] # Show searchfield. Default true.
487
+ # <% label_title = _t("Create #{resource_name}", default: _t('Create')) %>
488
+ # <% toolbar(
489
+ # buttons: [
490
+ # {
491
+ # icon: 'create',
492
+ # label: label_title,
493
+ # url: new_resource_path,
494
+ # title: label_title,
495
+ # hotkey: 'alt-n',
496
+ # overlay_options: {
497
+ # title: label_title,
498
+ # size: "430x400"
499
+ # },
500
+ # if_permitted_to: [:new, resource_permission_scope]
501
+ # }
502
+ # ]
503
+ # ) %>
504
+ #
505
+ # @option options [Array] :buttons ([])
506
+ # Pass an Array with button options. They will be passed to {#toolbar_button} helper.
507
+ # @option options [Boolean] :search (true)
508
+ # Show searchfield.
418
509
  #
419
510
  def toolbar(options = {})
420
511
  defaults = {
@@ -467,14 +558,24 @@ module Alchemy
467
558
 
468
559
  # Renders a textfield ready to display a datepicker
469
560
  #
470
- # Uses a HTML5 +input type="date"+ field.
471
- #
472
- # Pass a type as third option to override that. But old browsers hand this as text field anyway. So there is no need to override that.
561
+ # Uses a HTML5 <tt><input type="date"></tt> field.
473
562
  #
474
563
  # === Example
475
564
  #
476
565
  # <%= alchemy_datepicker(@person, :birthday) %>
477
566
  #
567
+ # @param [ActiveModel::Base] object
568
+ # An instance of a model
569
+ # @param [String or Symbol] method
570
+ # The attribute method to be called for the date value
571
+ #
572
+ # @option html_options [String] :type ('date')
573
+ # The type of text field
574
+ # @option html_options [String] :class ('thin_border date')
575
+ # CSS classes of the input field
576
+ # @option html_options [String] :value (object.send(method.to_sym).nil? ? nil : l(object.send(method.to_sym), :format => :datepicker))
577
+ # The value the input displays
578
+ #
478
579
  def alchemy_datepicker(object, method, html_options={})
479
580
  text_field(object.class.name.underscore.to_sym, method.to_sym, {
480
581
  :type => 'date',
@@ -1,6 +1,7 @@
1
1
  module Alchemy
2
2
  module Admin
3
3
  module PagesHelper
4
+ include Alchemy::BaseHelper
4
5
 
5
6
  def tinymce_javascript_tags
6
7
  init = Alchemy::Tinymce.init
@@ -99,7 +100,9 @@ module Alchemy
99
100
  # Returns the translated explanation of the page´s status.
100
101
  #
101
102
  def combined_page_status(page)
102
- _t(page.status.to_a.map{ |k, v| "#{k}.#{v}" }.flatten, :scope => "page_states").delete_if(&:blank?).join("<br>").html_safe
103
+ page.status.map do |state, value|
104
+ page.status_title(state)
105
+ end.delete_if(&:blank?).join("<br>").html_safe
103
106
  end
104
107
 
105
108
  end
@@ -99,7 +99,7 @@ module Alchemy
99
99
  #
100
100
  # @option options :tag (:div)
101
101
  # The HTML tag to be used for the wrapping element.
102
- # @option options :id (the element's ID)
102
+ # @option options :id (the element's dom_id)
103
103
  # The wrapper tag's DOM ID.
104
104
  # @option options :class (the element's essence name)
105
105
  # The wrapper tag's DOM class.
@@ -1,30 +1,75 @@
1
1
  module Alchemy
2
+ # This helpers are useful to render elements from pages.
3
+ #
4
+ # The most important helper for frontend developers is the {#render_elements} helper.
5
+ #
2
6
  module ElementsHelper
3
-
4
7
  include Alchemy::EssencesHelper
5
8
  include Alchemy::UrlHelper
6
9
  include Alchemy::ElementsBlockHelper
7
10
 
8
- # Renders all elements from current page.
9
- #
10
- # === Options are:
11
- #
12
- # :only => [] # A list of element names to be rendered only. Very useful if you want to render a specific element type in a special html part (e.g.. <div>) of your page and all other elements in another part.
13
- # :except => [] # A list of element names to be rendered. The opposite of the only option.
14
- # :from_page => @page # The Alchemy::Page.page_layout string from which the elements are rendered from, or you even pass a Page object.
15
- # :from_cell => nil # The Cell object from which the elements are rendered from.
16
- # :count => nil # The amount of elements to be rendered (begins with first element found)
17
- # :fallback => { # You can use the fallback option as an override. So you can take elements from a glo´bal laout page and only if the user adds an element on current page the local one gets rendered.
18
- # :for => 'ELEMENT_NAME', # The name of the element the fallback is for
19
- # :with => 'ELEMENT_NAME', # (OPTIONAL) the name of element to fallback with
20
- # :from => String || Page # Pass a page_layout name from a page the fallback elements lie on or pass the page object.
21
- # } #
22
- # :sort_by => Content#name # A Content name to sort the elements by
23
- # :reverse => boolean # Reverse the rendering order
24
- # :random => boolean # Randomize the output of elements
25
- #
26
- # === Note:
27
- # This helper also stores all pages where elements gets rendered on, so we can sweep them later if caching expires!
11
+ # Renders all elements from current page
12
+ #
13
+ # == Examples:
14
+ #
15
+ # === Render only certain elements:
16
+ #
17
+ # <header>
18
+ # <%= render_elements only: ['header', 'claim'] %>
19
+ # </header>
20
+ # <section id="content">
21
+ # <%= render_elements except: ['header', 'claim'] %>
22
+ # </section>
23
+ #
24
+ # === Render elements from global page:
25
+ #
26
+ # <footer>
27
+ # <%= render_elements from_page: 'footer' %>
28
+ # </footer>
29
+ #
30
+ # === Render elements from cell:
31
+ #
32
+ # <aside>
33
+ # <%= render_elements from_cell: 'sidebar' %>
34
+ # </aside>
35
+ #
36
+ # === Fallback to elements from global page:
37
+ #
38
+ # You can use the fallback option as an override for elements that are stored on another page.
39
+ # So you can take elements from a global page and only if the user adds an element on current page the
40
+ # local one gets rendered.
41
+ #
42
+ # 1. You have to pass the the name of the element the fallback is for as <tt>for</tt> key.
43
+ # 2. You have to pass a <tt>page_layout</tt> name or {Alchemy::Page} from where the fallback elements is taken from as <tt>from</tt> key.
44
+ # 3. You can pass the name of element to fallback with as <tt>with</tt> key. This is optional (the element name from the <tt>for</tt> key is taken as default).
45
+ #
46
+ # <%= render_elements(fallback: {
47
+ # for: 'contact_teaser',
48
+ # from: 'sidebar',
49
+ # with: 'contact_teaser'
50
+ # }) %>
51
+ #
52
+ # @param [Hash] options
53
+ # Additional options.
54
+ #
55
+ # @option options [Number] :count
56
+ # The amount of elements to be rendered (begins with first element found)
57
+ # @option options [Array or String] :except ([])
58
+ # A list of element names not to be rendered.
59
+ # @option options [Hash] :fallback
60
+ # Define elements that are rendered from another page.
61
+ # @option options [Alchemy::Cell or String] :from_cell
62
+ # The cell the elements are rendered from. You can pass a {Alchemy::Cell} name String or a {Alchemy::Cell} object.
63
+ # @option options [Alchemy::Page or String] :from_page (@page)
64
+ # The page the elements are rendered from. You can pass a page_layout String or a {Alchemy::Page} object.
65
+ # @option options [Array or String] :only ([])
66
+ # A list of element names only to be rendered.
67
+ # @option options [Boolean] :random
68
+ # Randomize the output of elements
69
+ # @option options [Boolean] :reverse
70
+ # Reverse the rendering order
71
+ # @option options [String] :sort_by
72
+ # The name of a {Alchemy::Content} to sort the elements by
28
73
  #
29
74
  def render_elements(options = {})
30
75
  default_options = {
@@ -76,26 +121,69 @@ module Alchemy
76
121
  end
77
122
  end
78
123
 
79
- # This helper renders the Element partial for either the view or the editor part.
80
- # Generate element partials with rails generate alchemy:elements
81
- def render_element(element, part = :view, options = {}, i = 1)
124
+ # This helper renders a {Alchemy::Element} partial.
125
+ #
126
+ # A element has always two partials:
127
+ #
128
+ # 1. A view partial (This is the view presented to the website visitor)
129
+ # 2. A editor partial (This is the form presented to the website editor while in page edit mode)
130
+ #
131
+ # The partials are located in <tt>app/views/alchemy/elements</tt>.
132
+ #
133
+ # == View partial naming
134
+ #
135
+ # The partials have to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with the partial part.
136
+ #
137
+ # === Example
138
+ #
139
+ # Given a headline element
140
+ #
141
+ # # elements.yml
142
+ # - name: headline
143
+ # contents:
144
+ # - name: text
145
+ # type: EssenceText
146
+ #
147
+ # Then your element view partials has to be named like:
148
+ #
149
+ # app/views/alchemy/elements/_headline_editor.html.erb
150
+ # app/views/alchemy/elements/_headline_view.html.erb
151
+ #
152
+ # === Element partials generator
153
+ #
154
+ # You can use this handy generator to let Alchemy generate the partials for you:
155
+ #
156
+ # $ rails generate alchemy:elements --skip
157
+ #
158
+ # == Usage
159
+ #
160
+ # <%= render_element(Alchemy::Element.published.named(:headline).first) %>
161
+ #
162
+ # @param [Alchemy::Element] element
163
+ # The element you want to render the view for
164
+ # @param [Symbol] part
165
+ # The type of element partial (<tt>:editor</tt> or <tt>:view</tt>) you want to render
166
+ # @param [Hash] options
167
+ # Additional options
168
+ # @param [Number] counter
169
+ # a counter
170
+ #
171
+ # @note If the view partial is not found <tt>alchemy/elements/_view_not_found.html.erb</tt> or <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
172
+ #
173
+ def render_element(element, part = :view, options = {}, counter = 1)
82
174
  begin
83
175
  if element.blank?
84
176
  warning('Element is nil')
85
177
  render :partial => "alchemy/elements/#{part}_not_found", :locals => {:name => 'nil'}
86
178
  else
87
- default_options = {
88
- :shorten_to => nil
89
- }
90
- options = default_options.merge(options)
91
179
  element.store_page(@page) if part == :view
92
180
  locals = options.delete(:locals)
93
181
  render(
94
182
  :partial => "alchemy/elements/#{element.name.underscore}_#{part}",
95
183
  :locals => {
96
184
  :element => element,
97
- :options => options,
98
- :counter => i
185
+ :counter => counter,
186
+ :options => options
99
187
  }.merge(locals || {})
100
188
  )
101
189
  end
@@ -189,7 +277,7 @@ module Alchemy
189
277
 
190
278
  # Returns the element's tags information as an attribute hash.
191
279
  #
192
- # @param [Alchemy::Element] element The element.
280
+ # @param [Alchemy::Element] element The {Alchemy::Element} you want to render the tags from.
193
281
  #
194
282
  # @option options [Proc] :formatter
195
283
  # ('lambda { |tags| tags.join(' ') }')