alchemy_cms 2.0.rc6 → 2.0

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 (39) hide show
  1. data/.travis.yml +2 -1
  2. data/LICENSE +24 -619
  3. data/README.md +38 -36
  4. data/alchemy_cms.gemspec +1 -1
  5. data/app/controllers/admin/elements_controller.rb +3 -2
  6. data/app/controllers/admin/pages_controller.rb +20 -14
  7. data/app/controllers/admin/trash_controller.rb +4 -0
  8. data/app/controllers/pages_controller.rb +27 -16
  9. data/app/helpers/admin/elements_helper.rb +55 -0
  10. data/app/helpers/alchemy_helper.rb +0 -45
  11. data/app/helpers/elements_helper.rb +8 -1
  12. data/app/helpers/pages_helper.rb +0 -10
  13. data/app/models/element.rb +39 -5
  14. data/app/models/page.rb +27 -7
  15. data/app/sweepers/pages_sweeper.rb +0 -9
  16. data/app/views/admin/pages/update.js.erb +15 -1
  17. data/app/views/admin/partials/_upload_form.html.erb +2 -2
  18. data/app/views/elements/_contactform_view.html.erb +10 -23
  19. data/app/views/elements/_searchresult_view.html.erb +47 -40
  20. data/app/views/essences/_essence_html_view.html.erb +1 -1
  21. data/app/views/pages/show.rss.builder +20 -25
  22. data/assets/javascripts/alchemy.js +2 -2
  23. data/assets/stylesheets/elements.css +1 -1
  24. data/assets/stylesheets/standard_set.css +84 -14
  25. data/config/alchemy/elements.yml +2 -0
  26. data/config/alchemy/page_layouts.yml +1 -0
  27. data/config/locales/de.yml +5 -5
  28. data/lib/alchemy/version.rb +1 -1
  29. data/lib/rails/generators/alchemy/plugin/templates/config.yml +3 -3
  30. data/spec/controllers/admin/trash_controller_spec.rb +22 -0
  31. data/spec/controllers/pages_controller_spec.rb +39 -0
  32. data/spec/dummy/db/schema.rb +10 -9
  33. data/spec/factories.rb +5 -0
  34. data/spec/helpers/elements_helper_spec.rb +7 -0
  35. data/spec/integration/pages_controller_spec.rb +1 -1
  36. data/spec/models/element_spec.rb +51 -5
  37. data/spec/models/page_spec.rb +70 -10
  38. metadata +10 -7
  39. data/TODO.txt +0 -1
@@ -488,16 +488,6 @@ module PagesHelper
488
488
  render :partial => "cells/#{name}", :locals => {:cell => cell}
489
489
  end
490
490
 
491
- # Renders all element partials from given cell.
492
- def render_cell_elements(cell)
493
- return warning("No cell given.") if cell.blank?
494
- ret = ""
495
- cell.elements.each do |element|
496
- ret << render_element(element)
497
- end
498
- ret.html_safe
499
- end
500
-
501
491
  # Returns true or false if no elements are in the cell found by name.
502
492
  def cell_empty?(name)
503
493
  cell = @page.cells.find_by_name(name)
@@ -52,9 +52,11 @@ class Element < ActiveRecord::Base
52
52
 
53
53
  # nullifies the page_id aka. trashs it.
54
54
  def trash
55
- self.page_id = nil
56
- self.folded = true
57
- self.save(false)
55
+ self.update_attributes({
56
+ :page_id => nil,
57
+ :folded => true,
58
+ :public => false
59
+ })
58
60
  end
59
61
 
60
62
  def trashed?
@@ -77,9 +79,39 @@ class Element < ActiveRecord::Base
77
79
  self.contents.find_all_by_essence_type(essence_type)
78
80
  end
79
81
 
