##// END OF EJS Templates
Merged r8130 from trunk....
Jean-Philippe Lang -
r8041:ff02412e7518
parent child
Show More
@@ -1,258 +1,258
1 1 ActionController::Routing::Routes.draw do |map|
2 2 # Add your own custom routes here.
3 3 # The priority is based upon order of creation: first created -> highest priority.
4 4
5 5 # Here's a sample route:
6 6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 7 # Keep in mind you can assign values other than :controller and :action
8 8
9 9 map.home '', :controller => 'welcome'
10 10
11 11 map.signin 'login', :controller => 'account', :action => 'login'
12 12 map.signout 'logout', :controller => 'account', :action => 'logout'
13 13
14 14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
15 15 map.connect 'help/:ctrl/:page', :controller => 'help'
16 16
17 17 map.with_options :controller => 'time_entry_reports', :action => 'report',:conditions => {:method => :get} do |time_report|
18 18 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report'
19 19 time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report.:format'
20 20 time_report.connect 'projects/:project_id/time_entries/report'
21 21 time_report.connect 'projects/:project_id/time_entries/report.:format'
22 22 time_report.connect 'time_entries/report'
23 23 time_report.connect 'time_entries/report.:format'
24 24 end
25 25
26 26 map.bulk_edit_time_entry 'time_entries/bulk_edit',
27 27 :controller => 'timelog', :action => 'bulk_edit', :conditions => { :method => :get }
28 28 map.bulk_update_time_entry 'time_entries/bulk_edit',
29 29 :controller => 'timelog', :action => 'bulk_update', :conditions => { :method => :post }
30 30 map.time_entries_context_menu '/time_entries/context_menu',
31 31 :controller => 'context_menus', :action => 'time_entries'
32 32 # TODO: wasteful since this is also nested under issues, projects, and projects/issues
33 33 map.resources :time_entries, :controller => 'timelog'
34 34
35 35 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
36 36 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
37 37 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
38 38
39 39 map.with_options :controller => 'messages' do |messages_routes|
40 40 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
41 41 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
42 42 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
43 43 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
44 44 end
45 45 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
46 46 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
47 47 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
48 48 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
49 49 end
50 50 end
51 51
52 52 map.with_options :controller => 'boards' do |board_routes|
53 53 board_routes.with_options :conditions => {:method => :get} do |board_views|
54 54 board_views.connect 'projects/:project_id/boards', :action => 'index'
55 55 board_views.connect 'projects/:project_id/boards/new', :action => 'new'
56 56 board_views.connect 'projects/:project_id/boards/:id', :action => 'show'
57 57 board_views.connect 'projects/:project_id/boards/:id.:format', :action => 'show'
58 58 board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'
59 59 end
60 60 board_routes.with_options :conditions => {:method => :post} do |board_actions|
61 61 board_actions.connect 'projects/:project_id/boards', :action => 'new'
62 62 board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/
63 63 end
64 64 end
65 65
66 66 map.with_options :controller => 'documents' do |document_routes|
67 67 document_routes.with_options :conditions => {:method => :get} do |document_views|
68 68 document_views.connect 'projects/:project_id/documents', :action => 'index'
69 69 document_views.connect 'projects/:project_id/documents/new', :action => 'new'
70 70 document_views.connect 'documents/:id', :action => 'show'
71 71 document_views.connect 'documents/:id/edit', :action => 'edit'
72 72 end
73 73 document_routes.with_options :conditions => {:method => :post} do |document_actions|
74 74 document_actions.connect 'projects/:project_id/documents', :action => 'new'
75 75 document_actions.connect 'documents/:id/:action', :action => /destroy|edit/
76 76 end
77 77 end
78 78
79 79 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
80 80 map.resources :queries, :except => [:show]
81 81
82 82 # Misc issue routes. TODO: move into resources
83 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues'
83 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get }
84 84 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
85 85 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
86 86 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
87 87 map.bulk_edit_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_edit', :conditions => { :method => :get }
88 88 map.bulk_update_issue 'issues/bulk_edit', :controller => 'issues', :action => 'bulk_update', :conditions => { :method => :post }
89 89 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
90 90 map.connect '/issues/:id/destroy', :controller => 'issues', :action => 'destroy', :conditions => { :method => :post } # legacy
91 91
92 92 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
93 93 gantts_routes.connect '/projects/:project_id/issues/gantt'
94 94 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
95 95 gantts_routes.connect '/issues/gantt.:format'
96 96 end
97 97
98 98 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
99 99 calendars_routes.connect '/projects/:project_id/issues/calendar'
100 100 calendars_routes.connect '/issues/calendar'
101 101 end
102 102
103 103 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
104 104 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
105 105 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
106 106 end
107 107
108 108 # Following two routes conflict with the resources because #index allows POST
109 109 map.connect '/issues', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
110 110 map.connect '/issues/create', :controller => 'issues', :action => 'index', :conditions => { :method => :post }
111 111
112 112 map.resources :issues, :member => { :edit => :post }, :collection => {} do |issues|
113 113 issues.resources :time_entries, :controller => 'timelog'
114 114 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
115 115 end
116 116
117 117 map.resources :issues, :path_prefix => '/projects/:project_id', :collection => { :create => :post } do |issues|
118 118 issues.resources :time_entries, :controller => 'timelog'
119 119 end
120 120
121 121 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
122 122
123 123 map.with_options :controller => 'users' do |users|
124 124 users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get}
125 125
126 126 users.with_options :conditions => {:method => :post} do |user_actions|
127 127 user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
128 128 user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
129 129 user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
130 130 end
131 131 end
132 132
133 133 map.resources :users, :member => {
134 134 :edit_membership => :post,
135 135 :destroy_membership => :post
136 136 }
137 137
138 138 # For nice "roadmap" in the url for the index action
139 139 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
140 140
141 141 map.all_news 'news', :controller => 'news', :action => 'index'
142 142 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
143 143 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
144 144 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
145 145 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
146 146
147 147 map.resources :projects, :member => {
148 148 :copy => [:get, :post],
149 149 :settings => :get,
150 150 :modules => :post,
151 151 :archive => :post,
152 152 :unarchive => :post
153 153 } do |project|
154 154 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
155 155 project.resources :files, :only => [:index, :new, :create]
156 156 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
157 157 project.resources :news, :shallow => true
158 158 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id'
159 159 project.resources :queries, :only => [:new, :create]
160 160 project.resources :issue_categories, :shallow => true
161 161
162 162 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
163 163 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
164 164 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
165 165 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
166 166 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
167 167 project.resources :wiki, :except => [:new, :create], :member => {
168 168 :rename => [:get, :post],
169 169 :history => :get,
170 170 :preview => :any,
171 171 :protect => :post,
172 172 :add_attachment => :post
173 173 }, :collection => {
174 174 :export => :get,
175 175 :date_index => :get
176 176 }
177 177
178 178 end
179 179
180 180 # Destroy uses a get request to prompt the user before the actual DELETE request
181 181 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
182 182
183 183 # TODO: port to be part of the resources route(s)
184 184 map.with_options :controller => 'projects' do |project_mapper|
185 185 project_mapper.with_options :conditions => {:method => :get} do |project_views|
186 186 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
187 187 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
188 188 end
189 189 end
190 190
191 191 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
192 192 activity.connect 'projects/:id/activity'
193 193 activity.connect 'projects/:id/activity.:format'
194 194 activity.connect 'activity', :id => nil
195 195 activity.connect 'activity.:format', :id => nil
196 196 end
197 197
198 198 map.with_options :controller => 'repositories' do |repositories|
199 199 repositories.with_options :conditions => {:method => :get} do |repository_views|
200 200 repository_views.connect 'projects/:id/repository', :action => 'show'
201 201 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
202 202 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
203 203 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
204 204 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
205 205 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
206 206 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
207 207 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
208 208 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
209 209 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
210 210 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
211 211 # TODO: why the following route is required?
212 212 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
213 213 repository_views.connect 'projects/:id/repository/:action/*path'
214 214 end
215 215
216 216 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
217 217 end
218 218
219 219 map.resources :attachments, :only => [:show, :destroy]
220 220 # additional routes for having the file name at the end of url
221 221 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
222 222 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
223 223
224 224 map.resources :groups, :member => {:autocomplete_for_user => :get}
225 225 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
226 226 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
227 227
228 228 map.resources :trackers, :except => :show
229 229 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
230 230
231 231 #left old routes at the bottom for backwards compat
232 232 map.connect 'projects/:project_id/issues/:action', :controller => 'issues'
233 233 map.connect 'projects/:project_id/documents/:action', :controller => 'documents'
234 234 map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'
235 235 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
236 236 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
237 237 map.connect 'projects/:project_id/news/:action', :controller => 'news'
238 238 map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/
239 239 map.with_options :controller => 'repositories' do |omap|
240 240 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
241 241 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
242 242 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
243 243 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
244 244 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
245 245 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
246 246 end
247 247
248 248 map.with_options :controller => 'sys' do |sys|
249 249 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
250 250 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
251 251 end
252 252
253 253 # Install the default route as the lowest priority.
254 254 map.connect ':controller/:action/:id'
255 255 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
256 256 # Used for OpenID
257 257 map.root :controller => 'account', :action => 'login'
258 258 end
@@ -1,415 +1,417
1 1 /* redMine - project management software
2 2 Copyright (C) 2006-2008 Jean-Philippe Lang */
3 3
4 4 function checkAll (id, checked) {
5 5 var els = Element.descendants(id);
6 6 for (var i = 0; i < els.length; i++) {
7 7 if (els[i].disabled==false) {
8 8 els[i].checked = checked;
9 9 }
10 10 }
11 11 }
12 12
13 13 function toggleCheckboxesBySelector(selector) {
14 14 boxes = $$(selector);
15 15 var all_checked = true;
16 16 for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }
17 17 for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; }
18 18 }
19 19
20 20 function setCheckboxesBySelector(checked, selector) {
21 21 var boxes = $$(selector);
22 22 boxes.each(function(ele) {
23 23 ele.checked = checked;
24 24 });
25 25 }
26 26
27 27 function showAndScrollTo(id, focus) {
28 28 Element.show(id);
29 29 if (focus!=null) { Form.Element.focus(focus); }
30 30 Element.scrollTo(id);
31 31 }
32 32
33 33 function toggleRowGroup(el) {
34 34 var tr = Element.up(el, 'tr');
35 35 var n = Element.next(tr);
36 36 tr.toggleClassName('open');
37 37 while (n != undefined && !n.hasClassName('group')) {
38 38 Element.toggle(n);
39 39 n = Element.next(n);
40 40 }
41 41 }
42 42
43 43 function collapseAllRowGroups(el) {
44 44 var tbody = Element.up(el, 'tbody');
45 45 tbody.childElements('tr').each(function(tr) {
46 46 if (tr.hasClassName('group')) {
47 47 tr.removeClassName('open');
48 48 } else {
49 49 tr.hide();
50 50 }
51 51 })
52 52 }
53 53
54 54 function expandAllRowGroups(el) {
55 55 var tbody = Element.up(el, 'tbody');
56 56 tbody.childElements('tr').each(function(tr) {
57 57 if (tr.hasClassName('group')) {
58 58 tr.addClassName('open');
59 59 } else {
60 60 tr.show();
61 61 }
62 62 })
63 63 }
64 64
65 65 function toggleAllRowGroups(el) {
66 66 var tr = Element.up(el, 'tr');
67 67 if (tr.hasClassName('open')) {
68 68 collapseAllRowGroups(el);
69 69 } else {
70 70 expandAllRowGroups(el);
71 71 }
72 72 }
73 73
74 74 function toggleFieldset(el) {
75 75 var fieldset = Element.up(el, 'fieldset');
76 76 fieldset.toggleClassName('collapsed');
77 77 Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2});
78 78 }
79 79
80 80 function hideFieldset(el) {
81 81 var fieldset = Element.up(el, 'fieldset');
82 82 fieldset.toggleClassName('collapsed');
83 83 fieldset.down('div').hide();
84 84 }
85 85
86 86 var fileFieldCount = 1;
87 87
88 88 function addFileField() {
89 89 var fields = $('attachments_fields');
90 90 if (fields.childElements().length >= 10) return false;
91 91 fileFieldCount++;
92 92 var s = document.createElement("span");
93 93 s.update(fields.down('span').innerHTML);
94 94 s.down('input.file').name = "attachments[" + fileFieldCount + "][file]";
95 95 s.down('input.description').name = "attachments[" + fileFieldCount + "][description]";
96 96 fields.appendChild(s);
97 97 }
98 98
99 99 function removeFileField(el) {
100 100 var fields = $('attachments_fields');
101 101 var s = Element.up(el, 'span');
102 102 if (fields.childElements().length > 1) {
103 103 s.remove();
104 104 } else {
105 105 s.update(s.innerHTML);
106 106 }
107 107 }
108 108
109 109 function checkFileSize(el, maxSize, message) {
110 110 var files = el.files;
111 111 if (files) {
112 112 for (var i=0; i<files.length; i++) {
113 113 if (files[i].size > maxSize) {
114 114 alert(message);
115 115 el.value = "";
116 116 }
117 117 }
118 118 }
119 119 }
120 120
121 121 function showTab(name) {
122 122 var f = $$('div#content .tab-content');
123 123 for(var i=0; i<f.length; i++){
124 124 Element.hide(f[i]);
125 125 }
126 126 var f = $$('div.tabs a');
127 127 for(var i=0; i<f.length; i++){
128 128 Element.removeClassName(f[i], "selected");
129 129 }
130 130 Element.show('tab-content-' + name);
131 131 Element.addClassName('tab-' + name, "selected");
132 132 return false;
133 133 }
134 134
135 135 function moveTabRight(el) {
136 136 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
137 137 var tabsWidth = 0;
138 138 var i;
139 139 for (i=0; i<lis.length; i++) {
140 140 if (lis[i].visible()) {
141 141 tabsWidth += lis[i].getWidth() + 6;
142 142 }
143 143 }
144 144 if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) {
145 145 return;
146 146 }
147 147 i=0;
148 148 while (i<lis.length && !lis[i].visible()) {
149 149 i++;
150 150 }
151 151 lis[i].hide();
152 152 }
153 153
154 154 function moveTabLeft(el) {
155 155 var lis = Element.up(el, 'div.tabs').down('ul').childElements();
156 156 var i = 0;
157 157 while (i<lis.length && !lis[i].visible()) {
158 158 i++;
159 159 }
160 160 if (i>0) {
161 161 lis[i-1].show();
162 162 }
163 163 }
164 164
165 165 function displayTabsButtons() {
166 166 var lis;
167 167 var tabsWidth = 0;
168 168 var i;
169 169 $$('div.tabs').each(function(el) {
170 170 lis = el.down('ul').childElements();
171 171 for (i=0; i<lis.length; i++) {
172 172 if (lis[i].visible()) {
173 173 tabsWidth += lis[i].getWidth() + 6;
174 174 }
175 175 }
176 176 if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) {
177 177 el.down('div.tabs-buttons').hide();
178 178 } else {
179 179 el.down('div.tabs-buttons').show();
180 180 }
181 181 });
182 182 }
183 183
184 184 function setPredecessorFieldsVisibility() {
185 185 relationType = $('relation_relation_type');
186 186 if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) {
187 187 Element.show('predecessor_fields');
188 188 } else {
189 189 Element.hide('predecessor_fields');
190 190 }
191 191 }
192 192
193 193 function promptToRemote(text, param, url) {
194 194 value = prompt(text + ':');
195 195 if (value) {
196 196 new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true});
197 197 return false;
198 198 }
199 199 }
200 200
201 201 function showModal(id, width) {
202 202 el = $(id);
203 203 if (el == undefined || el.visible()) {return;}
204 204 var h = $$('body')[0].getHeight();
205 205 var d = document.createElement("div");
206 206 d.id = 'modalbg';
207 207 $('main').appendChild(d);
208 208 $('modalbg').setStyle({ width: '100%', height: h + 'px' });
209 209 $('modalbg').show();
210 210
211 211 var pageWidth = document.viewport.getWidth();
212 212 el.setStyle({'width': width});
213 213 el.setStyle({'left': (((pageWidth - el.getWidth())/2 *100) / pageWidth) + '%'});
214 214 el.addClassName('modal');
215 215 el.show();
216 216
217 217 var submit = el.down("input[type=submit]");
218 218 if (submit) {
219 219 submit.focus();
220 220 }
221 221 }
222 222
223 223 function hideModal(el) {
224 224 var modal = Element.up(el, 'div.modal');
225 225 if (modal) {
226 226 modal.hide();
227 227 }
228 228 var bg = $('modalbg');
229 229 if (bg) {
230 230 bg.remove();
231 231 }
232 232 }
233 233
234 234 function collapseScmEntry(id) {
235 235 var els = document.getElementsByClassName(id, 'browser');
236 236 for (var i = 0; i < els.length; i++) {
237 237 if (els[i].hasClassName('open')) {
238 238 collapseScmEntry(els[i].id);
239 239 }
240 240 Element.hide(els[i]);
241 241 }
242 242 $(id).removeClassName('open');
243 243 }
244 244
245 245 function expandScmEntry(id) {
246 246 var els = document.getElementsByClassName(id, 'browser');
247 247 for (var i = 0; i < els.length; i++) {
248 248 Element.show(els[i]);
249 249 if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) {
250 250 expandScmEntry(els[i].id);
251 251 }
252 252 }
253 253 $(id).addClassName('open');
254 254 }
255 255
256 256 function scmEntryClick(id) {
257 257 el = $(id);
258 258 if (el.hasClassName('open')) {
259 259 collapseScmEntry(id);
260 260 el.addClassName('collapsed');
261 261 return false;
262 262 } else if (el.hasClassName('loaded')) {
263 263 expandScmEntry(id);
264 264 el.removeClassName('collapsed');
265 265 return false;
266 266 }
267 267 if (el.hasClassName('loading')) {
268 268 return false;
269 269 }
270 270 el.addClassName('loading');
271 271 return true;
272 272 }
273 273
274 274 function scmEntryLoaded(id) {
275 275 Element.addClassName(id, 'open');
276 276 Element.addClassName(id, 'loaded');
277 277 Element.removeClassName(id, 'loading');
278 278 }
279 279
280 280 function randomKey(size) {
281 281 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');
282 282 var key = '';
283 283 for (i = 0; i < size; i++) {
284 284 key += chars[Math.floor(Math.random() * chars.length)];
285 285 }
286 286 return key;
287 287 }
288 288
289 289 function observeParentIssueField(url) {
290 290 new Ajax.Autocompleter('issue_parent_issue_id',
291 291 'parent_issue_candidates',
292 292 url,
293 293 { minChars: 3,
294 294 frequency: 0.5,
295 295 paramName: 'q',
296 method: 'get',
296 297 updateElement: function(value) {
297 298 document.getElementById('issue_parent_issue_id').value = value.id;
298 299 }});
299 300 }
300 301
301 302 function observeRelatedIssueField(url) {
302 303 new Ajax.Autocompleter('relation_issue_to_id',
303 304 'related_issue_candidates',
304 305 url,
305 306 { minChars: 3,
306 307 frequency: 0.5,
307 308 paramName: 'q',
309 method: 'get',
308 310 updateElement: function(value) {
309 311 document.getElementById('relation_issue_to_id').value = value.id;
310 312 },
311 313 parameters: 'scope=all'
312 314 });
313 315 }
314 316
315 317 function setVisible(id, visible) {
316 318 var el = $(id);
317 319 if (el) {if (visible) {el.show();} else {el.hide();}}
318 320 }
319 321
320 322 function observeProjectModules() {
321 323 var f = function() {
322 324 /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
323 325 var c = ($('project_enabled_module_names_issue_tracking').checked == true);
324 326 setVisible('project_trackers', c);
325 327 setVisible('project_issue_custom_fields', c);
326 328 };
327 329
328 330 Event.observe(window, 'load', f);
329 331 Event.observe('project_enabled_module_names_issue_tracking', 'change', f);
330 332 }
331 333
332 334 /*
333 335 * Class used to warn user when leaving a page with unsaved textarea
334 336 * Author: mathias.fischer@berlinonline.de
335 337 */
336 338
337 339 var WarnLeavingUnsaved = Class.create({
338 340 observedForms: false,
339 341 observedElements: false,
340 342 changedForms: false,
341 343 message: null,
342 344
343 345 initialize: function(message){
344 346 this.observedForms = $$('form');
345 347 this.observedElements = $$('textarea');
346 348 this.message = message;
347 349
348 350 this.observedElements.each(this.observeChange.bind(this));
349 351 this.observedForms.each(this.submitAction.bind(this));
350 352
351 353 window.onbeforeunload = this.unload.bind(this);
352 354 },
353 355
354 356 unload: function(){
355 357 this.observedElements.each(function(el) {el.blur();})
356 358 if(this.changedForms)
357 359 return this.message;
358 360 },
359 361
360 362 setChanged: function(){
361 363 this.changedForms = true;
362 364 },
363 365
364 366 setUnchanged: function(){
365 367 this.changedForms = false;
366 368 },
367 369
368 370 observeChange: function(element){
369 371 element.observe('change',this.setChanged.bindAsEventListener(this));
370 372 },
371 373
372 374 submitAction: function(element){
373 375 element.observe('submit',this.setUnchanged.bindAsEventListener(this));
374 376 }
375 377 });
376 378
377 379 /*
378 380 * 1 - registers a callback which copies the csrf token into the
379 381 * X-CSRF-Token header with each ajax request. Necessary to
380 382 * work with rails applications which have fixed
381 383 * CVE-2011-0447
382 384 * 2 - shows and hides ajax indicator
383 385 */
384 386 Ajax.Responders.register({
385 387 onCreate: function(request){
386 388 var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
387 389
388 390 if (csrf_meta_tag) {
389 391 var header = 'X-CSRF-Token',
390 392 token = csrf_meta_tag.readAttribute('content');
391 393
392 394 if (!request.options.requestHeaders) {
393 395 request.options.requestHeaders = {};
394 396 }
395 397 request.options.requestHeaders[header] = token;
396 398 }
397 399
398 400 if ($('ajax-indicator') && Ajax.activeRequestCount > 0) {
399 401 Element.show('ajax-indicator');
400 402 }
401 403 },
402 404 onComplete: function(){
403 405 if ($('ajax-indicator') && Ajax.activeRequestCount == 0) {
404 406 Element.hide('ajax-indicator');
405 407 }
406 408 }
407 409 });
408 410
409 411 function hideOnLoad() {
410 412 $$('.hol').each(function(el) {
411 413 el.hide();
412 414 });
413 415 }
414 416
415 417 Event.observe(window, 'load', hideOnLoad);
General Comments 0
You need to be logged in to leave comments. Login now