##// END OF EJS Templates
Adds pagination to users list when adding project or group members (#9549)....
Jean-Philippe Lang -
r10970:1257f1960ff6
parent child
Show More
@@ -0,0 +1,1
1 $('#users').html('<%= escape_javascript(render_principals_for_new_group_users(@group)) %>');
@@ -0,0 +1,1
1 $('#principals_for_new_member').html('<%= escape_javascript(render_principals_for_new_members(@project)) %>');
@@ -1,140 +1,141
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 GroupsController < ApplicationController
18 class GroupsController < ApplicationController
19 layout 'admin'
19 layout 'admin'
20
20
21 before_filter :require_admin
21 before_filter :require_admin
22 before_filter :find_group, :except => [:index, :new, :create]
22 before_filter :find_group, :except => [:index, :new, :create]
23 accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user
23 accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user
24
24
25 helper :custom_fields
25 helper :custom_fields
26
26
27 def index
27 def index
28 @groups = Group.sorted.all
28 @groups = Group.sorted.all
29
29
30 respond_to do |format|
30 respond_to do |format|
31 format.html
31 format.html
32 format.api
32 format.api
33 end
33 end
34 end
34 end
35
35
36 def show
36 def show
37 respond_to do |format|
37 respond_to do |format|
38 format.html
38 format.html
39 format.api
39 format.api
40 end
40 end
41 end
41 end
42
42
43 def new
43 def new
44 @group = Group.new
44 @group = Group.new
45 end
45 end
46
46
47 def create
47 def create
48 @group = Group.new
48 @group = Group.new
49 @group.safe_attributes = params[:group]
49 @group.safe_attributes = params[:group]
50
50
51 respond_to do |format|
51 respond_to do |format|
52 if @group.save
52 if @group.save
53 format.html {
53 format.html {
54 flash[:notice] = l(:notice_successful_create)
54 flash[:notice] = l(:notice_successful_create)
55 redirect_to(params[:continue] ? new_group_path : groups_path)
55 redirect_to(params[:continue] ? new_group_path : groups_path)
56 }
56 }
57 format.api { render :action => 'show', :status => :created, :location => group_url(@group) }
57 format.api { render :action => 'show', :status => :created, :location => group_url(@group) }
58 else
58 else
59 format.html { render :action => "new" }
59 format.html { render :action => "new" }
60 format.api { render_validation_errors(@group) }
60 format.api { render_validation_errors(@group) }
61 end
61 end
62 end
62 end
63 end
63 end
64
64
65 def edit
65 def edit
66 end
66 end
67
67
68 def update
68 def update
69 @group.safe_attributes = params[:group]
69 @group.safe_attributes = params[:group]
70
70
71 respond_to do |format|
71 respond_to do |format|
72 if @group.save
72 if @group.save
73 flash[:notice] = l(:notice_successful_update)
73 flash[:notice] = l(:notice_successful_update)
74 format.html { redirect_to(groups_path) }
74 format.html { redirect_to(groups_path) }
75 format.api { render_api_ok }
75 format.api { render_api_ok }
76 else
76 else
77 format.html { render :action => "edit" }
77 format.html { render :action => "edit" }
78 format.api { render_validation_errors(@group) }
78 format.api { render_validation_errors(@group) }
79 end
79 end
80 end
80 end
81 end
81 end
82
82
83 def destroy
83 def destroy
84 @group.destroy
84 @group.destroy
85
85
86 respond_to do |format|
86 respond_to do |format|
87 format.html { redirect_to(groups_path) }
87 format.html { redirect_to(groups_path) }
88 format.api { render_api_ok }
88 format.api { render_api_ok }
89 end
89 end
90 end
90 end
91
91
92 def add_users
92 def add_users
93 @users = User.find_all_by_id(params[:user_id] || params[:user_ids])
93 @users = User.find_all_by_id(params[:user_id] || params[:user_ids])
94 @group.users << @users if request.post?
94 @group.users << @users if request.post?
95 respond_to do |format|
95 respond_to do |format|
96 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
96 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
97 format.js
97 format.js
98 format.api { render_api_ok }
98 format.api { render_api_ok }
99 end
99 end
100 end
100 end
101
101
102 def remove_user
102 def remove_user
103 @group.users.delete(User.find(params[:user_id])) if request.delete?
103 @group.users.delete(User.find(params[:user_id])) if request.delete?
104 respond_to do |format|
104 respond_to do |format|
105 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
105 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
106 format.js
106 format.js
107 format.api { render_api_ok }
107 format.api { render_api_ok }
108 end
108 end
109 end
109 end
110
110
111 def autocomplete_for_user
111 def autocomplete_for_user
112 @users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100)
112 respond_to do |format|
113 render :layout => false
113 format.js
114 end
114 end
115 end
115
116
116 def edit_membership
117 def edit_membership
117 @membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
118 @membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
118 @membership.save if request.post?
119 @membership.save if request.post?
119 respond_to do |format|
120 respond_to do |format|
120 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
121 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
121 format.js
122 format.js
122 end
123 end
123 end
124 end
124
125
125 def destroy_membership
126 def destroy_membership
126 Member.find(params[:membership_id]).destroy if request.post?
127 Member.find(params[:membership_id]).destroy if request.post?
127 respond_to do |format|
128 respond_to do |format|
128 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
129 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
129 format.js
130 format.js
130 end
131 end
131 end
132 end
132
133
133 private
134 private
134
135
135 def find_group
136 def find_group
136 @group = Group.find(params[:id])
137 @group = Group.find(params[:id])
137 rescue ActiveRecord::RecordNotFound
138 rescue ActiveRecord::RecordNotFound
138 render_404
139 render_404
139 end
140 end
140 end
141 end
@@ -1,124 +1,125
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 MembersController < ApplicationController
18 class MembersController < ApplicationController
19 model_object Member
19 model_object Member
20 before_filter :find_model_object, :except => [:index, :create, :autocomplete]
20 before_filter :find_model_object, :except => [:index, :create, :autocomplete]
21 before_filter :find_project_from_association, :except => [:index, :create, :autocomplete]
21 before_filter :find_project_from_association, :except => [:index, :create, :autocomplete]
22 before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete]
22 before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete]
23 before_filter :authorize
23 before_filter :authorize
24 accept_api_auth :index, :show, :create, :update, :destroy
24 accept_api_auth :index, :show, :create, :update, :destroy
25
25
26 def index
26 def index
27 @offset, @limit = api_offset_and_limit
27 @offset, @limit = api_offset_and_limit
28 @member_count = @project.member_principals.count
28 @member_count = @project.member_principals.count
29 @member_pages = Paginator.new @member_count, @limit, params['page']
29 @member_pages = Paginator.new @member_count, @limit, params['page']
30 @offset ||= @member_pages.offset
30 @offset ||= @member_pages.offset
31 @members = @project.member_principals.all(
31 @members = @project.member_principals.all(
32 :order => "#{Member.table_name}.id",
32 :order => "#{Member.table_name}.id",
33 :limit => @limit,
33 :limit => @limit,
34 :offset => @offset
34 :offset => @offset
35 )
35 )
36
36
37 respond_to do |format|
37 respond_to do |format|
38 format.html { head 406 }
38 format.html { head 406 }
39 format.api
39 format.api
40 end
40 end
41 end
41 end
42
42
43 def show
43 def show
44 respond_to do |format|
44 respond_to do |format|
45 format.html { head 406 }
45 format.html { head 406 }
46 format.api
46 format.api
47 end
47 end
48 end
48 end
49
49
50 def create
50 def create
51 members = []
51 members = []
52 if params[:membership]
52 if params[:membership]
53 if params[:membership][:user_ids]
53 if params[:membership][:user_ids]
54 attrs = params[:membership].dup
54 attrs = params[:membership].dup
55 user_ids = attrs.delete(:user_ids)
55 user_ids = attrs.delete(:user_ids)
56 user_ids.each do |user_id|
56 user_ids.each do |user_id|
57 members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id)
57 members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id)
58 end
58 end
59 else
59 else
60 members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id])
60 members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id])
61 end
61 end
62 @project.members << members
62 @project.members << members
63 end
63 end
64
64
65 respond_to do |format|
65 respond_to do |format|
66 format.html { redirect_to_settings_in_projects }
66 format.html { redirect_to_settings_in_projects }
67 format.js { @members = members }
67 format.js { @members = members }
68 format.api {
68 format.api {
69 @member = members.first
69 @member = members.first
70 if @member.valid?
70 if @member.valid?
71 render :action => 'show', :status => :created, :location => membership_url(@member)
71 render :action => 'show', :status => :created, :location => membership_url(@member)
72 else
72 else
73 render_validation_errors(@member)
73 render_validation_errors(@member)
74 end
74 end
75 }
75 }
76 end
76 end
77 end
77 end
78
78
79 def update
79 def update
80 if params[:membership]
80 if params[:membership]
81 @member.role_ids = params[:membership][:role_ids]
81 @member.role_ids = params[:membership][:role_ids]
82 end
82 end
83 saved = @member.save
83 saved = @member.save
84 respond_to do |format|
84 respond_to do |format|
85 format.html { redirect_to_settings_in_projects }
85 format.html { redirect_to_settings_in_projects }
86 format.js
86 format.js
87 format.api {
87 format.api {
88 if saved
88 if saved
89 render_api_ok
89 render_api_ok
90 else
90 else
91 render_validation_errors(@member)
91 render_validation_errors(@member)
92 end
92 end
93 }
93 }
94 end
94 end
95 end
95 end
96
96
97 def destroy
97 def destroy
98 if request.delete? && @member.deletable?
98 if request.delete? && @member.deletable?
99 @member.destroy
99 @member.destroy
100 end
100 end
101 respond_to do |format|
101 respond_to do |format|
102 format.html { redirect_to_settings_in_projects }
102 format.html { redirect_to_settings_in_projects }
103 format.js
103 format.js
104 format.api {
104 format.api {
105 if @member.destroyed?
105 if @member.destroyed?
106 render_api_ok
106 render_api_ok
107 else
107 else
108 head :unprocessable_entity
108 head :unprocessable_entity
109 end
109 end
110 }
110 }
111 end
111 end
112 end
112 end
113
113
114 def autocomplete
114 def autocomplete
115 @principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100)
115 respond_to do |format|
116 render :layout => false
116 format.js
117 end
117 end
118 end
118
119
119 private
120 private
120
121
121 def redirect_to_settings_in_projects
122 def redirect_to_settings_in_projects
122 redirect_to settings_project_path(@project, :tab => 'members')
123 redirect_to settings_project_path(@project, :tab => 'members')
123 end
124 end
124 end
125 end
@@ -1,261 +1,262
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 ProjectsController < ApplicationController
18 class ProjectsController < ApplicationController
19 menu_item :overview
19 menu_item :overview
20 menu_item :roadmap, :only => :roadmap
20 menu_item :roadmap, :only => :roadmap
21 menu_item :settings, :only => :settings
21 menu_item :settings, :only => :settings
22
22
23 before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
23 before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
24 before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
24 before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
25 before_filter :authorize_global, :only => [:new, :create]
25 before_filter :authorize_global, :only => [:new, :create]
26 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
26 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
27 accept_rss_auth :index
27 accept_rss_auth :index
28 accept_api_auth :index, :show, :create, :update, :destroy
28 accept_api_auth :index, :show, :create, :update, :destroy
29
29
30 after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
30 after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
31 if controller.request.post?
31 if controller.request.post?
32 controller.send :expire_action, :controller => 'welcome', :action => 'robots'
32 controller.send :expire_action, :controller => 'welcome', :action => 'robots'
33 end
33 end
34 end
34 end
35
35
36 helper :sort
36 helper :sort
37 include SortHelper
37 include SortHelper
38 helper :custom_fields
38 helper :custom_fields
39 include CustomFieldsHelper
39 include CustomFieldsHelper
40 helper :issues
40 helper :issues
41 helper :queries
41 helper :queries
42 include QueriesHelper
42 include QueriesHelper
43 helper :repositories
43 helper :repositories
44 include RepositoriesHelper
44 include RepositoriesHelper
45 include ProjectsHelper
45 include ProjectsHelper
46 helper :members
46
47
47 # Lists visible projects
48 # Lists visible projects
48 def index
49 def index
49 respond_to do |format|
50 respond_to do |format|
50 format.html {
51 format.html {
51 scope = Project
52 scope = Project
52 unless params[:closed]
53 unless params[:closed]
53 scope = scope.active
54 scope = scope.active
54 end
55 end
55 @projects = scope.visible.order('lft').all
56 @projects = scope.visible.order('lft').all
56 }
57 }
57 format.api {
58 format.api {
58 @offset, @limit = api_offset_and_limit
59 @offset, @limit = api_offset_and_limit
59 @project_count = Project.visible.count
60 @project_count = Project.visible.count
60 @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
61 @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
61 }
62 }
62 format.atom {
63 format.atom {
63 projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
64 projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
64 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
65 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
65 }
66 }
66 end
67 end
67 end
68 end
68
69
69 def new
70 def new
70 @issue_custom_fields = IssueCustomField.sorted.all
71 @issue_custom_fields = IssueCustomField.sorted.all
71 @trackers = Tracker.sorted.all
72 @trackers = Tracker.sorted.all
72 @project = Project.new
73 @project = Project.new
73 @project.safe_attributes = params[:project]
74 @project.safe_attributes = params[:project]
74 end
75 end
75
76
76 def create
77 def create
77 @issue_custom_fields = IssueCustomField.sorted.all
78 @issue_custom_fields = IssueCustomField.sorted.all
78 @trackers = Tracker.sorted.all
79 @trackers = Tracker.sorted.all
79 @project = Project.new
80 @project = Project.new
80 @project.safe_attributes = params[:project]
81 @project.safe_attributes = params[:project]
81
82
82 if validate_parent_id && @project.save
83 if validate_parent_id && @project.save
83 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
84 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
84 # Add current user as a project member if he is not admin
85 # Add current user as a project member if he is not admin
85 unless User.current.admin?
86 unless User.current.admin?
86 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
87 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
87 m = Member.new(:user => User.current, :roles => [r])
88 m = Member.new(:user => User.current, :roles => [r])
88 @project.members << m
89 @project.members << m
89 end
90 end
90 respond_to do |format|
91 respond_to do |format|
91 format.html {
92 format.html {
92 flash[:notice] = l(:notice_successful_create)
93 flash[:notice] = l(:notice_successful_create)
93 if params[:continue]
94 if params[:continue]
94 attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}
95 attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}
95 redirect_to new_project_path(attrs)
96 redirect_to new_project_path(attrs)
96 else
97 else
97 redirect_to settings_project_path(@project)
98 redirect_to settings_project_path(@project)
98 end
99 end
99 }
100 }
100 format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
101 format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
101 end
102 end
102 else
103 else
103 respond_to do |format|
104 respond_to do |format|
104 format.html { render :action => 'new' }
105 format.html { render :action => 'new' }
105 format.api { render_validation_errors(@project) }
106 format.api { render_validation_errors(@project) }
106 end
107 end
107 end
108 end
108 end
109 end
109
110
110 def copy
111 def copy
111 @issue_custom_fields = IssueCustomField.sorted.all
112 @issue_custom_fields = IssueCustomField.sorted.all
112 @trackers = Tracker.sorted.all
113 @trackers = Tracker.sorted.all
113 @source_project = Project.find(params[:id])
114 @source_project = Project.find(params[:id])
114 if request.get?
115 if request.get?
115 @project = Project.copy_from(@source_project)
116 @project = Project.copy_from(@source_project)
116 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
117 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
117 else
118 else
118 Mailer.with_deliveries(params[:notifications] == '1') do
119 Mailer.with_deliveries(params[:notifications] == '1') do
119 @project = Project.new
120 @project = Project.new
120 @project.safe_attributes = params[:project]
121 @project.safe_attributes = params[:project]
121 if validate_parent_id && @project.copy(@source_project, :only => params[:only])
122 if validate_parent_id && @project.copy(@source_project, :only => params[:only])
122 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
123 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
123 flash[:notice] = l(:notice_successful_create)
124 flash[:notice] = l(:notice_successful_create)
124 redirect_to settings_project_path(@project)
125 redirect_to settings_project_path(@project)
125 elsif !@project.new_record?
126 elsif !@project.new_record?
126 # Project was created
127 # Project was created
127 # But some objects were not copied due to validation failures
128 # But some objects were not copied due to validation failures
128 # (eg. issues from disabled trackers)
129 # (eg. issues from disabled trackers)
129 # TODO: inform about that
130 # TODO: inform about that
130 redirect_to settings_project_path(@project)
131 redirect_to settings_project_path(@project)
131 end
132 end
132 end
133 end
133 end
134 end
134 rescue ActiveRecord::RecordNotFound
135 rescue ActiveRecord::RecordNotFound
135 # source_project not found
136 # source_project not found
136 render_404
137 render_404
137 end
138 end
138
139
139 # Show @project
140 # Show @project
140 def show
141 def show
141 if params[:jump]
142 if params[:jump]
142 # try to redirect to the requested menu item
143 # try to redirect to the requested menu item
143 redirect_to_project_menu_item(@project, params[:jump]) && return
144 redirect_to_project_menu_item(@project, params[:jump]) && return
144 end
145 end
145
146
146 @users_by_role = @project.users_by_role
147 @users_by_role = @project.users_by_role
147 @subprojects = @project.children.visible.all
148 @subprojects = @project.children.visible.all
148 @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
149 @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
149 @trackers = @project.rolled_up_trackers
150 @trackers = @project.rolled_up_trackers
150
151
151 cond = @project.project_condition(Setting.display_subprojects_issues?)
152 cond = @project.project_condition(Setting.display_subprojects_issues?)
152
153
153 @open_issues_by_tracker = Issue.visible.open.where(cond).count(:group => :tracker)
154 @open_issues_by_tracker = Issue.visible.open.where(cond).count(:group => :tracker)
154 @total_issues_by_tracker = Issue.visible.where(cond).count(:group => :tracker)
155 @total_issues_by_tracker = Issue.visible.where(cond).count(:group => :tracker)
155
156
156 if User.current.allowed_to?(:view_time_entries, @project)
157 if User.current.allowed_to?(:view_time_entries, @project)
157 @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
158 @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
158 end
159 end
159
160
160 @key = User.current.rss_key
161 @key = User.current.rss_key
161
162
162 respond_to do |format|
163 respond_to do |format|
163 format.html
164 format.html
164 format.api
165 format.api
165 end
166 end
166 end
167 end
167
168
168 def settings
169 def settings
169 @issue_custom_fields = IssueCustomField.sorted.all
170 @issue_custom_fields = IssueCustomField.sorted.all
170 @issue_category ||= IssueCategory.new
171 @issue_category ||= IssueCategory.new
171 @member ||= @project.members.new
172 @member ||= @project.members.new
172 @trackers = Tracker.sorted.all
173 @trackers = Tracker.sorted.all
173 @wiki ||= @project.wiki
174 @wiki ||= @project.wiki
174 end
175 end
175
176
176 def edit
177 def edit
177 end
178 end
178
179
179 def update
180 def update
180 @project.safe_attributes = params[:project]
181 @project.safe_attributes = params[:project]
181 if validate_parent_id && @project.save
182 if validate_parent_id && @project.save
182 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
183 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
183 respond_to do |format|
184 respond_to do |format|
184 format.html {
185 format.html {
185 flash[:notice] = l(:notice_successful_update)
186 flash[:notice] = l(:notice_successful_update)
186 redirect_to settings_project_path(@project)
187 redirect_to settings_project_path(@project)
187 }
188 }
188 format.api { render_api_ok }
189 format.api { render_api_ok }
189 end
190 end
190 else
191 else
191 respond_to do |format|
192 respond_to do |format|
192 format.html {
193 format.html {
193 settings
194 settings
194 render :action => 'settings'
195 render :action => 'settings'
195 }
196 }
196 format.api { render_validation_errors(@project) }
197 format.api { render_validation_errors(@project) }
197 end
198 end
198 end
199 end
199 end
200 end
200
201
201 def modules
202 def modules
202 @project.enabled_module_names = params[:enabled_module_names]
203 @project.enabled_module_names = params[:enabled_module_names]
203 flash[:notice] = l(:notice_successful_update)
204 flash[:notice] = l(:notice_successful_update)
204 redirect_to settings_project_path(@project, :tab => 'modules')
205 redirect_to settings_project_path(@project, :tab => 'modules')
205 end
206 end
206
207
207 def archive
208 def archive
208 if request.post?
209 if request.post?
209 unless @project.archive
210 unless @project.archive
210 flash[:error] = l(:error_can_not_archive_project)
211 flash[:error] = l(:error_can_not_archive_project)
211 end
212 end
212 end
213 end
213 redirect_to admin_projects_path(:status => params[:status])
214 redirect_to admin_projects_path(:status => params[:status])
214 end
215 end
215
216
216 def unarchive
217 def unarchive
217 @project.unarchive if request.post? && !@project.active?
218 @project.unarchive if request.post? && !@project.active?
218 redirect_to admin_projects_path(:status => params[:status])
219 redirect_to admin_projects_path(:status => params[:status])
219 end
220 end
220
221
221 def close
222 def close
222 @project.close
223 @project.close
223 redirect_to project_path(@project)
224 redirect_to project_path(@project)
224 end
225 end
225
226
226 def reopen
227 def reopen
227 @project.reopen
228 @project.reopen
228 redirect_to project_path(@project)
229 redirect_to project_path(@project)
229 end
230 end
230
231
231 # Delete @project
232 # Delete @project
232 def destroy
233 def destroy
233 @project_to_destroy = @project
234 @project_to_destroy = @project
234 if api_request? || params[:confirm]
235 if api_request? || params[:confirm]
235 @project_to_destroy.destroy
236 @project_to_destroy.destroy
236 respond_to do |format|
237 respond_to do |format|
237 format.html { redirect_to admin_projects_path }
238 format.html { redirect_to admin_projects_path }
238 format.api { render_api_ok }
239 format.api { render_api_ok }
239 end
240 end
240 end
241 end
241 # hide project in layout
242 # hide project in layout
242 @project = nil
243 @project = nil
243 end
244 end
244
245
245 private
246 private
246
247
247 # Validates parent_id param according to user's permissions
248 # Validates parent_id param according to user's permissions
248 # TODO: move it to Project model in a validation that depends on User.current
249 # TODO: move it to Project model in a validation that depends on User.current
249 def validate_parent_id
250 def validate_parent_id
250 return true if User.current.admin?
251 return true if User.current.admin?
251 parent_id = params[:project] && params[:project][:parent_id]
252 parent_id = params[:project] && params[:project][:parent_id]
252 if parent_id || @project.new_record?
253 if parent_id || @project.new_record?
253 parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
254 parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
254 unless @project.allowed_parents.include?(parent)
255 unless @project.allowed_parents.include?(parent)
255 @project.errors.add :parent_id, :invalid
256 @project.errors.add :parent_id, :invalid
256 return false
257 return false
257 end
258 end
258 end
259 end
259 true
260 true
260 end
261 end
261 end
262 end
@@ -1,27 +1,42
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module GroupsHelper
20 module GroupsHelper
21 def group_settings_tabs
21 def group_settings_tabs
22 tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general},
22 tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general},
23 {:name => 'users', :partial => 'groups/users', :label => :label_user_plural},
23 {:name => 'users', :partial => 'groups/users', :label => :label_user_plural},
24 {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
24 {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
25 ]
25 ]
26 end
26 end
27
28 def render_principals_for_new_group_users(group)
29 scope = User.active.not_in_group(group).like(params[:q])
30 principal_count = scope.count
31 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
32 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
33
34 s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
35
36 links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
37 link_to text, autocomplete_for_user_group_path(group, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
38 }
39
40 s + content_tag('p', links, :class => 'pagination')
41 end
27 end
42 end
@@ -1,21 +1,35
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module MembersHelper
20 module MembersHelper
21 def render_principals_for_new_members(project)
22 scope = Principal.active.not_member_of(project).like(params[:q]).order('type, login, lastname ASC')
23 principal_count = scope.count
24 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
25 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
26
27 s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
28
29 links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
30 link_to text, autocomplete_project_memberships_path(project, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
31 }
32
33 s + content_tag('p', links, :class => 'pagination')
34 end
21 end
35 end
@@ -1,43 +1,39
1 <div class="splitcontentleft">
1 <div class="splitcontentleft">
2 <% if @group.users.any? %>
2 <% if @group.users.any? %>
3 <table class="list users">
3 <table class="list users">
4 <thead><tr>
4 <thead><tr>
5 <th><%= l(:label_user) %></th>
5 <th><%= l(:label_user) %></th>
6 <th style="width:15%"></th>
6 <th style="width:15%"></th>
7 </tr></thead>
7 </tr></thead>
8 <tbody>
8 <tbody>
9 <% @group.users.sort.each do |user| %>
9 <% @group.users.sort.each do |user| %>
10 <tr id="user-<%= user.id %>" class="<%= cycle 'odd', 'even' %>">
10 <tr id="user-<%= user.id %>" class="<%= cycle 'odd', 'even' %>">
11 <td class="user"><%= link_to_user user %></td>
11 <td class="user"><%= link_to_user user %></td>
12 <td class="buttons">
12 <td class="buttons">
13 <%= delete_link group_user_path(@group, :user_id => user), :remote => true %>
13 <%= delete_link group_user_path(@group, :user_id => user), :remote => true %>
14 </td>
14 </td>
15 </tr>
15 </tr>
16 <% end %>
16 <% end %>
17 </tbody>
17 </tbody>
18 </table>
18 </table>
19 <% else %>
19 <% else %>
20 <p class="nodata"><%= l(:label_no_data) %></p>
20 <p class="nodata"><%= l(:label_no_data) %></p>
21 <% end %>
21 <% end %>
22 </div>
22 </div>
23
23
24 <div class="splitcontentright">
24 <div class="splitcontentright">
25 <% users = User.active.not_in_group(@group).all(:limit => 100) %>
26 <% if users.any? %>
27 <%= form_for(@group, :remote => true, :url => group_users_path(@group),
25 <%= form_for(@group, :remote => true, :url => group_users_path(@group),
28 :html => {:method => :post}) do |f| %>
26 :html => {:method => :post}) do |f| %>
29 <fieldset><legend><%=l(:label_user_new)%></legend>
27 <fieldset><legend><%=l(:label_user_new)%></legend>
30
28
31 <p><%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
29 <p><%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
32 <%= javascript_tag "observeSearchfield('user_search', 'users', '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
30 <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
33
31
34 <div id="users">
32 <div id="users">
35 <%= principals_check_box_tags 'user_ids[]', users %>
33 <%= render_principals_for_new_group_users(@group) %>
36 </div>
34 </div>
37
35
38 <p><%= submit_tag l(:button_add) %></p>
36 <p><%= submit_tag l(:button_add) %></p>
39 </fieldset>
37 </fieldset>
40 <% end %>
38 <% end %>
41 <% end %>
42
43 </div>
39 </div>
@@ -1,77 +1,75
1 <%= error_messages_for 'member' %>
1 <%= error_messages_for 'member' %>
2 <% roles = Role.find_all_givable
2 <% roles = Role.find_all_givable
3 members = @project.member_principals.includes(:roles, :principal).all.sort %>
3 members = @project.member_principals.includes(:roles, :principal).all.sort %>
4
4
5 <div class="splitcontentleft">
5 <div class="splitcontentleft">
6 <% if members.any? %>
6 <% if members.any? %>
7 <table class="list members">
7 <table class="list members">
8 <thead><tr>
8 <thead><tr>
9 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
9 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
10 <th><%= l(:label_role_plural) %></th>
10 <th><%= l(:label_role_plural) %></th>
11 <th style="width:15%"></th>
11 <th style="width:15%"></th>
12 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
12 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
13 </tr></thead>
13 </tr></thead>
14 <tbody>
14 <tbody>
15 <% members.each do |member| %>
15 <% members.each do |member| %>
16 <% next if member.new_record? %>
16 <% next if member.new_record? %>
17 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
17 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
18 <td class="<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
18 <td class="<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
19 <td class="roles">
19 <td class="roles">
20 <span id="member-<%= member.id %>-roles"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>
20 <span id="member-<%= member.id %>-roles"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>
21 <%= form_for(member, {:as => :membership, :remote => true, :url => membership_path(member),
21 <%= form_for(member, {:as => :membership, :remote => true, :url => membership_path(member),
22 :method => :put,
22 :method => :put,
23 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }}
23 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }}
24 ) do |f| %>
24 ) do |f| %>
25 <p><% roles.each do |role| %>
25 <p><% roles.each do |role| %>
26 <label><%= check_box_tag 'membership[role_ids][]', role.id, member.roles.include?(role),
26 <label><%= check_box_tag 'membership[role_ids][]', role.id, member.roles.include?(role),
27 :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />
27 :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />
28 <% end %></p>
28 <% end %></p>
29 <%= hidden_field_tag 'membership[role_ids][]', '' %>
29 <%= hidden_field_tag 'membership[role_ids][]', '' %>
30 <p><%= submit_tag l(:button_change), :class => "small" %>
30 <p><%= submit_tag l(:button_change), :class => "small" %>
31 <%= link_to_function l(:button_cancel),
31 <%= link_to_function l(:button_cancel),
32 "$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;"
32 "$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;"
33 %></p>
33 %></p>
34 <% end %>
34 <% end %>
35 </td>
35 </td>
36 <td class="buttons">
36 <td class="buttons">
37 <%= link_to_function l(:button_edit),
37 <%= link_to_function l(:button_edit),
38 "$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;",
38 "$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;",
39 :class => 'icon icon-edit' %>
39 :class => 'icon icon-edit' %>
40 <%= delete_link membership_path(member),
40 <%= delete_link membership_path(member),
41 :remote => true,
41 :remote => true,
42 :data => (!User.current.admin? && member.include?(User.current) ? {:confirm => l(:text_own_membership_delete_confirmation)} : {}) if member.deletable? %>
42 :data => (!User.current.admin? && member.include?(User.current) ? {:confirm => l(:text_own_membership_delete_confirmation)} : {}) if member.deletable? %>
43 </td>
43 </td>
44 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
44 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
45 </tr>
45 </tr>
46 <% end; reset_cycle %>
46 <% end; reset_cycle %>
47 </tbody>
47 </tbody>
48 </table>
48 </table>
49 <% else %>
49 <% else %>
50 <p class="nodata"><%= l(:label_no_data) %></p>
50 <p class="nodata"><%= l(:label_no_data) %></p>
51 <% end %>
51 <% end %>
52 </div>
52 </div>
53
53
54 <% principals = Principal.active.not_member_of(@project).all(:limit => 100, :order => 'type, login, lastname ASC') %>
55
56 <div class="splitcontentright">
54 <div class="splitcontentright">
57 <% if roles.any? && principals.any? %>
55 <% if roles.any? %>
58 <%= form_for(@member, {:as => :membership, :url => project_memberships_path(@project), :remote => true, :method => :post}) do |f| %>
56 <%= form_for(@member, {:as => :membership, :url => project_memberships_path(@project), :remote => true, :method => :post}) do |f| %>
59 <fieldset><legend><%=l(:label_member_new)%></legend>
57 <fieldset><legend><%=l(:label_member_new)%></legend>
60
58
61 <p><%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %></p>
59 <p><%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %></p>
62 <%= javascript_tag "observeSearchfield('principal_search', 'principals', '#{ escape_javascript autocomplete_project_memberships_path(@project) }')" %>
60 <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %>
63
61
64 <div id="principals">
62 <div id="principals_for_new_member">
65 <%= principals_check_box_tags 'membership[user_ids][]', principals %>
63 <%= render_principals_for_new_members(@project) %>
66 </div>
64 </div>
67
65
68 <p><%= l(:label_role_plural) %>:
66 <p><%= l(:label_role_plural) %>:
69 <% roles.each do |role| %>
67 <% roles.each do |role| %>
70 <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
68 <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>
71 <% end %></p>
69 <% end %></p>
72
70
73 <p><%= submit_tag l(:button_add), :id => 'member-add-submit' %></p>
71 <p><%= submit_tag l(:button_add), :id => 'member-add-submit' %></p>
74 </fieldset>
72 </fieldset>
75 <% end %>
73 <% end %>
76 <% end %>
74 <% end %>
77 </div>
75 </div>
@@ -1,590 +1,590
1 /* Redmine - project management software
1 /* Redmine - project management software
2 Copyright (C) 2006-2013 Jean-Philippe Lang */
2 Copyright (C) 2006-2013 Jean-Philippe Lang */
3
3
4 function checkAll(id, checked) {
4 function checkAll(id, checked) {
5 if (checked) {
5 if (checked) {
6 $('#'+id).find('input[type=checkbox]').attr('checked', true);
6 $('#'+id).find('input[type=checkbox]').attr('checked', true);
7 } else {
7 } else {
8 $('#'+id).find('input[type=checkbox]').removeAttr('checked');
8 $('#'+id).find('input[type=checkbox]').removeAttr('checked');
9 }
9 }
10 }
10 }
11
11
12 function toggleCheckboxesBySelector(selector) {
12 function toggleCheckboxesBySelector(selector) {
13 var all_checked = true;
13 var all_checked = true;
14 $(selector).each(function(index) {
14 $(selector).each(function(index) {
15 if (!$(this).is(':checked')) { all_checked = false; }
15 if (!$(this).is(':checked')) { all_checked = false; }
16 });
16 });
17 $(selector).attr('checked', !all_checked)
17 $(selector).attr('checked', !all_checked)
18 }
18 }
19
19
20 function showAndScrollTo(id, focus) {
20 function showAndScrollTo(id, focus) {
21 $('#'+id).show();
21 $('#'+id).show();
22 if (focus!=null) {
22 if (focus!=null) {
23 $('#'+focus).focus();
23 $('#'+focus).focus();
24 }
24 }
25 $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100);
25 $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100);
26 }
26 }
27
27
28 function toggleRowGroup(el) {
28 function toggleRowGroup(el) {
29 var tr = $(el).parents('tr').first();
29 var tr = $(el).parents('tr').first();
30 var n = tr.next();
30 var n = tr.next();
31 tr.toggleClass('open');
31 tr.toggleClass('open');
32 while (n.length && !n.hasClass('group')) {
32 while (n.length && !n.hasClass('group')) {
33 n.toggle();
33 n.toggle();
34 n = n.next('tr');
34 n = n.next('tr');
35 }
35 }
36 }
36 }
37
37
38 function collapseAllRowGroups(el) {
38 function collapseAllRowGroups(el) {
39 var tbody = $(el).parents('tbody').first();
39 var tbody = $(el).parents('tbody').first();
40 tbody.children('tr').each(function(index) {
40 tbody.children('tr').each(function(index) {
41 if ($(this).hasClass('group')) {
41 if ($(this).hasClass('group')) {
42 $(this).removeClass('open');
42 $(this).removeClass('open');
43 } else {
43 } else {
44 $(this).hide();
44 $(this).hide();
45 }
45 }
46 });
46 });
47 }
47 }
48
48
49 function expandAllRowGroups(el) {
49 function expandAllRowGroups(el) {
50 var tbody = $(el).parents('tbody').first();
50 var tbody = $(el).parents('tbody').first();
51 tbody.children('tr').each(function(index) {
51 tbody.children('tr').each(function(index) {
52 if ($(this).hasClass('group')) {
52 if ($(this).hasClass('group')) {
53 $(this).addClass('open');
53 $(this).addClass('open');
54 } else {
54 } else {
55 $(this).show();
55 $(this).show();
56 }
56 }
57 });
57 });
58 }
58 }
59
59
60 function toggleAllRowGroups(el) {
60 function toggleAllRowGroups(el) {
61 var tr = $(el).parents('tr').first();
61 var tr = $(el).parents('tr').first();
62 if (tr.hasClass('open')) {
62 if (tr.hasClass('open')) {
63 collapseAllRowGroups(el);
63 collapseAllRowGroups(el);
64 } else {
64 } else {
65 expandAllRowGroups(el);
65 expandAllRowGroups(el);
66 }
66 }
67 }
67 }
68
68
69 function toggleFieldset(el) {
69 function toggleFieldset(el) {
70 var fieldset = $(el).parents('fieldset').first();
70 var fieldset = $(el).parents('fieldset').first();
71 fieldset.toggleClass('collapsed');
71 fieldset.toggleClass('collapsed');
72 fieldset.children('div').toggle();
72 fieldset.children('div').toggle();
73 }
73 }
74
74
75 function hideFieldset(el) {
75 function hideFieldset(el) {
76 var fieldset = $(el).parents('fieldset').first();
76 var fieldset = $(el).parents('fieldset').first();
77 fieldset.toggleClass('collapsed');
77 fieldset.toggleClass('collapsed');
78 fieldset.children('div').hide();
78 fieldset.children('div').hide();
79 }
79 }
80
80
81 function initFilters(){
81 function initFilters(){
82 $('#add_filter_select').change(function(){
82 $('#add_filter_select').change(function(){
83 addFilter($(this).val(), '', []);
83 addFilter($(this).val(), '', []);
84 });
84 });
85 $('#filters-table td.field input[type=checkbox]').each(function(){
85 $('#filters-table td.field input[type=checkbox]').each(function(){
86 toggleFilter($(this).val());
86 toggleFilter($(this).val());
87 });
87 });
88 $('#filters-table td.field input[type=checkbox]').live('click',function(){
88 $('#filters-table td.field input[type=checkbox]').live('click',function(){
89 toggleFilter($(this).val());
89 toggleFilter($(this).val());
90 });
90 });
91 $('#filters-table .toggle-multiselect').live('click',function(){
91 $('#filters-table .toggle-multiselect').live('click',function(){
92 toggleMultiSelect($(this).siblings('select'));
92 toggleMultiSelect($(this).siblings('select'));
93 });
93 });
94 $('#filters-table input[type=text]').live('keypress', function(e){
94 $('#filters-table input[type=text]').live('keypress', function(e){
95 if (e.keyCode == 13) submit_query_form("query_form");
95 if (e.keyCode == 13) submit_query_form("query_form");
96 });
96 });
97 }
97 }
98
98
99 function addFilter(field, operator, values) {
99 function addFilter(field, operator, values) {
100 var fieldId = field.replace('.', '_');
100 var fieldId = field.replace('.', '_');
101 var tr = $('#tr_'+fieldId);
101 var tr = $('#tr_'+fieldId);
102 if (tr.length > 0) {
102 if (tr.length > 0) {
103 tr.show();
103 tr.show();
104 } else {
104 } else {
105 buildFilterRow(field, operator, values);
105 buildFilterRow(field, operator, values);
106 }
106 }
107 $('#cb_'+fieldId).attr('checked', true);
107 $('#cb_'+fieldId).attr('checked', true);
108 toggleFilter(field);
108 toggleFilter(field);
109 $('#add_filter_select').val('').children('option').each(function(){
109 $('#add_filter_select').val('').children('option').each(function(){
110 if ($(this).attr('value') == field) {
110 if ($(this).attr('value') == field) {
111 $(this).attr('disabled', true);
111 $(this).attr('disabled', true);
112 }
112 }
113 });
113 });
114 }
114 }
115
115
116 function buildFilterRow(field, operator, values) {
116 function buildFilterRow(field, operator, values) {
117 var fieldId = field.replace('.', '_');
117 var fieldId = field.replace('.', '_');
118 var filterTable = $("#filters-table");
118 var filterTable = $("#filters-table");
119 var filterOptions = availableFilters[field];
119 var filterOptions = availableFilters[field];
120 var operators = operatorByType[filterOptions['type']];
120 var operators = operatorByType[filterOptions['type']];
121 var filterValues = filterOptions['values'];
121 var filterValues = filterOptions['values'];
122 var i, select;
122 var i, select;
123
123
124 var tr = $('<tr class="filter">').attr('id', 'tr_'+fieldId).html(
124 var tr = $('<tr class="filter">').attr('id', 'tr_'+fieldId).html(
125 '<td class="field"><input checked="checked" id="cb_'+fieldId+'" name="f[]" value="'+field+'" type="checkbox"><label for="cb_'+fieldId+'"> '+filterOptions['name']+'</label></td>' +
125 '<td class="field"><input checked="checked" id="cb_'+fieldId+'" name="f[]" value="'+field+'" type="checkbox"><label for="cb_'+fieldId+'"> '+filterOptions['name']+'</label></td>' +
126 '<td class="operator"><select id="operators_'+fieldId+'" name="op['+field+']"></td>' +
126 '<td class="operator"><select id="operators_'+fieldId+'" name="op['+field+']"></td>' +
127 '<td class="values"></td>'
127 '<td class="values"></td>'
128 );
128 );
129 filterTable.append(tr);
129 filterTable.append(tr);
130
130
131 select = tr.find('td.operator select');
131 select = tr.find('td.operator select');
132 for (i=0;i<operators.length;i++){
132 for (i=0;i<operators.length;i++){
133 var option = $('<option>').val(operators[i]).text(operatorLabels[operators[i]]);
133 var option = $('<option>').val(operators[i]).text(operatorLabels[operators[i]]);
134 if (operators[i] == operator) {option.attr('selected', true)};
134 if (operators[i] == operator) {option.attr('selected', true)};
135 select.append(option);
135 select.append(option);
136 }
136 }
137 select.change(function(){toggleOperator(field)});
137 select.change(function(){toggleOperator(field)});
138
138
139 switch (filterOptions['type']){
139 switch (filterOptions['type']){
140 case "list":
140 case "list":
141 case "list_optional":
141 case "list_optional":
142 case "list_status":
142 case "list_status":
143 case "list_subprojects":
143 case "list_subprojects":
144 tr.find('td.values').append(
144 tr.find('td.values').append(
145 '<span style="display:none;"><select class="value" id="values_'+fieldId+'_1" name="v['+field+'][]"></select>' +
145 '<span style="display:none;"><select class="value" id="values_'+fieldId+'_1" name="v['+field+'][]"></select>' +
146 ' <span class="toggle-multiselect">&nbsp;</span></span>'
146 ' <span class="toggle-multiselect">&nbsp;</span></span>'
147 );
147 );
148 select = tr.find('td.values select');
148 select = tr.find('td.values select');
149 if (values.length > 1) {select.attr('multiple', true)};
149 if (values.length > 1) {select.attr('multiple', true)};
150 for (i=0;i<filterValues.length;i++){
150 for (i=0;i<filterValues.length;i++){
151 var filterValue = filterValues[i];
151 var filterValue = filterValues[i];
152 var option = $('<option>');
152 var option = $('<option>');
153 if ($.isArray(filterValue)) {
153 if ($.isArray(filterValue)) {
154 option.val(filterValue[1]).text(filterValue[0]);
154 option.val(filterValue[1]).text(filterValue[0]);
155 if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
155 if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
156 } else {
156 } else {
157 option.val(filterValue).text(filterValue);
157 option.val(filterValue).text(filterValue);
158 if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
158 if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
159 }
159 }
160 select.append(option);
160 select.append(option);
161 }
161 }
162 break;
162 break;
163 case "date":
163 case "date":
164 case "date_past":
164 case "date_past":
165 tr.find('td.values').append(
165 tr.find('td.values').append(
166 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" /></span>' +
166 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" /></span>' +
167 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" /></span>' +
167 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" /></span>' +
168 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" /> '+labelDayPlural+'</span>'
168 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" /> '+labelDayPlural+'</span>'
169 );
169 );
170 $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
170 $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
171 $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
171 $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
172 $('#values_'+fieldId).val(values[0]);
172 $('#values_'+fieldId).val(values[0]);
173 break;
173 break;
174 case "string":
174 case "string":
175 case "text":
175 case "text":
176 tr.find('td.values').append(
176 tr.find('td.values').append(
177 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" /></span>'
177 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" /></span>'
178 );
178 );
179 $('#values_'+fieldId).val(values[0]);
179 $('#values_'+fieldId).val(values[0]);
180 break;
180 break;
181 case "relation":
181 case "relation":
182 tr.find('td.values').append(
182 tr.find('td.values').append(
183 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="6" class="value" /></span>' +
183 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="6" class="value" /></span>' +
184 '<span style="display:none;"><select class="value" name="v['+field+'][]" id="values_'+fieldId+'_1"></select></span>'
184 '<span style="display:none;"><select class="value" name="v['+field+'][]" id="values_'+fieldId+'_1"></select></span>'
185 );
185 );
186 $('#values_'+fieldId).val(values[0]);
186 $('#values_'+fieldId).val(values[0]);
187 select = tr.find('td.values select');
187 select = tr.find('td.values select');
188 for (i=0;i<allProjects.length;i++){
188 for (i=0;i<allProjects.length;i++){
189 var filterValue = allProjects[i];
189 var filterValue = allProjects[i];
190 var option = $('<option>');
190 var option = $('<option>');
191 option.val(filterValue[1]).text(filterValue[0]);
191 option.val(filterValue[1]).text(filterValue[0]);
192 if (values[0] == filterValue[1]) {option.attr('selected', true)};
192 if (values[0] == filterValue[1]) {option.attr('selected', true)};
193 select.append(option);
193 select.append(option);
194 }
194 }
195 case "integer":
195 case "integer":
196 case "float":
196 case "float":
197 tr.find('td.values').append(
197 tr.find('td.values').append(
198 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" /></span>' +
198 '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" /></span>' +
199 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" /></span>'
199 ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" /></span>'
200 );
200 );
201 $('#values_'+fieldId+'_1').val(values[0]);
201 $('#values_'+fieldId+'_1').val(values[0]);
202 $('#values_'+fieldId+'_2').val(values[1]);
202 $('#values_'+fieldId+'_2').val(values[1]);
203 break;
203 break;
204 }
204 }
205 }
205 }
206
206
207 function toggleFilter(field) {
207 function toggleFilter(field) {
208 var fieldId = field.replace('.', '_');
208 var fieldId = field.replace('.', '_');
209 if ($('#cb_' + fieldId).is(':checked')) {
209 if ($('#cb_' + fieldId).is(':checked')) {
210 $("#operators_" + fieldId).show().removeAttr('disabled');
210 $("#operators_" + fieldId).show().removeAttr('disabled');
211 toggleOperator(field);
211 toggleOperator(field);
212 } else {
212 } else {
213 $("#operators_" + fieldId).hide().attr('disabled', true);
213 $("#operators_" + fieldId).hide().attr('disabled', true);
214 enableValues(field, []);
214 enableValues(field, []);
215 }
215 }
216 }
216 }
217
217
218 function enableValues(field, indexes) {
218 function enableValues(field, indexes) {
219 var fieldId = field.replace('.', '_');
219 var fieldId = field.replace('.', '_');
220 $('#tr_'+fieldId+' td.values .value').each(function(index) {
220 $('#tr_'+fieldId+' td.values .value').each(function(index) {
221 if ($.inArray(index, indexes) >= 0) {
221 if ($.inArray(index, indexes) >= 0) {
222 $(this).removeAttr('disabled');
222 $(this).removeAttr('disabled');
223 $(this).parents('span').first().show();
223 $(this).parents('span').first().show();
224 } else {
224 } else {
225 $(this).val('');
225 $(this).val('');
226 $(this).attr('disabled', true);
226 $(this).attr('disabled', true);
227 $(this).parents('span').first().hide();
227 $(this).parents('span').first().hide();
228 }
228 }
229
229
230 if ($(this).hasClass('group')) {
230 if ($(this).hasClass('group')) {
231 $(this).addClass('open');
231 $(this).addClass('open');
232 } else {
232 } else {
233 $(this).show();
233 $(this).show();
234 }
234 }
235 });
235 });
236 }
236 }
237
237
238 function toggleOperator(field) {
238 function toggleOperator(field) {
239 var fieldId = field.replace('.', '_');
239 var fieldId = field.replace('.', '_');
240 var operator = $("#operators_" + fieldId);
240 var operator = $("#operators_" + fieldId);
241 switch (operator.val()) {
241 switch (operator.val()) {
242 case "!*":
242 case "!*":
243 case "*":
243 case "*":
244 case "t":
244 case "t":
245 case "ld":
245 case "ld":
246 case "w":
246 case "w":
247 case "lw":
247 case "lw":
248 case "l2w":
248 case "l2w":
249 case "m":
249 case "m":
250 case "lm":
250 case "lm":
251 case "y":
251 case "y":
252 case "o":
252 case "o":
253 case "c":
253 case "c":
254 enableValues(field, []);
254 enableValues(field, []);
255 break;
255 break;
256 case "><":
256 case "><":
257 enableValues(field, [0,1]);
257 enableValues(field, [0,1]);
258 break;
258 break;
259 case "<t+":
259 case "<t+":
260 case ">t+":
260 case ">t+":
261 case "><t+":
261 case "><t+":
262 case "t+":
262 case "t+":
263 case ">t-":
263 case ">t-":
264 case "<t-":
264 case "<t-":
265 case "><t-":
265 case "><t-":
266 case "t-":
266 case "t-":
267 enableValues(field, [2]);
267 enableValues(field, [2]);
268 break;
268 break;
269 case "=p":
269 case "=p":
270 case "=!p":
270 case "=!p":
271 case "!p":
271 case "!p":
272 enableValues(field, [1]);
272 enableValues(field, [1]);
273 break;
273 break;
274 default:
274 default:
275 enableValues(field, [0]);
275 enableValues(field, [0]);
276 break;
276 break;
277 }
277 }
278 }
278 }
279
279
280 function toggleMultiSelect(el) {
280 function toggleMultiSelect(el) {
281 if (el.attr('multiple')) {
281 if (el.attr('multiple')) {
282 el.removeAttr('multiple');
282 el.removeAttr('multiple');
283 } else {
283 } else {
284 el.attr('multiple', true);
284 el.attr('multiple', true);
285 }
285 }
286 }
286 }
287
287
288 function submit_query_form(id) {
288 function submit_query_form(id) {
289 selectAllOptions("selected_columns");
289 selectAllOptions("selected_columns");
290 $('#'+id).submit();
290 $('#'+id).submit();
291 }
291 }
292
292
293 function showTab(name) {
293 function showTab(name) {
294 $('div#content .tab-content').hide();
294 $('div#content .tab-content').hide();
295 $('div.tabs a').removeClass('selected');
295 $('div.tabs a').removeClass('selected');
296 $('#tab-content-' + name).show();
296 $('#tab-content-' + name).show();
297 $('#tab-' + name).addClass('selected');
297 $('#tab-' + name).addClass('selected');
298 return false;
298 return false;
299 }
299 }
300
300
301 function moveTabRight(el) {
301 function moveTabRight(el) {
302 var lis = $(el).parents('div.tabs').first().find('ul').children();
302 var lis = $(el).parents('div.tabs').first().find('ul').children();
303 var tabsWidth = 0;
303 var tabsWidth = 0;
304 var i = 0;
304 var i = 0;
305 lis.each(function(){
305 lis.each(function(){
306 if ($(this).is(':visible')) {
306 if ($(this).is(':visible')) {
307 tabsWidth += $(this).width() + 6;
307 tabsWidth += $(this).width() + 6;
308 }
308 }
309 });
309 });
310 if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; }
310 if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; }
311 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
311 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
312 lis.eq(i).hide();
312 lis.eq(i).hide();
313 }
313 }
314
314
315 function moveTabLeft(el) {
315 function moveTabLeft(el) {
316 var lis = $(el).parents('div.tabs').first().find('ul').children();
316 var lis = $(el).parents('div.tabs').first().find('ul').children();
317 var i = 0;
317 var i = 0;
318 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
318 while (i<lis.length && !lis.eq(i).is(':visible')) { i++; }
319 if (i>0) {
319 if (i>0) {
320 lis.eq(i-1).show();
320 lis.eq(i-1).show();
321 }
321 }
322 }
322 }
323
323
324 function displayTabsButtons() {
324 function displayTabsButtons() {
325 var lis;
325 var lis;
326 var tabsWidth = 0;
326 var tabsWidth = 0;
327 var el;
327 var el;
328 $('div.tabs').each(function() {
328 $('div.tabs').each(function() {
329 el = $(this);
329 el = $(this);
330 lis = el.find('ul').children();
330 lis = el.find('ul').children();
331 lis.each(function(){
331 lis.each(function(){
332 if ($(this).is(':visible')) {
332 if ($(this).is(':visible')) {
333 tabsWidth += $(this).width() + 6;
333 tabsWidth += $(this).width() + 6;
334 }
334 }
335 });
335 });
336 if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
336 if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
337 el.find('div.tabs-buttons').hide();
337 el.find('div.tabs-buttons').hide();
338 } else {
338 } else {
339 el.find('div.tabs-buttons').show();
339 el.find('div.tabs-buttons').show();
340 }
340 }
341 });
341 });
342 }
342 }
343
343
344 function setPredecessorFieldsVisibility() {
344 function setPredecessorFieldsVisibility() {
345 var relationType = $('#relation_relation_type');
345 var relationType = $('#relation_relation_type');
346 if (relationType.val() == "precedes" || relationType.val() == "follows") {
346 if (relationType.val() == "precedes" || relationType.val() == "follows") {
347 $('#predecessor_fields').show();
347 $('#predecessor_fields').show();
348 } else {
348 } else {
349 $('#predecessor_fields').hide();
349 $('#predecessor_fields').hide();
350 }
350 }
351 }
351 }
352
352
353 function showModal(id, width) {
353 function showModal(id, width) {
354 var el = $('#'+id).first();
354 var el = $('#'+id).first();
355 if (el.length == 0 || el.is(':visible')) {return;}
355 if (el.length == 0 || el.is(':visible')) {return;}
356 var title = el.find('h3.title').text();
356 var title = el.find('h3.title').text();
357 el.dialog({
357 el.dialog({
358 width: width,
358 width: width,
359 modal: true,
359 modal: true,
360 resizable: false,
360 resizable: false,
361 dialogClass: 'modal',
361 dialogClass: 'modal',
362 title: title
362 title: title
363 });
363 });
364 el.find("input[type=text], input[type=submit]").first().focus();
364 el.find("input[type=text], input[type=submit]").first().focus();
365 }
365 }
366
366
367 function hideModal(el) {
367 function hideModal(el) {
368 var modal;
368 var modal;
369 if (el) {
369 if (el) {
370 modal = $(el).parents('.ui-dialog-content');
370 modal = $(el).parents('.ui-dialog-content');
371 } else {
371 } else {
372 modal = $('#ajax-modal');
372 modal = $('#ajax-modal');
373 }
373 }
374 modal.dialog("close");
374 modal.dialog("close");
375 }
375 }
376
376
377 function submitPreview(url, form, target) {
377 function submitPreview(url, form, target) {
378 $.ajax({
378 $.ajax({
379 url: url,
379 url: url,
380 type: 'post',
380 type: 'post',
381 data: $('#'+form).serialize(),
381 data: $('#'+form).serialize(),
382 success: function(data){
382 success: function(data){
383 $('#'+target).html(data);
383 $('#'+target).html(data);
384 }
384 }
385 });
385 });
386 }
386 }
387
387
388 function collapseScmEntry(id) {
388 function collapseScmEntry(id) {
389 $('.'+id).each(function() {
389 $('.'+id).each(function() {
390 if ($(this).hasClass('open')) {
390 if ($(this).hasClass('open')) {
391 collapseScmEntry($(this).attr('id'));
391 collapseScmEntry($(this).attr('id'));
392 }
392 }
393 $(this).hide();
393 $(this).hide();
394 });
394 });
395 $('#'+id).removeClass('open');
395 $('#'+id).removeClass('open');
396 }
396 }
397
397
398 function expandScmEntry(id) {
398 function expandScmEntry(id) {
399 $('.'+id).each(function() {
399 $('.'+id).each(function() {
400 $(this).show();
400 $(this).show();
401 if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
401 if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
402 expandScmEntry($(this).attr('id'));
402 expandScmEntry($(this).attr('id'));
403 }
403 }
404 });
404 });
405 $('#'+id).addClass('open');
405 $('#'+id).addClass('open');
406 }
406 }
407
407
408 function scmEntryClick(id, url) {
408 function scmEntryClick(id, url) {
409 el = $('#'+id);
409 el = $('#'+id);
410 if (el.hasClass('open')) {
410 if (el.hasClass('open')) {
411 collapseScmEntry(id);
411 collapseScmEntry(id);
412 el.addClass('collapsed');
412 el.addClass('collapsed');
413 return false;
413 return false;
414 } else if (el.hasClass('loaded')) {
414 } else if (el.hasClass('loaded')) {
415 expandScmEntry(id);
415 expandScmEntry(id);
416 el.removeClass('collapsed');
416 el.removeClass('collapsed');
417 return false;
417 return false;
418 }
418 }
419 if (el.hasClass('loading')) {
419 if (el.hasClass('loading')) {
420 return false;
420 return false;
421 }
421 }
422 el.addClass('loading');
422 el.addClass('loading');
423 $.ajax({
423 $.ajax({
424 url: url,
424 url: url,
425 success: function(data){
425 success: function(data){
426 el.after(data);
426 el.after(data);
427 el.addClass('open').addClass('loaded').removeClass('loading');
427 el.addClass('open').addClass('loaded').removeClass('loading');
428 }
428 }
429 });
429 });
430 return true;
430 return true;
431 }
431 }
432
432
433 function randomKey(size) {
433 function randomKey(size) {
434 var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
434 var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
435 var key = '';
435 var key = '';
436 for (i = 0; i < size; i++) {
436 for (i = 0; i < size; i++) {
437 key += chars[Math.floor(Math.random() * chars.length)];
437 key += chars[Math.floor(Math.random() * chars.length)];
438 }
438 }
439 return key;
439 return key;
440 }
440 }
441
441
442 // Can't use Rails' remote select because we need the form data
442 // Can't use Rails' remote select because we need the form data
443 function updateIssueFrom(url) {
443 function updateIssueFrom(url) {
444 $.ajax({
444 $.ajax({
445 url: url,
445 url: url,
446 type: 'post',
446 type: 'post',
447 data: $('#issue-form').serialize()
447 data: $('#issue-form').serialize()
448 });
448 });
449 }
449 }
450
450
451 function updateBulkEditFrom(url) {
451 function updateBulkEditFrom(url) {
452 $.ajax({
452 $.ajax({
453 url: url,
453 url: url,
454 type: 'post',
454 type: 'post',
455 data: $('#bulk_edit_form').serialize()
455 data: $('#bulk_edit_form').serialize()
456 });
456 });
457 }
457 }
458
458
459 function observeAutocompleteField(fieldId, url, options) {
459 function observeAutocompleteField(fieldId, url, options) {
460 $(document).ready(function() {
460 $(document).ready(function() {
461 $('#'+fieldId).autocomplete($.extend({
461 $('#'+fieldId).autocomplete($.extend({
462 source: url,
462 source: url,
463 minLength: 2,
463 minLength: 2,
464 search: function(){$('#'+fieldId).addClass('ajax-loading');},
464 search: function(){$('#'+fieldId).addClass('ajax-loading');},
465 response: function(){$('#'+fieldId).removeClass('ajax-loading');},
465 response: function(){$('#'+fieldId).removeClass('ajax-loading');},
466 }, options));
466 }, options));
467 $('#'+fieldId).addClass('autocomplete');
467 $('#'+fieldId).addClass('autocomplete');
468 });
468 });
469 }
469 }
470
470
471 function observeSearchfield(fieldId, targetId, url) {
471 function observeSearchfield(fieldId, targetId, url) {
472 $('#'+fieldId).each(function() {
472 $('#'+fieldId).each(function() {
473 var $this = $(this);
473 var $this = $(this);
474 $this.addClass('autocomplete');
474 $this.addClass('autocomplete');
475 $this.attr('data-value-was', $this.val());
475 $this.attr('data-value-was', $this.val());
476 var check = function() {
476 var check = function() {
477 var val = $this.val();
477 var val = $this.val();
478 if ($this.attr('data-value-was') != val){
478 if ($this.attr('data-value-was') != val){
479 $this.attr('data-value-was', val);
479 $this.attr('data-value-was', val);
480 $.ajax({
480 $.ajax({
481 url: url,
481 url: url,
482 type: 'get',
482 type: 'get',
483 data: {q: $this.val()},
483 data: {q: $this.val()},
484 success: function(data){ $('#'+targetId).html(data); },
484 success: function(data){ if(targetId) $('#'+targetId).html(data); },
485 beforeSend: function(){ $this.addClass('ajax-loading'); },
485 beforeSend: function(){ $this.addClass('ajax-loading'); },
486 complete: function(){ $this.removeClass('ajax-loading'); }
486 complete: function(){ $this.removeClass('ajax-loading'); }
487 });
487 });
488 }
488 }
489 };
489 };
490 var reset = function() {
490 var reset = function() {
491 if (timer) {
491 if (timer) {
492 clearInterval(timer);
492 clearInterval(timer);
493 timer = setInterval(check, 300);
493 timer = setInterval(check, 300);
494 }
494 }
495 };
495 };
496 var timer = setInterval(check, 300);
496 var timer = setInterval(check, 300);
497 $this.bind('keyup click mousemove', reset);
497 $this.bind('keyup click mousemove', reset);
498 });
498 });
499 }
499 }
500
500
501 function observeProjectModules() {
501 function observeProjectModules() {
502 var f = function() {
502 var f = function() {
503 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
503 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
504 if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
504 if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
505 $('#project_trackers').show();
505 $('#project_trackers').show();
506 }else{
506 }else{
507 $('#project_trackers').hide();
507 $('#project_trackers').hide();
508 }
508 }
509 };
509 };
510
510
511 $(window).load(f);
511 $(window).load(f);
512 $('#project_enabled_module_names_issue_tracking').change(f);
512 $('#project_enabled_module_names_issue_tracking').change(f);
513 }
513 }
514
514
515 function initMyPageSortable(list, url) {
515 function initMyPageSortable(list, url) {
516 $('#list-'+list).sortable({
516 $('#list-'+list).sortable({
517 connectWith: '.block-receiver',
517 connectWith: '.block-receiver',
518 tolerance: 'pointer',
518 tolerance: 'pointer',
519 update: function(){
519 update: function(){
520 $.ajax({
520 $.ajax({
521 url: url,
521 url: url,
522 type: 'post',
522 type: 'post',
523 data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
523 data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
524 });
524 });
525 }
525 }
526 });
526 });
527 $("#list-top, #list-left, #list-right").disableSelection();
527 $("#list-top, #list-left, #list-right").disableSelection();
528 }
528 }
529
529
530 var warnLeavingUnsavedMessage;
530 var warnLeavingUnsavedMessage;
531 function warnLeavingUnsaved(message) {
531 function warnLeavingUnsaved(message) {
532 warnLeavingUnsavedMessage = message;
532 warnLeavingUnsavedMessage = message;
533
533
534 $('form').submit(function(){
534 $('form').submit(function(){
535 $('textarea').removeData('changed');
535 $('textarea').removeData('changed');
536 });
536 });
537 $('textarea').change(function(){
537 $('textarea').change(function(){
538 $(this).data('changed', 'changed');
538 $(this).data('changed', 'changed');
539 });
539 });
540 window.onbeforeunload = function(){
540 window.onbeforeunload = function(){
541 var warn = false;
541 var warn = false;
542 $('textarea').blur().each(function(){
542 $('textarea').blur().each(function(){
543 if ($(this).data('changed')) {
543 if ($(this).data('changed')) {
544 warn = true;
544 warn = true;
545 }
545 }
546 });
546 });
547 if (warn) {return warnLeavingUnsavedMessage;}
547 if (warn) {return warnLeavingUnsavedMessage;}
548 };
548 };
549 };
549 };
550
550
551 function setupAjaxIndicator() {
551 function setupAjaxIndicator() {
552
552
553 $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) {
553 $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) {
554
554
555 if ($('.ajax-loading').length == 0 && settings.contentType != 'application/octet-stream') {
555 if ($('.ajax-loading').length == 0 && settings.contentType != 'application/octet-stream') {
556 $('#ajax-indicator').show();
556 $('#ajax-indicator').show();
557 }
557 }
558 });
558 });
559
559
560 $('#ajax-indicator').bind('ajaxStop', function() {
560 $('#ajax-indicator').bind('ajaxStop', function() {
561 $('#ajax-indicator').hide();
561 $('#ajax-indicator').hide();
562 });
562 });
563 }
563 }
564
564
565 function hideOnLoad() {
565 function hideOnLoad() {
566 $('.hol').hide();
566 $('.hol').hide();
567 }
567 }
568
568
569 function addFormObserversForDoubleSubmit() {
569 function addFormObserversForDoubleSubmit() {
570 $('form[method=post]').each(function() {
570 $('form[method=post]').each(function() {
571 if (!$(this).hasClass('multiple-submit')) {
571 if (!$(this).hasClass('multiple-submit')) {
572 $(this).submit(function(form_submission) {
572 $(this).submit(function(form_submission) {
573 if ($(form_submission.target).attr('data-submitted')) {
573 if ($(form_submission.target).attr('data-submitted')) {
574 form_submission.preventDefault();
574 form_submission.preventDefault();
575 } else {
575 } else {
576 $(form_submission.target).attr('data-submitted', true);
576 $(form_submission.target).attr('data-submitted', true);
577 }
577 }
578 });
578 });
579 }
579 }
580 });
580 });
581 }
581 }
582
582
583 function blockEventPropagation(event) {
583 function blockEventPropagation(event) {
584 event.stopPropagation();
584 event.stopPropagation();
585 event.preventDefault();
585 event.preventDefault();
586 }
586 }
587
587
588 $(document).ready(setupAjaxIndicator);
588 $(document).ready(setupAjaxIndicator);
589 $(document).ready(hideOnLoad);
589 $(document).ready(hideOnLoad);
590 $(document).ready(addFormObserversForDoubleSubmit);
590 $(document).ready(addFormObserversForDoubleSubmit);
@@ -1,1147 +1,1147
1 html {overflow-y:scroll;}
1 html {overflow-y:scroll;}
2 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
3
3
4 h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;}
4 h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;}
5 #content h1, h2, h3, h4 {color: #555;}
5 #content h1, h2, h3, h4 {color: #555;}
6 h2, .wiki h1 {font-size: 20px;}
6 h2, .wiki h1 {font-size: 20px;}
7 h3, .wiki h2 {font-size: 16px;}
7 h3, .wiki h2 {font-size: 16px;}
8 h4, .wiki h3 {font-size: 13px;}
8 h4, .wiki h3 {font-size: 13px;}
9 h4 {border-bottom: 1px dotted #bbb;}
9 h4 {border-bottom: 1px dotted #bbb;}
10
10
11 /***** Layout *****/
11 /***** Layout *****/
12 #wrapper {background: white;}
12 #wrapper {background: white;}
13
13
14 #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
14 #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
15 #top-menu ul {margin: 0; padding: 0;}
15 #top-menu ul {margin: 0; padding: 0;}
16 #top-menu li {
16 #top-menu li {
17 float:left;
17 float:left;
18 list-style-type:none;
18 list-style-type:none;
19 margin: 0px 0px 0px 0px;
19 margin: 0px 0px 0px 0px;
20 padding: 0px 0px 0px 0px;
20 padding: 0px 0px 0px 0px;
21 white-space:nowrap;
21 white-space:nowrap;
22 }
22 }
23 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
23 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
24 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
24 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
25
25
26 #account {float:right;}
26 #account {float:right;}
27
27
28 #header {height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
28 #header {height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
29 #header a {color:#f8f8f8;}
29 #header a {color:#f8f8f8;}
30 #header h1 a.ancestor { font-size: 80%; }
30 #header h1 a.ancestor { font-size: 80%; }
31 #quick-search {float:right;}
31 #quick-search {float:right;}
32
32
33 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
33 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
34 #main-menu ul {margin: 0; padding: 0;}
34 #main-menu ul {margin: 0; padding: 0;}
35 #main-menu li {
35 #main-menu li {
36 float:left;
36 float:left;
37 list-style-type:none;
37 list-style-type:none;
38 margin: 0px 2px 0px 0px;
38 margin: 0px 2px 0px 0px;
39 padding: 0px 0px 0px 0px;
39 padding: 0px 0px 0px 0px;
40 white-space:nowrap;
40 white-space:nowrap;
41 }
41 }
42 #main-menu li a {
42 #main-menu li a {
43 display: block;
43 display: block;
44 color: #fff;
44 color: #fff;
45 text-decoration: none;
45 text-decoration: none;
46 font-weight: bold;
46 font-weight: bold;
47 margin: 0;
47 margin: 0;
48 padding: 4px 10px 4px 10px;
48 padding: 4px 10px 4px 10px;
49 }
49 }
50 #main-menu li a:hover {background:#759FCF; color:#fff;}
50 #main-menu li a:hover {background:#759FCF; color:#fff;}
51 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
51 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
52
52
53 #admin-menu ul {margin: 0; padding: 0;}
53 #admin-menu ul {margin: 0; padding: 0;}
54 #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;}
54 #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;}
55
55
56 #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}
56 #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}
57 #admin-menu a.projects { background-image: url(../images/projects.png); }
57 #admin-menu a.projects { background-image: url(../images/projects.png); }
58 #admin-menu a.users { background-image: url(../images/user.png); }
58 #admin-menu a.users { background-image: url(../images/user.png); }
59 #admin-menu a.groups { background-image: url(../images/group.png); }
59 #admin-menu a.groups { background-image: url(../images/group.png); }
60 #admin-menu a.roles { background-image: url(../images/database_key.png); }
60 #admin-menu a.roles { background-image: url(../images/database_key.png); }
61 #admin-menu a.trackers { background-image: url(../images/ticket.png); }
61 #admin-menu a.trackers { background-image: url(../images/ticket.png); }
62 #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }
62 #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }
63 #admin-menu a.workflows { background-image: url(../images/ticket_go.png); }
63 #admin-menu a.workflows { background-image: url(../images/ticket_go.png); }
64 #admin-menu a.custom_fields { background-image: url(../images/textfield.png); }
64 #admin-menu a.custom_fields { background-image: url(../images/textfield.png); }
65 #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }
65 #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }
66 #admin-menu a.settings { background-image: url(../images/changeset.png); }
66 #admin-menu a.settings { background-image: url(../images/changeset.png); }
67 #admin-menu a.plugins { background-image: url(../images/plugin.png); }
67 #admin-menu a.plugins { background-image: url(../images/plugin.png); }
68 #admin-menu a.info { background-image: url(../images/help.png); }
68 #admin-menu a.info { background-image: url(../images/help.png); }
69 #admin-menu a.server_authentication { background-image: url(../images/server_key.png); }
69 #admin-menu a.server_authentication { background-image: url(../images/server_key.png); }
70
70
71 #main {background-color:#EEEEEE;}
71 #main {background-color:#EEEEEE;}
72
72
73 #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;}
73 #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;}
74 * html #sidebar{ width: 22%; }
74 * html #sidebar{ width: 22%; }
75 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
75 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
76 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
76 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
77 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
77 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
78 #sidebar .contextual { margin-right: 1em; }
78 #sidebar .contextual { margin-right: 1em; }
79
79
80 #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
80 #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
81 * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
81 * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
82 html>body #content { min-height: 600px; }
82 html>body #content { min-height: 600px; }
83 * html body #content { height: 600px; } /* IE */
83 * html body #content { height: 600px; } /* IE */
84
84
85 #main.nosidebar #sidebar{ display: none; }
85 #main.nosidebar #sidebar{ display: none; }
86 #main.nosidebar #content{ width: auto; border-right: 0; }
86 #main.nosidebar #content{ width: auto; border-right: 0; }
87
87
88 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
88 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
89
89
90 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
90 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
91 #login-form table td {padding: 6px;}
91 #login-form table td {padding: 6px;}
92 #login-form label {font-weight: bold;}
92 #login-form label {font-weight: bold;}
93 #login-form input#username, #login-form input#password { width: 300px; }
93 #login-form input#username, #login-form input#password { width: 300px; }
94
94
95 div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;}
95 div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;}
96 div.modal h3.title {display:none;}
96 div.modal h3.title {display:none;}
97 div.modal p.buttons {text-align:right; margin-bottom:0;}
97 div.modal p.buttons {text-align:right; margin-bottom:0;}
98
98
99 input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
99 input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
100
100
101 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
101 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
102
102
103 /***** Links *****/
103 /***** Links *****/
104 a, a:link, a:visited{ color: #169; text-decoration: none; }
104 a, a:link, a:visited{ color: #169; text-decoration: none; }
105 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
105 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
106 a img{ border: 0; }
106 a img{ border: 0; }
107
107
108 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
108 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
109 a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; }
109 a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; }
110 a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;}
110 a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;}
111
111
112 #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;}
112 #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;}
113 #sidebar a.selected:hover {text-decoration:none;}
113 #sidebar a.selected:hover {text-decoration:none;}
114 #admin-menu a {line-height:1.7em;}
114 #admin-menu a {line-height:1.7em;}
115 #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;}
115 #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;}
116
116
117 a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;}
117 a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;}
118 a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;}
118 a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;}
119
119
120 a#toggle-completed-versions {color:#999;}
120 a#toggle-completed-versions {color:#999;}
121 /***** Tables *****/
121 /***** Tables *****/
122 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
122 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
123 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
123 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
124 table.list td { vertical-align: top; padding-right:10px; }
124 table.list td { vertical-align: top; padding-right:10px; }
125 table.list td.id { width: 2%; text-align: center;}
125 table.list td.id { width: 2%; text-align: center;}
126 table.list td.checkbox { width: 15px; padding: 2px 0 0 0; }
126 table.list td.checkbox { width: 15px; padding: 2px 0 0 0; }
127 table.list td.checkbox input {padding:0px;}
127 table.list td.checkbox input {padding:0px;}
128 table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }
128 table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }
129 table.list td.buttons a { padding-right: 0.6em; }
129 table.list td.buttons a { padding-right: 0.6em; }
130 table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; }
130 table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; }
131
131
132 tr.project td.name a { white-space:nowrap; }
132 tr.project td.name a { white-space:nowrap; }
133 tr.project.closed, tr.project.archived { color: #aaa; }
133 tr.project.closed, tr.project.archived { color: #aaa; }
134 tr.project.closed a, tr.project.archived a { color: #aaa; }
134 tr.project.closed a, tr.project.archived a { color: #aaa; }
135
135
136 tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
136 tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
137 tr.project.idnt-1 td.name {padding-left: 0.5em;}
137 tr.project.idnt-1 td.name {padding-left: 0.5em;}
138 tr.project.idnt-2 td.name {padding-left: 2em;}
138 tr.project.idnt-2 td.name {padding-left: 2em;}
139 tr.project.idnt-3 td.name {padding-left: 3.5em;}
139 tr.project.idnt-3 td.name {padding-left: 3.5em;}
140 tr.project.idnt-4 td.name {padding-left: 5em;}
140 tr.project.idnt-4 td.name {padding-left: 5em;}
141 tr.project.idnt-5 td.name {padding-left: 6.5em;}
141 tr.project.idnt-5 td.name {padding-left: 6.5em;}
142 tr.project.idnt-6 td.name {padding-left: 8em;}
142 tr.project.idnt-6 td.name {padding-left: 8em;}
143 tr.project.idnt-7 td.name {padding-left: 9.5em;}
143 tr.project.idnt-7 td.name {padding-left: 9.5em;}
144 tr.project.idnt-8 td.name {padding-left: 11em;}
144 tr.project.idnt-8 td.name {padding-left: 11em;}
145 tr.project.idnt-9 td.name {padding-left: 12.5em;}
145 tr.project.idnt-9 td.name {padding-left: 12.5em;}
146
146
147 tr.issue { text-align: center; white-space: nowrap; }
147 tr.issue { text-align: center; white-space: nowrap; }
148 tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.relations { white-space: normal; }
148 tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.relations { white-space: normal; }
149 tr.issue td.subject, tr.issue td.relations { text-align: left; }
149 tr.issue td.subject, tr.issue td.relations { text-align: left; }
150 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
150 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
151 tr.issue td.relations span {white-space: nowrap;}
151 tr.issue td.relations span {white-space: nowrap;}
152 table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
152 table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
153 table.issues td.description pre {white-space:normal;}
153 table.issues td.description pre {white-space:normal;}
154
154
155 tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
155 tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
156 tr.issue.idnt-1 td.subject {padding-left: 0.5em;}
156 tr.issue.idnt-1 td.subject {padding-left: 0.5em;}
157 tr.issue.idnt-2 td.subject {padding-left: 2em;}
157 tr.issue.idnt-2 td.subject {padding-left: 2em;}
158 tr.issue.idnt-3 td.subject {padding-left: 3.5em;}
158 tr.issue.idnt-3 td.subject {padding-left: 3.5em;}
159 tr.issue.idnt-4 td.subject {padding-left: 5em;}
159 tr.issue.idnt-4 td.subject {padding-left: 5em;}
160 tr.issue.idnt-5 td.subject {padding-left: 6.5em;}
160 tr.issue.idnt-5 td.subject {padding-left: 6.5em;}
161 tr.issue.idnt-6 td.subject {padding-left: 8em;}
161 tr.issue.idnt-6 td.subject {padding-left: 8em;}
162 tr.issue.idnt-7 td.subject {padding-left: 9.5em;}
162 tr.issue.idnt-7 td.subject {padding-left: 9.5em;}
163 tr.issue.idnt-8 td.subject {padding-left: 11em;}
163 tr.issue.idnt-8 td.subject {padding-left: 11em;}
164 tr.issue.idnt-9 td.subject {padding-left: 12.5em;}
164 tr.issue.idnt-9 td.subject {padding-left: 12.5em;}
165
165
166 tr.entry { border: 1px solid #f8f8f8; }
166 tr.entry { border: 1px solid #f8f8f8; }
167 tr.entry td { white-space: nowrap; }
167 tr.entry td { white-space: nowrap; }
168 tr.entry td.filename { width: 30%; }
168 tr.entry td.filename { width: 30%; }
169 tr.entry td.filename_no_report { width: 70%; }
169 tr.entry td.filename_no_report { width: 70%; }
170 tr.entry td.size { text-align: right; font-size: 90%; }
170 tr.entry td.size { text-align: right; font-size: 90%; }
171 tr.entry td.revision, tr.entry td.author { text-align: center; }
171 tr.entry td.revision, tr.entry td.author { text-align: center; }
172 tr.entry td.age { text-align: right; }
172 tr.entry td.age { text-align: right; }
173 tr.entry.file td.filename a { margin-left: 16px; }
173 tr.entry.file td.filename a { margin-left: 16px; }
174 tr.entry.file td.filename_no_report a { margin-left: 16px; }
174 tr.entry.file td.filename_no_report a { margin-left: 16px; }
175
175
176 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
176 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
177 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
177 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
178
178
179 tr.changeset { height: 20px }
179 tr.changeset { height: 20px }
180 tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; }
180 tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; }
181 tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; }
181 tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; }
182 tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;}
182 tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;}
183 tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;}
183 tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;}
184
184
185 table.files tr.file td { text-align: center; }
185 table.files tr.file td { text-align: center; }
186 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
186 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
187 table.files tr.file td.digest { font-size: 80%; }
187 table.files tr.file td.digest { font-size: 80%; }
188
188
189 table.members td.roles, table.memberships td.roles { width: 45%; }
189 table.members td.roles, table.memberships td.roles { width: 45%; }
190
190
191 tr.message { height: 2.6em; }
191 tr.message { height: 2.6em; }
192 tr.message td.subject { padding-left: 20px; }
192 tr.message td.subject { padding-left: 20px; }
193 tr.message td.created_on { white-space: nowrap; }
193 tr.message td.created_on { white-space: nowrap; }
194 tr.message td.last_message { font-size: 80%; white-space: nowrap; }
194 tr.message td.last_message { font-size: 80%; white-space: nowrap; }
195 tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; }
195 tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; }
196 tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; }
196 tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; }
197
197
198 tr.version.closed, tr.version.closed a { color: #999; }
198 tr.version.closed, tr.version.closed a { color: #999; }
199 tr.version td.name { padding-left: 20px; }
199 tr.version td.name { padding-left: 20px; }
200 tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }
200 tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }
201 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; }
201 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; }
202
202
203 tr.user td { width:13%; }
203 tr.user td { width:13%; }
204 tr.user td.email { width:18%; }
204 tr.user td.email { width:18%; }
205 tr.user td { white-space: nowrap; }
205 tr.user td { white-space: nowrap; }
206 tr.user.locked, tr.user.registered { color: #aaa; }
206 tr.user.locked, tr.user.registered { color: #aaa; }
207 tr.user.locked a, tr.user.registered a { color: #aaa; }
207 tr.user.locked a, tr.user.registered a { color: #aaa; }
208
208
209 table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;}
209 table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;}
210
210
211 tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;}
211 tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;}
212
212
213 tr.time-entry { text-align: center; white-space: nowrap; }
213 tr.time-entry { text-align: center; white-space: nowrap; }
214 tr.time-entry td.issue, tr.time-entry td.comments { text-align: left; white-space: normal; }
214 tr.time-entry td.issue, tr.time-entry td.comments { text-align: left; white-space: normal; }
215 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
215 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
216 td.hours .hours-dec { font-size: 0.9em; }
216 td.hours .hours-dec { font-size: 0.9em; }
217
217
218 table.plugins td { vertical-align: middle; }
218 table.plugins td { vertical-align: middle; }
219 table.plugins td.configure { text-align: right; padding-right: 1em; }
219 table.plugins td.configure { text-align: right; padding-right: 1em; }
220 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
220 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
221 table.plugins span.description { display: block; font-size: 0.9em; }
221 table.plugins span.description { display: block; font-size: 0.9em; }
222 table.plugins span.url { display: block; font-size: 0.9em; }
222 table.plugins span.url { display: block; font-size: 0.9em; }
223
223
224 table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }
224 table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }
225 table.list tbody tr.group span.count {position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;}
225 table.list tbody tr.group span.count {position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;}
226 tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;}
226 tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;}
227 tr.group:hover a.toggle-all { display:inline;}
227 tr.group:hover a.toggle-all { display:inline;}
228 a.toggle-all:hover {text-decoration:none;}
228 a.toggle-all:hover {text-decoration:none;}
229
229
230 table.list tbody tr:hover { background-color:#ffffdd; }
230 table.list tbody tr:hover { background-color:#ffffdd; }
231 table.list tbody tr.group:hover { background-color:inherit; }
231 table.list tbody tr.group:hover { background-color:inherit; }
232 table td {padding:2px;}
232 table td {padding:2px;}
233 table p {margin:0;}
233 table p {margin:0;}
234 .odd {background-color:#f6f7f8;}
234 .odd {background-color:#f6f7f8;}
235 .even {background-color: #fff;}
235 .even {background-color: #fff;}
236
236
237 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
237 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
238 a.sort.asc { background-image: url(../images/sort_asc.png); }
238 a.sort.asc { background-image: url(../images/sort_asc.png); }
239 a.sort.desc { background-image: url(../images/sort_desc.png); }
239 a.sort.desc { background-image: url(../images/sort_desc.png); }
240
240
241 table.attributes { width: 100% }
241 table.attributes { width: 100% }
242 table.attributes th { vertical-align: top; text-align: left; }
242 table.attributes th { vertical-align: top; text-align: left; }
243 table.attributes td { vertical-align: top; }
243 table.attributes td { vertical-align: top; }
244
244
245 table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
245 table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
246 table.boards td.topic-count, table.boards td.message-count {text-align:center;}
246 table.boards td.topic-count, table.boards td.message-count {text-align:center;}
247 table.boards td.last-message {font-size:80%;}
247 table.boards td.last-message {font-size:80%;}
248
248
249 table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;}
249 table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;}
250
250
251 table.query-columns {
251 table.query-columns {
252 border-collapse: collapse;
252 border-collapse: collapse;
253 border: 0;
253 border: 0;
254 }
254 }
255
255
256 table.query-columns td.buttons {
256 table.query-columns td.buttons {
257 vertical-align: middle;
257 vertical-align: middle;
258 text-align: center;
258 text-align: center;
259 }
259 }
260
260
261 td.center {text-align:center;}
261 td.center {text-align:center;}
262
262
263 h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; }
263 h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; }
264
264
265 div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }
265 div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }
266 div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; }
266 div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; }
267 div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; }
267 div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; }
268 div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; }
268 div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; }
269
269
270 #watchers ul {margin: 0; padding: 0;}
270 #watchers ul {margin: 0; padding: 0;}
271 #watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;}
271 #watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;}
272 #watchers select {width: 95%; display: block;}
272 #watchers select {width: 95%; display: block;}
273 #watchers a.delete {opacity: 0.4;}
273 #watchers a.delete {opacity: 0.4;}
274 #watchers a.delete:hover {opacity: 1;}
274 #watchers a.delete:hover {opacity: 1;}
275 #watchers img.gravatar {margin: 0 4px 2px 0;}
275 #watchers img.gravatar {margin: 0 4px 2px 0;}
276
276
277 span#watchers_inputs {overflow:auto; display:block;}
277 span#watchers_inputs {overflow:auto; display:block;}
278 span.search_for_watchers {display:block;}
278 span.search_for_watchers {display:block;}
279 span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
279 span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
280 span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
280 span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
281
281
282
282
283 .highlight { background-color: #FCFD8D;}
283 .highlight { background-color: #FCFD8D;}
284 .highlight.token-1 { background-color: #faa;}
284 .highlight.token-1 { background-color: #faa;}
285 .highlight.token-2 { background-color: #afa;}
285 .highlight.token-2 { background-color: #afa;}
286 .highlight.token-3 { background-color: #aaf;}
286 .highlight.token-3 { background-color: #aaf;}
287
287
288 .box{
288 .box{
289 padding:6px;
289 padding:6px;
290 margin-bottom: 10px;
290 margin-bottom: 10px;
291 background-color:#f6f6f6;
291 background-color:#f6f6f6;
292 color:#505050;
292 color:#505050;
293 line-height:1.5em;
293 line-height:1.5em;
294 border: 1px solid #e4e4e4;
294 border: 1px solid #e4e4e4;
295 }
295 }
296
296
297 div.square {
297 div.square {
298 border: 1px solid #999;
298 border: 1px solid #999;
299 float: left;
299 float: left;
300 margin: .3em .4em 0 .4em;
300 margin: .3em .4em 0 .4em;
301 overflow: hidden;
301 overflow: hidden;
302 width: .6em; height: .6em;
302 width: .6em; height: .6em;
303 }
303 }
304 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
304 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
305 .contextual input, .contextual select {font-size:0.9em;}
305 .contextual input, .contextual select {font-size:0.9em;}
306 .message .contextual { margin-top: 0; }
306 .message .contextual { margin-top: 0; }
307
307
308 .splitcontent {overflow:auto;}
308 .splitcontent {overflow:auto;}
309 .splitcontentleft{float:left; width:49%;}
309 .splitcontentleft{float:left; width:49%;}
310 .splitcontentright{float:right; width:49%;}
310 .splitcontentright{float:right; width:49%;}
311 form {display: inline;}
311 form {display: inline;}
312 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
312 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
313 fieldset {border: 1px solid #e4e4e4; margin:0;}
313 fieldset {border: 1px solid #e4e4e4; margin:0;}
314 legend {color: #484848;}
314 legend {color: #484848;}
315 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
315 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
316 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
316 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
317 blockquote blockquote { margin-left: 0;}
317 blockquote blockquote { margin-left: 0;}
318 acronym { border-bottom: 1px dotted; cursor: help; }
318 acronym { border-bottom: 1px dotted; cursor: help; }
319 textarea.wiki-edit {width:99%; resize:vertical;}
319 textarea.wiki-edit {width:99%; resize:vertical;}
320 li p {margin-top: 0;}
320 li p {margin-top: 0;}
321 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
321 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
322 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
322 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
323 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
323 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
324 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
324 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
325
325
326 div.issue div.subject div div { padding-left: 16px; }
326 div.issue div.subject div div { padding-left: 16px; }
327 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
327 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
328 div.issue div.subject>div>p { margin-top: 0.5em; }
328 div.issue div.subject>div>p { margin-top: 0.5em; }
329 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
329 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
330 div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;}
330 div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;}
331 div.issue .next-prev-links {color:#999;}
331 div.issue .next-prev-links {color:#999;}
332 div.issue table.attributes th {width:22%;}
332 div.issue table.attributes th {width:22%;}
333 div.issue table.attributes td {width:28%;}
333 div.issue table.attributes td {width:28%;}
334
334
335 #issue_tree table.issues, #relations table.issues { border: 0; }
335 #issue_tree table.issues, #relations table.issues { border: 0; }
336 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
336 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
337 #relations td.buttons {padding:0;}
337 #relations td.buttons {padding:0;}
338
338
339 fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }
339 fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }
340 fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
340 fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
341 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }
341 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }
342
342
343 fieldset#date-range p { margin: 2px 0 2px 0; }
343 fieldset#date-range p { margin: 2px 0 2px 0; }
344 fieldset#filters table { border-collapse: collapse; }
344 fieldset#filters table { border-collapse: collapse; }
345 fieldset#filters table td { padding: 0; vertical-align: middle; }
345 fieldset#filters table td { padding: 0; vertical-align: middle; }
346 fieldset#filters tr.filter { height: 2.1em; }
346 fieldset#filters tr.filter { height: 2.1em; }
347 fieldset#filters td.field { width:230px; }
347 fieldset#filters td.field { width:230px; }
348 fieldset#filters td.operator { width:180px; }
348 fieldset#filters td.operator { width:180px; }
349 fieldset#filters td.operator select {max-width:170px;}
349 fieldset#filters td.operator select {max-width:170px;}
350 fieldset#filters td.values { white-space:nowrap; }
350 fieldset#filters td.values { white-space:nowrap; }
351 fieldset#filters td.values select {min-width:130px;}
351 fieldset#filters td.values select {min-width:130px;}
352 fieldset#filters td.values input {height:1em;}
352 fieldset#filters td.values input {height:1em;}
353 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
353 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
354
354
355 .toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;}
355 .toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;}
356 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
356 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
357
357
358 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
358 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
359 div#issue-changesets div.changeset { padding: 4px;}
359 div#issue-changesets div.changeset { padding: 4px;}
360 div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; }
360 div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; }
361 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
361 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
362
362
363 .journal ul.details img {margin:0 0 -3px 4px;}
363 .journal ul.details img {margin:0 0 -3px 4px;}
364 div.journal {overflow:auto;}
364 div.journal {overflow:auto;}
365 div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;}
365 div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;}
366
366
367 div#activity dl, #search-results { margin-left: 2em; }
367 div#activity dl, #search-results { margin-left: 2em; }
368 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
368 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
369 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
369 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
370 div#activity dt.me .time { border-bottom: 1px solid #999; }
370 div#activity dt.me .time { border-bottom: 1px solid #999; }
371 div#activity dt .time { color: #777; font-size: 80%; }
371 div#activity dt .time { color: #777; font-size: 80%; }
372 div#activity dd .description, #search-results dd .description { font-style: italic; }
372 div#activity dd .description, #search-results dd .description { font-style: italic; }
373 div#activity span.project:after, #search-results span.project:after { content: " -"; }
373 div#activity span.project:after, #search-results span.project:after { content: " -"; }
374 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
374 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
375 div#activity dt.grouped {margin-left:5em;}
375 div#activity dt.grouped {margin-left:5em;}
376 div#activity dd.grouped {margin-left:9em;}
376 div#activity dd.grouped {margin-left:9em;}
377
377
378 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
378 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
379
379
380 div#search-results-counts {float:right;}
380 div#search-results-counts {float:right;}
381 div#search-results-counts ul { margin-top: 0.5em; }
381 div#search-results-counts ul { margin-top: 0.5em; }
382 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
382 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
383
383
384 dt.issue { background-image: url(../images/ticket.png); }
384 dt.issue { background-image: url(../images/ticket.png); }
385 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
385 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
386 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
386 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
387 dt.issue-note { background-image: url(../images/ticket_note.png); }
387 dt.issue-note { background-image: url(../images/ticket_note.png); }
388 dt.changeset { background-image: url(../images/changeset.png); }
388 dt.changeset { background-image: url(../images/changeset.png); }
389 dt.news { background-image: url(../images/news.png); }
389 dt.news { background-image: url(../images/news.png); }
390 dt.message { background-image: url(../images/message.png); }
390 dt.message { background-image: url(../images/message.png); }
391 dt.reply { background-image: url(../images/comments.png); }
391 dt.reply { background-image: url(../images/comments.png); }
392 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
392 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
393 dt.attachment { background-image: url(../images/attachment.png); }
393 dt.attachment { background-image: url(../images/attachment.png); }
394 dt.document { background-image: url(../images/document.png); }
394 dt.document { background-image: url(../images/document.png); }
395 dt.project { background-image: url(../images/projects.png); }
395 dt.project { background-image: url(../images/projects.png); }
396 dt.time-entry { background-image: url(../images/time.png); }
396 dt.time-entry { background-image: url(../images/time.png); }
397
397
398 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
398 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
399
399
400 div#roadmap .related-issues { margin-bottom: 1em; }
400 div#roadmap .related-issues { margin-bottom: 1em; }
401 div#roadmap .related-issues td.checkbox { display: none; }
401 div#roadmap .related-issues td.checkbox { display: none; }
402 div#roadmap .wiki h1:first-child { display: none; }
402 div#roadmap .wiki h1:first-child { display: none; }
403 div#roadmap .wiki h1 { font-size: 120%; }
403 div#roadmap .wiki h1 { font-size: 120%; }
404 div#roadmap .wiki h2 { font-size: 110%; }
404 div#roadmap .wiki h2 { font-size: 110%; }
405 body.controller-versions.action-show div#roadmap .related-issues {width:70%;}
405 body.controller-versions.action-show div#roadmap .related-issues {width:70%;}
406
406
407 div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
407 div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
408 div#version-summary fieldset { margin-bottom: 1em; }
408 div#version-summary fieldset { margin-bottom: 1em; }
409 div#version-summary fieldset.time-tracking table { width:100%; }
409 div#version-summary fieldset.time-tracking table { width:100%; }
410 div#version-summary th, div#version-summary td.total-hours { text-align: right; }
410 div#version-summary th, div#version-summary td.total-hours { text-align: right; }
411
411
412 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
412 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
413 table#time-report tbody tr.subtotal { font-style: italic; color:#777;}
413 table#time-report tbody tr.subtotal { font-style: italic; color:#777;}
414 table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; }
414 table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; }
415 table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;}
415 table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;}
416 table#time-report .hours-dec { font-size: 0.9em; }
416 table#time-report .hours-dec { font-size: 0.9em; }
417
417
418 div.wiki-page .contextual a {opacity: 0.4}
418 div.wiki-page .contextual a {opacity: 0.4}
419 div.wiki-page .contextual a:hover {opacity: 1}
419 div.wiki-page .contextual a:hover {opacity: 1}
420
420
421 form .attributes select { width: 60%; }
421 form .attributes select { width: 60%; }
422 input#issue_subject { width: 99%; }
422 input#issue_subject { width: 99%; }
423 select#issue_done_ratio { width: 95px; }
423 select#issue_done_ratio { width: 95px; }
424
424
425 ul.projects {margin:0; padding-left:1em;}
425 ul.projects {margin:0; padding-left:1em;}
426 ul.projects ul {padding-left:1.6em;}
426 ul.projects ul {padding-left:1.6em;}
427 ul.projects.root {margin:0; padding:0;}
427 ul.projects.root {margin:0; padding:0;}
428 ul.projects li {list-style-type:none;}
428 ul.projects li {list-style-type:none;}
429
429
430 #projects-index ul.projects ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;}
430 #projects-index ul.projects ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;}
431 #projects-index ul.projects li.root {margin-bottom: 1em;}
431 #projects-index ul.projects li.root {margin-bottom: 1em;}
432 #projects-index ul.projects li.child {margin-top: 1em;}
432 #projects-index ul.projects li.child {margin-top: 1em;}
433 #projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
433 #projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
434 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
434 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
435
435
436 #notified-projects ul, #tracker_project_ids ul {max-height:250px; overflow-y:auto;}
436 #notified-projects ul, #tracker_project_ids ul {max-height:250px; overflow-y:auto;}
437
437
438 #related-issues li img {vertical-align:middle;}
438 #related-issues li img {vertical-align:middle;}
439
439
440 ul.properties {padding:0; font-size: 0.9em; color: #777;}
440 ul.properties {padding:0; font-size: 0.9em; color: #777;}
441 ul.properties li {list-style-type:none;}
441 ul.properties li {list-style-type:none;}
442 ul.properties li span {font-style:italic;}
442 ul.properties li span {font-style:italic;}
443
443
444 .total-hours { font-size: 110%; font-weight: bold; }
444 .total-hours { font-size: 110%; font-weight: bold; }
445 .total-hours span.hours-int { font-size: 120%; }
445 .total-hours span.hours-int { font-size: 120%; }
446
446
447 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
447 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
448 #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; }
448 #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; }
449
449
450 #workflow_copy_form select { width: 200px; }
450 #workflow_copy_form select { width: 200px; }
451 table.transitions td.enabled {background: #bfb;}
451 table.transitions td.enabled {background: #bfb;}
452 table.fields_permissions select {font-size:90%}
452 table.fields_permissions select {font-size:90%}
453 table.fields_permissions td.readonly {background:#ddd;}
453 table.fields_permissions td.readonly {background:#ddd;}
454 table.fields_permissions td.required {background:#d88;}
454 table.fields_permissions td.required {background:#d88;}
455
455
456 textarea#custom_field_possible_values {width: 99%}
456 textarea#custom_field_possible_values {width: 99%}
457 input#content_comments {width: 99%}
457 input#content_comments {width: 99%}
458
458
459 p.pagination {margin-top:8px; font-size: 90%}
459 p.pagination {margin-top:8px; font-size: 90%}
460
460
461 /***** Tabular forms ******/
461 /***** Tabular forms ******/
462 .tabular p{
462 .tabular p{
463 margin: 0;
463 margin: 0;
464 padding: 3px 0 3px 0;
464 padding: 3px 0 3px 0;
465 padding-left: 180px; /* width of left column containing the label elements */
465 padding-left: 180px; /* width of left column containing the label elements */
466 min-height: 1.8em;
466 min-height: 1.8em;
467 clear:left;
467 clear:left;
468 }
468 }
469
469
470 html>body .tabular p {overflow:hidden;}
470 html>body .tabular p {overflow:hidden;}
471
471
472 .tabular label{
472 .tabular label{
473 font-weight: bold;
473 font-weight: bold;
474 float: left;
474 float: left;
475 text-align: right;
475 text-align: right;
476 /* width of left column */
476 /* width of left column */
477 margin-left: -180px;
477 margin-left: -180px;
478 /* width of labels. Should be smaller than left column to create some right margin */
478 /* width of labels. Should be smaller than left column to create some right margin */
479 width: 175px;
479 width: 175px;
480 }
480 }
481
481
482 .tabular label.floating{
482 .tabular label.floating{
483 font-weight: normal;
483 font-weight: normal;
484 margin-left: 0px;
484 margin-left: 0px;
485 text-align: left;
485 text-align: left;
486 width: 270px;
486 width: 270px;
487 }
487 }
488
488
489 .tabular label.block{
489 .tabular label.block{
490 font-weight: normal;
490 font-weight: normal;
491 margin-left: 0px !important;
491 margin-left: 0px !important;
492 text-align: left;
492 text-align: left;
493 float: none;
493 float: none;
494 display: block;
494 display: block;
495 width: auto;
495 width: auto;
496 }
496 }
497
497
498 .tabular label.inline{
498 .tabular label.inline{
499 font-weight: normal;
499 font-weight: normal;
500 float:none;
500 float:none;
501 margin-left: 5px !important;
501 margin-left: 5px !important;
502 width: auto;
502 width: auto;
503 }
503 }
504
504
505 label.no-css {
505 label.no-css {
506 font-weight: inherit;
506 font-weight: inherit;
507 float:none;
507 float:none;
508 text-align:left;
508 text-align:left;
509 margin-left:0px;
509 margin-left:0px;
510 width:auto;
510 width:auto;
511 }
511 }
512 input#time_entry_comments { width: 90%;}
512 input#time_entry_comments { width: 90%;}
513
513
514 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
514 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
515
515
516 .tabular.settings p{ padding-left: 300px; }
516 .tabular.settings p{ padding-left: 300px; }
517 .tabular.settings label{ margin-left: -300px; width: 295px; }
517 .tabular.settings label{ margin-left: -300px; width: 295px; }
518 .tabular.settings textarea { width: 99%; }
518 .tabular.settings textarea { width: 99%; }
519
519
520 .settings.enabled_scm table {width:100%}
520 .settings.enabled_scm table {width:100%}
521 .settings.enabled_scm td.scm_name{ font-weight: bold; }
521 .settings.enabled_scm td.scm_name{ font-weight: bold; }
522
522
523 fieldset.settings label { display: block; }
523 fieldset.settings label { display: block; }
524 fieldset#notified_events .parent { padding-left: 20px; }
524 fieldset#notified_events .parent { padding-left: 20px; }
525
525
526 span.required {color: #bb0000;}
526 span.required {color: #bb0000;}
527 .summary {font-style: italic;}
527 .summary {font-style: italic;}
528
528
529 #attachments_fields input.description {margin-left:4px; width:340px;}
529 #attachments_fields input.description {margin-left:4px; width:340px;}
530 #attachments_fields span {display:block; white-space:nowrap;}
530 #attachments_fields span {display:block; white-space:nowrap;}
531 #attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../images/attachment.png) no-repeat 1px 50%; padding-left:18px;}
531 #attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../images/attachment.png) no-repeat 1px 50%; padding-left:18px;}
532 #attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;}
532 #attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;}
533 #attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;}
533 #attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;}
534 #attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; }
534 #attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; }
535 a.remove-upload {background: url(../images/delete.png) no-repeat 1px 50%; width:1px; display:inline-block; padding-left:16px;}
535 a.remove-upload {background: url(../images/delete.png) no-repeat 1px 50%; width:1px; display:inline-block; padding-left:16px;}
536 a.remove-upload:hover {text-decoration:none !important;}
536 a.remove-upload:hover {text-decoration:none !important;}
537
537
538 div.fileover { background-color: lavender; }
538 div.fileover { background-color: lavender; }
539
539
540 div.attachments { margin-top: 12px; }
540 div.attachments { margin-top: 12px; }
541 div.attachments p { margin:4px 0 2px 0; }
541 div.attachments p { margin:4px 0 2px 0; }
542 div.attachments img { vertical-align: middle; }
542 div.attachments img { vertical-align: middle; }
543 div.attachments span.author { font-size: 0.9em; color: #888; }
543 div.attachments span.author { font-size: 0.9em; color: #888; }
544
544
545 div.thumbnails {margin-top:0.6em;}
545 div.thumbnails {margin-top:0.6em;}
546 div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;}
546 div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;}
547 div.thumbnails img {margin: 3px;}
547 div.thumbnails img {margin: 3px;}
548
548
549 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
549 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
550 .other-formats span + span:before { content: "| "; }
550 .other-formats span + span:before { content: "| "; }
551
551
552 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
552 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
553
553
554 em.info {font-style:normal;font-size:90%;color:#888;display:block;}
554 em.info {font-style:normal;font-size:90%;color:#888;display:block;}
555 em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;}
555 em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;}
556
556
557 textarea.text_cf {width:90%;}
557 textarea.text_cf {width:90%;}
558
558
559 /* Project members tab */
559 /* Project members tab */
560 div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }
560 div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }
561 div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }
561 div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }
562 div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }
562 div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }
563 div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }
563 div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }
564 div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
564 div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
565 div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }
565 div#tab-content-members #principals, div#tab-content-users #principals { max-height: 400px; overflow:auto; }
566
566
567 #users_for_watcher {height: 200px; overflow:auto;}
567 #users_for_watcher {height: 200px; overflow:auto;}
568 #users_for_watcher label {display: block;}
568 #users_for_watcher label {display: block;}
569
569
570 table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }
570 table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }
571
571
572 input#principal_search, input#user_search {width:90%}
572 input#principal_search, input#user_search {width:90%}
573
573
574 input.autocomplete {
574 input.autocomplete {
575 background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px;
575 background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px;
576 border:1px solid #9EB1C2; border-radius:2px; height:1.5em;
576 border:1px solid #9EB1C2; border-radius:2px; height:1.5em;
577 }
577 }
578 input.autocomplete.ajax-loading {
578 input.autocomplete.ajax-loading {
579 background-image: url(../images/loading.gif);
579 background-image: url(../images/loading.gif);
580 }
580 }
581
581
582 * html div#tab-content-members fieldset div { height: 450px; }
582 * html div#tab-content-members fieldset div { height: 450px; }
583
583
584 /***** Flash & error messages ****/
584 /***** Flash & error messages ****/
585 #errorExplanation, div.flash, .nodata, .warning, .conflict {
585 #errorExplanation, div.flash, .nodata, .warning, .conflict {
586 padding: 4px 4px 4px 30px;
586 padding: 4px 4px 4px 30px;
587 margin-bottom: 12px;
587 margin-bottom: 12px;
588 font-size: 1.1em;
588 font-size: 1.1em;
589 border: 2px solid;
589 border: 2px solid;
590 }
590 }
591
591
592 div.flash {margin-top: 8px;}
592 div.flash {margin-top: 8px;}
593
593
594 div.flash.error, #errorExplanation {
594 div.flash.error, #errorExplanation {
595 background: url(../images/exclamation.png) 8px 50% no-repeat;
595 background: url(../images/exclamation.png) 8px 50% no-repeat;
596 background-color: #ffe3e3;
596 background-color: #ffe3e3;
597 border-color: #dd0000;
597 border-color: #dd0000;
598 color: #880000;
598 color: #880000;
599 }
599 }
600
600
601 div.flash.notice {
601 div.flash.notice {
602 background: url(../images/true.png) 8px 5px no-repeat;
602 background: url(../images/true.png) 8px 5px no-repeat;
603 background-color: #dfffdf;
603 background-color: #dfffdf;
604 border-color: #9fcf9f;
604 border-color: #9fcf9f;
605 color: #005f00;
605 color: #005f00;
606 }
606 }
607
607
608 div.flash.warning, .conflict {
608 div.flash.warning, .conflict {
609 background: url(../images/warning.png) 8px 5px no-repeat;
609 background: url(../images/warning.png) 8px 5px no-repeat;
610 background-color: #FFEBC1;
610 background-color: #FFEBC1;
611 border-color: #FDBF3B;
611 border-color: #FDBF3B;
612 color: #A6750C;
612 color: #A6750C;
613 text-align: left;
613 text-align: left;
614 }
614 }
615
615
616 .nodata, .warning {
616 .nodata, .warning {
617 text-align: center;
617 text-align: center;
618 background-color: #FFEBC1;
618 background-color: #FFEBC1;
619 border-color: #FDBF3B;
619 border-color: #FDBF3B;
620 color: #A6750C;
620 color: #A6750C;
621 }
621 }
622
622
623 #errorExplanation ul { font-size: 0.9em;}
623 #errorExplanation ul { font-size: 0.9em;}
624 #errorExplanation h2, #errorExplanation p { display: none; }
624 #errorExplanation h2, #errorExplanation p { display: none; }
625
625
626 .conflict-details {font-size:80%;}
626 .conflict-details {font-size:80%;}
627
627
628 /***** Ajax indicator ******/
628 /***** Ajax indicator ******/
629 #ajax-indicator {
629 #ajax-indicator {
630 position: absolute; /* fixed not supported by IE */
630 position: absolute; /* fixed not supported by IE */
631 background-color:#eee;
631 background-color:#eee;
632 border: 1px solid #bbb;
632 border: 1px solid #bbb;
633 top:35%;
633 top:35%;
634 left:40%;
634 left:40%;
635 width:20%;
635 width:20%;
636 font-weight:bold;
636 font-weight:bold;
637 text-align:center;
637 text-align:center;
638 padding:0.6em;
638 padding:0.6em;
639 z-index:100;
639 z-index:100;
640 opacity: 0.5;
640 opacity: 0.5;
641 }
641 }
642
642
643 html>body #ajax-indicator { position: fixed; }
643 html>body #ajax-indicator { position: fixed; }
644
644
645 #ajax-indicator span {
645 #ajax-indicator span {
646 background-position: 0% 40%;
646 background-position: 0% 40%;
647 background-repeat: no-repeat;
647 background-repeat: no-repeat;
648 background-image: url(../images/loading.gif);
648 background-image: url(../images/loading.gif);
649 padding-left: 26px;
649 padding-left: 26px;
650 vertical-align: bottom;
650 vertical-align: bottom;
651 }
651 }
652
652
653 /***** Calendar *****/
653 /***** Calendar *****/
654 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
654 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
655 table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; }
655 table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; }
656 table.cal thead th.week-number {width: auto;}
656 table.cal thead th.week-number {width: auto;}
657 table.cal tbody tr {height: 100px;}
657 table.cal tbody tr {height: 100px;}
658 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
658 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
659 table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;}
659 table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;}
660 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
660 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
661 table.cal td.odd p.day-num {color: #bbb;}
661 table.cal td.odd p.day-num {color: #bbb;}
662 table.cal td.today {background:#ffffdd;}
662 table.cal td.today {background:#ffffdd;}
663 table.cal td.today p.day-num {font-weight: bold;}
663 table.cal td.today p.day-num {font-weight: bold;}
664 table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
664 table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
665 table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
665 table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
666 table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
666 table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
667 p.cal.legend span {display:block;}
667 p.cal.legend span {display:block;}
668
668
669 /***** Tooltips ******/
669 /***** Tooltips ******/
670 .tooltip{position:relative;z-index:24;}
670 .tooltip{position:relative;z-index:24;}
671 .tooltip:hover{z-index:25;color:#000;}
671 .tooltip:hover{z-index:25;color:#000;}
672 .tooltip span.tip{display: none; text-align:left;}
672 .tooltip span.tip{display: none; text-align:left;}
673
673
674 div.tooltip:hover span.tip{
674 div.tooltip:hover span.tip{
675 display:block;
675 display:block;
676 position:absolute;
676 position:absolute;
677 top:12px; left:24px; width:270px;
677 top:12px; left:24px; width:270px;
678 border:1px solid #555;
678 border:1px solid #555;
679 background-color:#fff;
679 background-color:#fff;
680 padding: 4px;
680 padding: 4px;
681 font-size: 0.8em;
681 font-size: 0.8em;
682 color:#505050;
682 color:#505050;
683 }
683 }
684
684
685 img.ui-datepicker-trigger {
685 img.ui-datepicker-trigger {
686 cursor: pointer;
686 cursor: pointer;
687 vertical-align: middle;
687 vertical-align: middle;
688 margin-left: 4px;
688 margin-left: 4px;
689 }
689 }
690
690
691 /***** Progress bar *****/
691 /***** Progress bar *****/
692 table.progress {
692 table.progress {
693 border-collapse: collapse;
693 border-collapse: collapse;
694 border-spacing: 0pt;
694 border-spacing: 0pt;
695 empty-cells: show;
695 empty-cells: show;
696 text-align: center;
696 text-align: center;
697 float:left;
697 float:left;
698 margin: 1px 6px 1px 0px;
698 margin: 1px 6px 1px 0px;
699 }
699 }
700
700
701 table.progress td { height: 1em; }
701 table.progress td { height: 1em; }
702 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
702 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
703 table.progress td.done { background: #D3EDD3 none repeat scroll 0%; }
703 table.progress td.done { background: #D3EDD3 none repeat scroll 0%; }
704 table.progress td.todo { background: #eee none repeat scroll 0%; }
704 table.progress td.todo { background: #eee none repeat scroll 0%; }
705 p.percent {font-size: 80%;}
705 p.percent {font-size: 80%;}
706 p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;}
706 p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;}
707
707
708 #roadmap table.progress td { height: 1.2em; }
708 #roadmap table.progress td { height: 1.2em; }
709 /***** Tabs *****/
709 /***** Tabs *****/
710 #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;}
710 #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;}
711 #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;}
711 #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;}
712 #content .tabs ul li {
712 #content .tabs ul li {
713 float:left;
713 float:left;
714 list-style-type:none;
714 list-style-type:none;
715 white-space:nowrap;
715 white-space:nowrap;
716 margin-right:4px;
716 margin-right:4px;
717 background:#fff;
717 background:#fff;
718 position:relative;
718 position:relative;
719 margin-bottom:-1px;
719 margin-bottom:-1px;
720 }
720 }
721 #content .tabs ul li a{
721 #content .tabs ul li a{
722 display:block;
722 display:block;
723 font-size: 0.9em;
723 font-size: 0.9em;
724 text-decoration:none;
724 text-decoration:none;
725 line-height:1.3em;
725 line-height:1.3em;
726 padding:4px 6px 4px 6px;
726 padding:4px 6px 4px 6px;
727 border: 1px solid #ccc;
727 border: 1px solid #ccc;
728 border-bottom: 1px solid #bbbbbb;
728 border-bottom: 1px solid #bbbbbb;
729 background-color: #f6f6f6;
729 background-color: #f6f6f6;
730 color:#999;
730 color:#999;
731 font-weight:bold;
731 font-weight:bold;
732 border-top-left-radius:3px;
732 border-top-left-radius:3px;
733 border-top-right-radius:3px;
733 border-top-right-radius:3px;
734 }
734 }
735
735
736 #content .tabs ul li a:hover {
736 #content .tabs ul li a:hover {
737 background-color: #ffffdd;
737 background-color: #ffffdd;
738 text-decoration:none;
738 text-decoration:none;
739 }
739 }
740
740
741 #content .tabs ul li a.selected {
741 #content .tabs ul li a.selected {
742 background-color: #fff;
742 background-color: #fff;
743 border: 1px solid #bbbbbb;
743 border: 1px solid #bbbbbb;
744 border-bottom: 1px solid #fff;
744 border-bottom: 1px solid #fff;
745 color:#444;
745 color:#444;
746 }
746 }
747
747
748 #content .tabs ul li a.selected:hover {background-color: #fff;}
748 #content .tabs ul li a.selected:hover {background-color: #fff;}
749
749
750 div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; }
750 div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; }
751
751
752 button.tab-left, button.tab-right {
752 button.tab-left, button.tab-right {
753 font-size: 0.9em;
753 font-size: 0.9em;
754 cursor: pointer;
754 cursor: pointer;
755 height:24px;
755 height:24px;
756 border: 1px solid #ccc;
756 border: 1px solid #ccc;
757 border-bottom: 1px solid #bbbbbb;
757 border-bottom: 1px solid #bbbbbb;
758 position:absolute;
758 position:absolute;
759 padding:4px;
759 padding:4px;
760 width: 20px;
760 width: 20px;
761 bottom: -1px;
761 bottom: -1px;
762 }
762 }
763
763
764 button.tab-left {
764 button.tab-left {
765 right: 20px;
765 right: 20px;
766 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
766 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
767 border-top-left-radius:3px;
767 border-top-left-radius:3px;
768 }
768 }
769
769
770 button.tab-right {
770 button.tab-right {
771 right: 0;
771 right: 0;
772 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;
772 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;
773 border-top-right-radius:3px;
773 border-top-right-radius:3px;
774 }
774 }
775
775
776 /***** Diff *****/
776 /***** Diff *****/
777 .diff_out { background: #fcc; }
777 .diff_out { background: #fcc; }
778 .diff_out span { background: #faa; }
778 .diff_out span { background: #faa; }
779 .diff_in { background: #cfc; }
779 .diff_in { background: #cfc; }
780 .diff_in span { background: #afa; }
780 .diff_in span { background: #afa; }
781
781
782 .text-diff {
782 .text-diff {
783 padding: 1em;
783 padding: 1em;
784 background-color:#f6f6f6;
784 background-color:#f6f6f6;
785 color:#505050;
785 color:#505050;
786 border: 1px solid #e4e4e4;
786 border: 1px solid #e4e4e4;
787 }
787 }
788
788
789 /***** Wiki *****/
789 /***** Wiki *****/
790 div.wiki table {
790 div.wiki table {
791 border-collapse: collapse;
791 border-collapse: collapse;
792 margin-bottom: 1em;
792 margin-bottom: 1em;
793 }
793 }
794
794
795 div.wiki table, div.wiki td, div.wiki th {
795 div.wiki table, div.wiki td, div.wiki th {
796 border: 1px solid #bbb;
796 border: 1px solid #bbb;
797 padding: 4px;
797 padding: 4px;
798 }
798 }
799
799
800 div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;}
800 div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;}
801
801
802 div.wiki .external {
802 div.wiki .external {
803 background-position: 0% 60%;
803 background-position: 0% 60%;
804 background-repeat: no-repeat;
804 background-repeat: no-repeat;
805 padding-left: 12px;
805 padding-left: 12px;
806 background-image: url(../images/external.png);
806 background-image: url(../images/external.png);
807 }
807 }
808
808
809 div.wiki a.new {color: #b73535;}
809 div.wiki a.new {color: #b73535;}
810
810
811 div.wiki ul, div.wiki ol {margin-bottom:1em;}
811 div.wiki ul, div.wiki ol {margin-bottom:1em;}
812
812
813 div.wiki pre {
813 div.wiki pre {
814 margin: 1em 1em 1em 1.6em;
814 margin: 1em 1em 1em 1.6em;
815 padding: 8px;
815 padding: 8px;
816 background-color: #fafafa;
816 background-color: #fafafa;
817 border: 1px solid #e2e2e2;
817 border: 1px solid #e2e2e2;
818 width:auto;
818 width:auto;
819 overflow-x: auto;
819 overflow-x: auto;
820 overflow-y: hidden;
820 overflow-y: hidden;
821 }
821 }
822
822
823 div.wiki ul.toc {
823 div.wiki ul.toc {
824 background-color: #ffffdd;
824 background-color: #ffffdd;
825 border: 1px solid #e4e4e4;
825 border: 1px solid #e4e4e4;
826 padding: 4px;
826 padding: 4px;
827 line-height: 1.2em;
827 line-height: 1.2em;
828 margin-bottom: 12px;
828 margin-bottom: 12px;
829 margin-right: 12px;
829 margin-right: 12px;
830 margin-left: 0;
830 margin-left: 0;
831 display: table
831 display: table
832 }
832 }
833 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
833 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
834
834
835 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
835 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
836 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
836 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
837 div.wiki ul.toc ul { margin: 0; padding: 0; }
837 div.wiki ul.toc ul { margin: 0; padding: 0; }
838 div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;}
838 div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;}
839 div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;}
839 div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;}
840 div.wiki ul.toc a {
840 div.wiki ul.toc a {
841 font-size: 0.9em;
841 font-size: 0.9em;
842 font-weight: normal;
842 font-weight: normal;
843 text-decoration: none;
843 text-decoration: none;
844 color: #606060;
844 color: #606060;
845 }
845 }
846 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
846 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
847
847
848 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
848 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
849 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
849 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
850 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
850 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
851
851
852 div.wiki img { vertical-align: middle; }
852 div.wiki img { vertical-align: middle; }
853
853
854 /***** My page layout *****/
854 /***** My page layout *****/
855 .block-receiver {
855 .block-receiver {
856 border:1px dashed #c0c0c0;
856 border:1px dashed #c0c0c0;
857 margin-bottom: 20px;
857 margin-bottom: 20px;
858 padding: 15px 0 15px 0;
858 padding: 15px 0 15px 0;
859 }
859 }
860
860
861 .mypage-box {
861 .mypage-box {
862 margin:0 0 20px 0;
862 margin:0 0 20px 0;
863 color:#505050;
863 color:#505050;
864 line-height:1.5em;
864 line-height:1.5em;
865 }
865 }
866
866
867 .handle {cursor: move;}
867 .handle {cursor: move;}
868
868
869 a.close-icon {
869 a.close-icon {
870 display:block;
870 display:block;
871 margin-top:3px;
871 margin-top:3px;
872 overflow:hidden;
872 overflow:hidden;
873 width:12px;
873 width:12px;
874 height:12px;
874 height:12px;
875 background-repeat: no-repeat;
875 background-repeat: no-repeat;
876 cursor:pointer;
876 cursor:pointer;
877 background-image:url('../images/close.png');
877 background-image:url('../images/close.png');
878 }
878 }
879 a.close-icon:hover {background-image:url('../images/close_hl.png');}
879 a.close-icon:hover {background-image:url('../images/close_hl.png');}
880
880
881 /***** Gantt chart *****/
881 /***** Gantt chart *****/
882 .gantt_hdr {
882 .gantt_hdr {
883 position:absolute;
883 position:absolute;
884 top:0;
884 top:0;
885 height:16px;
885 height:16px;
886 border-top: 1px solid #c0c0c0;
886 border-top: 1px solid #c0c0c0;
887 border-bottom: 1px solid #c0c0c0;
887 border-bottom: 1px solid #c0c0c0;
888 border-right: 1px solid #c0c0c0;
888 border-right: 1px solid #c0c0c0;
889 text-align: center;
889 text-align: center;
890 overflow: hidden;
890 overflow: hidden;
891 }
891 }
892
892
893 .gantt_hdr.nwday {background-color:#f1f1f1;}
893 .gantt_hdr.nwday {background-color:#f1f1f1;}
894
894
895 .gantt_subjects { font-size: 0.8em; }
895 .gantt_subjects { font-size: 0.8em; }
896 .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; }
896 .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; }
897
897
898 .task {
898 .task {
899 position: absolute;
899 position: absolute;
900 height:8px;
900 height:8px;
901 font-size:0.8em;
901 font-size:0.8em;
902 color:#888;
902 color:#888;
903 padding:0;
903 padding:0;
904 margin:0;
904 margin:0;
905 line-height:16px;
905 line-height:16px;
906 white-space:nowrap;
906 white-space:nowrap;
907 }
907 }
908
908
909 .task.label {width:100%;}
909 .task.label {width:100%;}
910 .task.label.project, .task.label.version { font-weight: bold; }
910 .task.label.project, .task.label.version { font-weight: bold; }
911
911
912 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
912 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
913 .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; }
913 .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; }
914 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
914 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
915
915
916 .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;}
916 .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;}
917 .task_late.parent, .task_done.parent { height: 3px;}
917 .task_late.parent, .task_done.parent { height: 3px;}
918 .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;}
918 .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;}
919 .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;}
919 .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;}
920
920
921 .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
921 .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
922 .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
922 .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
923 .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
923 .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
924 .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
924 .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
925
925
926 .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
926 .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
927 .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
927 .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
928 .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
928 .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
929 .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
929 .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
930
930
931 .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;}
931 .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;}
932 .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;}
932 .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;}
933
933
934 /***** Icons *****/
934 /***** Icons *****/
935 .icon {
935 .icon {
936 background-position: 0% 50%;
936 background-position: 0% 50%;
937 background-repeat: no-repeat;
937 background-repeat: no-repeat;
938 padding-left: 20px;
938 padding-left: 20px;
939 padding-top: 2px;
939 padding-top: 2px;
940 padding-bottom: 3px;
940 padding-bottom: 3px;
941 }
941 }
942
942
943 .icon-add { background-image: url(../images/add.png); }
943 .icon-add { background-image: url(../images/add.png); }
944 .icon-edit { background-image: url(../images/edit.png); }
944 .icon-edit { background-image: url(../images/edit.png); }
945 .icon-copy { background-image: url(../images/copy.png); }
945 .icon-copy { background-image: url(../images/copy.png); }
946 .icon-duplicate { background-image: url(../images/duplicate.png); }
946 .icon-duplicate { background-image: url(../images/duplicate.png); }
947 .icon-del { background-image: url(../images/delete.png); }
947 .icon-del { background-image: url(../images/delete.png); }
948 .icon-move { background-image: url(../images/move.png); }
948 .icon-move { background-image: url(../images/move.png); }
949 .icon-save { background-image: url(../images/save.png); }
949 .icon-save { background-image: url(../images/save.png); }
950 .icon-cancel { background-image: url(../images/cancel.png); }
950 .icon-cancel { background-image: url(../images/cancel.png); }
951 .icon-multiple { background-image: url(../images/table_multiple.png); }
951 .icon-multiple { background-image: url(../images/table_multiple.png); }
952 .icon-folder { background-image: url(../images/folder.png); }
952 .icon-folder { background-image: url(../images/folder.png); }
953 .open .icon-folder { background-image: url(../images/folder_open.png); }
953 .open .icon-folder { background-image: url(../images/folder_open.png); }
954 .icon-package { background-image: url(../images/package.png); }
954 .icon-package { background-image: url(../images/package.png); }
955 .icon-user { background-image: url(../images/user.png); }
955 .icon-user { background-image: url(../images/user.png); }
956 .icon-projects { background-image: url(../images/projects.png); }
956 .icon-projects { background-image: url(../images/projects.png); }
957 .icon-help { background-image: url(../images/help.png); }
957 .icon-help { background-image: url(../images/help.png); }
958 .icon-attachment { background-image: url(../images/attachment.png); }
958 .icon-attachment { background-image: url(../images/attachment.png); }
959 .icon-history { background-image: url(../images/history.png); }
959 .icon-history { background-image: url(../images/history.png); }
960 .icon-time { background-image: url(../images/time.png); }
960 .icon-time { background-image: url(../images/time.png); }
961 .icon-time-add { background-image: url(../images/time_add.png); }
961 .icon-time-add { background-image: url(../images/time_add.png); }
962 .icon-stats { background-image: url(../images/stats.png); }
962 .icon-stats { background-image: url(../images/stats.png); }
963 .icon-warning { background-image: url(../images/warning.png); }
963 .icon-warning { background-image: url(../images/warning.png); }
964 .icon-fav { background-image: url(../images/fav.png); }
964 .icon-fav { background-image: url(../images/fav.png); }
965 .icon-fav-off { background-image: url(../images/fav_off.png); }
965 .icon-fav-off { background-image: url(../images/fav_off.png); }
966 .icon-reload { background-image: url(../images/reload.png); }
966 .icon-reload { background-image: url(../images/reload.png); }
967 .icon-lock { background-image: url(../images/locked.png); }
967 .icon-lock { background-image: url(../images/locked.png); }
968 .icon-unlock { background-image: url(../images/unlock.png); }
968 .icon-unlock { background-image: url(../images/unlock.png); }
969 .icon-checked { background-image: url(../images/true.png); }
969 .icon-checked { background-image: url(../images/true.png); }
970 .icon-details { background-image: url(../images/zoom_in.png); }
970 .icon-details { background-image: url(../images/zoom_in.png); }
971 .icon-report { background-image: url(../images/report.png); }
971 .icon-report { background-image: url(../images/report.png); }
972 .icon-comment { background-image: url(../images/comment.png); }
972 .icon-comment { background-image: url(../images/comment.png); }
973 .icon-summary { background-image: url(../images/lightning.png); }
973 .icon-summary { background-image: url(../images/lightning.png); }
974 .icon-server-authentication { background-image: url(../images/server_key.png); }
974 .icon-server-authentication { background-image: url(../images/server_key.png); }
975 .icon-issue { background-image: url(../images/ticket.png); }
975 .icon-issue { background-image: url(../images/ticket.png); }
976 .icon-zoom-in { background-image: url(../images/zoom_in.png); }
976 .icon-zoom-in { background-image: url(../images/zoom_in.png); }
977 .icon-zoom-out { background-image: url(../images/zoom_out.png); }
977 .icon-zoom-out { background-image: url(../images/zoom_out.png); }
978 .icon-passwd { background-image: url(../images/textfield_key.png); }
978 .icon-passwd { background-image: url(../images/textfield_key.png); }
979 .icon-test { background-image: url(../images/bullet_go.png); }
979 .icon-test { background-image: url(../images/bullet_go.png); }
980
980
981 .icon-file { background-image: url(../images/files/default.png); }
981 .icon-file { background-image: url(../images/files/default.png); }
982 .icon-file.text-plain { background-image: url(../images/files/text.png); }
982 .icon-file.text-plain { background-image: url(../images/files/text.png); }
983 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
983 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
984 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
984 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
985 .icon-file.text-x-java { background-image: url(../images/files/java.png); }
985 .icon-file.text-x-java { background-image: url(../images/files/java.png); }
986 .icon-file.text-x-javascript { background-image: url(../images/files/js.png); }
986 .icon-file.text-x-javascript { background-image: url(../images/files/js.png); }
987 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
987 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
988 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
988 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
989 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
989 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
990 .icon-file.text-css { background-image: url(../images/files/css.png); }
990 .icon-file.text-css { background-image: url(../images/files/css.png); }
991 .icon-file.text-html { background-image: url(../images/files/html.png); }
991 .icon-file.text-html { background-image: url(../images/files/html.png); }
992 .icon-file.image-gif { background-image: url(../images/files/image.png); }
992 .icon-file.image-gif { background-image: url(../images/files/image.png); }
993 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
993 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
994 .icon-file.image-png { background-image: url(../images/files/image.png); }
994 .icon-file.image-png { background-image: url(../images/files/image.png); }
995 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
995 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
996 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
996 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
997 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
997 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
998 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
998 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
999
999
1000 img.gravatar {
1000 img.gravatar {
1001 padding: 2px;
1001 padding: 2px;
1002 border: solid 1px #d5d5d5;
1002 border: solid 1px #d5d5d5;
1003 background: #fff;
1003 background: #fff;
1004 vertical-align: middle;
1004 vertical-align: middle;
1005 }
1005 }
1006
1006
1007 div.issue img.gravatar {
1007 div.issue img.gravatar {
1008 float: left;
1008 float: left;
1009 margin: 0 6px 0 0;
1009 margin: 0 6px 0 0;
1010 padding: 5px;
1010 padding: 5px;
1011 }
1011 }
1012
1012
1013 div.issue table img.gravatar {
1013 div.issue table img.gravatar {
1014 height: 14px;
1014 height: 14px;
1015 width: 14px;
1015 width: 14px;
1016 padding: 2px;
1016 padding: 2px;
1017 float: left;
1017 float: left;
1018 margin: 0 0.5em 0 0;
1018 margin: 0 0.5em 0 0;
1019 }
1019 }
1020
1020
1021 h2 img.gravatar {margin: -2px 4px -4px 0;}
1021 h2 img.gravatar {margin: -2px 4px -4px 0;}
1022 h3 img.gravatar {margin: -4px 4px -4px 0;}
1022 h3 img.gravatar {margin: -4px 4px -4px 0;}
1023 h4 img.gravatar {margin: -6px 4px -4px 0;}
1023 h4 img.gravatar {margin: -6px 4px -4px 0;}
1024 td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;}
1024 td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;}
1025 #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;}
1025 #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;}
1026 /* Used on 12px Gravatar img tags without the icon background */
1026 /* Used on 12px Gravatar img tags without the icon background */
1027 .icon-gravatar {float: left; margin-right: 4px;}
1027 .icon-gravatar {float: left; margin-right: 4px;}
1028
1028
1029 #activity dt, .journal {clear: left;}
1029 #activity dt, .journal {clear: left;}
1030
1030
1031 .journal-link {float: right;}
1031 .journal-link {float: right;}
1032
1032
1033 h2 img { vertical-align:middle; }
1033 h2 img { vertical-align:middle; }
1034
1034
1035 .hascontextmenu { cursor: context-menu; }
1035 .hascontextmenu { cursor: context-menu; }
1036
1036
1037 /************* CodeRay styles *************/
1037 /************* CodeRay styles *************/
1038 .syntaxhl div {display: inline;}
1038 .syntaxhl div {display: inline;}
1039 .syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;}
1039 .syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;}
1040 .syntaxhl .code pre { overflow: auto }
1040 .syntaxhl .code pre { overflow: auto }
1041 .syntaxhl .debug { color: white !important; background: blue !important; }
1041 .syntaxhl .debug { color: white !important; background: blue !important; }
1042
1042
1043 .syntaxhl .annotation { color:#007 }
1043 .syntaxhl .annotation { color:#007 }
1044 .syntaxhl .attribute-name { color:#b48 }
1044 .syntaxhl .attribute-name { color:#b48 }
1045 .syntaxhl .attribute-value { color:#700 }
1045 .syntaxhl .attribute-value { color:#700 }
1046 .syntaxhl .binary { color:#509 }
1046 .syntaxhl .binary { color:#509 }
1047 .syntaxhl .char .content { color:#D20 }
1047 .syntaxhl .char .content { color:#D20 }
1048 .syntaxhl .char .delimiter { color:#710 }
1048 .syntaxhl .char .delimiter { color:#710 }
1049 .syntaxhl .char { color:#D20 }
1049 .syntaxhl .char { color:#D20 }
1050 .syntaxhl .class { color:#258; font-weight:bold }
1050 .syntaxhl .class { color:#258; font-weight:bold }
1051 .syntaxhl .class-variable { color:#369 }
1051 .syntaxhl .class-variable { color:#369 }
1052 .syntaxhl .color { color:#0A0 }
1052 .syntaxhl .color { color:#0A0 }
1053 .syntaxhl .comment { color:#385 }
1053 .syntaxhl .comment { color:#385 }
1054 .syntaxhl .comment .char { color:#385 }
1054 .syntaxhl .comment .char { color:#385 }
1055 .syntaxhl .comment .delimiter { color:#385 }
1055 .syntaxhl .comment .delimiter { color:#385 }
1056 .syntaxhl .complex { color:#A08 }
1056 .syntaxhl .complex { color:#A08 }
1057 .syntaxhl .constant { color:#258; font-weight:bold }
1057 .syntaxhl .constant { color:#258; font-weight:bold }
1058 .syntaxhl .decorator { color:#B0B }
1058 .syntaxhl .decorator { color:#B0B }
1059 .syntaxhl .definition { color:#099; font-weight:bold }
1059 .syntaxhl .definition { color:#099; font-weight:bold }
1060 .syntaxhl .delimiter { color:black }
1060 .syntaxhl .delimiter { color:black }
1061 .syntaxhl .directive { color:#088; font-weight:bold }
1061 .syntaxhl .directive { color:#088; font-weight:bold }
1062 .syntaxhl .doc { color:#970 }
1062 .syntaxhl .doc { color:#970 }
1063 .syntaxhl .doc-string { color:#D42; font-weight:bold }
1063 .syntaxhl .doc-string { color:#D42; font-weight:bold }
1064 .syntaxhl .doctype { color:#34b }
1064 .syntaxhl .doctype { color:#34b }
1065 .syntaxhl .entity { color:#800; font-weight:bold }
1065 .syntaxhl .entity { color:#800; font-weight:bold }
1066 .syntaxhl .error { color:#F00; background-color:#FAA }
1066 .syntaxhl .error { color:#F00; background-color:#FAA }
1067 .syntaxhl .escape { color:#666 }
1067 .syntaxhl .escape { color:#666 }
1068 .syntaxhl .exception { color:#C00; font-weight:bold }
1068 .syntaxhl .exception { color:#C00; font-weight:bold }
1069 .syntaxhl .float { color:#06D }
1069 .syntaxhl .float { color:#06D }
1070 .syntaxhl .function { color:#06B; font-weight:bold }
1070 .syntaxhl .function { color:#06B; font-weight:bold }
1071 .syntaxhl .global-variable { color:#d70 }
1071 .syntaxhl .global-variable { color:#d70 }
1072 .syntaxhl .hex { color:#02b }
1072 .syntaxhl .hex { color:#02b }
1073 .syntaxhl .imaginary { color:#f00 }
1073 .syntaxhl .imaginary { color:#f00 }
1074 .syntaxhl .include { color:#B44; font-weight:bold }
1074 .syntaxhl .include { color:#B44; font-weight:bold }
1075 .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
1075 .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
1076 .syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
1076 .syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
1077 .syntaxhl .instance-variable { color:#33B }
1077 .syntaxhl .instance-variable { color:#33B }
1078 .syntaxhl .integer { color:#06D }
1078 .syntaxhl .integer { color:#06D }
1079 .syntaxhl .key .char { color: #60f }
1079 .syntaxhl .key .char { color: #60f }
1080 .syntaxhl .key .delimiter { color: #404 }
1080 .syntaxhl .key .delimiter { color: #404 }
1081 .syntaxhl .key { color: #606 }
1081 .syntaxhl .key { color: #606 }
1082 .syntaxhl .keyword { color:#939; font-weight:bold }
1082 .syntaxhl .keyword { color:#939; font-weight:bold }
1083 .syntaxhl .label { color:#970; font-weight:bold }
1083 .syntaxhl .label { color:#970; font-weight:bold }
1084 .syntaxhl .local-variable { color:#963 }
1084 .syntaxhl .local-variable { color:#963 }
1085 .syntaxhl .namespace { color:#707; font-weight:bold }
1085 .syntaxhl .namespace { color:#707; font-weight:bold }
1086 .syntaxhl .octal { color:#40E }
1086 .syntaxhl .octal { color:#40E }
1087 .syntaxhl .operator { }
1087 .syntaxhl .operator { }
1088 .syntaxhl .predefined { color:#369; font-weight:bold }
1088 .syntaxhl .predefined { color:#369; font-weight:bold }
1089 .syntaxhl .predefined-constant { color:#069 }
1089 .syntaxhl .predefined-constant { color:#069 }
1090 .syntaxhl .predefined-type { color:#0a5; font-weight:bold }
1090 .syntaxhl .predefined-type { color:#0a5; font-weight:bold }
1091 .syntaxhl .preprocessor { color:#579 }
1091 .syntaxhl .preprocessor { color:#579 }
1092 .syntaxhl .pseudo-class { color:#00C; font-weight:bold }
1092 .syntaxhl .pseudo-class { color:#00C; font-weight:bold }
1093 .syntaxhl .regexp .content { color:#808 }
1093 .syntaxhl .regexp .content { color:#808 }
1094 .syntaxhl .regexp .delimiter { color:#404 }
1094 .syntaxhl .regexp .delimiter { color:#404 }
1095 .syntaxhl .regexp .modifier { color:#C2C }
1095 .syntaxhl .regexp .modifier { color:#C2C }
1096 .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
1096 .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
1097 .syntaxhl .reserved { color:#080; font-weight:bold }
1097 .syntaxhl .reserved { color:#080; font-weight:bold }
1098 .syntaxhl .shell .content { color:#2B2 }
1098 .syntaxhl .shell .content { color:#2B2 }
1099 .syntaxhl .shell .delimiter { color:#161 }
1099 .syntaxhl .shell .delimiter { color:#161 }
1100 .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
1100 .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
1101 .syntaxhl .string .char { color: #46a }
1101 .syntaxhl .string .char { color: #46a }
1102 .syntaxhl .string .content { color: #46a }
1102 .syntaxhl .string .content { color: #46a }
1103 .syntaxhl .string .delimiter { color: #46a }
1103 .syntaxhl .string .delimiter { color: #46a }
1104 .syntaxhl .string .modifier { color: #46a }
1104 .syntaxhl .string .modifier { color: #46a }
1105 .syntaxhl .symbol .content { color:#d33 }
1105 .syntaxhl .symbol .content { color:#d33 }
1106 .syntaxhl .symbol .delimiter { color:#d33 }
1106 .syntaxhl .symbol .delimiter { color:#d33 }
1107 .syntaxhl .symbol { color:#d33 }
1107 .syntaxhl .symbol { color:#d33 }
1108 .syntaxhl .tag { color:#070 }
1108 .syntaxhl .tag { color:#070 }
1109 .syntaxhl .type { color:#339; font-weight:bold }
1109 .syntaxhl .type { color:#339; font-weight:bold }
1110 .syntaxhl .value { color: #088; }
1110 .syntaxhl .value { color: #088; }
1111 .syntaxhl .variable { color:#037 }
1111 .syntaxhl .variable { color:#037 }
1112
1112
1113 .syntaxhl .insert { background: hsla(120,100%,50%,0.12) }
1113 .syntaxhl .insert { background: hsla(120,100%,50%,0.12) }
1114 .syntaxhl .delete { background: hsla(0,100%,50%,0.12) }
1114 .syntaxhl .delete { background: hsla(0,100%,50%,0.12) }
1115 .syntaxhl .change { color: #bbf; background: #007; }
1115 .syntaxhl .change { color: #bbf; background: #007; }
1116 .syntaxhl .head { color: #f8f; background: #505 }
1116 .syntaxhl .head { color: #f8f; background: #505 }
1117 .syntaxhl .head .filename { color: white; }
1117 .syntaxhl .head .filename { color: white; }
1118
1118
1119 .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
1119 .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
1120 .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
1120 .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
1121
1121
1122 .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
1122 .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
1123 .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
1123 .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
1124 .syntaxhl .change .change { color: #88f }
1124 .syntaxhl .change .change { color: #88f }
1125 .syntaxhl .head .head { color: #f4f }
1125 .syntaxhl .head .head { color: #f4f }
1126
1126
1127 /***** Media print specific styles *****/
1127 /***** Media print specific styles *****/
1128 @media print {
1128 @media print {
1129 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
1129 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
1130 #main { background: #fff; }
1130 #main { background: #fff; }
1131 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
1131 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
1132 #wiki_add_attachment { display:none; }
1132 #wiki_add_attachment { display:none; }
1133 .hide-when-print { display: none; }
1133 .hide-when-print { display: none; }
1134 .autoscroll {overflow-x: visible;}
1134 .autoscroll {overflow-x: visible;}
1135 table.list {margin-top:0.5em;}
1135 table.list {margin-top:0.5em;}
1136 table.list th, table.list td {border: 1px solid #aaa;}
1136 table.list th, table.list td {border: 1px solid #aaa;}
1137 }
1137 }
1138
1138
1139 /* Accessibility specific styles */
1139 /* Accessibility specific styles */
1140 .hidden-for-sighted {
1140 .hidden-for-sighted {
1141 position:absolute;
1141 position:absolute;
1142 left:-10000px;
1142 left:-10000px;
1143 top:auto;
1143 top:auto;
1144 width:1px;
1144 width:1px;
1145 height:1px;
1145 height:1px;
1146 overflow:hidden;
1146 overflow:hidden;
1147 }
1147 }
@@ -1,205 +1,202
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class GroupsControllerTest < ActionController::TestCase
20 class GroupsControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles, :groups_users
21 fixtures :projects, :users, :members, :member_roles, :roles, :groups_users
22
22
23 def setup
23 def setup
24 @request.session[:user_id] = 1
24 @request.session[:user_id] = 1
25 end
25 end
26
26
27 def test_index
27 def test_index
28 get :index
28 get :index
29 assert_response :success
29 assert_response :success
30 assert_template 'index'
30 assert_template 'index'
31 end
31 end
32
32
33 def test_show
33 def test_show
34 get :show, :id => 10
34 get :show, :id => 10
35 assert_response :success
35 assert_response :success
36 assert_template 'show'
36 assert_template 'show'
37 end
37 end
38
38
39 def test_show_invalid_should_return_404
39 def test_show_invalid_should_return_404
40 get :show, :id => 99
40 get :show, :id => 99
41 assert_response 404
41 assert_response 404
42 end
42 end
43
43
44 def test_new
44 def test_new
45 get :new
45 get :new
46 assert_response :success
46 assert_response :success
47 assert_template 'new'
47 assert_template 'new'
48 assert_select 'input[name=?]', 'group[name]'
48 assert_select 'input[name=?]', 'group[name]'
49 end
49 end
50
50
51 def test_create
51 def test_create
52 assert_difference 'Group.count' do
52 assert_difference 'Group.count' do
53 post :create, :group => {:name => 'New group'}
53 post :create, :group => {:name => 'New group'}
54 end
54 end
55 assert_redirected_to '/groups'
55 assert_redirected_to '/groups'
56 group = Group.first(:order => 'id DESC')
56 group = Group.first(:order => 'id DESC')
57 assert_equal 'New group', group.name
57 assert_equal 'New group', group.name
58 assert_equal [], group.users
58 assert_equal [], group.users
59 end
59 end
60
60
61 def test_create_and_continue
61 def test_create_and_continue
62 assert_difference 'Group.count' do
62 assert_difference 'Group.count' do
63 post :create, :group => {:name => 'New group'}, :continue => 'Create and continue'
63 post :create, :group => {:name => 'New group'}, :continue => 'Create and continue'
64 end
64 end
65 assert_redirected_to '/groups/new'
65 assert_redirected_to '/groups/new'
66 group = Group.first(:order => 'id DESC')
66 group = Group.first(:order => 'id DESC')
67 assert_equal 'New group', group.name
67 assert_equal 'New group', group.name
68 end
68 end
69
69
70 def test_create_with_failure
70 def test_create_with_failure
71 assert_no_difference 'Group.count' do
71 assert_no_difference 'Group.count' do
72 post :create, :group => {:name => ''}
72 post :create, :group => {:name => ''}
73 end
73 end
74 assert_response :success
74 assert_response :success
75 assert_template 'new'
75 assert_template 'new'
76 end
76 end
77
77
78 def test_edit
78 def test_edit
79 get :edit, :id => 10
79 get :edit, :id => 10
80 assert_response :success
80 assert_response :success
81 assert_template 'edit'
81 assert_template 'edit'
82
82
83 assert_select 'div#tab-content-users'
83 assert_select 'div#tab-content-users'
84 assert_select 'div#tab-content-memberships' do
84 assert_select 'div#tab-content-memberships' do
85 assert_select 'a', :text => 'Private child of eCookbook'
85 assert_select 'a', :text => 'Private child of eCookbook'
86 end
86 end
87 end
87 end
88
88
89 def test_update
89 def test_update
90 new_name = 'New name'
90 new_name = 'New name'
91 put :update, :id => 10, :group => {:name => new_name}
91 put :update, :id => 10, :group => {:name => new_name}
92 assert_redirected_to '/groups'
92 assert_redirected_to '/groups'
93 group = Group.find(10)
93 group = Group.find(10)
94 assert_equal new_name, group.name
94 assert_equal new_name, group.name
95 end
95 end
96
96
97 def test_update_with_failure
97 def test_update_with_failure
98 put :update, :id => 10, :group => {:name => ''}
98 put :update, :id => 10, :group => {:name => ''}
99 assert_response :success
99 assert_response :success
100 assert_template 'edit'
100 assert_template 'edit'
101 end
101 end
102
102
103 def test_destroy
103 def test_destroy
104 assert_difference 'Group.count', -1 do
104 assert_difference 'Group.count', -1 do
105 post :destroy, :id => 10
105 post :destroy, :id => 10
106 end
106 end
107 assert_redirected_to '/groups'
107 assert_redirected_to '/groups'
108 end
108 end
109
109
110 def test_add_users
110 def test_add_users
111 assert_difference 'Group.find(10).users.count', 2 do
111 assert_difference 'Group.find(10).users.count', 2 do
112 post :add_users, :id => 10, :user_ids => ['2', '3']
112 post :add_users, :id => 10, :user_ids => ['2', '3']
113 end
113 end
114 end
114 end
115
115
116 def test_xhr_add_users
116 def test_xhr_add_users
117 assert_difference 'Group.find(10).users.count', 2 do
117 assert_difference 'Group.find(10).users.count', 2 do
118 xhr :post, :add_users, :id => 10, :user_ids => ['2', '3']
118 xhr :post, :add_users, :id => 10, :user_ids => ['2', '3']
119 assert_response :success
119 assert_response :success
120 assert_template 'add_users'
120 assert_template 'add_users'
121 assert_equal 'text/javascript', response.content_type
121 assert_equal 'text/javascript', response.content_type
122 end
122 end
123 assert_match /John Smith/, response.body
123 assert_match /John Smith/, response.body
124 end
124 end
125
125
126 def test_remove_user
126 def test_remove_user
127 assert_difference 'Group.find(10).users.count', -1 do
127 assert_difference 'Group.find(10).users.count', -1 do
128 delete :remove_user, :id => 10, :user_id => '8'
128 delete :remove_user, :id => 10, :user_id => '8'
129 end
129 end
130 end
130 end
131
131
132 def test_xhr_remove_user
132 def test_xhr_remove_user
133 assert_difference 'Group.find(10).users.count', -1 do
133 assert_difference 'Group.find(10).users.count', -1 do
134 xhr :delete, :remove_user, :id => 10, :user_id => '8'
134 xhr :delete, :remove_user, :id => 10, :user_id => '8'
135 assert_response :success
135 assert_response :success
136 assert_template 'remove_user'
136 assert_template 'remove_user'
137 assert_equal 'text/javascript', response.content_type
137 assert_equal 'text/javascript', response.content_type
138 end
138 end
139 end
139 end
140
140
141 def test_new_membership
141 def test_new_membership
142 assert_difference 'Group.find(10).members.count' do
142 assert_difference 'Group.find(10).members.count' do
143 post :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
143 post :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
144 end
144 end
145 end
145 end
146
146
147 def test_xhr_new_membership
147 def test_xhr_new_membership
148 assert_difference 'Group.find(10).members.count' do
148 assert_difference 'Group.find(10).members.count' do
149 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
149 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
150 assert_response :success
150 assert_response :success
151 assert_template 'edit_membership'
151 assert_template 'edit_membership'
152 assert_equal 'text/javascript', response.content_type
152 assert_equal 'text/javascript', response.content_type
153 end
153 end
154 assert_match /OnlineStore/, response.body
154 assert_match /OnlineStore/, response.body
155 end
155 end
156
156
157 def test_xhr_new_membership_with_failure
157 def test_xhr_new_membership_with_failure
158 assert_no_difference 'Group.find(10).members.count' do
158 assert_no_difference 'Group.find(10).members.count' do
159 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 999, :role_ids => ['1', '2']}
159 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 999, :role_ids => ['1', '2']}
160 assert_response :success
160 assert_response :success
161 assert_template 'edit_membership'
161 assert_template 'edit_membership'
162 assert_equal 'text/javascript', response.content_type
162 assert_equal 'text/javascript', response.content_type
163 end
163 end
164 assert_match /alert/, response.body, "Alert message not sent"
164 assert_match /alert/, response.body, "Alert message not sent"
165 end
165 end
166
166
167 def test_edit_membership
167 def test_edit_membership
168 assert_no_difference 'Group.find(10).members.count' do
168 assert_no_difference 'Group.find(10).members.count' do
169 post :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
169 post :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
170 end
170 end
171 end
171 end
172
172
173 def test_xhr_edit_membership
173 def test_xhr_edit_membership
174 assert_no_difference 'Group.find(10).members.count' do
174 assert_no_difference 'Group.find(10).members.count' do
175 xhr :post, :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
175 xhr :post, :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
176 assert_response :success
176 assert_response :success
177 assert_template 'edit_membership'
177 assert_template 'edit_membership'
178 assert_equal 'text/javascript', response.content_type
178 assert_equal 'text/javascript', response.content_type
179 end
179 end
180 end
180 end
181
181
182 def test_destroy_membership
182 def test_destroy_membership
183 assert_difference 'Group.find(10).members.count', -1 do
183 assert_difference 'Group.find(10).members.count', -1 do
184 post :destroy_membership, :id => 10, :membership_id => 6
184 post :destroy_membership, :id => 10, :membership_id => 6
185 end
185 end
186 end
186 end
187
187
188 def test_xhr_destroy_membership
188 def test_xhr_destroy_membership
189 assert_difference 'Group.find(10).members.count', -1 do
189 assert_difference 'Group.find(10).members.count', -1 do
190 xhr :post, :destroy_membership, :id => 10, :membership_id => 6
190 xhr :post, :destroy_membership, :id => 10, :membership_id => 6
191 assert_response :success
191 assert_response :success
192 assert_template 'destroy_membership'
192 assert_template 'destroy_membership'
193 assert_equal 'text/javascript', response.content_type
193 assert_equal 'text/javascript', response.content_type
194 end
194 end
195 end
195 end
196
196
197 def test_autocomplete_for_user
197 def test_autocomplete_for_user
198 get :autocomplete_for_user, :id => 10, :q => 'mis'
198 get :autocomplete_for_user, :id => 10, :q => 'smi', :format => 'js'
199 assert_response :success
199 assert_response :success
200 users = assigns(:users)
200 assert_include 'John Smith', response.body
201 assert_not_nil users
202 assert users.any?
203 assert !users.include?(Group.find(10).users.first)
204 end
201 end
205 end
202 end
@@ -1,114 +1,111
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class MembersControllerTest < ActionController::TestCase
20 class MembersControllerTest < ActionController::TestCase
21 fixtures :projects, :members, :member_roles, :roles, :users
21 fixtures :projects, :members, :member_roles, :roles, :users
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 2
25 @request.session[:user_id] = 2
26 end
26 end
27
27
28 def test_create
28 def test_create
29 assert_difference 'Member.count' do
29 assert_difference 'Member.count' do
30 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_id => 7}
30 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_id => 7}
31 end
31 end
32 assert_redirected_to '/projects/ecookbook/settings/members'
32 assert_redirected_to '/projects/ecookbook/settings/members'
33 assert User.find(7).member_of?(Project.find(1))
33 assert User.find(7).member_of?(Project.find(1))
34 end
34 end
35
35
36 def test_create_multiple
36 def test_create_multiple
37 assert_difference 'Member.count', 3 do
37 assert_difference 'Member.count', 3 do
38 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
38 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
39 end
39 end
40 assert_redirected_to '/projects/ecookbook/settings/members'
40 assert_redirected_to '/projects/ecookbook/settings/members'
41 assert User.find(7).member_of?(Project.find(1))
41 assert User.find(7).member_of?(Project.find(1))
42 end
42 end
43
43
44 def test_xhr_create
44 def test_xhr_create
45 assert_difference 'Member.count', 3 do
45 assert_difference 'Member.count', 3 do
46 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
46 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
47 assert_response :success
47 assert_response :success
48 assert_template 'create'
48 assert_template 'create'
49 assert_equal 'text/javascript', response.content_type
49 assert_equal 'text/javascript', response.content_type
50 end
50 end
51 assert User.find(7).member_of?(Project.find(1))
51 assert User.find(7).member_of?(Project.find(1))
52 assert User.find(8).member_of?(Project.find(1))
52 assert User.find(8).member_of?(Project.find(1))
53 assert User.find(9).member_of?(Project.find(1))
53 assert User.find(9).member_of?(Project.find(1))
54 assert_include 'tab-content-members', response.body
54 assert_include 'tab-content-members', response.body
55 end
55 end
56
56
57 def test_xhr_create_with_failure
57 def test_xhr_create_with_failure
58 assert_no_difference 'Member.count' do
58 assert_no_difference 'Member.count' do
59 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [], :user_ids => [7, 8, 9]}
59 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [], :user_ids => [7, 8, 9]}
60 assert_response :success
60 assert_response :success
61 assert_template 'create'
61 assert_template 'create'
62 assert_equal 'text/javascript', response.content_type
62 assert_equal 'text/javascript', response.content_type
63 end
63 end
64 assert_match /alert/, response.body, "Alert message not sent"
64 assert_match /alert/, response.body, "Alert message not sent"
65 end
65 end
66
66
67 def test_edit
67 def test_edit
68 assert_no_difference 'Member.count' do
68 assert_no_difference 'Member.count' do
69 put :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
69 put :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
70 end
70 end
71 assert_redirected_to '/projects/ecookbook/settings/members'
71 assert_redirected_to '/projects/ecookbook/settings/members'
72 end
72 end
73
73
74 def test_xhr_edit
74 def test_xhr_edit
75 assert_no_difference 'Member.count' do
75 assert_no_difference 'Member.count' do
76 xhr :put, :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
76 xhr :put, :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
77 assert_response :success
77 assert_response :success
78 assert_template 'update'
78 assert_template 'update'
79 assert_equal 'text/javascript', response.content_type
79 assert_equal 'text/javascript', response.content_type
80 end
80 end
81 member = Member.find(2)
81 member = Member.find(2)
82 assert_equal [1], member.role_ids
82 assert_equal [1], member.role_ids
83 assert_equal 3, member.user_id
83 assert_equal 3, member.user_id
84 assert_include 'tab-content-members', response.body
84 assert_include 'tab-content-members', response.body
85 end
85 end
86
86
87 def test_destroy
87 def test_destroy
88 assert_difference 'Member.count', -1 do
88 assert_difference 'Member.count', -1 do
89 delete :destroy, :id => 2
89 delete :destroy, :id => 2
90 end
90 end
91 assert_redirected_to '/projects/ecookbook/settings/members'
91 assert_redirected_to '/projects/ecookbook/settings/members'
92 assert !User.find(3).member_of?(Project.find(1))
92 assert !User.find(3).member_of?(Project.find(1))
93 end
93 end
94
94
95 def test_xhr_destroy
95 def test_xhr_destroy
96 assert_difference 'Member.count', -1 do
96 assert_difference 'Member.count', -1 do
97 xhr :delete, :destroy, :id => 2
97 xhr :delete, :destroy, :id => 2
98 assert_response :success
98 assert_response :success
99 assert_template 'destroy'
99 assert_template 'destroy'
100 assert_equal 'text/javascript', response.content_type
100 assert_equal 'text/javascript', response.content_type
101 end
101 end
102 assert_nil Member.find_by_id(2)
102 assert_nil Member.find_by_id(2)
103 assert_include 'tab-content-members', response.body
103 assert_include 'tab-content-members', response.body
104 end
104 end
105
105
106 def test_autocomplete
106 def test_autocomplete
107 get :autocomplete, :project_id => 1, :q => 'mis'
107 get :autocomplete, :project_id => 1, :q => 'mis', :format => 'js'
108 assert_response :success
108 assert_response :success
109 assert_template 'autocomplete'
109 assert_include 'User Misc', response.body
110
111 assert_tag :label, :content => /User Misc/,
112 :child => { :tag => 'input', :attributes => { :name => 'membership[user_ids][]', :value => '8' } }
113 end
110 end
114 end
111 end
@@ -1,102 +1,106
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingGroupsTest < ActionController::IntegrationTest
20 class RoutingGroupsTest < ActionController::IntegrationTest
21 def test_groups_resources
21 def test_groups_resources
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/groups" },
23 { :method => 'get', :path => "/groups" },
24 { :controller => 'groups', :action => 'index' }
24 { :controller => 'groups', :action => 'index' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'get', :path => "/groups.xml" },
27 { :method => 'get', :path => "/groups.xml" },
28 { :controller => 'groups', :action => 'index', :format => 'xml' }
28 { :controller => 'groups', :action => 'index', :format => 'xml' }
29 )
29 )
30 assert_routing(
30 assert_routing(
31 { :method => 'post', :path => "/groups" },
31 { :method => 'post', :path => "/groups" },
32 { :controller => 'groups', :action => 'create' }
32 { :controller => 'groups', :action => 'create' }
33 )
33 )
34 assert_routing(
34 assert_routing(
35 { :method => 'post', :path => "/groups.xml" },
35 { :method => 'post', :path => "/groups.xml" },
36 { :controller => 'groups', :action => 'create', :format => 'xml' }
36 { :controller => 'groups', :action => 'create', :format => 'xml' }
37 )
37 )
38 assert_routing(
38 assert_routing(
39 { :method => 'get', :path => "/groups/new" },
39 { :method => 'get', :path => "/groups/new" },
40 { :controller => 'groups', :action => 'new' }
40 { :controller => 'groups', :action => 'new' }
41 )
41 )
42 assert_routing(
42 assert_routing(
43 { :method => 'get', :path => "/groups/1/edit" },
43 { :method => 'get', :path => "/groups/1/edit" },
44 { :controller => 'groups', :action => 'edit', :id => '1' }
44 { :controller => 'groups', :action => 'edit', :id => '1' }
45 )
45 )
46 assert_routing(
46 assert_routing(
47 { :method => 'get', :path => "/groups/1/autocomplete_for_user" },
47 { :method => 'get', :path => "/groups/1/autocomplete_for_user" },
48 { :controller => 'groups', :action => 'autocomplete_for_user', :id => '1' }
48 { :controller => 'groups', :action => 'autocomplete_for_user', :id => '1' }
49 )
49 )
50 assert_routing(
50 assert_routing(
51 { :method => 'get', :path => "/groups/1/autocomplete_for_user.js" },
52 { :controller => 'groups', :action => 'autocomplete_for_user', :id => '1', :format => 'js' }
53 )
54 assert_routing(
51 { :method => 'get', :path => "/groups/1" },
55 { :method => 'get', :path => "/groups/1" },
52 { :controller => 'groups', :action => 'show', :id => '1' }
56 { :controller => 'groups', :action => 'show', :id => '1' }
53 )
57 )
54 assert_routing(
58 assert_routing(
55 { :method => 'get', :path => "/groups/1.xml" },
59 { :method => 'get', :path => "/groups/1.xml" },
56 { :controller => 'groups', :action => 'show', :id => '1', :format => 'xml' }
60 { :controller => 'groups', :action => 'show', :id => '1', :format => 'xml' }
57 )
61 )
58 assert_routing(
62 assert_routing(
59 { :method => 'put', :path => "/groups/1" },
63 { :method => 'put', :path => "/groups/1" },
60 { :controller => 'groups', :action => 'update', :id => '1' }
64 { :controller => 'groups', :action => 'update', :id => '1' }
61 )
65 )
62 assert_routing(
66 assert_routing(
63 { :method => 'put', :path => "/groups/1.xml" },
67 { :method => 'put', :path => "/groups/1.xml" },
64 { :controller => 'groups', :action => 'update', :id => '1', :format => 'xml' }
68 { :controller => 'groups', :action => 'update', :id => '1', :format => 'xml' }
65 )
69 )
66 assert_routing(
70 assert_routing(
67 { :method => 'delete', :path => "/groups/1" },
71 { :method => 'delete', :path => "/groups/1" },
68 { :controller => 'groups', :action => 'destroy', :id => '1' }
72 { :controller => 'groups', :action => 'destroy', :id => '1' }
69 )
73 )
70 assert_routing(
74 assert_routing(
71 { :method => 'delete', :path => "/groups/1.xml" },
75 { :method => 'delete', :path => "/groups/1.xml" },
72 { :controller => 'groups', :action => 'destroy', :id => '1', :format => 'xml' }
76 { :controller => 'groups', :action => 'destroy', :id => '1', :format => 'xml' }
73 )
77 )
74 end
78 end
75
79
76 def test_groups
80 def test_groups
77 assert_routing(
81 assert_routing(
78 { :method => 'post', :path => "/groups/567/users" },
82 { :method => 'post', :path => "/groups/567/users" },
79 { :controller => 'groups', :action => 'add_users', :id => '567' }
83 { :controller => 'groups', :action => 'add_users', :id => '567' }
80 )
84 )
81 assert_routing(
85 assert_routing(
82 { :method => 'post', :path => "/groups/567/users.xml" },
86 { :method => 'post', :path => "/groups/567/users.xml" },
83 { :controller => 'groups', :action => 'add_users', :id => '567', :format => 'xml' }
87 { :controller => 'groups', :action => 'add_users', :id => '567', :format => 'xml' }
84 )
88 )
85 assert_routing(
89 assert_routing(
86 { :method => 'delete', :path => "/groups/567/users/12" },
90 { :method => 'delete', :path => "/groups/567/users/12" },
87 { :controller => 'groups', :action => 'remove_user', :id => '567', :user_id => '12' }
91 { :controller => 'groups', :action => 'remove_user', :id => '567', :user_id => '12' }
88 )
92 )
89 assert_routing(
93 assert_routing(
90 { :method => 'delete', :path => "/groups/567/users/12.xml" },
94 { :method => 'delete', :path => "/groups/567/users/12.xml" },
91 { :controller => 'groups', :action => 'remove_user', :id => '567', :user_id => '12', :format => 'xml' }
95 { :controller => 'groups', :action => 'remove_user', :id => '567', :user_id => '12', :format => 'xml' }
92 )
96 )
93 assert_routing(
97 assert_routing(
94 { :method => 'post', :path => "/groups/destroy_membership/567" },
98 { :method => 'post', :path => "/groups/destroy_membership/567" },
95 { :controller => 'groups', :action => 'destroy_membership', :id => '567' }
99 { :controller => 'groups', :action => 'destroy_membership', :id => '567' }
96 )
100 )
97 assert_routing(
101 assert_routing(
98 { :method => 'post', :path => "/groups/edit_membership/567" },
102 { :method => 'post', :path => "/groups/edit_membership/567" },
99 { :controller => 'groups', :action => 'edit_membership', :id => '567' }
103 { :controller => 'groups', :action => 'edit_membership', :id => '567' }
100 )
104 )
101 end
105 end
102 end
106 end
@@ -1,59 +1,63
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingMembersTest < ActionController::IntegrationTest
20 class RoutingMembersTest < ActionController::IntegrationTest
21 def test_members
21 def test_members
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/5234/memberships.xml" },
23 { :method => 'get', :path => "/projects/5234/memberships.xml" },
24 { :controller => 'members', :action => 'index', :project_id => '5234', :format => 'xml' }
24 { :controller => 'members', :action => 'index', :project_id => '5234', :format => 'xml' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'get', :path => "/memberships/5234.xml" },
27 { :method => 'get', :path => "/memberships/5234.xml" },
28 { :controller => 'members', :action => 'show', :id => '5234', :format => 'xml' }
28 { :controller => 'members', :action => 'show', :id => '5234', :format => 'xml' }
29 )
29 )
30 assert_routing(
30 assert_routing(
31 { :method => 'post', :path => "/projects/5234/memberships" },
31 { :method => 'post', :path => "/projects/5234/memberships" },
32 { :controller => 'members', :action => 'create', :project_id => '5234' }
32 { :controller => 'members', :action => 'create', :project_id => '5234' }
33 )
33 )
34 assert_routing(
34 assert_routing(
35 { :method => 'post', :path => "/projects/5234/memberships.xml" },
35 { :method => 'post', :path => "/projects/5234/memberships.xml" },
36 { :controller => 'members', :action => 'create', :project_id => '5234', :format => 'xml' }
36 { :controller => 'members', :action => 'create', :project_id => '5234', :format => 'xml' }
37 )
37 )
38 assert_routing(
38 assert_routing(
39 { :method => 'put', :path => "/memberships/5234" },
39 { :method => 'put', :path => "/memberships/5234" },
40 { :controller => 'members', :action => 'update', :id => '5234' }
40 { :controller => 'members', :action => 'update', :id => '5234' }
41 )
41 )
42 assert_routing(
42 assert_routing(
43 { :method => 'put', :path => "/memberships/5234.xml" },
43 { :method => 'put', :path => "/memberships/5234.xml" },
44 { :controller => 'members', :action => 'update', :id => '5234', :format => 'xml' }
44 { :controller => 'members', :action => 'update', :id => '5234', :format => 'xml' }
45 )
45 )
46 assert_routing(
46 assert_routing(
47 { :method => 'delete', :path => "/memberships/5234" },
47 { :method => 'delete', :path => "/memberships/5234" },
48 { :controller => 'members', :action => 'destroy', :id => '5234' }
48 { :controller => 'members', :action => 'destroy', :id => '5234' }
49 )
49 )
50 assert_routing(
50 assert_routing(
51 { :method => 'delete', :path => "/memberships/5234.xml" },
51 { :method => 'delete', :path => "/memberships/5234.xml" },
52 { :controller => 'members', :action => 'destroy', :id => '5234', :format => 'xml' }
52 { :controller => 'members', :action => 'destroy', :id => '5234', :format => 'xml' }
53 )
53 )
54 assert_routing(
54 assert_routing(
55 { :method => 'get', :path => "/projects/5234/memberships/autocomplete" },
55 { :method => 'get', :path => "/projects/5234/memberships/autocomplete" },
56 { :controller => 'members', :action => 'autocomplete', :project_id => '5234' }
56 { :controller => 'members', :action => 'autocomplete', :project_id => '5234' }
57 )
57 )
58 assert_routing(
59 { :method => 'get', :path => "/projects/5234/memberships/autocomplete.js" },
60 { :controller => 'members', :action => 'autocomplete', :project_id => '5234', :format => 'js' }
61 )
58 end
62 end
59 end
63 end
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now