82
+ # Returns the content that is marked as rss title.
83
+ #
84
+ # Mark a content as rss title in your +elements.yml+ file:
85
+ #
86
+ # - name: news
87
+ # contents:
88
+ # - name: headline
89
+ # type: EssenceText
90
+ # rss_title: true
91
+ #
92
+ def content_for_rss_title
93
+ rss_title = content_descriptions.detect { |c| c['rss_title'] }
94
+ contents.find_by_name(rss_title['name'])
95
+ end
96
+
97
+ # Returns the content that is marked as rss description.
98
+ #
99
+ # Mark a content as rss description in your +elements.yml+ file:
100
+ #
101
+ # - name: news
102
+ # contents:
103
+ # - name: body
104
+ # type: EssenceRichtext
105
+ # rss_description: true
106
+ #
107
+ def content_for_rss_description
108
+ rss_title = content_descriptions.detect { |c| c['rss_description'] }
109
+ contents.find_by_name(rss_title['name'])
110
+ end
111
+
80
112
  # Inits a new element for page as described in /config/alchemy/elements.yml from element_name
81
113
  def self.new_from_scratch(attributes)
82
- attributes.stringify_keys!
114
+ attributes.stringify_keys!
83
115
  return Element.new if attributes['name'].blank?
84
116
  element_descriptions = Element.descriptions
85
117
  return if element_descriptions.blank?
@@ -162,8 +194,9 @@ class Element < ActiveRecord::Base
162
194
 
163
195
  # returns the description of the element with my name in element.yml
164
196
  def description
165
- Element.descriptions.detect{ |d| d['name'] == self.name }
197
+ self.class.descriptions.detect{ |d| d['name'] == self.name }
166
198
  end
199
+ alias_method :definition, :description
167
200
 
168
201
  # Human name for displaying in selectboxes and element editor views.
169
202
  # The name is beeing translated from elements name value as described in config/alchemy/elements.yml
@@ -379,6 +412,7 @@ private
379
412
 
380
413
  # List all elements for page_layout
381
414
  def self.all_for_page(page)
415
+ raise TypeError if page.class != Page
382
416
  # if page_layout has cells, collect elements from cells and group them by cellname
383
417
  page_layout = Alchemy::PageLayout.get(page.page_layout)
384
418
  if page_layout.blank?
@@ -35,6 +35,7 @@ class Page < ActiveRecord::Base
35
35
  scope :language_roots, where(:language_root => true)
36
36
  scope :layoutpages, where(:layoutpage => true)
37
37
  scope :all_locked, where(:locked => true)
38
+ scope :not_locked, where(:locked => false)
38
39
  scope :visible, where(:visible => true)
39
40
  scope :public, where(:public => true)
40
41
  scope :accessable, where(:restricted => false)
@@ -43,10 +44,13 @@ class Page < ActiveRecord::Base
43
44
  where(:language_root => true).where("language_code IN ('#{Language.all_codes_for_published.join('\',\'')}')").where(:public => true)
44
45
  }
45
46
  scope :all_last_edited_from, lambda { |user| where(:updater_id => user.id).order('updated_at DESC').limit(5) }
46
-
47
- # Returns all pages for langugae that are not locked and public.
47
+
48
+ # Returns all pages that have the given language_id
49
+ scope :with_language, lambda { |language_id| where(:language_id => language_id) }
50
+
51
+ # Returns all pages that are not locked and public.
48
52
  # Used for flushing all page caches at once.
49
- scope :flushables, lambda { |language_id| where({:public => true, :locked => false, :language_id => language_id}) }
53
+ scope :flushables, public.not_locked
50
54
 
51
55
  scope :contentpages, where("pages.layoutpage = 0 AND pages.parent_id IS NOT NULL")
52
56
 
@@ -59,12 +63,17 @@ class Page < ActiveRecord::Base
59
63
  # :count => Integer # Limit the count of returned elements
60
64
  # :offset => Integer # Starts with an offset while returning elements
61
65
  # :random => Boolean # Returning elements randomly shuffled
66
+ # :from_cell => Cell # Returning elements from given cell
62
67
  #
63
68
  # Returns only public elements by default.
64
69
  # Pass true as second argument to get all elements.
65
70
  #
