typo 5.4 → 5.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGELOG +23 -30
  2. data/Typo users guide.pdf +0 -0
  3. data/app/controllers/admin/content_controller.rb +28 -36
  4. data/app/controllers/admin/tags_controller.rb +4 -4
  5. data/app/controllers/articles_controller.rb +119 -1
  6. data/app/controllers/comments_controller.rb +0 -7
  7. data/app/controllers/content_controller.rb +1 -0
  8. data/app/helpers/admin/content_helper.rb +9 -28
  9. data/app/helpers/admin/themes_helper.rb +4 -6
  10. data/app/helpers/articles_helper.rb +4 -0
  11. data/app/models/article.rb +21 -12
  12. data/app/models/blog.rb +0 -1
  13. data/app/models/category.rb +1 -6
  14. data/app/models/content.rb +10 -6
  15. data/app/models/feedback/states.rb +6 -6
  16. data/app/models/tag.rb +8 -8
  17. data/app/views/admin/content/_drafts.html.erb +1 -1
  18. data/app/views/admin/content/_form.html.erb +7 -4
  19. data/app/views/admin/content/index.html.erb +3 -3
  20. data/app/views/admin/feedback/index.html.erb +4 -4
  21. data/app/views/admin/settings/feedback.html.erb +8 -7
  22. data/app/views/admin/settings/write.html.erb +71 -72
  23. data/app/views/admin/tags/index.html.erb +4 -4
  24. data/app/views/admin/themes/editor.html.erb +13 -10
  25. data/app/views/articles/_article.html.erb +6 -4
  26. data/bin/typo +25 -0
  27. data/config/initializers/access_rules.rb +4 -0
  28. data/config/routes.rb +2 -2
  29. data/db/schema.rb +32 -26
  30. data/db/schema.sqlite3.sql +3 -0
  31. data/lang/fr_FR.rb +46 -44
  32. data/lib/tasks/release.rake +1 -1
  33. data/lib/typo_version.rb +1 -1
  34. data/public/images/admin/loading.gif +0 -0
  35. data/public/images/closelabel.gif +0 -0
  36. data/public/stylesheets/administration.css +28 -8
  37. data/spec/controllers/admin/content_controller_spec.rb +91 -7
  38. data/spec/controllers/articles_controller_spec.rb +209 -0
  39. data/spec/controllers/comments_controller_spec.rb +0 -17
  40. data/spec/controllers/xml_controller_spec.rb +0 -5
  41. data/spec/factories.rb +8 -3
  42. data/spec/models/article_spec.rb +31 -4
  43. data/spec/models/configuration_spec.rb +0 -4
  44. data/spec/models/user_spec.rb +13 -0
  45. data/spec/spec_helper.rb +13 -0
  46. data/spec/views/articles/index_spec.rb +9 -11
  47. data/spec/views/articles/read_spec.rb +3 -5
  48. data/test/fixtures/blogs.yml +0 -1
  49. data/themes/dirtylicious/views/articles/_article.html.erb +6 -4
  50. data/themes/scribbish/views/articles/_article.html.erb +6 -4
  51. data/themes/standard_issue/views/articles/_article.html.erb +6 -4
  52. data/themes/true-blue-3/views/articles/_article.html.erb +8 -6
  53. data/themes/true-blue-3/views/categories/_article.html.erb +1 -1
  54. data/themes/typographic/views/articles/_article.html.erb +7 -5
  55. metadata +6 -8
  56. data/app/controllers/admin/previews_controller.rb +0 -10
  57. data/app/controllers/previews_controller.rb +0 -10
  58. data/app/controllers/redirect_controller.rb +0 -143
  59. data/app/helpers/redirect_helper.rb +0 -13
  60. data/spec/controllers/previews_controller_spec.rb +0 -28
  61. data/spec/controllers/redirect_controller_spec.rb +0 -165
@@ -6,51 +6,32 @@ module Admin::ContentHelper
6
6
  end
7
7
 
8
8
  def params_qsa
