typo 5.4 → 5.4.1

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 (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>