66
71
  def find_selected_elements(options = {}, show_non_public = false)
67
- elements = self.elements
72
+ if options[:from_cell].class.name == 'Cell'
73
+ elements = options[:from_cell].elements
74
+ else
75
+ elements = self.elements
76
+ end
68
77
  if !options[:only].blank?
69
78
  elements = self.elements.named(options[:only])
70
79
  elsif !options[:except].blank?
@@ -82,13 +91,24 @@ class Page < ActiveRecord::Base
82
91
  def find_elements(options = {}, show_non_public = false) #:nodoc:
83
92
  # TODO: What is this? A Kind of proxy method? Why not rendering the elements directly if you already have them????
84
93
  if !options[:collection].blank? && options[:collection].is_a?(Array)
85
- all_elements = options[:collection]
94
+ return options[:collection]
86
95
  else
87
- all_elements = find_selected_elements(options, show_non_public)
96
+ find_selected_elements(options, show_non_public)
88
97
  end
89
- all_elements
90
98
  end
91
99
 
100
+ # Returns all elements that should be feeded via rss.
101
+ #
102
+ # Define feedable elements in your +page_layouts.yml+:
103
+ #
104
+ # - name: news
105
+ # feed: true
106
+ # feed_elements: [element_name, element_2_name]
107
+ #
108
+ def feed_elements
109
+ elements.find_all_by_name(definition['feed_elements'])
110
+ end
111
+
92
112
  def elements_grouped_by_cells
93
113
  group = ActiveSupport::OrderedHash.new
94
114
  cells.each { |cell| group[cell] = cell.elements }
@@ -34,13 +34,4 @@ private
34
34
  end
35
35
  end
36
36
 
37
- def expire_page(page)
38
- if multi_language?
39
- path = "#{page.language_code}/#{page.urlname_was}"
40
- else
41
- path = page.urlname_was
42
- end
43
- expire_action(path) unless page.do_not_sweep
44
- end
45
-
46
37
  end
@@ -1,19 +1,33 @@
1
1
  (function($) {
2
+
2
3
  Alchemy.closeCurrentWindow();
4
+
3
5
  <%- if request.referer.include?('edit') -%>
6
+
4
7
  Alchemy.reloadPreview();
5
8
  $('#<%= dom_id(@page) -%>_status').replaceWith('<%= escape_javascript(render(:partial => "page_status")) -%>');
9
+
6
10
  <%- else -%>
11
+
7
12
  $('#<%= dom_id(@page) -%> > .sitemap_page > .sitemap_sitename .sitemap_pagename_link').text('<%= @page.name -%>');
13
+
8
14
  <%- if @page.locked? && @page.locker == current_user -%>
9
15
  $('#locked_page_<%= @page.id -%> > a').text('<%= @page.name -%>');
10
16
  <%- end -%>
17
+
11
18
  $('#page_<%= @page.id -%>_infos').html('<%= escape_javascript(render(:partial => "page_infos", :locals => {:page => @page})) -%>');
19
+
12
20
  <%- if @page.restricted? -%>
21
+
13
22
  $('#<%= dom_id(@page) -%> .page_status:nth-child(3)').addClass('restricted', 'not_restricted').removeClass('not_restricted');
23
+
14
24
  <%- else -%>
25
+
15
26
  $('#<%= dom_id(@page) -%> .page_status:nth-child(3)').addClass('not_restricted').removeClass('restricted');
16
27
  <%- end -%>
28
+
17
29
  <%- end -%>
18
- Alchemy.growl('<%= @notice -%>');
30
+
31
+ Alchemy.growl("<%= @notice -%>");
32
+
19
33
  })(jQuery);
@@ -22,7 +22,7 @@
22
22
  <%- end -%>
23
23
  <p style="margin-top: 8px" id="choose_alternative_uploader">
24
24
  <small>
