alchemy_cms 2.0.rc6 → 2.0

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