9
- { 'search[category]' => @search[:category],
10
- 'search[user_id]' => @search[:user_id],
11
- 'search[published_at]' => @search[:published_at],
9
+ { 'search[category]' => @search[:category],
10
+ 'search[user_id]' => @search[:user_id],
11
+ 'search[published_at]' => @search[:published_at],
12
12
  'searched[published]' => @search[:published] }
13
13
  end
14
14
 
15
15
  def link_to_destroy_draft(record, controller = @controller.controller_name)
16
16
  if record.state.to_s == "Draft"
17
- link_to(_("Destroy this draft"),
17
+ link_to(_("Destroy this draft"),
18
18
  { :controller => controller, :action => 'destroy', :id => record.id },
19
19
  :confirm => _("Are you sure?"), :method => :post )
20
20
  end
21
21
  end
22
22
 
23
- def checkbox_for_collection(container, selected = nil)
24
- container = container.to_a if Hash === container
25
-
26
- options_for_select = container.inject([]) do |options, element|
27
- text, value = option_text_and_value(element)
28
- selected_attribute = ' checked' if option_value_selected?(value, selected)
29
- options << %(<input type="checkbox" name="categories[]" id="category_#{html_escape(value.to_s)}" value="#{html_escape(value.to_s)}"#{selected_attribute} /><label for="category_#{html_escape(value.to_s)}">#{html_escape(text.to_s)}</label>)
30
- end
31
-
32
- options_for_select.join("<br />")
33
- end
34
-
35
- def checkboxes_from_collection(collection, value_method, text_method, selected = nil)
36
- options = collection.map do |element|
37
- [element.send(text_method), element.send(value_method)]
38
- end
39
- checkbox_for_collection(options, selected)
40
- end
41
-
42
23
  def auto_complete_result(entries, field, phrase = nil)
43
24
  return unless entries
44
25
  items = entries.map { |entry| content_tag("li", phrase ? highlight(entry[field], phrase) : h(entry[field])) }
45
26
  content_tag("ul", items.uniq)
46
27
  end
47
-
28
+
48
29
  def auto_complete_field(field_id, options = {})
49
30
  function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
50
31
  function << "'#{field_id}', "
51
32
  function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
52
33
  function << "'#{url_for(options[:url])}'"
53
-
34
+
54
35
  js_options = {}
55
36
  js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
56
37
  js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
@@ -60,7 +41,7 @@ module Admin::ContentHelper
60
41
  js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
61
42
  js_options[:method] = "'#{options[:method].to_s}'" if options[:method]
62
43
 
63
- { :after_update_element => :afterUpdateElement,
44
+ { :after_update_element => :afterUpdateElement,
64
45
  :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
65
46
  js_options[v] = options[k] if options[k]
66
47
  end
@@ -69,7 +50,7 @@ module Admin::ContentHelper
69
50
 
70
51
  javascript_tag(function)
71
52
  end
72
-
53
+
73
54
  def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
74
55
  (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
75
56
  text_field(object, method, tag_options) +
@@ -98,7 +79,7 @@ module Admin::ContentHelper
98
79
  background-color: #ffb;
99
80
  }
100
81
  div.auto_complete ul strong.highlight {
101
- color: #800;
82
+ color: #800;
102
83
  margin:0;
103
84
  padding:0;
104
85
  }
@@ -1,24 +1,22 @@
1
1
  module Admin::ThemesHelper
2
2
  require('find')
3
3
  def fetch_stylesheets
4
- list = '<ul>'
4
+ list = ''
5
5
  Find.find(this_blog.current_theme.path + "/stylesheets") do |path|
6
6
  if path =~ /css$/
7
- list << content_tag(:li, link_to(File.basename(path), {:controller => 'themes', :action => 'editor', :type => 'stylesheet', :file => File.basename(path)}))
7
+ list << content_tag(:p, link_to(File.basename(path), {:controller => 'themes', :action => 'editor', :type => 'stylesheet', :file => File.basename(path)}))
8
8
  end
9
9
  end
10
- list << '</ul>'
11
10
  list
12
11
  end
13
12
 
14
13
  def fetch_layouts
15
- list = '<ul>'
14
+ list = ''
16
15
  Find.find(this_blog.current_theme.path + "/layouts") do |path|
17
16
  if path =~ /rhtml$|erb$/
18
- list << content_tag(:li, link_to(File.basename(path), {:controller => 'themes', :action => 'editor', :type => 'layout', :file => File.basename(path)}))
17
+ list << content_tag(:p, link_to(File.basename(path), {:controller => 'themes', :action => 'editor', :type => 'layout', :file => File.basename(path)}))
19
18
  end
20
19
  end
21
- list << '</ul>'
22
20
  list
23
21
  end
24
22
 
@@ -2,6 +2,8 @@ module ArticlesHelper
2
2
  def feed_atom
3
3
  if params[:action] == 'search'
4
4
  url_for(:only_path => false,:format => :atom, :q => params[:q])
5
+ elsif not @article.nil?
6
+ @article.feed_url(:atom)
5
7
  else
6
8
  @auto_discovery_url_atom
7
9
  end
@@ -10,6 +12,8 @@ module ArticlesHelper
10
12
  def feed_rss
11
13
  if params[:action] == 'search'
12
14
  url_for(:only_path => false,:format => :rss, :q => params[:q])
15
+ elsif not @article.nil?
16
+ @article.feed_url(:rss20)
13
17
  else
14
18
  @auto_discovery_url_rss
15
19
  end
@@ -49,7 +49,12 @@ class Article < Content
49
49
 
50
50
  named_scope :category, lambda {|category_id| {:conditions => ['categorizations.category_id = ?', category_id], :include => 'categorizations'}}
51
51
  named_scope :drafts, :conditions => ['state = ?', 'draft']
52
+ named_scope :without_parent, {:conditions => {:parent_id => nil}}
53
+ named_scope :child_of, lambda { |article_id| {:conditions => {:parent_id => article_id}} }
52
54
 
55
+ def has_child?
56
+ Article.exists?({:parent_id => self.id})
57
+ end
53
58
 
54
59
  belongs_to :user
55
60
 
@@ -72,6 +77,14 @@ class Article < Content
72
77
  include Article::States
73
78
 
74
79
  class << self
80
+ def last_draft(article_id)
81
+ article = Article.find(article_id)
82
+ while article.has_child?
83
+ article = Article.child_of(article.id).first
84
+ end
85
+ article
86
+ end
87
+
75
88
  def published_articles
76
89
  find(:conditions => { :published => true }, :order => 'published_at DESC')
77
90
  end
@@ -481,14 +494,10 @@ class Article < Content
481
494
  else
482
495
  rss_desc = ""
483
496
  end
484
-
485
- entry.summary html(:body), "type" => "html"
486
- if blog.show_extended_on_rss
487
- post = html(:all)
488
- content = blog.rss_description ? post + rss_desc : post
489
497
 
490
- entry.content(content, :type => "html")
491
- end
498
+ post = blog.show_extended_on_rss ? post = html(:all) : post = html(:body)
499
+ content = blog.rss_description ? post + rss_desc : post
500
+ entry.content(content, :type => "html")
492
501
  end
493
502
 
494
503
  def add_comment(params)
@@ -499,8 +508,8 @@ class Article < Content
499
508
  self.categorizations.build(:category => category, :is_primary => is_primary)
500
509
  end
501
510
 
502
- def access_by?(user)
503
- user.admin? || user_id == user.id
511
+ def access_by?(user)
512
+ user.admin? || user_id == user.id
504
513
  end
505
514
 
506
515
  protected
@@ -517,9 +526,9 @@ class Article < Content
517
526
  end
518
527
 
519
528
  def set_defaults
520
- if self.attributes.include?("permalink") and
521
- (self.permalink.blank? or
522
- self.permalink.to_s =~ /article-draft/ or
529
+ if self.attributes.include?("permalink") and
530
+ (self.permalink.blank? or
531
+ self.permalink.to_s =~ /article-draft/ or
523
532
  self.state == "draft"
524
533
  )
525
534
  self.permalink = self.stripped_title
data/app/models/blog.rb CHANGED
@@ -38,7 +38,6 @@ class Blog < ActiveRecord::Base
38
38
  # Spam
39
39
  setting :sp_global, :boolean, false
40
40
  setting :sp_article_auto_close, :integer, 0
41
- setting :sp_allow_non_ajax_comments, :boolean, true
42
41
  setting :sp_url_limit, :integer, 0
43
42
  setting :sp_akismet_key, :string, ''
44
43
 
@@ -7,11 +7,6 @@ class Category < ActiveRecord::Base
7
7
  :through => :categorizations,
8
8
  :order => "published_at DESC, created_at DESC"
9
9
 
10
- has_many :published_articles,
11
- :through => :categorizations,
12
- :class_name => 'Article',
13
- :conditions => { :published => true },
14
- :order => "published_at DESC"
15
10
 
16
11
  default_scope :order => 'position ASC'
17
12
 
@@ -60,7 +55,7 @@ class Category < ActiveRecord::Base
60
55
  end
61
56
 
62
57
  def published_articles
63
- self.articles.find_already_published
58
+ articles.already_published
64
59
  end
65
60
 
66
61
  def display_name
@@ -8,6 +8,7 @@ class Content < ActiveRecord::Base
8
8
  :source => 'notify_user',
9
9
  :uniq => true
10
10
 
11
+
11
12
  def notify_users=(collection)
12
13
  return notify_users.clear if collection.empty?
13
14
  self.class.transaction do
@@ -46,6 +47,9 @@ class Content < ActiveRecord::Base
46
47
  {:conditions => ['state = ? AND ' + (['(LOWER(body) LIKE ? OR LOWER(extended) LIKE ? OR LOWER(title) LIKE ?)']*tokens.size).join(' AND '),
47
48
  "published", *tokens.collect{ |token| [token] * 3 }.flatten]}
48
49
  }
50
+ named_scope :already_published, lambda { {:conditions => ['published = ? AND published_at < ?', true, Time.now],
51
+ :order => default_order,
52
+ }}
49
53
 
50
54
  serialize :whiteboard
51
55
 
@@ -122,27 +126,27 @@ class Content < ActiveRecord::Base
122
126
  find_published(what, options)
123
127
  end
124
128
  end
125
-
129
+
126
130
  def find_by_published_at(column_name = :published_at)
127
131
  from_where = "FROM #{self.table_name} WHERE #{column_name} is not NULL AND type='#{self.name}'"
128
132
 
129
133
  # Implement adapter-specific groupings below, or allow us to fall through to the generic ruby-side grouping
130
-
134
+
131
135
  if defined?(ActiveRecord::ConnectionAdapters::MysqlAdapter) && self.connection.is_a?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
132
136
  # MySQL uses date_format
133
137
  find_by_sql("SELECT date_format(#{column_name}, '%Y-%m') AS publication #{from_where} GROUP BY publication ORDER BY publication DESC")
134
-
138
+
135
139
  elsif defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && self.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
136
140
  # PostgreSQL uses to_char
137
141
  find_by_sql("SELECT to_char(#{column_name}, 'YYYY-MM') AS publication #{from_where} GROUP BY publication ORDER BY publication DESC")
138
-
142
+
139
143
  else
140
144
  # If we don't have an adapter-safe conversion from date -> YYYY-MM,
141
145
  # we'll do the GROUP BY server-side. There won't be very many objects
142
146
  # in this array anyway.
143
147
  date_map = {}
144
148
  dates = find_by_sql("SELECT #{column_name} AS publication #{from_where}")
145
-
149
+
146
150
  dates.map! do |d|
147
151
  d.publication = Time.parse(d.publication).strftime('%Y-%m')
148
152
  d.freeze
@@ -153,7 +157,7 @@ class Content < ActiveRecord::Base
153
157
  end
154
158
  dates.reject!{|d| d.blank? || d.publication.blank?}
155
159
  dates.sort!{|a,b| b.publication <=> a.publication}
156
-
160
+
157
161
  dates
158
162
  end
159
163
  end
@@ -59,7 +59,7 @@ module Feedback::States
59
59
  def before_save
60
60
  classify_content
61
61
  end
62
-
62
+
63
63
  def to_s
64
64
  _("Unclassified")
65
65
  end
@@ -73,7 +73,7 @@ module Feedback::States
73
73
  end
74
74
  def to_s
75
75
  _("Just Presumed Ham")
76
- end
76
+ end
77
77
  end
78
78
 
79
79
  class PresumedHam < Base
@@ -119,7 +119,7 @@ module Feedback::States
119
119
  end
120
120
  def to_s
121
121
  _("Just Marked As Ham")
122
- end
122
+ end
123
123
  end
124
124
 
125
125
  class Ham < Base
@@ -153,7 +153,7 @@ module Feedback::States
153
153
  end
154
154
  def to_s
155
155
  _("Ham")
156
- end
156
+ end
157
157
  end
158
158
 
159
159
  class PresumedSpam < Base
@@ -194,7 +194,7 @@ module Feedback::States
194
194
  end
195
195
  def to_s
196
196
  _("Just Marked As Spam")
197
- end
197
+ end
198
198
  end
199
199
 
200
200
  class Spam < Base
@@ -215,6 +215,6 @@ module Feedback::States
215
215
  end
216
216
  def to_s
217
217
  _("Spam")
218
- end
218
+ end
219
219
  end
220
220
  end
data/app/models/tag.rb CHANGED
@@ -3,7 +3,7 @@ class Tag < ActiveRecord::Base
3
3
  validates_uniqueness_of :name
4
4
  attr_reader :description
5
5
  attr_reader :keywords
6
-
6
+
7
7
  def self.get(name)
8
8
  tagname = name.tr(' ', '').downcase
9
9
  tag = find_by_name_or_display_name(tagname, name)
@@ -43,8 +43,8 @@ class Tag < ActiveRecord::Base
43
43
  ON articles_tags.article_id = articles.id
44
44
  WHERE articles.published = ?
45
45
  GROUP BY tags.id, tags.name, tags.display_name
46
- ORDER BY #{orderby}
47
- LIMIT ? OFFSET ?
46
+ ORDER BY #{orderby}
47
+ LIMIT ? OFFSET ?
48
48
  },true, limit, start]).each{|item| item.article_counter = item.article_counter.to_i }
49
49
  end
50
50
 
@@ -59,15 +59,15 @@ class Tag < ActiveRecord::Base
59
59
  def self.to_prefix
60
60
  'tag'
61
61
  end
62
-
63
- # Return all tags with the char or string
62
+
63
+ # Return all tags with the char or string
64
64
  # send by parameter
65
65
  def self.find_with_char(char)
66
66
  find :all, :conditions => ['name LIKE ? ', "%#{char}%"], :order => 'name ASC'
67
67
  end
68
-
68
+
69
69
  def published_articles
70
- articles.find_already_published
70
+ articles.already_published
71
71
  end
72
72
 
73
73
  def permalink
@@ -95,5 +95,5 @@ class Tag < ActiveRecord::Base
95
95
  def to_param
96
96
  permalink
97
97
  end
98
-
98
+
99
99
  end
@@ -1,6 +1,6 @@
1
1
  <div class='bordered'>
2
2
  <h3><label class="block content"><%= _("Drafts:") %></label></h3>
3
- <% for draft in @drafts %>
3
+ <% Article.drafts.all.each do |draft| %>
4
4
  <%= link_to("#{draft.title}<br />", :action => 'edit', :id => draft.id) %>
5
5
  <% end %>
6
6
  </div>
@@ -11,22 +11,25 @@
11
11
  <label for="article_allow_comments"><%= _("Allow comments") %></label><br />
12
12
  <%= check_box 'article', 'allow_pings' %>
13
13
  <label for="article_allow_pings"><%= _("Allow trackbacks")%></label><br />
14
- <%= check_box 'article', 'published' %>
14
+ <%= check_box 'article', 'published' %>
15
15
  <label for="article_published"><%= _("Published")%></label><br />
16
16
  <p class='right'>
17
17
  <input id='save_draft' type="submit" value="<%= _('Save as draft') %> &raquo;" name="article[draft]"/>&nbsp;
18
18
  <%= save( _("Publish") + " &raquo;") %><br />
19
19
  <%= link_to_destroy_with_profiles(@article) unless @article.id.nil? %>
20
- <%= link_to_destroy_draft @article %>
20
+ <%= link_to_destroy_draft @article %>
21
21
  </p>
22
- <span id='preview_link'><%= link_to(_("Preview"), {:controller => '/previews', :id => @article.id}, {:target => 'new'}) if @article.id %></span>
22
+ <span id='preview_link'><%= link_to(_("Preview"), {:controller => '/articles', :action => 'preview', :id => @article.id}, {:target => 'new'}) if @article.id %></span>
23
23
  </div>
24
24
  <div class='editor_bottom'>
25
25
  <div class='editor_bottom_right'></div>
26
26
  </div>
27
27
  <div id="categories">
28
28
  <h3><%= _("Categories") %></h3>
29
- <%= checkboxes_from_collection(@categories, "id", "name", @selected) %>
29
+ <%- Category.all.each do |cat| %>
30
+ <%= check_box_tag('categories[]', cat.id, (@article.categories.map(&:id).include? cat.id), :id => "category_#{h(cat.id)}") %>
31
+ <%= label_tag "category_#{h(cat.id)}", h(cat.name) %><br />
32
+ <% end -%>
30
33
  </div>
31
34
  <%= render :partial => 'drafts'%>
32
35
  </div>
@@ -1,7 +1,7 @@
1
1
  <% @page_heading = _('Manage articles') %>
2
2
  <% subtabs_for(:content) %>
3
3
 
4
- <div class="list" id="articles">
4
+ <div class="list" id="articles">
5
5
  <% form_remote_tag :url => {:action => 'index'},
6
6
  :method => :get,
7
7
  :name => 'article',
@@ -26,7 +26,7 @@
26
26
  </tr>
27
27
  <tr class="menubar">
28
28
  <td>&nbsp;</td>
29
- <td><%= collection_select_with_current('search', 'category', @categories, "id", "name", @search[:category].to_i, true)
29
+ <td><%= collection_select_with_current('search', 'category', Category.all, "id", "name", @search[:category].to_i, true)
30
30
  %></td>
31
31
  <td>
32
32
  <%= collection_select_with_current(:search, :published_at, Article.find_by_published_at, "publication", "publication", @search[:published_at], true) %>
@@ -47,4 +47,4 @@
47
47
  </table>
48
48
 
49
49
  <%end%>
50
- </div>
50
+ </div>