25
- <%= raw _('If you have any problems using the Flash® uploader you can switch to the %{link}') % {:link => %(<a href="#" onclick="jQuery('#choose_alternative_uploader').hide();jQuery('#alternativeUpload').show();jQuery('#SWFUpload_0').hide();" style="text-decoration: underline">%{value}</a>) % {:value => _('regular method')}} %>
25
+ <%= raw _('If you have any problems using the Flash® uploader you can switch to the %{link}') % {:link => %(<a href="#" onclick="jQuery('#choose_alternative_uploader').hide();jQuery('#alternativeUpload').show();jQuery('object.swfupload').hide();" style="text-decoration: underline">%{value}</a>) % {:value => _('regular method')}} %>
26
26
  </small>
27
27
  </p>
28
28
  <div id="swfUploadFlashError" style="display: none">
@@ -46,7 +46,7 @@
46
46
  <p>
47
47
  <small>
48
48
  <a href="#"
49
- onclick="jQuery('#choose_alternative_uploader').show();jQuery('#alternativeUpload').hide();jQuery('#SWFUpload_0').show();"
49
+ onclick="jQuery('#choose_alternative_uploader').show();jQuery('#alternativeUpload').hide();jQuery('object.swfupload').show();"
50
50
  style="text-decoration: underline">
51
51
  <%= _('Switch to Flash® Uploader') %>
52
52
  </a>
@@ -1,13 +1,11 @@
1
- <%= form_for(@mail ||= Mail.new, :html => {:id => "contact", "data-alchemy-element" => (@preview_mode ? element.id : nil)}) do |f| %>
1
+ <%= form_for(@message ||= Message.new, :html => {:id => "contact", "data-alchemy-element" => (@preview_mode ? element.id : nil)}) do |f| %>
2
2
  <%= f.error_messages %>
3
3
  <%= f.hidden_field "contact_form_id", :value => element.id %>
4
4
  <%= hidden_field_tag "mail_to", params[:mail_to] %>
5
5
  <table class="contactform">
6
6
  <tr>
7
7
  <td class="label">
8
- <label for="mail_salutation">
9
- <%= t('alchemy.contactform.labels.salutation') %>
10
- </label>
8
+ <%= f.label :salutation, t('alchemy.contactform.labels.salutation') %>
11
9
  </td>
12
10
  <td class="field">
13
11
  <%= f.select(
@@ -23,9 +21,7 @@
23
21
  </tr>
24
22
  <tr>
25
23
  <td class="label">
26
- <label for="mail_firstname">
27
- <%= t('alchemy.contactform.labels.firstname') %>
28
- </label>
24
+ <%= f.label :firstname, t('alchemy.contactform.labels.firstname') %>
29
25
  </td>
30
26
  <td class="field">
31
27
  <%= f.text_field(:firstname, :class => "field") %>
@@ -33,9 +29,7 @@
33
29
  </tr>
34
30
  <tr>
35
31
  <td class="label">
36
- <label for="mail_lastname">
37
- <%= t('alchemy.contactform.labels.lastname') %>
38
- </label><small>*</small>
32
+ <%= f.label :lastname, (t('alchemy.contactform.labels.lastname') + '<small>*</small>').html_safe %>
39
33
  </td>
40
34
  <td class="field">
41
35
  <%= f.text_field(:lastname, :class => "field") %>
@@ -43,9 +37,7 @@
43
37
  </tr>
44
38
  <tr>
45
39
  <td class="label">
46
- <label for="mail_address">
47
- <%= t('alchemy.contactform.labels.address') %>
48
- </label>
40
+ <%= f.label :address, t('alchemy.contactform.labels.address') %>
49
41
  </td>
50
42
  <td class="field">
51
43
  <%= f.text_field :address, :class => 'field' %>
@@ -53,9 +45,7 @@
53
45
  </tr>
54
46
  <tr>
55
47
  <td class="label">
56
- <label for="mail_zip">
57
- <%= t('alchemy.contactform.labels.zip') %>
58
- </label>
48
+ <%= f.label :zip, t('alchemy.contactform.labels.zip') %>
59
49
  </td>
60
50
  <td class="field">
61
51
  <%= f.text_field :zip, :class => 'field short' %>
@@ -64,9 +54,7 @@
64
54
  </tr>
65
55
  <tr>
66
56
  <td class="label">
67
- <label for="mail_phone">
68
- <%= t('alchemy.contactform.labels.phone') %>
69
- </label>
57
+ <%= f.label :phone, t('alchemy.contactform.labels.phone') %>
70
58
  </td>
71
59
  <td class="field">
72
60
  <%= f.text_field :phone, :class => 'field' %>
@@ -74,9 +62,7 @@
74
62
  </tr>
75
63
  <tr>
76
64
  <td class="label">
77
- <label for="mail_email">
78
- <%= t('alchemy.contactform.labels.email') %>
79
- </label><small>*</small>
65
+ <%= f.label :email, (t('alchemy.contactform.labels.email') + '<small>*</small>').html_safe %>
80
66
  </td>
81
67
  <td class="field">
82
68
  <%= f.text_field :email, :class => 'field' %>
@@ -84,8 +70,9 @@
84
70
  </tr>
85
71
  </table>
86
72
  <div id="message">
87
- <%= f.text_area :message %>
73
+ <%= f.text_area :message %>
88
74
  </div>
75
+ <p class="foot_notice">*) <%= t('alchemy.contactform.labels.mandatory_fields') %></p>
89
76
  <p class="right">
