@@ -1,94 +1,100 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | class MembersController < ApplicationController |
|
19 | 19 | model_object Member |
|
20 | 20 | before_filter :find_model_object, :except => [:new, :autocomplete_for_member] |
|
21 | 21 | before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member] |
|
22 | 22 | before_filter :find_project, :only => [:new, :autocomplete_for_member] |
|
23 | 23 | before_filter :authorize |
|
24 | 24 | |
|
25 | 25 | def new |
|
26 | 26 | members = [] |
|
27 | 27 | if params[:member] && request.post? |
|
28 | 28 | attrs = params[:member].dup |
|
29 | 29 | if (user_ids = attrs.delete(:user_ids)) |
|
30 | 30 | user_ids.each do |user_id| |
|
31 | 31 | members << Member.new(attrs.merge(:user_id => user_id)) |
|
32 | 32 | end |
|
33 | 33 | else |
|
34 | 34 | members << Member.new(attrs) |
|
35 | 35 | end |
|
36 | 36 | @project.members << members |
|
37 | 37 | end |
|
38 | 38 | respond_to do |format| |
|
39 | 39 | if members.present? && members.all? {|m| m.valid? } |
|
40 | 40 | |
|
41 | 41 | format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
|
42 | 42 | |
|
43 | 43 | format.js { |
|
44 | 44 | render(:update) {|page| |
|
45 | 45 | page.replace_html "tab-content-members", :partial => 'projects/settings/members' |
|
46 | page << 'hideOnLoad()' | |
|
46 | 47 | members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } |
|
47 | 48 | } |
|
48 | 49 | } |
|
49 | 50 | else |
|
50 | 51 | |
|
51 | 52 | format.js { |
|
52 | 53 | render(:update) {|page| |
|
53 | 54 | errors = members.collect {|m| |
|
54 | 55 | m.errors.full_messages |
|
55 | 56 | }.flatten.uniq |
|
56 | 57 | |
|
57 | 58 | page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', '))) |
|
58 | 59 | } |
|
59 | 60 | } |
|
60 | 61 | |
|
61 | 62 | end |
|
62 | 63 | end |
|
63 | 64 | end |
|
64 | 65 | |
|
65 | 66 | def edit |
|
66 | 67 | if request.post? and @member.update_attributes(params[:member]) |
|
67 | 68 | respond_to do |format| |
|
68 | 69 | format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
|
69 | 70 | format.js { |
|
70 | 71 | render(:update) {|page| |
|
71 | 72 | page.replace_html "tab-content-members", :partial => 'projects/settings/members' |
|
73 | page << 'hideOnLoad()' | |
|
72 | 74 | page.visual_effect(:highlight, "member-#{@member.id}") |
|
73 | 75 | } |
|
74 | 76 | } |
|
75 | 77 | end |
|
76 | 78 | end |
|
77 | 79 | end |
|
78 | 80 | |
|
79 | 81 | def destroy |
|
80 | 82 | if request.post? && @member.deletable? |
|
81 | 83 | @member.destroy |
|
82 | 84 | end |
|
83 | 85 | respond_to do |format| |
|
84 | 86 | format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
|
85 | format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} } | |
|
87 | format.js { render(:update) {|page| | |
|
88 | page.replace_html "tab-content-members", :partial => 'projects/settings/members' | |
|
89 | page << 'hideOnLoad()' | |
|
90 | } | |
|
91 | } | |
|
86 | 92 | end |
|
87 | 93 | end |
|
88 | 94 | |
|
89 | 95 | def autocomplete_for_member |
|
90 | 96 | @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals |
|
91 | 97 | render :layout => false |
|
92 | 98 | end |
|
93 | 99 | |
|
94 | 100 | end |
@@ -1,233 +1,235 | |||
|
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 showAndScrollTo(id, focus) { |
|
21 | 21 | Element.show(id); |
|
22 | 22 | if (focus!=null) { Form.Element.focus(focus); } |
|
23 | 23 | Element.scrollTo(id); |
|
24 | 24 | } |
|
25 | 25 | |
|
26 | 26 | function toggleRowGroup(el) { |
|
27 | 27 | var tr = Element.up(el, 'tr'); |
|
28 | 28 | var n = Element.next(tr); |
|
29 | 29 | tr.toggleClassName('open'); |
|
30 | 30 | while (n != undefined && !n.hasClassName('group')) { |
|
31 | 31 | Element.toggle(n); |
|
32 | 32 | n = Element.next(n); |
|
33 | 33 | } |
|
34 | 34 | } |
|
35 | 35 | |
|
36 | 36 | function toggleFieldset(el) { |
|
37 | 37 | var fieldset = Element.up(el, 'fieldset'); |
|
38 | 38 | fieldset.toggleClassName('collapsed'); |
|
39 | 39 | Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2}); |
|
40 | 40 | } |
|
41 | 41 | |
|
42 | 42 | var fileFieldCount = 1; |
|
43 | 43 | |
|
44 | 44 | function addFileField() { |
|
45 | 45 | if (fileFieldCount >= 10) return false |
|
46 | 46 | fileFieldCount++; |
|
47 | 47 | var f = document.createElement("input"); |
|
48 | 48 | f.type = "file"; |
|
49 | 49 | f.name = "attachments[" + fileFieldCount + "][file]"; |
|
50 | 50 | f.size = 30; |
|
51 | 51 | var d = document.createElement("input"); |
|
52 | 52 | d.type = "text"; |
|
53 | 53 | d.name = "attachments[" + fileFieldCount + "][description]"; |
|
54 | 54 | d.size = 60; |
|
55 | 55 | var dLabel = document.createElement("label"); |
|
56 | 56 | dLabel.addClassName('inline'); |
|
57 | 57 | // Pulls the languge value used for Optional Description |
|
58 | 58 | dLabel.update($('attachment_description_label_content').innerHTML) |
|
59 | 59 | |
|
60 | 60 | p = document.getElementById("attachments_fields"); |
|
61 | 61 | p.appendChild(document.createElement("br")); |
|
62 | 62 | p.appendChild(f); |
|
63 | 63 | p.appendChild(dLabel); |
|
64 | 64 | dLabel.appendChild(d); |
|
65 | 65 | |
|
66 | 66 | } |
|
67 | 67 | |
|
68 | 68 | function showTab(name) { |
|
69 | 69 | var f = $$('div#content .tab-content'); |
|
70 | 70 | for(var i=0; i<f.length; i++){ |
|
71 | 71 | Element.hide(f[i]); |
|
72 | 72 | } |
|
73 | 73 | var f = $$('div.tabs a'); |
|
74 | 74 | for(var i=0; i<f.length; i++){ |
|
75 | 75 | Element.removeClassName(f[i], "selected"); |
|
76 | 76 | } |
|
77 | 77 | Element.show('tab-content-' + name); |
|
78 | 78 | Element.addClassName('tab-' + name, "selected"); |
|
79 | 79 | return false; |
|
80 | 80 | } |
|
81 | 81 | |
|
82 | 82 | function moveTabRight(el) { |
|
83 | 83 | var lis = Element.up(el, 'div.tabs').down('ul').childElements(); |
|
84 | 84 | var tabsWidth = 0; |
|
85 | 85 | var i; |
|
86 | 86 | for (i=0; i<lis.length; i++) { |
|
87 | 87 | if (lis[i].visible()) { |
|
88 | 88 | tabsWidth += lis[i].getWidth() + 6; |
|
89 | 89 | } |
|
90 | 90 | } |
|
91 | 91 | if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) { |
|
92 | 92 | return; |
|
93 | 93 | } |
|
94 | 94 | i=0; |
|
95 | 95 | while (i<lis.length && !lis[i].visible()) { |
|
96 | 96 | i++; |
|
97 | 97 | } |
|
98 | 98 | lis[i].hide(); |
|
99 | 99 | } |
|
100 | 100 | |
|
101 | 101 | function moveTabLeft(el) { |
|
102 | 102 | var lis = Element.up(el, 'div.tabs').down('ul').childElements(); |
|
103 | 103 | var i = 0; |
|
104 | 104 | while (i<lis.length && !lis[i].visible()) { |
|
105 | 105 | i++; |
|
106 | 106 | } |
|
107 | 107 | if (i>0) { |
|
108 | 108 | lis[i-1].show(); |
|
109 | 109 | } |
|
110 | 110 | } |
|
111 | 111 | |
|
112 | 112 | function displayTabsButtons() { |
|
113 | 113 | var lis; |
|
114 | 114 | var tabsWidth = 0; |
|
115 | 115 | var i; |
|
116 | 116 | $$('div.tabs').each(function(el) { |
|
117 | 117 | lis = el.down('ul').childElements(); |
|
118 | 118 | for (i=0; i<lis.length; i++) { |
|
119 | 119 | if (lis[i].visible()) { |
|
120 | 120 | tabsWidth += lis[i].getWidth() + 6; |
|
121 | 121 | } |
|
122 | 122 | } |
|
123 | 123 | if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) { |
|
124 | 124 | el.down('div.tabs-buttons').hide(); |
|
125 | 125 | } else { |
|
126 | 126 | el.down('div.tabs-buttons').show(); |
|
127 | 127 | } |
|
128 | 128 | }); |
|
129 | 129 | } |
|
130 | 130 | |
|
131 | 131 | function setPredecessorFieldsVisibility() { |
|
132 | 132 | relationType = $('relation_relation_type'); |
|
133 | 133 | if (relationType && (relationType.value == "precedes" || relationType.value == "follows")) { |
|
134 | 134 | Element.show('predecessor_fields'); |
|
135 | 135 | } else { |
|
136 | 136 | Element.hide('predecessor_fields'); |
|
137 | 137 | } |
|
138 | 138 | } |
|
139 | 139 | |
|
140 | 140 | function promptToRemote(text, param, url) { |
|
141 | 141 | value = prompt(text + ':'); |
|
142 | 142 | if (value) { |
|
143 | 143 | new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true}); |
|
144 | 144 | return false; |
|
145 | 145 | } |
|
146 | 146 | } |
|
147 | 147 | |
|
148 | 148 | function collapseScmEntry(id) { |
|
149 | 149 | var els = document.getElementsByClassName(id, 'browser'); |
|
150 | 150 | for (var i = 0; i < els.length; i++) { |
|
151 | 151 | if (els[i].hasClassName('open')) { |
|
152 | 152 | collapseScmEntry(els[i].id); |
|
153 | 153 | } |
|
154 | 154 | Element.hide(els[i]); |
|
155 | 155 | } |
|
156 | 156 | $(id).removeClassName('open'); |
|
157 | 157 | } |
|
158 | 158 | |
|
159 | 159 | function expandScmEntry(id) { |
|
160 | 160 | var els = document.getElementsByClassName(id, 'browser'); |
|
161 | 161 | for (var i = 0; i < els.length; i++) { |
|
162 | 162 | Element.show(els[i]); |
|
163 | 163 | if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) { |
|
164 | 164 | expandScmEntry(els[i].id); |
|
165 | 165 | } |
|
166 | 166 | } |
|
167 | 167 | $(id).addClassName('open'); |
|
168 | 168 | } |
|
169 | 169 | |
|
170 | 170 | function scmEntryClick(id) { |
|
171 | 171 | el = $(id); |
|
172 | 172 | if (el.hasClassName('open')) { |
|
173 | 173 | collapseScmEntry(id); |
|
174 | 174 | el.addClassName('collapsed'); |
|
175 | 175 | return false; |
|
176 | 176 | } else if (el.hasClassName('loaded')) { |
|
177 | 177 | expandScmEntry(id); |
|
178 | 178 | el.removeClassName('collapsed'); |
|
179 | 179 | return false; |
|
180 | 180 | } |
|
181 | 181 | if (el.hasClassName('loading')) { |
|
182 | 182 | return false; |
|
183 | 183 | } |
|
184 | 184 | el.addClassName('loading'); |
|
185 | 185 | return true; |
|
186 | 186 | } |
|
187 | 187 | |
|
188 | 188 | function scmEntryLoaded(id) { |
|
189 | 189 | Element.addClassName(id, 'open'); |
|
190 | 190 | Element.addClassName(id, 'loaded'); |
|
191 | 191 | Element.removeClassName(id, 'loading'); |
|
192 | 192 | } |
|
193 | 193 | |
|
194 | 194 | function randomKey(size) { |
|
195 | 195 | 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'); |
|
196 | 196 | var key = ''; |
|
197 | 197 | for (i = 0; i < size; i++) { |
|
198 | 198 | key += chars[Math.floor(Math.random() * chars.length)]; |
|
199 | 199 | } |
|
200 | 200 | return key; |
|
201 | 201 | } |
|
202 | 202 | |
|
203 | 203 | function observeParentIssueField(url) { |
|
204 | 204 | new Ajax.Autocompleter('issue_parent_issue_id', |
|
205 | 205 | 'parent_issue_candidates', |
|
206 | 206 | url, |
|
207 | 207 | { minChars: 3, |
|
208 | 208 | frequency: 0.5, |
|
209 | 209 | paramName: 'q', |
|
210 | 210 | updateElement: function(value) { |
|
211 | 211 | document.getElementById('issue_parent_issue_id').value = value.id; |
|
212 | 212 | }}); |
|
213 | 213 | } |
|
214 | 214 | |
|
215 | 215 | /* shows and hides ajax indicator */ |
|
216 | 216 | Ajax.Responders.register({ |
|
217 | 217 | onCreate: function(){ |
|
218 | 218 | if ($('ajax-indicator') && Ajax.activeRequestCount > 0) { |
|
219 | 219 | Element.show('ajax-indicator'); |
|
220 | 220 | } |
|
221 | 221 | }, |
|
222 | 222 | onComplete: function(){ |
|
223 | 223 | if ($('ajax-indicator') && Ajax.activeRequestCount == 0) { |
|
224 | 224 | Element.hide('ajax-indicator'); |
|
225 | 225 | } |
|
226 | 226 | } |
|
227 | 227 | }); |
|
228 | 228 | |
|
229 | Event.observe(window, 'load', function() { | |
|
229 | function hideOnLoad() { | |
|
230 | 230 | $$('.hol').each(function(el) { |
|
231 | 231 | el.hide(); |
|
232 | 232 | }); |
|
233 | }); | |
|
233 | } | |
|
234 | ||
|
235 | Event.observe(window, 'load', hideOnLoad); |
General Comments 0
You need to be logged in to leave comments.
Login now