##// END OF EJS Templates
Merged r2168 to r2171 from trunk....
Jean-Philippe Lang -
r2170:733987fbb6e4
parent child
Show More
@@ -27,7 +27,7 class AdminController < ApplicationController
27
27
28 def projects
28 def projects
29 sort_init 'name', 'asc'
29 sort_init 'name', 'asc'
30 sort_update
30 sort_update %w(name is_public created_on)
31
31
32 @status = params[:status] ? params[:status].to_i : 1
32 @status = params[:status] ? params[:status].to_i : 1
33 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
33 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
@@ -35,8 +35,10 class BoardsController < ApplicationController
35 end
35 end
36
36
37 def show
37 def show
38 sort_init "#{Message.table_name}.updated_on", "desc"
38 sort_init 'updated_on', 'desc'
39 sort_update
39 sort_update 'created_on' => "#{Message.table_name}.created_on",
40 'replies' => "#{Message.table_name}.replies_count",
41 'updated_on' => "#{Message.table_name}.updated_on"
40
42
41 @topic_count = @board.topics.count
43 @topic_count = @board.topics.count
42 @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
44 @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
@@ -45,9 +45,10 class IssuesController < ApplicationController
45 helper :timelog
45 helper :timelog
46
46
47 def index
47 def index
48 sort_init "#{Issue.table_name}.id", "desc"
49 sort_update
50 retrieve_query
48 retrieve_query
49 sort_init 'id', 'desc'
50 sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h}))
51
51 if @query.valid?
52 if @query.valid?
52 limit = per_page_option
53 limit = per_page_option
53 respond_to do |format|
54 respond_to do |format|
@@ -78,9 +79,10 class IssuesController < ApplicationController
78 end
79 end
79
80
80 def changes
81 def changes
81 sort_init "#{Issue.table_name}.id", "desc"
82 sort_update
83 retrieve_query
82 retrieve_query
83 sort_init 'id', 'desc'
84 sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h}))
85
84 if @query.valid?
86 if @query.valid?
85 @journals = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
87 @journals = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
86 :conditions => @query.statement,
88 :conditions => @query.statement,
@@ -197,8 +197,12 class ProjectsController < ApplicationController
197 end
197 end
198
198
199 def list_files
199 def list_files
200 sort_init "#{Attachment.table_name}.filename", "asc"
200 sort_init 'filename', 'asc'
201 sort_update
201 sort_update 'filename' => "#{Attachment.table_name}.filename",
202 'created_on' => "#{Attachment.table_name}.created_on",
203 'size' => "#{Attachment.table_name}.filesize",
204 'downloads' => "#{Attachment.table_name}.downloads"
205
202 @versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
206 @versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
203 render :layout => !request.xhr?
207 render :layout => !request.xhr?
204 end
208 end
@@ -138,7 +138,12 class TimelogController < ApplicationController
138
138
139 def details
139 def details
140 sort_init 'spent_on', 'desc'
140 sort_init 'spent_on', 'desc'
141 sort_update
141 sort_update 'spent_on' => 'spent_on',
142 'user' => 'user_id',
143 'activity' => 'activity_id',
144 'project' => "#{Project.table_name}.name",
145 'issue' => 'issue_id',
146 'hours' => 'hours'
142
147
143 cond = ARCondition.new
148 cond = ARCondition.new
144 if @project.nil?
149 if @project.nil?
@@ -30,7 +30,7 class UsersController < ApplicationController
30
30
31 def list
31 def list
32 sort_init 'login', 'asc'
32 sort_init 'login', 'asc'
33 sort_update
33 sort_update %w(login firstname lastname mail admin created_on last_login_on)
34
34
35 @status = params[:status] ? params[:status].to_i : 1
35 @status = params[:status] ? params[:status].to_i : 1
36 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
36 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
@@ -22,8 +22,8 module QueriesHelper
22 end
22 end
23
23
24 def column_header(column)
24 def column_header(column)
25 column.sortable ? sort_header_tag(column.sortable, :caption => column.caption,
25 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
26 :default_order => column.default_order) :
26 :default_order => column.default_order) :
27 content_tag('th', column.caption)
27 content_tag('th', column.caption)
28 end
28 end
29
29
@@ -67,23 +67,31 module SortHelper
67
67
68 # Updates the sort state. Call this in the controller prior to calling
68 # Updates the sort state. Call this in the controller prior to calling
69 # sort_clause.
69 # sort_clause.
70 #
70 # sort_keys can be either an array or a hash of allowed keys
71 def sort_update()
71 def sort_update(sort_keys)
72 if params[:sort_key]
72 sort_key = params[:sort_key]
73 sort = {:key => params[:sort_key], :order => params[:sort_order]}
73 sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key])
74
75 sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC')
76
77 if sort_key
78 sort = {:key => sort_key, :order => sort_order}
74 elsif session[@sort_name]
79 elsif session[@sort_name]
75 sort = session[@sort_name] # Previous sort.
80 sort = session[@sort_name] # Previous sort.
76 else
81 else
77 sort = @sort_default
82 sort = @sort_default
78 end
83 end
79 session[@sort_name] = sort
84 session[@sort_name] = sort
85
86 sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key])
87 @sort_clause = (sort_column.blank? ? '' : "#{sort_column} #{sort[:order]}")
80 end
88 end
81
89
82 # Returns an SQL sort clause corresponding to the current sort state.
90 # Returns an SQL sort clause corresponding to the current sort state.
83 # Use this to sort the controller's table items collection.
91 # Use this to sort the controller's table items collection.
84 #
92 #
85 def sort_clause()
93 def sort_clause()
86 session[@sort_name][:key] + ' ' + (session[@sort_name][:order] || 'ASC')
94 @sort_clause || '' #session[@sort_name][:key] + ' ' + (session[@sort_name][:order] || 'ASC')
87 end
95 end
88
96
89 # Returns a link which sorts by the named column.
97 # Returns a link which sorts by the named column.
@@ -57,7 +57,7 class Mailer < ActionMailer::Base
57 subject l(:mail_subject_reminder, issues.size)
57 subject l(:mail_subject_reminder, issues.size)
58 body :issues => issues,
58 body :issues => issues,
59 :days => days,
59 :days => days,
60 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'issues.due_date', :sort_order => 'asc')
60 :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')
61 end
61 end
62
62
63 def document_added(document)
63 def document_added(document)
@@ -33,9 +33,9
33 <thead><tr>
33 <thead><tr>
34 <th><%= l(:field_subject) %></th>
34 <th><%= l(:field_subject) %></th>
35 <th><%= l(:field_author) %></th>
35 <th><%= l(:field_author) %></th>
36 <%= sort_header_tag("#{Message.table_name}.created_on", :caption => l(:field_created_on)) %>
36 <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
37 <%= sort_header_tag("#{Message.table_name}.replies_count", :caption => l(:label_reply_plural)) %>
37 <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %>
38 <%= sort_header_tag("#{Message.table_name}.updated_on", :caption => l(:label_message_last)) %>
38 <%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %>
39 </tr></thead>
39 </tr></thead>
40 <tbody>
40 <tbody>
41 <% @topics.each do |topic| %>
41 <% @topics.each do |topic| %>
@@ -4,7 +4,7
4 <th><%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;',
4 <th><%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;',
5 :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
5 :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
6 </th>
6 </th>
7 <%= sort_header_tag("#{Issue.table_name}.id", :caption => '#', :default_order => 'desc') %>
7 <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %>
8 <% query.columns.each do |column| %>
8 <% query.columns.each do |column| %>
9 <%= column_header(column) %>
9 <%= column_header(column) %>
10 <% end %>
10 <% end %>
@@ -20,7 +20,7
20 <h3><%= l(:label_query_plural) %></h3>
20 <h3><%= l(:label_query_plural) %></h3>
21
21
22 <% sidebar_queries.each do |query| -%>
22 <% sidebar_queries.each do |query| -%>
23 <%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %><br />
23 <%= link_to(h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query) %><br />
24 <% end -%>
24 <% end -%>
25 <%= call_hook(:view_issues_sidebar_queries_bottom) %>
25 <%= call_hook(:view_issues_sidebar_queries_bottom) %>
26 <% end -%>
26 <% end -%>
@@ -9,10 +9,10
9 <table class="list">
9 <table class="list">
10 <thead><tr>
10 <thead><tr>
11 <th><%=l(:field_version)%></th>
11 <th><%=l(:field_version)%></th>
12 <%= sort_header_tag("#{Attachment.table_name}.filename", :caption => l(:field_filename)) %>
12 <%= sort_header_tag('filename', :caption => l(:field_filename)) %>
13 <%= sort_header_tag("#{Attachment.table_name}.created_on", :caption => l(:label_date), :default_order => 'desc') %>
13 <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
14 <%= sort_header_tag("#{Attachment.table_name}.filesize", :caption => l(:field_filesize), :default_order => 'desc') %>
14 <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
15 <%= sort_header_tag("#{Attachment.table_name}.downloads", :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
15 <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
16 <th>MD5</th>
16 <th>MD5</th>
17 <% if delete_allowed %><th></th><% end %>
17 <% if delete_allowed %><th></th><% end %>
18 </tr></thead>
18 </tr></thead>
@@ -2,10 +2,10
2 <thead>
2 <thead>
3 <tr>
3 <tr>
4 <%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
4 <%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
5 <%= sort_header_tag('user_id', :caption => l(:label_member)) %>
5 <%= sort_header_tag('user', :caption => l(:label_member)) %>
6 <%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
6 <%= sort_header_tag('activity', :caption => l(:label_activity)) %>
7 <%= sort_header_tag("#{Project.table_name}.name", :caption => l(:label_project)) %>
7 <%= sort_header_tag('project', :caption => l(:label_project)) %>
8 <%= sort_header_tag('issue_id', :caption => l(:label_issue), :default_order => 'desc') %>
8 <%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %>
9 <th><%= l(:field_comments) %></th>
9 <th><%= l(:field_comments) %></th>
10 <%= sort_header_tag('hours', :caption => l(:field_hours)) %>
10 <%= sort_header_tag('hours', :caption => l(:field_hours)) %>
11 <th></th>
11 <th></th>
@@ -20,7 +20,7
20 <th class="line-num"><%= line_num %></th>
20 <th class="line-num"><%= line_num %></th>
21 <td class="revision"><%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %></td>
21 <td class="revision"><%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %></td>
22 <td class="author"><%= h(line[1]) %></td>
22 <td class="author"><%= h(line[1]) %></td>
23 <td class="line-code"><pre><%= line[2] %></pre></td>
23 <td class="line-code"><pre><%=h line[2] %></pre></td>
24 </tr>
24 </tr>
25 <% line_num += 1 %>
25 <% line_num += 1 %>
26 <% end -%>
26 <% end -%>
@@ -408,7 +408,7 class RedCloth3 < String
408 # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
408 # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing
409 # [ /"/, '&#8220;' ], # double opening
409 # [ /"/, '&#8220;' ], # double opening
410 # [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
410 # [ /\b( )?\.{3}/, '\1&#8230;' ], # ellipsis
411 [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
411 # [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '<acronym title="\2">\1</acronym>' ], # 3+ uppercase acronym
412 # [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
412 # [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\1<span class="caps">\2</span>\3', :no_span_caps ], # 3+ uppercase caps
413 # [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
413 # [ /(\.\s)?\s?--\s?/, '\1&#8212;' ], # em dash
414 # [ /\s->\s/, ' &rarr; ' ], # right arrow
414 # [ /\s->\s/, ' &rarr; ' ], # right arrow
@@ -448,9 +448,12 class RedCloth3 < String
448
448
449 # Search and replace for Textile glyphs (quotes, dashes, other symbols)
449 # Search and replace for Textile glyphs (quotes, dashes, other symbols)
450 def pgl( text )
450 def pgl( text )
451 GLYPHS.each do |re, resub, tog|
451 #GLYPHS.each do |re, resub, tog|
452 next if tog and method( tog ).call
452 # next if tog and method( tog ).call
453 text.gsub! re, resub
453 # text.gsub! re, resub
454 #end
455 text.gsub!(/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/) do |m|
456 "<acronym title=\"#{htmlesc $2}\">#{$1}</acronym>"
454 end
457 end
455 end
458 end
456
459
@@ -467,7 +470,7 class RedCloth3 < String
467 style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
470 style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
468 end
471 end
469
472
470 style << "#{ $1 };" if not filter_styles and
473 style << "#{ htmlesc $1 };" if not filter_styles and
471 text.sub!( /\{([^}]*)\}/, '' )
474 text.sub!( /\{([^}]*)\}/, '' )
472
475
473 lang = $1 if
476 lang = $1 if
@@ -810,7 +813,7 class RedCloth3 < String
810 end
813 end
811 atts = pba( atts )
814 atts = pba( atts )
812 atts = " href=\"#{ url }#{ slash }\"#{ atts }"
815 atts = " href=\"#{ url }#{ slash }\"#{ atts }"
813 atts << " title=\"#{ title }\"" if title
816 atts << " title=\"#{ htmlesc title }\"" if title
814 atts = shelve( atts ) if atts
817 atts = shelve( atts ) if atts
815
818
816 external = (url =~ /^https?:\/\//) ? ' class="external"' : ''
819 external = (url =~ /^https?:\/\//) ? ' class="external"' : ''
@@ -137,6 +137,16 class IssuesControllerTest < Test::Unit::TestCase
137 assert_not_nil assigns(:issues)
137 assert_not_nil assigns(:issues)
138 assert_equal 'application/pdf', @response.content_type
138 assert_equal 'application/pdf', @response.content_type
139 end
139 end
140
141 def test_index_sort
142 get :index, :sort_key => 'tracker'
143 assert_response :success
144
145 sort_params = @request.session['issuesindex_sort']
146 assert sort_params.is_a?(Hash)
147 assert_equal 'tracker', sort_params[:key]
148 assert_equal 'ASC', sort_params[:order]
149 end
140
150
141 def test_gantt
151 def test_gantt
142 get :gantt, :project_id => 1
152 get :gantt, :project_id => 1
@@ -76,6 +76,15 class ApplicationHelperTest < HelperTestCase
76 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
76 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
77 end
77 end
78
78
79 def test_acronyms
80 to_test = {
81 'this is an acronym: GPL(General Public License)' => 'this is an acronym: <acronym title="General Public License">GPL</acronym>',
82 'GPL(This is a double-quoted "title")' => '<acronym title="This is a double-quoted &quot;title&quot;">GPL</acronym>',
83 }
84 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
85
86 end
87
79 def test_attached_images
88 def test_attached_images
80 to_test = {
89 to_test = {
81 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
90 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />',
@@ -90,6 +99,7 class ApplicationHelperTest < HelperTestCase
90 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
99 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
91 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
100 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
92 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
101 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
102 '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with &quot;double-quotes&quot;" class="external">link</a>',
93 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
103 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
94 # no multiline link text
104 # no multiline link text
95 "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />\nand another on a second line\":test"
105 "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />\nand another on a second line\":test"
General Comments 0
You need to be logged in to leave comments. Login now