90
77
  <%= f.button t('alchemy.contactform.labels.send'), :name => nil, :class => 'button' %>
91
78
  </p>
@@ -1,42 +1,49 @@
1
1
  <div class="searchresult" id="<%= element_dom_id(element) %>" <%= element_preview_code(element) -%>>
2
-
3
- <%= form_tag show_page_path(:urlname => "suche", :lang => @page.language_code), :method => :get do %>
4
- <%= text_field_tag "query", params[:query], :class => 'field' %>
5
- <%= submit_tag _("search"), :name => nil %>
6
- <%- end -%>
7
-
8
- <%- if !@text_search_results.blank? || !@rtf_search_results.blank? -%>
9
-
10
- <h2>
11
- <%= t('alchemy.search.result_heading', :query => h(params[:query]), :count => @rtf_search_results.length + @text_search_results.length) %>
12
- </h2>
13
-
14
- <%- all_results = (@text_search_results + @rtf_search_results).sort{|y, x| x.ferret_score <=> y.ferret_score} -%>
15
-
16
- <div class="search_results">
17
- <ol>
18
- <%- all_results.each do |result| -%>
19
- <%- element = Content.find_by_essence_id_and_essence_type(result.id, result.class.to_s).element -%>
20
- <%- page = element.nil? ? nil : element.page -%>
21
- <li>
22
- <%= _('Excerpt') %>:
23
- <%= raw result.highlight(params[:query], {
24
- :field => (result.class == EssenceRichtext ? :stripped_body : :body),
25
- :num_excerpts => 1,
26
- :pre_tag => "<strong>",
27
- :post_tag => "</strong>"
28
- }) %><br/>
29
- <%- unless page.nil? -%>
30
- <span class="search_result_site"><%= _('Page') %>: </span><%= link_to page.urlname, show_page_path(:urlname => page.urlname, :lang => page.language) %>
31
- <%- end -%>
32
- </li>
33
- <%- end -%>
34
- </ol>
35
- </div>
36
-
37
- <%- elsif !params[:query].blank? -%>
38
-
39
- <h2><%= t('alchemy.search.no_results') %></h2>
40
-
41
- <%- end -%>
2
+
3
+ <%= form_tag show_page_path(:urlname => "suche", :lang => @page.language_code), :method => :get do %>
4
+ <%= text_field_tag "query", params[:query], :class => 'field' %>
5
+ <%= submit_tag _("search"), :name => nil %>
6
+ <%- end -%>
7
+
8
+ <%- if !@search_results.blank? -%>
9
+
10
+ <h2>
11
+ <%= t('alchemy.search.result_heading') % { :query => h(params[:query]), :count => @search_results.count } %>
12
+ </h2>
13
+
14
+ <div class="search_results">
15
+ <ul>
16
+ <%- @search_results.each do |result| -%>
17
+ <%- element = Content.find_by_essence_id_and_essence_type(result.id, result.class.to_s).element -%>
18
+ <%- page = element.nil? ? nil : element.page -%>
19
+ <li>
20
+ <%- unless page.nil? -%>
21
+ <h3>
22
+ <span class="search_result_site"><%= _('Page') %>:</span>
23
+ <%- if multi_language? -%>
24
+ <%= link_to page.name, show_page_path(:urlname => page.urlname, :lang => page.language_code) %>
25
+ <span class="search_result_language">(<%= page.language_code.upcase %>)</span>
26
+ <%- else -%>
27
+ <%= link_to page.name, show_page_path(:urlname => page.urlname) %>
28
+ <%- end -%>
29
+ </h3>
30
+ <%- end -%>
31
+ <h4><%= _('Excerpt') %>:</h4>
32
+ <%- result.highlight(
33
+ "*#{params[:query]}*", {
34
+ :field => (result.class == EssenceRichtext ? :stripped_body : :body)
35
+ }
36
+ ).each do |highlight| -%>
37
+ <p><%= sanitize highlight %></p>
38
+ <%- end -%>
39
+ </li>
40
+ <%- end -%>
41
+ </ul>
42
+ </div>
43
+
44
+ <%- elsif !params[:query].blank? -%>
45
+
46
+ <h2><%= t('alchemy.search.no_results') %></h2>
47
+
48
+ <%- end -%>
42
49
  </div>
