##// END OF EJS Templates
Adds projects association on tracker form (#2578)....
Jean-Philippe Lang -
r2333:945ec8942a4c
parent child
Show More
@@ -0,0 +1,68
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'trackers_controller'
20
21 # Re-raise errors caught by the controller.
22 class TrackersController; def rescue_action(e) raise e end; end
23
24 class TrackersControllerTest < Test::Unit::TestCase
25 fixtures :trackers, :projects, :projects_trackers, :users
26
27 def setup
28 @controller = TrackersController.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
31 User.current = nil
32 @request.session[:user_id] = 1 # admin
33 end
34
35 def test_get_edit
36 Tracker.find(1).project_ids = [1, 3]
37
38 get :edit, :id => 1
39 assert_response :success
40 assert_template 'edit'
41
42 assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
43 :value => '1',
44 :checked => 'checked' }
45
46 assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
47 :value => '2',
48 :checked => nil }
49
50 assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
51 :value => '',
52 :type => 'hidden'}
53 end
54
55 def test_post_edit
56 post :edit, :id => 1, :tracker => { :name => 'Renamed',
57 :project_ids => ['1', '2', ''] }
58 assert_redirected_to '/trackers/list'
59 assert_equal [1, 2], Tracker.find(1).project_ids.sort
60 end
61
62 def test_post_edit_without_projects
63 post :edit, :id => 1, :tracker => { :name => 'Renamed',
64 :project_ids => [''] }
65 assert_redirected_to '/trackers/list'
66 assert Tracker.find(1).project_ids.empty?
67 end
68 end
@@ -1,79 +1,83
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class TrackersController < ApplicationController
18 class TrackersController < ApplicationController
19 before_filter :require_admin
19 before_filter :require_admin
20
20
21 def index
21 def index
22 list
22 list
23 render :action => 'list' unless request.xhr?
23 render :action => 'list' unless request.xhr?
24 end
24 end
25
25
26 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
26 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
27 verify :method => :post, :only => [ :destroy, :move ], :redirect_to => { :action => :list }
27 verify :method => :post, :only => [ :destroy, :move ], :redirect_to => { :action => :list }
28
28
29 def list
29 def list
30 @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
30 @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
31 render :action => "list", :layout => false if request.xhr?
31 render :action => "list", :layout => false if request.xhr?
32 end
32 end
33
33
34 def new
34 def new
35 @tracker = Tracker.new(params[:tracker])
35 @tracker = Tracker.new(params[:tracker])
36 if request.post? and @tracker.save
36 if request.post? and @tracker.save
37 # workflow copy
37 # workflow copy
38 if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
38 if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
39 @tracker.workflows.copy(copy_from)
39 @tracker.workflows.copy(copy_from)
40 end
40 end
41 flash[:notice] = l(:notice_successful_create)
41 flash[:notice] = l(:notice_successful_create)
42 redirect_to :action => 'list'
42 redirect_to :action => 'list'
43 return
43 end
44 end
44 @trackers = Tracker.find :all, :order => 'position'
45 @trackers = Tracker.find :all, :order => 'position'
46 @projects = Project.find(:all)
45 end
47 end
46
48
47 def edit
49 def edit
48 @tracker = Tracker.find(params[:id])
50 @tracker = Tracker.find(params[:id])
49 if request.post? and @tracker.update_attributes(params[:tracker])
51 if request.post? and @tracker.update_attributes(params[:tracker])
50 flash[:notice] = l(:notice_successful_update)
52 flash[:notice] = l(:notice_successful_update)
51 redirect_to :action => 'list'
53 redirect_to :action => 'list'
54 return
52 end
55 end
56 @projects = Project.find(:all)
53 end
57 end
54
58
55 def move
59 def move
56 @tracker = Tracker.find(params[:id])
60 @tracker = Tracker.find(params[:id])
57 case params[:position]
61 case params[:position]
58 when 'highest'
62 when 'highest'
59 @tracker.move_to_top
63 @tracker.move_to_top
60 when 'higher'
64 when 'higher'
61 @tracker.move_higher
65 @tracker.move_higher
62 when 'lower'
66 when 'lower'
63 @tracker.move_lower
67 @tracker.move_lower
64 when 'lowest'
68 when 'lowest'
65 @tracker.move_to_bottom
69 @tracker.move_to_bottom
66 end if params[:position]
70 end if params[:position]
67 redirect_to :action => 'list'
71 redirect_to :action => 'list'
68 end
72 end
69
73
70 def destroy
74 def destroy
71 @tracker = Tracker.find(params[:id])
75 @tracker = Tracker.find(params[:id])
72 unless @tracker.issues.empty?
76 unless @tracker.issues.empty?
73 flash[:error] = "This tracker contains issues and can\'t be deleted."
77 flash[:error] = "This tracker contains issues and can\'t be deleted."
74 else
78 else
75 @tracker.destroy
79 @tracker.destroy
76 end
80 end
77 redirect_to :action => 'list'
81 redirect_to :action => 'list'
78 end
82 end
79 end
83 end
@@ -1,678 +1,702
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'coderay'
18 require 'coderay'
19 require 'coderay/helpers/file_type'
19 require 'coderay/helpers/file_type'
20 require 'forwardable'
20 require 'forwardable'
21 require 'cgi'
21 require 'cgi'
22
22
23 module ApplicationHelper
23 module ApplicationHelper
24 include Redmine::WikiFormatting::Macros::Definitions
24 include Redmine::WikiFormatting::Macros::Definitions
25 include GravatarHelper::PublicMethods
25 include GravatarHelper::PublicMethods
26
26
27 extend Forwardable
27 extend Forwardable
28 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
28 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
29
29
30 def current_role
30 def current_role
31 @current_role ||= User.current.role_for_project(@project)
31 @current_role ||= User.current.role_for_project(@project)
32 end
32 end
33
33
34 # Return true if user is authorized for controller/action, otherwise false
34 # Return true if user is authorized for controller/action, otherwise false
35 def authorize_for(controller, action)
35 def authorize_for(controller, action)
36 User.current.allowed_to?({:controller => controller, :action => action}, @project)
36 User.current.allowed_to?({:controller => controller, :action => action}, @project)
37 end
37 end
38
38
39 # Display a link if user is authorized
39 # Display a link if user is authorized
40 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
40 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
41 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
41 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
42 end
42 end
43
43
44 # Display a link to remote if user is authorized
44 # Display a link to remote if user is authorized
45 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
45 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
46 url = options[:url] || {}
46 url = options[:url] || {}
47 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
47 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
48 end
48 end
49
49
50 # Display a link to user's account page
50 # Display a link to user's account page
51 def link_to_user(user, options={})
51 def link_to_user(user, options={})
52 (user && !user.anonymous?) ? link_to(user.name(options[:format]), :controller => 'account', :action => 'show', :id => user) : 'Anonymous'
52 (user && !user.anonymous?) ? link_to(user.name(options[:format]), :controller => 'account', :action => 'show', :id => user) : 'Anonymous'
53 end
53 end
54
54
55 def link_to_issue(issue, options={})
55 def link_to_issue(issue, options={})
56 options[:class] ||= ''
56 options[:class] ||= ''
57 options[:class] << ' issue'
57 options[:class] << ' issue'
58 options[:class] << ' closed' if issue.closed?
58 options[:class] << ' closed' if issue.closed?
59 link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options
59 link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options
60 end
60 end
61
61
62 # Generates a link to an attachment.
62 # Generates a link to an attachment.
63 # Options:
63 # Options:
64 # * :text - Link text (default to attachment filename)
64 # * :text - Link text (default to attachment filename)
65 # * :download - Force download (default: false)
65 # * :download - Force download (default: false)
66 def link_to_attachment(attachment, options={})
66 def link_to_attachment(attachment, options={})
67 text = options.delete(:text) || attachment.filename
67 text = options.delete(:text) || attachment.filename
68 action = options.delete(:download) ? 'download' : 'show'
68 action = options.delete(:download) ? 'download' : 'show'
69
69
70 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
70 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
71 end
71 end
72
72
73 def toggle_link(name, id, options={})
73 def toggle_link(name, id, options={})
74 onclick = "Element.toggle('#{id}'); "
74 onclick = "Element.toggle('#{id}'); "
75 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
75 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
76 onclick << "return false;"
76 onclick << "return false;"
77 link_to(name, "#", :onclick => onclick)
77 link_to(name, "#", :onclick => onclick)
78 end
78 end
79
79
80 def image_to_function(name, function, html_options = {})
80 def image_to_function(name, function, html_options = {})
81 html_options.symbolize_keys!
81 html_options.symbolize_keys!
82 tag(:input, html_options.merge({
82 tag(:input, html_options.merge({
83 :type => "image", :src => image_path(name),
83 :type => "image", :src => image_path(name),
84 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
84 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
85 }))
85 }))
86 end
86 end
87
87
88 def prompt_to_remote(name, text, param, url, html_options = {})
88 def prompt_to_remote(name, text, param, url, html_options = {})
89 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
89 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
90 link_to name, {}, html_options
90 link_to name, {}, html_options
91 end
91 end
92
92
93 def format_date(date)
93 def format_date(date)
94 return nil unless date
94 return nil unless date
95 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
95 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
96 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
96 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
97 date.strftime(@date_format)
97 date.strftime(@date_format)
98 end
98 end
99
99
100 def format_time(time, include_date = true)
100 def format_time(time, include_date = true)
101 return nil unless time
101 return nil unless time
102 time = time.to_time if time.is_a?(String)
102 time = time.to_time if time.is_a?(String)
103 zone = User.current.time_zone
103 zone = User.current.time_zone
104 local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)
104 local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)
105 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
105 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
106 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
106 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
107 include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
107 include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
108 end
108 end
109
109
110 def format_activity_title(text)
110 def format_activity_title(text)
111 h(truncate_single_line(text, 100))
111 h(truncate_single_line(text, 100))
112 end
112 end
113
113
114 def format_activity_day(date)
114 def format_activity_day(date)
115 date == Date.today ? l(:label_today).titleize : format_date(date)
115 date == Date.today ? l(:label_today).titleize : format_date(date)
116 end
116 end
117
117
118 def format_activity_description(text)
118 def format_activity_description(text)
119 h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
119 h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
120 end
120 end
121
121
122 def distance_of_date_in_words(from_date, to_date = 0)
122 def distance_of_date_in_words(from_date, to_date = 0)
123 from_date = from_date.to_date if from_date.respond_to?(:to_date)
123 from_date = from_date.to_date if from_date.respond_to?(:to_date)
124 to_date = to_date.to_date if to_date.respond_to?(:to_date)
124 to_date = to_date.to_date if to_date.respond_to?(:to_date)
125 distance_in_days = (to_date - from_date).abs
125 distance_in_days = (to_date - from_date).abs
126 lwr(:actionview_datehelper_time_in_words_day, distance_in_days)
126 lwr(:actionview_datehelper_time_in_words_day, distance_in_days)
127 end
127 end
128
128
129 def due_date_distance_in_words(date)
129 def due_date_distance_in_words(date)
130 if date
130 if date
131 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
131 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
132 end
132 end
133 end
133 end
134
134
135 def render_page_hierarchy(pages, node=nil)
135 def render_page_hierarchy(pages, node=nil)
136 content = ''
136 content = ''
137 if pages[node]
137 if pages[node]
138 content << "<ul class=\"pages-hierarchy\">\n"
138 content << "<ul class=\"pages-hierarchy\">\n"
139 pages[node].each do |page|
139 pages[node].each do |page|
140 content << "<li>"
140 content << "<li>"
141 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
141 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
142 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
142 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
143 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
143 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
144 content << "</li>\n"
144 content << "</li>\n"
145 end
145 end
146 content << "</ul>\n"
146 content << "</ul>\n"
147 end
147 end
148 content
148 content
149 end
149 end
150
150
151 # Renders flash messages
151 # Renders flash messages
152 def render_flash_messages
152 def render_flash_messages
153 s = ''
153 s = ''
154 flash.each do |k,v|
154 flash.each do |k,v|
155 s << content_tag('div', v, :class => "flash #{k}")
155 s << content_tag('div', v, :class => "flash #{k}")
156 end
156 end
157 s
157 s
158 end
158 end
159
159
160 # Renders the project quick-jump box
160 # Renders the project quick-jump box
161 def render_project_jump_box
161 def render_project_jump_box
162 # Retrieve them now to avoid a COUNT query
162 # Retrieve them now to avoid a COUNT query
163 projects = User.current.projects.all
163 projects = User.current.projects.all
164 if projects.any?
164 if projects.any?
165 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
165 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
166 "<option selected='selected'>#{ l(:label_jump_to_a_project) }</option>" +
166 "<option selected='selected'>#{ l(:label_jump_to_a_project) }</option>" +
167 '<option disabled="disabled">---</option>'
167 '<option disabled="disabled">---</option>'
168 s << project_tree_options_for_select(projects) do |p|
168 s << project_tree_options_for_select(projects) do |p|
169 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
169 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
170 end
170 end
171 s << '</select>'
171 s << '</select>'
172 s
172 s
173 end
173 end
174 end
174 end
175
175
176 def project_tree_options_for_select(projects, options = {})
176 def project_tree_options_for_select(projects, options = {})
177 s = ''
177 s = ''
178 project_tree(projects) do |project, level|
178 project_tree(projects) do |project, level|
179 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
179 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
180 tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
180 tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
181 tag_options.merge!(yield(project)) if block_given?
181 tag_options.merge!(yield(project)) if block_given?
182 s << content_tag('option', name_prefix + h(project), tag_options)
182 s << content_tag('option', name_prefix + h(project), tag_options)
183 end
183 end
184 s
184 s
185 end
185 end
186
186
187 # Yields the given block for each project with its level in the tree
187 # Yields the given block for each project with its level in the tree
188 def project_tree(projects, &block)
188 def project_tree(projects, &block)
189 ancestors = []
189 ancestors = []
190 projects.sort_by(&:lft).each do |project|
190 projects.sort_by(&:lft).each do |project|
191 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
191 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
192 ancestors.pop
192 ancestors.pop
193 end
193 end
194 yield project, ancestors.size
194 yield project, ancestors.size
195 ancestors << project
195 ancestors << project
196 end
196 end
197 end
197 end
198
199 def project_nested_ul(projects, &block)
200 s = ''
201 if projects.any?
202 ancestors = []
203 projects.sort_by(&:lft).each do |project|
204 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
205 s << "<ul>\n"
206 else
207 ancestors.pop
208 s << "</li>"
209 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
210 ancestors.pop
211 s << "</ul></li>\n"
212 end
213 end
214 s << "<li>"
215 s << yield(project).to_s
216 ancestors << project
217 end
218 s << ("</li></ul>\n" * ancestors.size)
219 end
220 s
221 end
198
222
199 # Truncates and returns the string as a single line
223 # Truncates and returns the string as a single line
200 def truncate_single_line(string, *args)
224 def truncate_single_line(string, *args)
201 truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
225 truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
202 end
226 end
203
227
204 def html_hours(text)
228 def html_hours(text)
205 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
229 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
206 end
230 end
207
231
208 def authoring(created, author, options={})
232 def authoring(created, author, options={})
209 time_tag = @project.nil? ? content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) :
233 time_tag = @project.nil? ? content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) :
210 link_to(distance_of_time_in_words(Time.now, created),
234 link_to(distance_of_time_in_words(Time.now, created),
211 {:controller => 'projects', :action => 'activity', :id => @project, :from => created.to_date},
235 {:controller => 'projects', :action => 'activity', :id => @project, :from => created.to_date},
212 :title => format_time(created))
236 :title => format_time(created))
213 author_tag = (author.is_a?(User) && !author.anonymous?) ? link_to(h(author), :controller => 'account', :action => 'show', :id => author) : h(author || 'Anonymous')
237 author_tag = (author.is_a?(User) && !author.anonymous?) ? link_to(h(author), :controller => 'account', :action => 'show', :id => author) : h(author || 'Anonymous')
214 l(options[:label] || :label_added_time_by, author_tag, time_tag)
238 l(options[:label] || :label_added_time_by, author_tag, time_tag)
215 end
239 end
216
240
217 def l_or_humanize(s, options={})
241 def l_or_humanize(s, options={})
218 k = "#{options[:prefix]}#{s}".to_sym
242 k = "#{options[:prefix]}#{s}".to_sym
219 l_has_string?(k) ? l(k) : s.to_s.humanize
243 l_has_string?(k) ? l(k) : s.to_s.humanize
220 end
244 end
221
245
222 def day_name(day)
246 def day_name(day)
223 l(:general_day_names).split(',')[day-1]
247 l(:general_day_names).split(',')[day-1]
224 end
248 end
225
249
226 def month_name(month)
250 def month_name(month)
227 l(:actionview_datehelper_select_month_names).split(',')[month-1]
251 l(:actionview_datehelper_select_month_names).split(',')[month-1]
228 end
252 end
229
253
230 def syntax_highlight(name, content)
254 def syntax_highlight(name, content)
231 type = CodeRay::FileType[name]
255 type = CodeRay::FileType[name]
232 type ? CodeRay.scan(content, type).html : h(content)
256 type ? CodeRay.scan(content, type).html : h(content)
233 end
257 end
234
258
235 def to_path_param(path)
259 def to_path_param(path)
236 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
260 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
237 end
261 end
238
262
239 def pagination_links_full(paginator, count=nil, options={})
263 def pagination_links_full(paginator, count=nil, options={})
240 page_param = options.delete(:page_param) || :page
264 page_param = options.delete(:page_param) || :page
241 url_param = params.dup
265 url_param = params.dup
242 # don't reuse params if filters are present
266 # don't reuse params if filters are present
243 url_param.clear if url_param.has_key?(:set_filter)
267 url_param.clear if url_param.has_key?(:set_filter)
244
268
245 html = ''
269 html = ''
246 if paginator.current.previous
270 if paginator.current.previous
247 html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
271 html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
248 end
272 end
249
273
250 html << (pagination_links_each(paginator, options) do |n|
274 html << (pagination_links_each(paginator, options) do |n|
251 link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
275 link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
252 end || '')
276 end || '')
253
277
254 if paginator.current.next
278 if paginator.current.next
255 html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
279 html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
256 end
280 end
257
281
258 unless count.nil?
282 unless count.nil?
259 html << [
283 html << [
260 " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
284 " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
261 per_page_links(paginator.items_per_page)
285 per_page_links(paginator.items_per_page)
262 ].compact.join(' | ')
286 ].compact.join(' | ')
263 end
287 end
264
288
265 html
289 html
266 end
290 end
267
291
268 def per_page_links(selected=nil)
292 def per_page_links(selected=nil)
269 url_param = params.dup
293 url_param = params.dup
270 url_param.clear if url_param.has_key?(:set_filter)
294 url_param.clear if url_param.has_key?(:set_filter)
271
295
272 links = Setting.per_page_options_array.collect do |n|
296 links = Setting.per_page_options_array.collect do |n|
273 n == selected ? n : link_to_remote(n, {:update => "content",
297 n == selected ? n : link_to_remote(n, {:update => "content",
274 :url => params.dup.merge(:per_page => n),
298 :url => params.dup.merge(:per_page => n),
275 :method => :get},
299 :method => :get},
276 {:href => url_for(url_param.merge(:per_page => n))})
300 {:href => url_for(url_param.merge(:per_page => n))})
277 end
301 end
278 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
302 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
279 end
303 end
280
304
281 def breadcrumb(*args)
305 def breadcrumb(*args)
282 elements = args.flatten
306 elements = args.flatten
283 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
307 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
284 end
308 end
285
309
286 def other_formats_links(&block)
310 def other_formats_links(&block)
287 concat('<p class="other-formats">' + l(:label_export_to), block.binding)
311 concat('<p class="other-formats">' + l(:label_export_to), block.binding)
288 yield Redmine::Views::OtherFormatsBuilder.new(self)
312 yield Redmine::Views::OtherFormatsBuilder.new(self)
289 concat('</p>', block.binding)
313 concat('</p>', block.binding)
290 end
314 end
291
315
292 def html_title(*args)
316 def html_title(*args)
293 if args.empty?
317 if args.empty?
294 title = []
318 title = []
295 title << @project.name if @project
319 title << @project.name if @project
296 title += @html_title if @html_title
320 title += @html_title if @html_title
297 title << Setting.app_title
321 title << Setting.app_title
298 title.compact.join(' - ')
322 title.compact.join(' - ')
299 else
323 else
300 @html_title ||= []
324 @html_title ||= []
301 @html_title += args
325 @html_title += args
302 end
326 end
303 end
327 end
304
328
305 def accesskey(s)
329 def accesskey(s)
306 Redmine::AccessKeys.key_for s
330 Redmine::AccessKeys.key_for s
307 end
331 end
308
332
309 # Formats text according to system settings.
333 # Formats text according to system settings.
310 # 2 ways to call this method:
334 # 2 ways to call this method:
311 # * with a String: textilizable(text, options)
335 # * with a String: textilizable(text, options)
312 # * with an object and one of its attribute: textilizable(issue, :description, options)
336 # * with an object and one of its attribute: textilizable(issue, :description, options)
313 def textilizable(*args)
337 def textilizable(*args)
314 options = args.last.is_a?(Hash) ? args.pop : {}
338 options = args.last.is_a?(Hash) ? args.pop : {}
315 case args.size
339 case args.size
316 when 1
340 when 1
317 obj = options[:object]
341 obj = options[:object]
318 text = args.shift
342 text = args.shift
319 when 2
343 when 2
320 obj = args.shift
344 obj = args.shift
321 text = obj.send(args.shift).to_s
345 text = obj.send(args.shift).to_s
322 else
346 else
323 raise ArgumentError, 'invalid arguments to textilizable'
347 raise ArgumentError, 'invalid arguments to textilizable'
324 end
348 end
325 return '' if text.blank?
349 return '' if text.blank?
326
350
327 only_path = options.delete(:only_path) == false ? false : true
351 only_path = options.delete(:only_path) == false ? false : true
328
352
329 # when using an image link, try to use an attachment, if possible
353 # when using an image link, try to use an attachment, if possible
330 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
354 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
331
355
332 if attachments
356 if attachments
333 attachments = attachments.sort_by(&:created_on).reverse
357 attachments = attachments.sort_by(&:created_on).reverse
334 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
358 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
335 style = $1
359 style = $1
336 filename = $6
360 filename = $6
337 rf = Regexp.new(Regexp.escape(filename), Regexp::IGNORECASE)
361 rf = Regexp.new(Regexp.escape(filename), Regexp::IGNORECASE)
338 # search for the picture in attachments
362 # search for the picture in attachments
339 if found = attachments.detect { |att| att.filename =~ rf }
363 if found = attachments.detect { |att| att.filename =~ rf }
340 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
364 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
341 desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
365 desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
342 alt = desc.blank? ? nil : "(#{desc})"
366 alt = desc.blank? ? nil : "(#{desc})"
343 "!#{style}#{image_url}#{alt}!"
367 "!#{style}#{image_url}#{alt}!"
344 else
368 else
345 "!#{style}#{filename}!"
369 "!#{style}#{filename}!"
346 end
370 end
347 end
371 end
348 end
372 end
349
373
350 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }
374 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }
351
375
352 # different methods for formatting wiki links
376 # different methods for formatting wiki links
353 case options[:wiki_links]
377 case options[:wiki_links]
354 when :local
378 when :local
355 # used for local links to html files
379 # used for local links to html files
356 format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
380 format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
357 when :anchor
381 when :anchor
358 # used for single-file wiki export
382 # used for single-file wiki export
359 format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
383 format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
360 else
384 else
361 format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
385 format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
362 end
386 end
363
387
364 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
388 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
365
389
366 # Wiki links
390 # Wiki links
367 #
391 #
368 # Examples:
392 # Examples:
369 # [[mypage]]
393 # [[mypage]]
370 # [[mypage|mytext]]
394 # [[mypage|mytext]]
371 # wiki links can refer other project wikis, using project name or identifier:
395 # wiki links can refer other project wikis, using project name or identifier:
372 # [[project:]] -> wiki starting page
396 # [[project:]] -> wiki starting page
373 # [[project:|mytext]]
397 # [[project:|mytext]]
374 # [[project:mypage]]
398 # [[project:mypage]]
375 # [[project:mypage|mytext]]
399 # [[project:mypage|mytext]]
376 text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
400 text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
377 link_project = project
401 link_project = project
378 esc, all, page, title = $1, $2, $3, $5
402 esc, all, page, title = $1, $2, $3, $5
379 if esc.nil?
403 if esc.nil?
380 if page =~ /^([^\:]+)\:(.*)$/
404 if page =~ /^([^\:]+)\:(.*)$/
381 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
405 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
382 page = $2
406 page = $2
383 title ||= $1 if page.blank?
407 title ||= $1 if page.blank?
384 end
408 end
385
409
386 if link_project && link_project.wiki
410 if link_project && link_project.wiki
387 # extract anchor
411 # extract anchor
388 anchor = nil
412 anchor = nil
389 if page =~ /^(.+?)\#(.+)$/
413 if page =~ /^(.+?)\#(.+)$/
390 page, anchor = $1, $2
414 page, anchor = $1, $2
391 end
415 end
392 # check if page exists
416 # check if page exists
393 wiki_page = link_project.wiki.find_page(page)
417 wiki_page = link_project.wiki.find_page(page)
394 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
418 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
395 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
419 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
396 else
420 else
397 # project or wiki doesn't exist
421 # project or wiki doesn't exist
398 title || page
422 title || page
399 end
423 end
400 else
424 else
401 all
425 all
402 end
426 end
403 end
427 end
404
428
405 # Redmine links
429 # Redmine links
406 #
430 #
407 # Examples:
431 # Examples:
408 # Issues:
432 # Issues:
409 # #52 -> Link to issue #52
433 # #52 -> Link to issue #52
410 # Changesets:
434 # Changesets:
411 # r52 -> Link to revision 52
435 # r52 -> Link to revision 52
412 # commit:a85130f -> Link to scmid starting with a85130f
436 # commit:a85130f -> Link to scmid starting with a85130f
413 # Documents:
437 # Documents:
414 # document#17 -> Link to document with id 17
438 # document#17 -> Link to document with id 17
415 # document:Greetings -> Link to the document with title "Greetings"
439 # document:Greetings -> Link to the document with title "Greetings"
416 # document:"Some document" -> Link to the document with title "Some document"
440 # document:"Some document" -> Link to the document with title "Some document"
417 # Versions:
441 # Versions:
418 # version#3 -> Link to version with id 3
442 # version#3 -> Link to version with id 3
419 # version:1.0.0 -> Link to version named "1.0.0"
443 # version:1.0.0 -> Link to version named "1.0.0"
420 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
444 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
421 # Attachments:
445 # Attachments:
422 # attachment:file.zip -> Link to the attachment of the current object named file.zip
446 # attachment:file.zip -> Link to the attachment of the current object named file.zip
423 # Source files:
447 # Source files:
424 # source:some/file -> Link to the file located at /some/file in the project's repository
448 # source:some/file -> Link to the file located at /some/file in the project's repository
425 # source:some/file@52 -> Link to the file's revision 52
449 # source:some/file@52 -> Link to the file's revision 52
426 # source:some/file#L120 -> Link to line 120 of the file
450 # source:some/file#L120 -> Link to line 120 of the file
427 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
451 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
428 # export:some/file -> Force the download of the file
452 # export:some/file -> Force the download of the file
429 # Forum messages:
453 # Forum messages:
430 # message#1218 -> Link to message with id 1218
454 # message#1218 -> Link to message with id 1218
431 text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|\s|<|$)}) do |m|
455 text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|\s|<|$)}) do |m|
432 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
456 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
433 link = nil
457 link = nil
434 if esc.nil?
458 if esc.nil?
435 if prefix.nil? && sep == 'r'
459 if prefix.nil? && sep == 'r'
436 if project && (changeset = project.changesets.find_by_revision(oid))
460 if project && (changeset = project.changesets.find_by_revision(oid))
437 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
461 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
438 :class => 'changeset',
462 :class => 'changeset',
439 :title => truncate_single_line(changeset.comments, 100))
463 :title => truncate_single_line(changeset.comments, 100))
440 end
464 end
441 elsif sep == '#'
465 elsif sep == '#'
442 oid = oid.to_i
466 oid = oid.to_i
443 case prefix
467 case prefix
444 when nil
468 when nil
445 if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
469 if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
446 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
470 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
447 :class => (issue.closed? ? 'issue closed' : 'issue'),
471 :class => (issue.closed? ? 'issue closed' : 'issue'),
448 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
472 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
449 link = content_tag('del', link) if issue.closed?
473 link = content_tag('del', link) if issue.closed?
450 end
474 end
451 when 'document'
475 when 'document'
452 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
476 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
453 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
477 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
454 :class => 'document'
478 :class => 'document'
455 end
479 end
456 when 'version'
480 when 'version'
457 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
481 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
458 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
482 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
459 :class => 'version'
483 :class => 'version'
460 end
484 end
461 when 'message'
485 when 'message'
462 if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
486 if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
463 link = link_to h(truncate(message.subject, 60)), {:only_path => only_path,
487 link = link_to h(truncate(message.subject, 60)), {:only_path => only_path,
464 :controller => 'messages',
488 :controller => 'messages',
465 :action => 'show',
489 :action => 'show',
466 :board_id => message.board,
490 :board_id => message.board,
467 :id => message.root,
491 :id => message.root,
468 :anchor => (message.parent ? "message-#{message.id}" : nil)},
492 :anchor => (message.parent ? "message-#{message.id}" : nil)},
469 :class => 'message'
493 :class => 'message'
470 end
494 end
471 end
495 end
472 elsif sep == ':'
496 elsif sep == ':'
473 # removes the double quotes if any
497 # removes the double quotes if any
474 name = oid.gsub(%r{^"(.*)"$}, "\\1")
498 name = oid.gsub(%r{^"(.*)"$}, "\\1")
475 case prefix
499 case prefix
476 when 'document'
500 when 'document'
477 if project && document = project.documents.find_by_title(name)
501 if project && document = project.documents.find_by_title(name)
478 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
502 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
479 :class => 'document'
503 :class => 'document'
480 end
504 end
481 when 'version'
505 when 'version'
482 if project && version = project.versions.find_by_name(name)
506 if project && version = project.versions.find_by_name(name)
483 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
507 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
484 :class => 'version'
508 :class => 'version'
485 end
509 end
486 when 'commit'
510 when 'commit'
487 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
511 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
488 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
512 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
489 :class => 'changeset',
513 :class => 'changeset',
490 :title => truncate_single_line(changeset.comments, 100)
514 :title => truncate_single_line(changeset.comments, 100)
491 end
515 end
492 when 'source', 'export'
516 when 'source', 'export'
493 if project && project.repository
517 if project && project.repository
494 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
518 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
495 path, rev, anchor = $1, $3, $5
519 path, rev, anchor = $1, $3, $5
496 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
520 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
497 :path => to_path_param(path),
521 :path => to_path_param(path),
498 :rev => rev,
522 :rev => rev,
499 :anchor => anchor,
523 :anchor => anchor,
500 :format => (prefix == 'export' ? 'raw' : nil)},
524 :format => (prefix == 'export' ? 'raw' : nil)},
501 :class => (prefix == 'export' ? 'source download' : 'source')
525 :class => (prefix == 'export' ? 'source download' : 'source')
502 end
526 end
503 when 'attachment'
527 when 'attachment'
504 if attachments && attachment = attachments.detect {|a| a.filename == name }
528 if attachments && attachment = attachments.detect {|a| a.filename == name }
505 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
529 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
506 :class => 'attachment'
530 :class => 'attachment'
507 end
531 end
508 end
532 end
509 end
533 end
510 end
534 end
511 leading + (link || "#{prefix}#{sep}#{oid}")
535 leading + (link || "#{prefix}#{sep}#{oid}")
512 end
536 end
513
537
514 text
538 text
515 end
539 end
516
540
517 # Same as Rails' simple_format helper without using paragraphs
541 # Same as Rails' simple_format helper without using paragraphs
518 def simple_format_without_paragraph(text)
542 def simple_format_without_paragraph(text)
519 text.to_s.
543 text.to_s.
520 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
544 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
521 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
545 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
522 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
546 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
523 end
547 end
524
548
525 def error_messages_for(object_name, options = {})
549 def error_messages_for(object_name, options = {})
526 options = options.symbolize_keys
550 options = options.symbolize_keys
527 object = instance_variable_get("@#{object_name}")
551 object = instance_variable_get("@#{object_name}")
528 if object && !object.errors.empty?
552 if object && !object.errors.empty?
529 # build full_messages here with controller current language
553 # build full_messages here with controller current language
530 full_messages = []
554 full_messages = []
531 object.errors.each do |attr, msg|
555 object.errors.each do |attr, msg|
532 next if msg.nil?
556 next if msg.nil?
533 msg = msg.first if msg.is_a? Array
557 msg = msg.first if msg.is_a? Array
534 if attr == "base"
558 if attr == "base"
535 full_messages << l(msg)
559 full_messages << l(msg)
536 else
560 else
537 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
561 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
538 end
562 end
539 end
563 end
540 # retrieve custom values error messages
564 # retrieve custom values error messages
541 if object.errors[:custom_values]
565 if object.errors[:custom_values]
542 object.custom_values.each do |v|
566 object.custom_values.each do |v|
543 v.errors.each do |attr, msg|
567 v.errors.each do |attr, msg|
544 next if msg.nil?
568 next if msg.nil?
545 msg = msg.first if msg.is_a? Array
569 msg = msg.first if msg.is_a? Array
546 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
570 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
547 end
571 end
548 end
572 end
549 end
573 end
550 content_tag("div",
574 content_tag("div",
551 content_tag(
575 content_tag(
552 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
576 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
553 ) +
577 ) +
554 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
578 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
555 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
579 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
556 )
580 )
557 else
581 else
558 ""
582 ""
559 end
583 end
560 end
584 end
561
585
562 def lang_options_for_select(blank=true)
586 def lang_options_for_select(blank=true)
563 (blank ? [["(auto)", ""]] : []) +
587 (blank ? [["(auto)", ""]] : []) +
564 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
588 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
565 end
589 end
566
590
567 def label_tag_for(name, option_tags = nil, options = {})
591 def label_tag_for(name, option_tags = nil, options = {})
568 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
592 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
569 content_tag("label", label_text)
593 content_tag("label", label_text)
570 end
594 end
571
595
572 def labelled_tabular_form_for(name, object, options, &proc)
596 def labelled_tabular_form_for(name, object, options, &proc)
573 options[:html] ||= {}
597 options[:html] ||= {}
574 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
598 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
575 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
599 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
576 end
600 end
577
601
578 def back_url_hidden_field_tag
602 def back_url_hidden_field_tag
579 back_url = params[:back_url] || request.env['HTTP_REFERER']
603 back_url = params[:back_url] || request.env['HTTP_REFERER']
580 back_url = CGI.unescape(back_url.to_s)
604 back_url = CGI.unescape(back_url.to_s)
581 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
605 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
582 end
606 end
583
607
584 def check_all_links(form_name)
608 def check_all_links(form_name)
585 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
609 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
586 " | " +
610 " | " +
587 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
611 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
588 end
612 end
589
613
590 def progress_bar(pcts, options={})
614 def progress_bar(pcts, options={})
591 pcts = [pcts, pcts] unless pcts.is_a?(Array)
615 pcts = [pcts, pcts] unless pcts.is_a?(Array)
592 pcts[1] = pcts[1] - pcts[0]
616 pcts[1] = pcts[1] - pcts[0]
593 pcts << (100 - pcts[1] - pcts[0])
617 pcts << (100 - pcts[1] - pcts[0])
594 width = options[:width] || '100px;'
618 width = options[:width] || '100px;'
595 legend = options[:legend] || ''
619 legend = options[:legend] || ''
596 content_tag('table',
620 content_tag('table',
597 content_tag('tr',
621 content_tag('tr',
598 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') +
622 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') +
599 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') +
623 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') +
600 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '')
624 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '')
601 ), :class => 'progress', :style => "width: #{width};") +
625 ), :class => 'progress', :style => "width: #{width};") +
602 content_tag('p', legend, :class => 'pourcent')
626 content_tag('p', legend, :class => 'pourcent')
603 end
627 end
604
628
605 def context_menu_link(name, url, options={})
629 def context_menu_link(name, url, options={})
606 options[:class] ||= ''
630 options[:class] ||= ''
607 if options.delete(:selected)
631 if options.delete(:selected)
608 options[:class] << ' icon-checked disabled'
632 options[:class] << ' icon-checked disabled'
609 options[:disabled] = true
633 options[:disabled] = true
610 end
634 end
611 if options.delete(:disabled)
635 if options.delete(:disabled)
612 options.delete(:method)
636 options.delete(:method)
613 options.delete(:confirm)
637 options.delete(:confirm)
614 options.delete(:onclick)
638 options.delete(:onclick)
615 options[:class] << ' disabled'
639 options[:class] << ' disabled'
616 url = '#'
640 url = '#'
617 end
641 end
618 link_to name, url, options
642 link_to name, url, options
619 end
643 end
620
644
621 def calendar_for(field_id)
645 def calendar_for(field_id)
622 include_calendar_headers_tags
646 include_calendar_headers_tags
623 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
647 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
624 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
648 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
625 end
649 end
626
650
627 def include_calendar_headers_tags
651 def include_calendar_headers_tags
628 unless @calendar_headers_tags_included
652 unless @calendar_headers_tags_included
629 @calendar_headers_tags_included = true
653 @calendar_headers_tags_included = true
630 content_for :header_tags do
654 content_for :header_tags do
631 javascript_include_tag('calendar/calendar') +
655 javascript_include_tag('calendar/calendar') +
632 javascript_include_tag("calendar/lang/calendar-#{current_language}.js") +
656 javascript_include_tag("calendar/lang/calendar-#{current_language}.js") +
633 javascript_include_tag('calendar/calendar-setup') +
657 javascript_include_tag('calendar/calendar-setup') +
634 stylesheet_link_tag('calendar')
658 stylesheet_link_tag('calendar')
635 end
659 end
636 end
660 end
637 end
661 end
638
662
639 def content_for(name, content = nil, &block)
663 def content_for(name, content = nil, &block)
640 @has_content ||= {}
664 @has_content ||= {}
641 @has_content[name] = true
665 @has_content[name] = true
642 super(name, content, &block)
666 super(name, content, &block)
643 end
667 end
644
668
645 def has_content?(name)
669 def has_content?(name)
646 (@has_content && @has_content[name]) || false
670 (@has_content && @has_content[name]) || false
647 end
671 end
648
672
649 # Returns the avatar image tag for the given +user+ if avatars are enabled
673 # Returns the avatar image tag for the given +user+ if avatars are enabled
650 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
674 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
651 def avatar(user, options = { })
675 def avatar(user, options = { })
652 if Setting.gravatar_enabled?
676 if Setting.gravatar_enabled?
653 email = nil
677 email = nil
654 if user.respond_to?(:mail)
678 if user.respond_to?(:mail)
655 email = user.mail
679 email = user.mail
656 elsif user.to_s =~ %r{<(.+?)>}
680 elsif user.to_s =~ %r{<(.+?)>}
657 email = $1
681 email = $1
658 end
682 end
659 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
683 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
660 end
684 end
661 end
685 end
662
686
663 private
687 private
664
688
665 def wiki_helper
689 def wiki_helper
666 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
690 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
667 extend helper
691 extend helper
668 return self
692 return self
669 end
693 end
670
694
671 def link_to_remote_content_update(text, url_params)
695 def link_to_remote_content_update(text, url_params)
672 link_to_remote(text,
696 link_to_remote(text,
673 {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
697 {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
674 {:href => url_for(:params => url_params)}
698 {:href => url_for(:params => url_params)}
675 )
699 )
676 end
700 end
677
701
678 end
702 end
@@ -1,12 +1,27
1 <%= error_messages_for 'tracker' %>
1 <%= error_messages_for 'tracker' %>
2 <div class="box">
2
3 <div class="splitcontentleft">
4 <div class="box tabular">
3 <!--[form:tracker]-->
5 <!--[form:tracker]-->
4 <p><%= f.text_field :name, :required => true %></p>
6 <p><%= f.text_field :name, :required => true %></p>
5 <p><%= f.check_box :is_in_chlog %></p>
7 <p><%= f.check_box :is_in_chlog %></p>
6 <p><%= f.check_box :is_in_roadmap %></p>
8 <p><%= f.check_box :is_in_roadmap %></p>
7 <% if @tracker.new_record? && @trackers.any? %>
9 <% if @tracker.new_record? && @trackers.any? %>
8 <p><label><%= l(:label_copy_workflow_from) %></label>
10 <p><label><%= l(:label_copy_workflow_from) %></label>
9 <%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %></p>
11 <%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %></p>
10 <% end %>
12 <% end %>
11 <!--[eoform:tracker]-->
13 <!--[eoform:tracker]-->
12 </div>
14 </div>
15 </div>
16
17 <div class="splitcontentright">
18 <% if @projects.any? %>
19 <fieldset class="box" id="tracker_project_ids"><legend><%= l(:label_project_plural) %></legend>
20 <%= project_nested_ul(@projects) do |p|
21 content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p))
22 end %>
23 <%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %>
24 <p><%= check_all_links 'tracker_project_ids' %></p>
25 </fieldset>
26 <% end %>
27 </div>
@@ -1,6 +1,6
1 <h2><%=l(:label_tracker)%></h2>
1 <h2><%=l(:label_tracker)%></h2>
2
2
3 <% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'edit' } do |f| %>
3 <% form_for :tracker, @tracker, :url => { :action => 'edit' }, :builder => TabularFormBuilder do |f| %>
4 <%= render :partial => 'form', :locals => { :f => f } %>
4 <%= render :partial => 'form', :locals => { :f => f } %>
5 <%= submit_tag l(:button_save) %>
5 <%= submit_tag l(:button_save) %>
6 <% end %> No newline at end of file
6 <% end %>
@@ -1,6 +1,6
1 <h2><%=l(:label_tracker_new)%></h2>
1 <h2><%=l(:label_tracker_new)%></h2>
2
2
3 <% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'new' } do |f| %>
3 <% form_for :tracker, @tracker, :url => { :action => 'new' }, :builder => TabularFormBuilder do |f| %>
4 <%= render :partial => 'form', :locals => { :f => f } %>
4 <%= render :partial => 'form', :locals => { :f => f } %>
5 <%= submit_tag l(:button_create) %>
5 <%= submit_tag l(:button_create) %>
6 <% end %> No newline at end of file
6 <% end %>
@@ -1,701 +1,704
1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2
2
3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
4 h1 {margin:0; padding:0; font-size: 24px;}
4 h1 {margin:0; padding:0; font-size: 24px;}
5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
8
8
9 /***** Layout *****/
9 /***** Layout *****/
10 #wrapper {background: white;}
10 #wrapper {background: white;}
11
11
12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
13 #top-menu ul {margin: 0; padding: 0;}
13 #top-menu ul {margin: 0; padding: 0;}
14 #top-menu li {
14 #top-menu li {
15 float:left;
15 float:left;
16 list-style-type:none;
16 list-style-type:none;
17 margin: 0px 0px 0px 0px;
17 margin: 0px 0px 0px 0px;
18 padding: 0px 0px 0px 0px;
18 padding: 0px 0px 0px 0px;
19 white-space:nowrap;
19 white-space:nowrap;
20 }
20 }
21 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
21 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
23
23
24 #account {float:right;}
24 #account {float:right;}
25
25
26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
27 #header a {color:#f8f8f8;}
27 #header a {color:#f8f8f8;}
28 #quick-search {float:right;}
28 #quick-search {float:right;}
29
29
30 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
30 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
31 #main-menu ul {margin: 0; padding: 0;}
31 #main-menu ul {margin: 0; padding: 0;}
32 #main-menu li {
32 #main-menu li {
33 float:left;
33 float:left;
34 list-style-type:none;
34 list-style-type:none;
35 margin: 0px 2px 0px 0px;
35 margin: 0px 2px 0px 0px;
36 padding: 0px 0px 0px 0px;
36 padding: 0px 0px 0px 0px;
37 white-space:nowrap;
37 white-space:nowrap;
38 }
38 }
39 #main-menu li a {
39 #main-menu li a {
40 display: block;
40 display: block;
41 color: #fff;
41 color: #fff;
42 text-decoration: none;
42 text-decoration: none;
43 font-weight: bold;
43 font-weight: bold;
44 margin: 0;
44 margin: 0;
45 padding: 4px 10px 4px 10px;
45 padding: 4px 10px 4px 10px;
46 }
46 }
47 #main-menu li a:hover {background:#759FCF; color:#fff;}
47 #main-menu li a:hover {background:#759FCF; color:#fff;}
48 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
48 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
49
49
50 #main {background-color:#EEEEEE;}
50 #main {background-color:#EEEEEE;}
51
51
52 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
52 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
53 * html #sidebar{ width: 17%; }
53 * html #sidebar{ width: 17%; }
54 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
54 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
55 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
55 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
56 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
56 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
57
57
58 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
58 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
59 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
59 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
60 html>body #content { min-height: 600px; }
60 html>body #content { min-height: 600px; }
61 * html body #content { height: 600px; } /* IE */
61 * html body #content { height: 600px; } /* IE */
62
62
63 #main.nosidebar #sidebar{ display: none; }
63 #main.nosidebar #sidebar{ display: none; }
64 #main.nosidebar #content{ width: auto; border-right: 0; }
64 #main.nosidebar #content{ width: auto; border-right: 0; }
65
65
66 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
66 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
67
67
68 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
68 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
69 #login-form table td {padding: 6px;}
69 #login-form table td {padding: 6px;}
70 #login-form label {font-weight: bold;}
70 #login-form label {font-weight: bold;}
71
71
72 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
72 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
73
73
74 /***** Links *****/
74 /***** Links *****/
75 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
75 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
76 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
76 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
77 a img{ border: 0; }
77 a img{ border: 0; }
78
78
79 a.issue.closed { text-decoration: line-through; }
79 a.issue.closed { text-decoration: line-through; }
80
80
81 /***** Tables *****/
81 /***** Tables *****/
82 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
82 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
83 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
83 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
84 table.list td { vertical-align: top; }
84 table.list td { vertical-align: top; }
85 table.list td.id { width: 2%; text-align: center;}
85 table.list td.id { width: 2%; text-align: center;}
86 table.list td.checkbox { width: 15px; padding: 0px;}
86 table.list td.checkbox { width: 15px; padding: 0px;}
87
87
88 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
88 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
89 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
89 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
90
90
91 tr.issue { text-align: center; white-space: nowrap; }
91 tr.issue { text-align: center; white-space: nowrap; }
92 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
92 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
93 tr.issue td.subject { text-align: left; }
93 tr.issue td.subject { text-align: left; }
94 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
94 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
95
95
96 tr.entry { border: 1px solid #f8f8f8; }
96 tr.entry { border: 1px solid #f8f8f8; }
97 tr.entry td { white-space: nowrap; }
97 tr.entry td { white-space: nowrap; }
98 tr.entry td.filename { width: 30%; }
98 tr.entry td.filename { width: 30%; }
99 tr.entry td.size { text-align: right; font-size: 90%; }
99 tr.entry td.size { text-align: right; font-size: 90%; }
100 tr.entry td.revision, tr.entry td.author { text-align: center; }
100 tr.entry td.revision, tr.entry td.author { text-align: center; }
101 tr.entry td.age { text-align: right; }
101 tr.entry td.age { text-align: right; }
102
102
103 tr.entry span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
103 tr.entry span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
104 tr.entry.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
104 tr.entry.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
105 tr.entry.file td.filename a { margin-left: 16px; }
105 tr.entry.file td.filename a { margin-left: 16px; }
106
106
107 tr.changeset td.author { text-align: center; width: 15%; }
107 tr.changeset td.author { text-align: center; width: 15%; }
108 tr.changeset td.committed_on { text-align: center; width: 15%; }
108 tr.changeset td.committed_on { text-align: center; width: 15%; }
109
109
110 tr.message { height: 2.6em; }
110 tr.message { height: 2.6em; }
111 tr.message td.last_message { font-size: 80%; }
111 tr.message td.last_message { font-size: 80%; }
112 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
112 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
113 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
113 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
114
114
115 tr.user td { width:13%; }
115 tr.user td { width:13%; }
116 tr.user td.email { width:18%; }
116 tr.user td.email { width:18%; }
117 tr.user td { white-space: nowrap; }
117 tr.user td { white-space: nowrap; }
118 tr.user.locked, tr.user.registered { color: #aaa; }
118 tr.user.locked, tr.user.registered { color: #aaa; }
119 tr.user.locked a, tr.user.registered a { color: #aaa; }
119 tr.user.locked a, tr.user.registered a { color: #aaa; }
120
120
121 tr.time-entry { text-align: center; white-space: nowrap; }
121 tr.time-entry { text-align: center; white-space: nowrap; }
122 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
122 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
123 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
123 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
124 td.hours .hours-dec { font-size: 0.9em; }
124 td.hours .hours-dec { font-size: 0.9em; }
125
125
126 table.plugins td { vertical-align: middle; }
126 table.plugins td { vertical-align: middle; }
127 table.plugins td.configure { text-align: right; padding-right: 1em; }
127 table.plugins td.configure { text-align: right; padding-right: 1em; }
128 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
128 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
129 table.plugins span.description { display: block; font-size: 0.9em; }
129 table.plugins span.description { display: block; font-size: 0.9em; }
130 table.plugins span.url { display: block; font-size: 0.9em; }
130 table.plugins span.url { display: block; font-size: 0.9em; }
131
131
132 table.list tbody tr:hover { background-color:#ffffdd; }
132 table.list tbody tr:hover { background-color:#ffffdd; }
133 table td {padding:2px;}
133 table td {padding:2px;}
134 table p {margin:0;}
134 table p {margin:0;}
135 .odd {background-color:#f6f7f8;}
135 .odd {background-color:#f6f7f8;}
136 .even {background-color: #fff;}
136 .even {background-color: #fff;}
137
137
138 .highlight { background-color: #FCFD8D;}
138 .highlight { background-color: #FCFD8D;}
139 .highlight.token-1 { background-color: #faa;}
139 .highlight.token-1 { background-color: #faa;}
140 .highlight.token-2 { background-color: #afa;}
140 .highlight.token-2 { background-color: #afa;}
141 .highlight.token-3 { background-color: #aaf;}
141 .highlight.token-3 { background-color: #aaf;}
142
142
143 .box{
143 .box{
144 padding:6px;
144 padding:6px;
145 margin-bottom: 10px;
145 margin-bottom: 10px;
146 background-color:#f6f6f6;
146 background-color:#f6f6f6;
147 color:#505050;
147 color:#505050;
148 line-height:1.5em;
148 line-height:1.5em;
149 border: 1px solid #e4e4e4;
149 border: 1px solid #e4e4e4;
150 }
150 }
151
151
152 div.square {
152 div.square {
153 border: 1px solid #999;
153 border: 1px solid #999;
154 float: left;
154 float: left;
155 margin: .3em .4em 0 .4em;
155 margin: .3em .4em 0 .4em;
156 overflow: hidden;
156 overflow: hidden;
157 width: .6em; height: .6em;
157 width: .6em; height: .6em;
158 }
158 }
159 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
159 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
160 .contextual input {font-size:0.9em;}
160 .contextual input {font-size:0.9em;}
161
161
162 .splitcontentleft{float:left; width:49%;}
162 .splitcontentleft{float:left; width:49%;}
163 .splitcontentright{float:right; width:49%;}
163 .splitcontentright{float:right; width:49%;}
164 form {display: inline;}
164 form {display: inline;}
165 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
165 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
166 fieldset {border: 1px solid #e4e4e4; margin:0;}
166 fieldset {border: 1px solid #e4e4e4; margin:0;}
167 legend {color: #484848;}
167 legend {color: #484848;}
168 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
168 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
169 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
169 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
170 blockquote blockquote { margin-left: 0;}
170 blockquote blockquote { margin-left: 0;}
171 textarea.wiki-edit { width: 99%; }
171 textarea.wiki-edit { width: 99%; }
172 li p {margin-top: 0;}
172 li p {margin-top: 0;}
173 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
173 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
174 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
174 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
175 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
175 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
176 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
176 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
177
177
178 fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; }
178 fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; }
179 fieldset#filters p { margin: 1.2em 0 0.8em 2px; }
179 fieldset#filters p { margin: 1.2em 0 0.8em 2px; }
180 fieldset#filters table { border-collapse: collapse; }
180 fieldset#filters table { border-collapse: collapse; }
181 fieldset#filters table td { padding: 0; vertical-align: middle; }
181 fieldset#filters table td { padding: 0; vertical-align: middle; }
182 fieldset#filters tr.filter { height: 2em; }
182 fieldset#filters tr.filter { height: 2em; }
183 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
183 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
184 .buttons { font-size: 0.9em; }
184 .buttons { font-size: 0.9em; }
185
185
186 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
186 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
187 div#issue-changesets .changeset { padding: 4px;}
187 div#issue-changesets .changeset { padding: 4px;}
188 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
188 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
189 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
189 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
190
190
191 div#activity dl, #search-results { margin-left: 2em; }
191 div#activity dl, #search-results { margin-left: 2em; }
192 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
192 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
193 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
193 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
194 div#activity dt.me .time { border-bottom: 1px solid #999; }
194 div#activity dt.me .time { border-bottom: 1px solid #999; }
195 div#activity dt .time { color: #777; font-size: 80%; }
195 div#activity dt .time { color: #777; font-size: 80%; }
196 div#activity dd .description, #search-results dd .description { font-style: italic; }
196 div#activity dd .description, #search-results dd .description { font-style: italic; }
197 div#activity span.project:after, #search-results span.project:after { content: " -"; }
197 div#activity span.project:after, #search-results span.project:after { content: " -"; }
198 div#activity dd span.description, #search-results dd span.description { display:block; }
198 div#activity dd span.description, #search-results dd span.description { display:block; }
199
199
200 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
200 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
201
201
202 div#search-results-counts {float:right;}
202 div#search-results-counts {float:right;}
203 div#search-results-counts ul { margin-top: 0.5em; }
203 div#search-results-counts ul { margin-top: 0.5em; }
204 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
204 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
205
205
206 dt.issue { background-image: url(../images/ticket.png); }
206 dt.issue { background-image: url(../images/ticket.png); }
207 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
207 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
208 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
208 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
209 dt.issue-note { background-image: url(../images/ticket_note.png); }
209 dt.issue-note { background-image: url(../images/ticket_note.png); }
210 dt.changeset { background-image: url(../images/changeset.png); }
210 dt.changeset { background-image: url(../images/changeset.png); }
211 dt.news { background-image: url(../images/news.png); }
211 dt.news { background-image: url(../images/news.png); }
212 dt.message { background-image: url(../images/message.png); }
212 dt.message { background-image: url(../images/message.png); }
213 dt.reply { background-image: url(../images/comments.png); }
213 dt.reply { background-image: url(../images/comments.png); }
214 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
214 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
215 dt.attachment { background-image: url(../images/attachment.png); }
215 dt.attachment { background-image: url(../images/attachment.png); }
216 dt.document { background-image: url(../images/document.png); }
216 dt.document { background-image: url(../images/document.png); }
217 dt.project { background-image: url(../images/projects.png); }
217 dt.project { background-image: url(../images/projects.png); }
218
218
219 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
219 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
220
220
221 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
221 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
222 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
222 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
223 div#roadmap .wiki h1:first-child { display: none; }
223 div#roadmap .wiki h1:first-child { display: none; }
224 div#roadmap .wiki h1 { font-size: 120%; }
224 div#roadmap .wiki h1 { font-size: 120%; }
225 div#roadmap .wiki h2 { font-size: 110%; }
225 div#roadmap .wiki h2 { font-size: 110%; }
226
226
227 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
227 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
228 div#version-summary fieldset { margin-bottom: 1em; }
228 div#version-summary fieldset { margin-bottom: 1em; }
229 div#version-summary .total-hours { text-align: right; }
229 div#version-summary .total-hours { text-align: right; }
230
230
231 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
231 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
232 table#time-report tbody tr { font-style: italic; color: #777; }
232 table#time-report tbody tr { font-style: italic; color: #777; }
233 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
233 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
234 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
234 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
235 table#time-report .hours-dec { font-size: 0.9em; }
235 table#time-report .hours-dec { font-size: 0.9em; }
236
236
237 form#issue-form .attributes { margin-bottom: 8px; }
237 form#issue-form .attributes { margin-bottom: 8px; }
238 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
238 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
239 form#issue-form .attributes select { min-width: 30%; }
239 form#issue-form .attributes select { min-width: 30%; }
240
240
241 ul.projects { margin: 0; padding-left: 1em; }
241 ul.projects { margin: 0; padding-left: 1em; }
242 ul.projects.root { margin: 0; padding: 0; }
242 ul.projects.root { margin: 0; padding: 0; }
243 ul.projects ul { border-left: 3px solid #e0e0e0; }
243 ul.projects ul { border-left: 3px solid #e0e0e0; }
244 ul.projects li { list-style-type:none; }
244 ul.projects li { list-style-type:none; }
245 ul.projects li.root { margin-bottom: 1em; }
245 ul.projects li.root { margin-bottom: 1em; }
246 ul.projects li.child { margin-top: 1em;}
246 ul.projects li.child { margin-top: 1em;}
247 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
247 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
248 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
248 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
249
249
250 #tracker_project_ids ul { margin: 0; padding-left: 1em; }
251 #tracker_project_ids li { list-style-type:none; }
252
250 ul.properties {padding:0; font-size: 0.9em; color: #777;}
253 ul.properties {padding:0; font-size: 0.9em; color: #777;}
251 ul.properties li {list-style-type:none;}
254 ul.properties li {list-style-type:none;}
252 ul.properties li span {font-style:italic;}
255 ul.properties li span {font-style:italic;}
253
256
254 .total-hours { font-size: 110%; font-weight: bold; }
257 .total-hours { font-size: 110%; font-weight: bold; }
255 .total-hours span.hours-int { font-size: 120%; }
258 .total-hours span.hours-int { font-size: 120%; }
256
259
257 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
260 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
258 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
261 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
259
262
260 .pagination {font-size: 90%}
263 .pagination {font-size: 90%}
261 p.pagination {margin-top:8px;}
264 p.pagination {margin-top:8px;}
262
265
263 /***** Tabular forms ******/
266 /***** Tabular forms ******/
264 .tabular p{
267 .tabular p{
265 margin: 0;
268 margin: 0;
266 padding: 5px 0 8px 0;
269 padding: 5px 0 8px 0;
267 padding-left: 180px; /*width of left column containing the label elements*/
270 padding-left: 180px; /*width of left column containing the label elements*/
268 height: 1%;
271 height: 1%;
269 clear:left;
272 clear:left;
270 }
273 }
271
274
272 html>body .tabular p {overflow:hidden;}
275 html>body .tabular p {overflow:hidden;}
273
276
274 .tabular label{
277 .tabular label{
275 font-weight: bold;
278 font-weight: bold;
276 float: left;
279 float: left;
277 text-align: right;
280 text-align: right;
278 margin-left: -180px; /*width of left column*/
281 margin-left: -180px; /*width of left column*/
279 width: 175px; /*width of labels. Should be smaller than left column to create some right
282 width: 175px; /*width of labels. Should be smaller than left column to create some right
280 margin*/
283 margin*/
281 }
284 }
282
285
283 .tabular label.floating{
286 .tabular label.floating{
284 font-weight: normal;
287 font-weight: normal;
285 margin-left: 0px;
288 margin-left: 0px;
286 text-align: left;
289 text-align: left;
287 width: 270px;
290 width: 270px;
288 }
291 }
289
292
290 input#time_entry_comments { width: 90%;}
293 input#time_entry_comments { width: 90%;}
291
294
292 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
295 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
293
296
294 .tabular.settings p{ padding-left: 300px; }
297 .tabular.settings p{ padding-left: 300px; }
295 .tabular.settings label{ margin-left: -300px; width: 295px; }
298 .tabular.settings label{ margin-left: -300px; width: 295px; }
296
299
297 .required {color: #bb0000;}
300 .required {color: #bb0000;}
298 .summary {font-style: italic;}
301 .summary {font-style: italic;}
299
302
300 #attachments_fields input[type=text] {margin-left: 8px; }
303 #attachments_fields input[type=text] {margin-left: 8px; }
301
304
302 div.attachments { margin-top: 12px; }
305 div.attachments { margin-top: 12px; }
303 div.attachments p { margin:4px 0 2px 0; }
306 div.attachments p { margin:4px 0 2px 0; }
304 div.attachments img { vertical-align: middle; }
307 div.attachments img { vertical-align: middle; }
305 div.attachments span.author { font-size: 0.9em; color: #888; }
308 div.attachments span.author { font-size: 0.9em; color: #888; }
306
309
307 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
310 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
308 .other-formats span + span:before { content: "| "; }
311 .other-formats span + span:before { content: "| "; }
309
312
310 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
313 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
311
314
312 /***** Flash & error messages ****/
315 /***** Flash & error messages ****/
313 #errorExplanation, div.flash, .nodata, .warning {
316 #errorExplanation, div.flash, .nodata, .warning {
314 padding: 4px 4px 4px 30px;
317 padding: 4px 4px 4px 30px;
315 margin-bottom: 12px;
318 margin-bottom: 12px;
316 font-size: 1.1em;
319 font-size: 1.1em;
317 border: 2px solid;
320 border: 2px solid;
318 }
321 }
319
322
320 div.flash {margin-top: 8px;}
323 div.flash {margin-top: 8px;}
321
324
322 div.flash.error, #errorExplanation {
325 div.flash.error, #errorExplanation {
323 background: url(../images/false.png) 8px 5px no-repeat;
326 background: url(../images/false.png) 8px 5px no-repeat;
324 background-color: #ffe3e3;
327 background-color: #ffe3e3;
325 border-color: #dd0000;
328 border-color: #dd0000;
326 color: #550000;
329 color: #550000;
327 }
330 }
328
331
329 div.flash.notice {
332 div.flash.notice {
330 background: url(../images/true.png) 8px 5px no-repeat;
333 background: url(../images/true.png) 8px 5px no-repeat;
331 background-color: #dfffdf;
334 background-color: #dfffdf;
332 border-color: #9fcf9f;
335 border-color: #9fcf9f;
333 color: #005f00;
336 color: #005f00;
334 }
337 }
335
338
336 div.flash.warning {
339 div.flash.warning {
337 background: url(../images/warning.png) 8px 5px no-repeat;
340 background: url(../images/warning.png) 8px 5px no-repeat;
338 background-color: #FFEBC1;
341 background-color: #FFEBC1;
339 border-color: #FDBF3B;
342 border-color: #FDBF3B;
340 color: #A6750C;
343 color: #A6750C;
341 text-align: left;
344 text-align: left;
342 }
345 }
343
346
344 .nodata, .warning {
347 .nodata, .warning {
345 text-align: center;
348 text-align: center;
346 background-color: #FFEBC1;
349 background-color: #FFEBC1;
347 border-color: #FDBF3B;
350 border-color: #FDBF3B;
348 color: #A6750C;
351 color: #A6750C;
349 }
352 }
350
353
351 #errorExplanation ul { font-size: 0.9em;}
354 #errorExplanation ul { font-size: 0.9em;}
352
355
353 /***** Ajax indicator ******/
356 /***** Ajax indicator ******/
354 #ajax-indicator {
357 #ajax-indicator {
355 position: absolute; /* fixed not supported by IE */
358 position: absolute; /* fixed not supported by IE */
356 background-color:#eee;
359 background-color:#eee;
357 border: 1px solid #bbb;
360 border: 1px solid #bbb;
358 top:35%;
361 top:35%;
359 left:40%;
362 left:40%;
360 width:20%;
363 width:20%;
361 font-weight:bold;
364 font-weight:bold;
362 text-align:center;
365 text-align:center;
363 padding:0.6em;
366 padding:0.6em;
364 z-index:100;
367 z-index:100;
365 filter:alpha(opacity=50);
368 filter:alpha(opacity=50);
366 opacity: 0.5;
369 opacity: 0.5;
367 }
370 }
368
371
369 html>body #ajax-indicator { position: fixed; }
372 html>body #ajax-indicator { position: fixed; }
370
373
371 #ajax-indicator span {
374 #ajax-indicator span {
372 background-position: 0% 40%;
375 background-position: 0% 40%;
373 background-repeat: no-repeat;
376 background-repeat: no-repeat;
374 background-image: url(../images/loading.gif);
377 background-image: url(../images/loading.gif);
375 padding-left: 26px;
378 padding-left: 26px;
376 vertical-align: bottom;
379 vertical-align: bottom;
377 }
380 }
378
381
379 /***** Calendar *****/
382 /***** Calendar *****/
380 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
383 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
381 table.cal thead th {width: 14%;}
384 table.cal thead th {width: 14%;}
382 table.cal tbody tr {height: 100px;}
385 table.cal tbody tr {height: 100px;}
383 table.cal th { background-color:#EEEEEE; padding: 4px; }
386 table.cal th { background-color:#EEEEEE; padding: 4px; }
384 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
387 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
385 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
388 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
386 table.cal td.odd p.day-num {color: #bbb;}
389 table.cal td.odd p.day-num {color: #bbb;}
387 table.cal td.today {background:#ffffdd;}
390 table.cal td.today {background:#ffffdd;}
388 table.cal td.today p.day-num {font-weight: bold;}
391 table.cal td.today p.day-num {font-weight: bold;}
389
392
390 /***** Tooltips ******/
393 /***** Tooltips ******/
391 .tooltip{position:relative;z-index:24;}
394 .tooltip{position:relative;z-index:24;}
392 .tooltip:hover{z-index:25;color:#000;}
395 .tooltip:hover{z-index:25;color:#000;}
393 .tooltip span.tip{display: none; text-align:left;}
396 .tooltip span.tip{display: none; text-align:left;}
394
397
395 div.tooltip:hover span.tip{
398 div.tooltip:hover span.tip{
396 display:block;
399 display:block;
397 position:absolute;
400 position:absolute;
398 top:12px; left:24px; width:270px;
401 top:12px; left:24px; width:270px;
399 border:1px solid #555;
402 border:1px solid #555;
400 background-color:#fff;
403 background-color:#fff;
401 padding: 4px;
404 padding: 4px;
402 font-size: 0.8em;
405 font-size: 0.8em;
403 color:#505050;
406 color:#505050;
404 }
407 }
405
408
406 /***** Progress bar *****/
409 /***** Progress bar *****/
407 table.progress {
410 table.progress {
408 border: 1px solid #D7D7D7;
411 border: 1px solid #D7D7D7;
409 border-collapse: collapse;
412 border-collapse: collapse;
410 border-spacing: 0pt;
413 border-spacing: 0pt;
411 empty-cells: show;
414 empty-cells: show;
412 text-align: center;
415 text-align: center;
413 float:left;
416 float:left;
414 margin: 1px 6px 1px 0px;
417 margin: 1px 6px 1px 0px;
415 }
418 }
416
419
417 table.progress td { height: 0.9em; }
420 table.progress td { height: 0.9em; }
418 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
421 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
419 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
422 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
420 table.progress td.open { background: #FFF none repeat scroll 0%; }
423 table.progress td.open { background: #FFF none repeat scroll 0%; }
421 p.pourcent {font-size: 80%;}
424 p.pourcent {font-size: 80%;}
422 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
425 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
423
426
424 /***** Tabs *****/
427 /***** Tabs *****/
425 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative;}
428 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative;}
426 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em;}
429 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em;}
427 #content .tabs>ul { bottom:-1px; } /* others */
430 #content .tabs>ul { bottom:-1px; } /* others */
428 #content .tabs ul li {
431 #content .tabs ul li {
429 float:left;
432 float:left;
430 list-style-type:none;
433 list-style-type:none;
431 white-space:nowrap;
434 white-space:nowrap;
432 margin-right:8px;
435 margin-right:8px;
433 background:#fff;
436 background:#fff;
434 }
437 }
435 #content .tabs ul li a{
438 #content .tabs ul li a{
436 display:block;
439 display:block;
437 font-size: 0.9em;
440 font-size: 0.9em;
438 text-decoration:none;
441 text-decoration:none;
439 line-height:1.3em;
442 line-height:1.3em;
440 padding:4px 6px 4px 6px;
443 padding:4px 6px 4px 6px;
441 border: 1px solid #ccc;
444 border: 1px solid #ccc;
442 border-bottom: 1px solid #bbbbbb;
445 border-bottom: 1px solid #bbbbbb;
443 background-color: #eeeeee;
446 background-color: #eeeeee;
444 color:#777;
447 color:#777;
445 font-weight:bold;
448 font-weight:bold;
446 }
449 }
447
450
448 #content .tabs ul li a:hover {
451 #content .tabs ul li a:hover {
449 background-color: #ffffdd;
452 background-color: #ffffdd;
450 text-decoration:none;
453 text-decoration:none;
451 }
454 }
452
455
453 #content .tabs ul li a.selected {
456 #content .tabs ul li a.selected {
454 background-color: #fff;
457 background-color: #fff;
455 border: 1px solid #bbbbbb;
458 border: 1px solid #bbbbbb;
456 border-bottom: 1px solid #fff;
459 border-bottom: 1px solid #fff;
457 }
460 }
458
461
459 #content .tabs ul li a.selected:hover {
462 #content .tabs ul li a.selected:hover {
460 background-color: #fff;
463 background-color: #fff;
461 }
464 }
462
465
463 /***** Diff *****/
466 /***** Diff *****/
464 .diff_out { background: #fcc; }
467 .diff_out { background: #fcc; }
465 .diff_in { background: #cfc; }
468 .diff_in { background: #cfc; }
466
469
467 /***** Wiki *****/
470 /***** Wiki *****/
468 div.wiki table {
471 div.wiki table {
469 border: 1px solid #505050;
472 border: 1px solid #505050;
470 border-collapse: collapse;
473 border-collapse: collapse;
471 margin-bottom: 1em;
474 margin-bottom: 1em;
472 }
475 }
473
476
474 div.wiki table, div.wiki td, div.wiki th {
477 div.wiki table, div.wiki td, div.wiki th {
475 border: 1px solid #bbb;
478 border: 1px solid #bbb;
476 padding: 4px;
479 padding: 4px;
477 }
480 }
478
481
479 div.wiki .external {
482 div.wiki .external {
480 background-position: 0% 60%;
483 background-position: 0% 60%;
481 background-repeat: no-repeat;
484 background-repeat: no-repeat;
482 padding-left: 12px;
485 padding-left: 12px;
483 background-image: url(../images/external.png);
486 background-image: url(../images/external.png);
484 }
487 }
485
488
486 div.wiki a.new {
489 div.wiki a.new {
487 color: #b73535;
490 color: #b73535;
488 }
491 }
489
492
490 div.wiki pre {
493 div.wiki pre {
491 margin: 1em 1em 1em 1.6em;
494 margin: 1em 1em 1em 1.6em;
492 padding: 2px;
495 padding: 2px;
493 background-color: #fafafa;
496 background-color: #fafafa;
494 border: 1px solid #dadada;
497 border: 1px solid #dadada;
495 width:95%;
498 width:95%;
496 overflow-x: auto;
499 overflow-x: auto;
497 }
500 }
498
501
499 div.wiki ul.toc {
502 div.wiki ul.toc {
500 background-color: #ffffdd;
503 background-color: #ffffdd;
501 border: 1px solid #e4e4e4;
504 border: 1px solid #e4e4e4;
502 padding: 4px;
505 padding: 4px;
503 line-height: 1.2em;
506 line-height: 1.2em;
504 margin-bottom: 12px;
507 margin-bottom: 12px;
505 margin-right: 12px;
508 margin-right: 12px;
506 margin-left: 0;
509 margin-left: 0;
507 display: table
510 display: table
508 }
511 }
509 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
512 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
510
513
511 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
514 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
512 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
515 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
513 div.wiki ul.toc li { list-style-type:none;}
516 div.wiki ul.toc li { list-style-type:none;}
514 div.wiki ul.toc li.heading2 { margin-left: 6px; }
517 div.wiki ul.toc li.heading2 { margin-left: 6px; }
515 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
518 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
516
519
517 div.wiki ul.toc a {
520 div.wiki ul.toc a {
518 font-size: 0.9em;
521 font-size: 0.9em;
519 font-weight: normal;
522 font-weight: normal;
520 text-decoration: none;
523 text-decoration: none;
521 color: #606060;
524 color: #606060;
522 }
525 }
523 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
526 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
524
527
525 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
528 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
526 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
529 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
527 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
530 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
528
531
529 /***** My page layout *****/
532 /***** My page layout *****/
530 .block-receiver {
533 .block-receiver {
531 border:1px dashed #c0c0c0;
534 border:1px dashed #c0c0c0;
532 margin-bottom: 20px;
535 margin-bottom: 20px;
533 padding: 15px 0 15px 0;
536 padding: 15px 0 15px 0;
534 }
537 }
535
538
536 .mypage-box {
539 .mypage-box {
537 margin:0 0 20px 0;
540 margin:0 0 20px 0;
538 color:#505050;
541 color:#505050;
539 line-height:1.5em;
542 line-height:1.5em;
540 }
543 }
541
544
542 .handle {
545 .handle {
543 cursor: move;
546 cursor: move;
544 }
547 }
545
548
546 a.close-icon {
549 a.close-icon {
547 display:block;
550 display:block;
548 margin-top:3px;
551 margin-top:3px;
549 overflow:hidden;
552 overflow:hidden;
550 width:12px;
553 width:12px;
551 height:12px;
554 height:12px;
552 background-repeat: no-repeat;
555 background-repeat: no-repeat;
553 cursor:pointer;
556 cursor:pointer;
554 background-image:url('../images/close.png');
557 background-image:url('../images/close.png');
555 }
558 }
556
559
557 a.close-icon:hover {
560 a.close-icon:hover {
558 background-image:url('../images/close_hl.png');
561 background-image:url('../images/close_hl.png');
559 }
562 }
560
563
561 /***** Gantt chart *****/
564 /***** Gantt chart *****/
562 .gantt_hdr {
565 .gantt_hdr {
563 position:absolute;
566 position:absolute;
564 top:0;
567 top:0;
565 height:16px;
568 height:16px;
566 border-top: 1px solid #c0c0c0;
569 border-top: 1px solid #c0c0c0;
567 border-bottom: 1px solid #c0c0c0;
570 border-bottom: 1px solid #c0c0c0;
568 border-right: 1px solid #c0c0c0;
571 border-right: 1px solid #c0c0c0;
569 text-align: center;
572 text-align: center;
570 overflow: hidden;
573 overflow: hidden;
571 }
574 }
572
575
573 .task {
576 .task {
574 position: absolute;
577 position: absolute;
575 height:8px;
578 height:8px;
576 font-size:0.8em;
579 font-size:0.8em;
577 color:#888;
580 color:#888;
578 padding:0;
581 padding:0;
579 margin:0;
582 margin:0;
580 line-height:0.8em;
583 line-height:0.8em;
581 }
584 }
582
585
583 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
586 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
584 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
587 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
585 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
588 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
586 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
589 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
587
590
588 /***** Icons *****/
591 /***** Icons *****/
589 .icon {
592 .icon {
590 background-position: 0% 40%;
593 background-position: 0% 40%;
591 background-repeat: no-repeat;
594 background-repeat: no-repeat;
592 padding-left: 20px;
595 padding-left: 20px;
593 padding-top: 2px;
596 padding-top: 2px;
594 padding-bottom: 3px;
597 padding-bottom: 3px;
595 }
598 }
596
599
597 .icon22 {
600 .icon22 {
598 background-position: 0% 40%;
601 background-position: 0% 40%;
599 background-repeat: no-repeat;
602 background-repeat: no-repeat;
600 padding-left: 26px;
603 padding-left: 26px;
601 line-height: 22px;
604 line-height: 22px;
602 vertical-align: middle;
605 vertical-align: middle;
603 }
606 }
604
607
605 .icon-add { background-image: url(../images/add.png); }
608 .icon-add { background-image: url(../images/add.png); }
606 .icon-edit { background-image: url(../images/edit.png); }
609 .icon-edit { background-image: url(../images/edit.png); }
607 .icon-copy { background-image: url(../images/copy.png); }
610 .icon-copy { background-image: url(../images/copy.png); }
608 .icon-del { background-image: url(../images/delete.png); }
611 .icon-del { background-image: url(../images/delete.png); }
609 .icon-move { background-image: url(../images/move.png); }
612 .icon-move { background-image: url(../images/move.png); }
610 .icon-save { background-image: url(../images/save.png); }
613 .icon-save { background-image: url(../images/save.png); }
611 .icon-cancel { background-image: url(../images/cancel.png); }
614 .icon-cancel { background-image: url(../images/cancel.png); }
612 .icon-file { background-image: url(../images/file.png); }
615 .icon-file { background-image: url(../images/file.png); }
613 .icon-folder { background-image: url(../images/folder.png); }
616 .icon-folder { background-image: url(../images/folder.png); }
614 .open .icon-folder { background-image: url(../images/folder_open.png); }
617 .open .icon-folder { background-image: url(../images/folder_open.png); }
615 .icon-package { background-image: url(../images/package.png); }
618 .icon-package { background-image: url(../images/package.png); }
616 .icon-home { background-image: url(../images/home.png); }
619 .icon-home { background-image: url(../images/home.png); }
617 .icon-user { background-image: url(../images/user.png); }
620 .icon-user { background-image: url(../images/user.png); }
618 .icon-mypage { background-image: url(../images/user_page.png); }
621 .icon-mypage { background-image: url(../images/user_page.png); }
619 .icon-admin { background-image: url(../images/admin.png); }
622 .icon-admin { background-image: url(../images/admin.png); }
620 .icon-projects { background-image: url(../images/projects.png); }
623 .icon-projects { background-image: url(../images/projects.png); }
621 .icon-help { background-image: url(../images/help.png); }
624 .icon-help { background-image: url(../images/help.png); }
622 .icon-attachment { background-image: url(../images/attachment.png); }
625 .icon-attachment { background-image: url(../images/attachment.png); }
623 .icon-index { background-image: url(../images/index.png); }
626 .icon-index { background-image: url(../images/index.png); }
624 .icon-history { background-image: url(../images/history.png); }
627 .icon-history { background-image: url(../images/history.png); }
625 .icon-time { background-image: url(../images/time.png); }
628 .icon-time { background-image: url(../images/time.png); }
626 .icon-stats { background-image: url(../images/stats.png); }
629 .icon-stats { background-image: url(../images/stats.png); }
627 .icon-warning { background-image: url(../images/warning.png); }
630 .icon-warning { background-image: url(../images/warning.png); }
628 .icon-fav { background-image: url(../images/fav.png); }
631 .icon-fav { background-image: url(../images/fav.png); }
629 .icon-fav-off { background-image: url(../images/fav_off.png); }
632 .icon-fav-off { background-image: url(../images/fav_off.png); }
630 .icon-reload { background-image: url(../images/reload.png); }
633 .icon-reload { background-image: url(../images/reload.png); }
631 .icon-lock { background-image: url(../images/locked.png); }
634 .icon-lock { background-image: url(../images/locked.png); }
632 .icon-unlock { background-image: url(../images/unlock.png); }
635 .icon-unlock { background-image: url(../images/unlock.png); }
633 .icon-checked { background-image: url(../images/true.png); }
636 .icon-checked { background-image: url(../images/true.png); }
634 .icon-details { background-image: url(../images/zoom_in.png); }
637 .icon-details { background-image: url(../images/zoom_in.png); }
635 .icon-report { background-image: url(../images/report.png); }
638 .icon-report { background-image: url(../images/report.png); }
636 .icon-comment { background-image: url(../images/comment.png); }
639 .icon-comment { background-image: url(../images/comment.png); }
637
640
638 .icon22-projects { background-image: url(../images/22x22/projects.png); }
641 .icon22-projects { background-image: url(../images/22x22/projects.png); }
639 .icon22-users { background-image: url(../images/22x22/users.png); }
642 .icon22-users { background-image: url(../images/22x22/users.png); }
640 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
643 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
641 .icon22-role { background-image: url(../images/22x22/role.png); }
644 .icon22-role { background-image: url(../images/22x22/role.png); }
642 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
645 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
643 .icon22-options { background-image: url(../images/22x22/options.png); }
646 .icon22-options { background-image: url(../images/22x22/options.png); }
644 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
647 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
645 .icon22-authent { background-image: url(../images/22x22/authent.png); }
648 .icon22-authent { background-image: url(../images/22x22/authent.png); }
646 .icon22-info { background-image: url(../images/22x22/info.png); }
649 .icon22-info { background-image: url(../images/22x22/info.png); }
647 .icon22-comment { background-image: url(../images/22x22/comment.png); }
650 .icon22-comment { background-image: url(../images/22x22/comment.png); }
648 .icon22-package { background-image: url(../images/22x22/package.png); }
651 .icon22-package { background-image: url(../images/22x22/package.png); }
649 .icon22-settings { background-image: url(../images/22x22/settings.png); }
652 .icon22-settings { background-image: url(../images/22x22/settings.png); }
650 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
653 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
651
654
652 img.gravatar {
655 img.gravatar {
653 padding: 2px;
656 padding: 2px;
654 border: solid 1px #d5d5d5;
657 border: solid 1px #d5d5d5;
655 background: #fff;
658 background: #fff;
656 }
659 }
657
660
658 div.issue img.gravatar {
661 div.issue img.gravatar {
659 float: right;
662 float: right;
660 margin: 0 0 0 1em;
663 margin: 0 0 0 1em;
661 padding: 5px;
664 padding: 5px;
662 }
665 }
663
666
664 div.issue table img.gravatar {
667 div.issue table img.gravatar {
665 height: 14px;
668 height: 14px;
666 width: 14px;
669 width: 14px;
667 padding: 2px;
670 padding: 2px;
668 float: left;
671 float: left;
669 margin: 0 0.5em 0 0;
672 margin: 0 0.5em 0 0;
670 }
673 }
671
674
672 #history img.gravatar {
675 #history img.gravatar {
673 padding: 3px;
676 padding: 3px;
674 margin: 0 1.5em 1em 0;
677 margin: 0 1.5em 1em 0;
675 float: left;
678 float: left;
676 }
679 }
677
680
678 td.username img.gravatar {
681 td.username img.gravatar {
679 float: left;
682 float: left;
680 margin: 0 1em 0 0;
683 margin: 0 1em 0 0;
681 }
684 }
682
685
683 #activity dt img.gravatar {
686 #activity dt img.gravatar {
684 float: left;
687 float: left;
685 margin: 0 1em 1em 0;
688 margin: 0 1em 1em 0;
686 }
689 }
687
690
688 #activity dt,
691 #activity dt,
689 .journal {
692 .journal {
690 clear: left;
693 clear: left;
691 }
694 }
692
695
693 h2 img { vertical-align:middle; }
696 h2 img { vertical-align:middle; }
694
697
695
698
696 /***** Media print specific styles *****/
699 /***** Media print specific styles *****/
697 @media print {
700 @media print {
698 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
701 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
699 #main { background: #fff; }
702 #main { background: #fff; }
700 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
703 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
701 }
704 }
General Comments 0
You need to be logged in to leave comments. Login now