@@ -1 +1 @@
1
- <%= content.essence.source %>
1
+ <%= raw content.essence.source %>
@@ -1,27 +1,22 @@
1
- xml.instruct! :xml, :version => "1.0"
1
+ xml.instruct! :xml, :version => "1.0"
2
2
  xml.rss :version => "2.0" do
3
- xml.channel do
4
- xml.title @page.title
5
- xml.description @page.meta_description
6
- if multi_language?
7
- xml.link show_page_url(:urlname => @page.urlname, :lang => session[:language_id])
8
- else
9
- xml.link show_page_url(:urlname => @page.urlname)
10
- end
11
-
12
- for element in @page.elements.find_all_by_name('news')
13
- xml.item do
14
- xml.title render_essence_view_by_name(element, 'headline')
15
- xml.description render_essence_view_by_name(element, 'text')
16
- xml.pubDate render_essence_view_by_name(element, 'date', :date_format => :rfc822)
17
- if multi_language?
18
- xml.link show_page_url(:urlname => element.page.urlname, :anchor => element_dom_id(element), :lang => session[:language_id])
19
- xml.guid show_page_url(:urlname => element.page.urlname, :anchor => element_dom_id(element), :lang => session[:language_id])
20
- else
21
- xml.link show_page_url(:urlname => element.page.urlname, :anchor => element_dom_id(element))
22
- xml.guid show_page_url(:urlname => element.page.urlname, :anchor => element_dom_id(element))
23
- end
24
- end
25
- end
26
- end
3
+
4
+ xml.channel do
5
+
6
+ xml.title @page.title
7
+ xml.description @page.meta_description
8
+ xml.link show_page_url(:urlname => @page.urlname, :lang => multi_language? ? @page.language_code : nil)
9
+
10
+ @page.feed_elements.each do |element|
11
+ xml.item do
12
+ xml.title element.content_for_rss_title.ingredient
13
+ xml.description element.content_for_rss_description.ingredient
14
+ xml.pubDate render_essence_view_by_name(element, 'date', :date_format => :rfc822)
15
+ xml.link show_page_url(:urlname => @page.urlname, :anchor => element_dom_id(element), :lang => multi_language? ? @page.language_code : nil)
16
+ xml.guid show_page_url(:urlname => @page.urlname, :anchor => element_dom_id(element), :lang => multi_language? ? @page.language_code : nil)
17
+ end
18
+ end
19
+
20
+ end
21
+
27
22
  end