##// END OF EJS Templates
fixes #76 added confirmation dialog for user removal....
marcink -
r739:554ed649 beta
parent child Browse files
Show More
@@ -1,105 +1,105 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # ldap authentication lib
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on Nov 17, 2010
22 22
23 23 @author: marcink
24 24 """
25 25
26 26 from rhodecode.lib.exceptions import *
27 27 import logging
28 28
29 29 log = logging.getLogger(__name__)
30 30
31 31 try:
32 32 import ldap
33 33 except ImportError:
34 34 pass
35 35
36 36 class AuthLdap(object):
37 37
38 38 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
39 39 use_ldaps=False, ldap_version=3):
40 40 self.ldap_version = ldap_version
41 41 if use_ldaps:
42 42 port = port or 689
43 43 self.LDAP_USE_LDAPS = use_ldaps
44 44 self.LDAP_SERVER_ADDRESS = server
45 45 self.LDAP_SERVER_PORT = port
46 46
47 47 #USE FOR READ ONLY BIND TO LDAP SERVER
48 48 self.LDAP_BIND_DN = bind_dn
49 49 self.LDAP_BIND_PASS = bind_pass
50 50
51 51 ldap_server_type = 'ldap'
52 52 if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
53 53 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
54 54 self.LDAP_SERVER_ADDRESS,
55 55 self.LDAP_SERVER_PORT)
56 56
57 57 self.BASE_DN = base_dn
58 58 self.AUTH_DN = "uid=%s,%s"
59 59
60 60 def authenticate_ldap(self, username, password):
61 61 """Authenticate a user via LDAP and return his/her LDAP properties.
62 62
63 63 Raises AuthenticationError if the credentials are rejected, or
64 64 EnvironmentError if the LDAP server can't be reached.
65 65
66 66 :param username: username
67 67 :param password: password
68 68 """
69 69
70 70 from rhodecode.lib.helpers import chop_at
71 71
72 72 uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
73 73 dn = self.AUTH_DN % (uid, self.BASE_DN)
74 74 log.debug("Authenticating %r at %s", dn, self.LDAP_SERVER)
75 75 if "," in username:
76 76 raise LdapUsernameError("invalid character in username: ,")
77 77 try:
78 ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, '/etc/openldap/cacerts')
78 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
79 79 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
80 80 server = ldap.initialize(self.LDAP_SERVER)
81 81 if self.ldap_version == 2:
82 82 server.protocol = ldap.VERSION2
83 83 else:
84 84 server.protocol = ldap.VERSION3
85 85
86 86 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
87 87 server.simple_bind_s(self.AUTH_DN % (self.LDAP_BIND_DN,
88 88 self.BASE_DN),
89 89 self.LDAP_BIND_PASS)
90 90
91 91 server.simple_bind_s(dn, password)
92 92 properties = server.search_s(dn, ldap.SCOPE_SUBTREE)
93 93 if not properties:
94 94 raise ldap.NO_SUCH_OBJECT()
95 95 except ldap.NO_SUCH_OBJECT, e:
96 96 log.debug("LDAP says no such user '%s' (%s)", uid, username)
97 97 raise LdapUsernameError()
98 98 except ldap.INVALID_CREDENTIALS, e:
99 99 log.debug("LDAP rejected password for user '%s' (%s)", uid, username)
100 100 raise LdapPasswordError()
101 101 except ldap.SERVER_DOWN, e:
102 102 raise LdapConnectionError("LDAP can't access authentication server")
103 103
104 104 return properties[0]
105 105
@@ -1,62 +1,63 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Users administration')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Users')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 <ul class="links">
22 22 <li>
23 23 <span>${h.link_to(u'ADD NEW USER',h.url('new_user'))}</span>
24 24 </li>
25 25
26 26 </ul>
27 27 </div>
28 28 <!-- end box / title -->
29 29 <div class="table">
30 30 <table class="table_disp">
31 31 <tr class="header">
32 32 <th></th>
33 33 <th class="left">${_('username')}</th>
34 34 <th class="left">${_('name')}</th>
35 35 <th class="left">${_('lastname')}</th>
36 36 <th class="left">${_('active')}</th>
37 37 <th class="left">${_('admin')}</th>
38 38 <th class="left">${_('ldap')}</th>
39 39 <th class="left">${_('action')}</th>
40 40 </tr>
41 41 %for cnt,user in enumerate(c.users_list):
42 42 %if user.name !='default':
43 43 <tr class="parity${cnt%2}">
44 44 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div></td>
45 45 <td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
46 46 <td>${user.name}</td>
47 47 <td>${user.lastname}</td>
48 48 <td>${h.bool2icon(user.active)}</td>
49 49 <td>${h.bool2icon(user.admin)}</td>
50 50 <td>${h.bool2icon(user.is_ldap)}</td>
51 51 <td>
52 52 ${h.form(url('user', id=user.user_id),method='delete')}
53 ${h.submit('remove','delete',id="remove_user_%s" % user.user_id,class_="delete_icon action_button")}
53 ${h.submit('remove_','delete',id="remove_user_%s" % user.user_id,
54 class_="delete_icon action_button",onclick="return confirm('Confirm to delete this user');")}
54 55 ${h.end_form()}
55 56 </td>
56 57 </tr>
57 58 %endif
58 59 %endfor
59 60 </table>
60 61 </div>
61 62 </div>
62 63 </%def>
@@ -1,606 +1,606 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('summary')}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('summary')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <script type="text/javascript">
21 21 var E = YAHOO.util.Event;
22 22 var D = YAHOO.util.Dom;
23 23
24 24 E.onDOMReady(function(e){
25 25 id = 'clone_url';
26 26 E.addListener(id,'click',function(e){
27 27 D.get('clone_url').select();
28 28 })
29 29 })
30 30 </script>
31 31 <div class="box box-left">
32 32 <!-- box / title -->
33 33 <div class="title">
34 34 ${self.breadcrumbs()}
35 35 </div>
36 36 <!-- end box / title -->
37 37 <div class="form">
38 38 <div class="fields">
39 39
40 40 <div class="field">
41 41 <div class="label">
42 42 <label>${_('Name')}:</label>
43 43 </div>
44 44 <div class="input-short">
45 45 %if c.repo_info.dbrepo.repo_type =='hg':
46 46 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
47 47 %endif
48 48 %if c.repo_info.dbrepo.repo_type =='git':
49 49 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
50 50 %endif
51 51
52 52 %if c.repo_info.dbrepo.private:
53 53 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
54 54 %else:
55 55 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
56 56 %endif
57 57 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
58 58
59 59 %if c.following:
60 60 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
61 61 onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
62 62 </span>
63 63 %else:
64 64 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
65 65 onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
66 66 </span>
67 67 %endif
68 68 <br/>
69 69 %if c.repo_info.dbrepo.fork:
70 70 <span style="margin-top:5px">
71 71 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
72 72 <img class="icon" alt="${_('public')}"
73 73 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
74 74 src="/images/icons/arrow_divide.png"/>
75 75 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
76 76 </a>
77 77 </span>
78 78 %endif
79 79 </div>
80 80 </div>
81 81
82 82
83 83 <div class="field">
84 84 <div class="label">
85 85 <label>${_('Description')}:</label>
86 86 </div>
87 87 <div class="input-short">
88 88 ${c.repo_info.dbrepo.description}
89 89 </div>
90 90 </div>
91 91
92 92
93 93 <div class="field">
94 94 <div class="label">
95 95 <label>${_('Contact')}:</label>
96 96 </div>
97 97 <div class="input-short">
98 98 <div class="gravatar">
99 99 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
100 100 </div>
101 101 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
102 102 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
103 103 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
104 104 </div>
105 105 </div>
106 106
107 107 <div class="field">
108 108 <div class="label">
109 109 <label>${_('Last change')}:</label>
110 110 </div>
111 111 <div class="input-short">
112 112 ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change}
113 113 ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author}
114 114
115 115 </div>
116 116 </div>
117 117
118 118 <div class="field">
119 119 <div class="label">
120 120 <label>${_('Clone url')}:</label>
121 121 </div>
122 122 <div class="input-short">
123 123 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
124 124 </div>
125 125 </div>
126 126
127 127 <div class="field">
128 128 <div class="label">
129 129 <label>${_('Trending languages')}:</label>
130 130 </div>
131 131 <div class="input-short">
132 132 <div id="lang_stats">
133 133
134 134 </div>
135 135 <script type="text/javascript">
136 136 var data = ${c.trending_languages|n};
137 137 var total = 0;
138 138 var no_data = true;
139 139 for (k in data){
140 140 total += data[k];
141 141 no_data = false;
142 142 }
143 143 var tbl = document.createElement('table');
144 144 tbl.setAttribute('class','trending_language_tbl');
145 145 for (k in data){
146 146 var tr = document.createElement('tr');
147 147 var percentage = Math.round((data[k]/total*100),2);
148 148 var value = data[k];
149 149 var td1 = document.createElement('td');
150 150 td1.width=150;
151 151 var trending_language_label = document.createElement('div');
152 152 trending_language_label.innerHTML = k;
153 153 td1.appendChild(trending_language_label);
154 154
155 155 var td2 = document.createElement('td');
156 156 td2.setAttribute('style','padding-right:14px !important');
157 157 var trending_language = document.createElement('div');
158 158 trending_language.title = k;
159 159 trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
160 160 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
161 161 trending_language.style.width=percentage+"%";
162 162 td2.appendChild(trending_language);
163 163
164 164 tr.appendChild(td1);
165 165 tr.appendChild(td2);
166 166 tbl.appendChild(tr);
167 167
168 168 }
169 169 if(no_data){
170 170 var tr = document.createElement('tr');
171 171 var td1 = document.createElement('td');
172 172 td1.innerHTML = "${_('No data loaded yet')}";
173 173 tr.appendChild(td1);
174 174 tbl.appendChild(tr);
175 175 }
176 176 YAHOO.util.Dom.get('lang_stats').appendChild(tbl);
177 177 </script>
178 178
179 179 </div>
180 180 </div>
181 181
182 182 <div class="field">
183 183 <div class="label">
184 184 <label>${_('Download')}:</label>
185 185 </div>
186 186 <div class="input-short">
187 187 %for cnt,archive in enumerate(c.repo_info._get_archives()):
188 188 %if cnt >=1:
189 189 |
190 190 %endif
191 191 ${h.link_to(c.repo_info.name+'.'+archive['type'],
192 192 h.url('files_archive_home',repo_name=c.repo_info.name,
193 193 revision='tip',fileformat=archive['extension']),class_="archive_icon")}
194 194 %endfor
195 195 </div>
196 196 </div>
197 197
198 198 <div class="field">
199 199 <div class="label">
200 200 <label>${_('Feeds')}:</label>
201 201 </div>
202 202 <div class="input-short">
203 203 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
204 204 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
205 205 </div>
206 206 </div>
207 207 </div>
208 208 </div>
209 209 </div>
210 210
211 211 <div class="box box-right" style="min-height:455px">
212 212 <!-- box / title -->
213 213 <div class="title">
214 214 <h5>${_('Commit activity by day / author')}</h5>
215 215 </div>
216 216
217 217 <div class="table">
218 218 <div id="commit_history" style="width:460px;height:300px;float:left"></div>
219 219 <div style="clear: both;height: 10px"></div>
220 220 <div id="overview" style="width:460px;height:100px;float:left"></div>
221 221
222 222 <div id="legend_data" style="clear:both;margin-top:10px;">
223 223 <div id="legend_container"></div>
224 224 <div id="legend_choices">
225 225 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
226 226 </div>
227 227 </div>
228 228 <script type="text/javascript">
229 229 /**
230 230 * Plots summary graph
231 231 *
232 232 * @class SummaryPlot
233 233 * @param {from} initial from for detailed graph
234 234 * @param {to} initial to for detailed graph
235 235 * @param {dataset}
236 236 * @param {overview_dataset}
237 237 */
238 238 function SummaryPlot(from,to,dataset,overview_dataset) {
239 239 var initial_ranges = {
240 240 "xaxis":{
241 241 "from":from,
242 242 "to":to,
243 243 },
244 244 };
245 245 var dataset = dataset;
246 246 var overview_dataset = [overview_dataset];
247 247 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
248 248 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
249 249 var plotContainer = YAHOO.util.Dom.get('commit_history');
250 250 var overviewContainer = YAHOO.util.Dom.get('overview');
251 251
252 252 var plot_options = {
253 253 bars: {show:true,align:'center',lineWidth:4},
254 254 legend: {show:true, container:"legend_container"},
255 255 points: {show:true,radius:0,fill:false},
256 256 yaxis: {tickDecimals:0,},
257 257 xaxis: {
258 258 mode: "time",
259 259 timeformat: "%d/%m",
260 260 min:from,
261 261 max:to,
262 262 },
263 263 grid: {
264 264 hoverable: true,
265 265 clickable: true,
266 266 autoHighlight:true,
267 267 color: "#999"
268 268 },
269 269 //selection: {mode: "x"}
270 270 };
271 271 var overview_options = {
272 272 legend:{show:false},
273 273 bars: {show:true,barWidth: 2,},
274 274 shadowSize: 0,
275 275 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
276 276 yaxis: {ticks: 3, min: 0,},
277 277 grid: {color: "#999",},
278 278 selection: {mode: "x"}
279 279 };
280 280
281 281 /**
282 282 *get dummy data needed in few places
283 283 */
284 284 function getDummyData(label){
285 285 return {"label":label,
286 286 "data":[{"time":0,
287 287 "commits":0,
288 288 "added":0,
289 289 "changed":0,
290 290 "removed":0,
291 291 }],
292 292 "schema":["commits"],
293 293 "color":'#ffffff',
294 294 }
295 295 }
296 296
297 297 /**
298 298 * generate checkboxes accordindly to data
299 299 * @param keys
300 300 * @returns
301 301 */
302 302 function generateCheckboxes(data) {
303 303 //append checkboxes
304 304 var i = 0;
305 305 choiceContainerTable.innerHTML = '';
306 306 for(var pos in data) {
307 307
308 308 data[pos].color = i;
309 309 i++;
310 310 if(data[pos].label != ''){
311 311 choiceContainerTable.innerHTML += '<tr><td>'+
312 312 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
313 313 +data[pos].label+
314 314 '</td></tr>';
315 315 }
316 316 }
317 317 }
318 318
319 319 /**
320 320 * ToolTip show
321 321 */
322 322 function showTooltip(x, y, contents) {
323 323 var div=document.getElementById('tooltip');
324 324 if(!div) {
325 325 div = document.createElement('div');
326 326 div.id="tooltip";
327 327 div.style.position="absolute";
328 328 div.style.border='1px solid #fdd';
329 329 div.style.padding='2px';
330 330 div.style.backgroundColor='#fee';
331 331 document.body.appendChild(div);
332 332 }
333 333 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
334 334 div.innerHTML = contents;
335 335 div.style.top=(y + 5) + "px";
336 336 div.style.left=(x + 5) + "px";
337 337
338 338 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
339 339 anim.animate();
340 340 }
341 341
342 342 /**
343 343 * This function will detect if selected period has some changesets
344 344 for this user if it does this data is then pushed for displaying
345 345 Additionally it will only display users that are selected by the checkbox
346 346 */
347 347 function getDataAccordingToRanges(ranges) {
348 348
349 349 var data = [];
350 350 var keys = [];
351 351 for(var key in dataset){
352 352 var push = false;
353 353
354 354 //method1 slow !!
355 355 //*
356 356 for(var ds in dataset[key].data){
357 357 commit_data = dataset[key].data[ds];
358 358 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
359 359 push = true;
360 360 break;
361 361 }
362 362 }
363 363 //*/
364 364
365 365 /*//method2 sorted commit data !!!
366 366
367 367 var first_commit = dataset[key].data[0].time;
368 368 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
369 369
370 370 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
371 371 push = true;
372 372 }
373 373 //*/
374 374
375 375 if(push){
376 376 data.push(dataset[key]);
377 377 }
378 378 }
379 379 if(data.length >= 1){
380 380 return data;
381 381 }
382 382 else{
383 383 //just return dummy data for graph to plot itself
384 384 return [getDummyData('')];
385 385 }
386 386
387 387 }
388 388
389 389 /**
390 390 * redraw using new checkbox data
391 391 */
392 392 function plotchoiced(e,args){
393 393 var cur_data = args[0];
394 394 var cur_ranges = args[1];
395 395
396 396 var new_data = [];
397 397 var inputs = choiceContainer.getElementsByTagName("input");
398 398
399 399 //show only checked labels
400 400 for(var i=0; i<inputs.length; i++) {
401 401 var checkbox_key = inputs[i].name;
402 402
403 403 if(inputs[i].checked){
404 404 for(var d in cur_data){
405 405 if(cur_data[d].label == checkbox_key){
406 406 new_data.push(cur_data[d]);
407 407 }
408 408 }
409 409 }
410 410 else{
411 411 //push dummy data to not hide the label
412 412 new_data.push(getDummyData(checkbox_key));
413 413 }
414 414 }
415 415
416 416 var new_options = YAHOO.lang.merge(plot_options, {
417 417 xaxis: {
418 418 min: cur_ranges.xaxis.from,
419 419 max: cur_ranges.xaxis.to,
420 420 mode:"time",
421 421 timeformat: "%d/%m",
422 422 },
423 423 });
424 424 if (!new_data){
425 425 new_data = [[0,1]];
426 426 }
427 427 // do the zooming
428 428 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
429 429
430 430 plot.subscribe("plotselected", plotselected);
431 431
432 432 //resubscribe plothover
433 433 plot.subscribe("plothover", plothover);
434 434
435 435 // don't fire event on the overview to prevent eternal loop
436 436 overview.setSelection(cur_ranges, true);
437 437
438 438 }
439 439
440 440 /**
441 441 * plot only selected items from overview
442 442 * @param ranges
443 443 * @returns
444 444 */
445 445 function plotselected(ranges,cur_data) {
446 446 //updates the data for new plot
447 447 data = getDataAccordingToRanges(ranges);
448 448 generateCheckboxes(data);
449 449
450 450 var new_options = YAHOO.lang.merge(plot_options, {
451 451 xaxis: {
452 452 min: ranges.xaxis.from,
453 453 max: ranges.xaxis.to,
454 454 mode:"time",
455 455 timeformat: "%d/%m",
456 456 },
457 457 yaxis: {
458 458 min: ranges.yaxis.from,
459 459 max: ranges.yaxis.to,
460 460 },
461 461
462 462 });
463 463 // do the zooming
464 464 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
465 465
466 466 plot.subscribe("plotselected", plotselected);
467 467
468 468 //resubscribe plothover
469 469 plot.subscribe("plothover", plothover);
470 470
471 471 // don't fire event on the overview to prevent eternal loop
472 472 overview.setSelection(ranges, true);
473 473
474 474 //resubscribe choiced
475 475 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
476 476 }
477 477
478 478 var previousPoint = null;
479 479
480 480 function plothover(o) {
481 481 var pos = o.pos;
482 482 var item = o.item;
483 483
484 484 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
485 485 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
486 486 if (item) {
487 487 if (previousPoint != item.datapoint) {
488 488 previousPoint = item.datapoint;
489 489
490 490 var tooltip = YAHOO.util.Dom.get("tooltip");
491 491 if(tooltip) {
492 492 tooltip.parentNode.removeChild(tooltip);
493 493 }
494 494 var x = item.datapoint.x.toFixed(2);
495 495 var y = item.datapoint.y.toFixed(2);
496 496
497 497 if (!item.series.label){
498 498 item.series.label = 'commits';
499 499 }
500 500 var d = new Date(x*1000);
501 501 var fd = d.toDateString()
502 502 var nr_commits = parseInt(y);
503 503
504 504 var cur_data = dataset[item.series.label].data[item.dataIndex];
505 505 var added = cur_data.added;
506 506 var changed = cur_data.changed;
507 507 var removed = cur_data.removed;
508 508
509 509 var nr_commits_suffix = " ${_('commits')} ";
510 510 var added_suffix = " ${_('files added')} ";
511 511 var changed_suffix = " ${_('files changed')} ";
512 512 var removed_suffix = " ${_('files removed')} ";
513 513
514 514
515 515 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
516 516 if(added==1){added_suffix=" ${_('file added')} ";}
517 517 if(changed==1){changed_suffix=" ${_('file changed')} ";}
518 518 if(removed==1){removed_suffix=" ${_('file removed')} ";}
519 519
520 520 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
521 521 +'<br/>'+
522 522 nr_commits + nr_commits_suffix+'<br/>'+
523 523 added + added_suffix +'<br/>'+
524 524 changed + changed_suffix + '<br/>'+
525 525 removed + removed_suffix + '<br/>');
526 526 }
527 527 }
528 528 else {
529 529 var tooltip = YAHOO.util.Dom.get("tooltip");
530 530
531 531 if(tooltip) {
532 532 tooltip.parentNode.removeChild(tooltip);
533 533 }
534 534 previousPoint = null;
535 535 }
536 536 }
537 537
538 538 /**
539 539 * MAIN EXECUTION
540 540 */
541 541
542 542 var data = getDataAccordingToRanges(initial_ranges);
543 543 generateCheckboxes(data);
544 544
545 545 //main plot
546 546 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
547 547
548 548 //overview
549 549 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
550 550
551 551 //show initial selection on overview
552 552 overview.setSelection(initial_ranges);
553 553
554 554 plot.subscribe("plotselected", plotselected);
555 555
556 556 overview.subscribe("plotselected", function (ranges) {
557 557 plot.setSelection(ranges);
558 558 });
559 559
560 560 plot.subscribe("plothover", plothover);
561 561
562 562 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
563 563 }
564 564 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
565 565 </script>
566 566
567 567 </div>
568 568 </div>
569 569
570 570 <div class="box">
571 571 <div class="title">
572 <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
572 <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
573 573 </div>
574 574 <div class="table">
575 575 <div id="shortlog_data">
576 576 <%include file='../shortlog/shortlog_data.html'/>
577 577 </div>
578 578 ##%if c.repo_changesets:
579 579 ## ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
580 580 ##%endif
581 581 </div>
582 582 </div>
583 583 <div class="box">
584 584 <div class="title">
585 585 <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
586 586 </div>
587 587 <div class="table">
588 588 <%include file='../tags/tags_data.html'/>
589 589 %if c.repo_changesets:
590 590 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
591 591 %endif
592 592 </div>
593 593 </div>
594 594 <div class="box">
595 595 <div class="title">
596 596 <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
597 597 </div>
598 598 <div class="table">
599 599 <%include file='../branches/branches_data.html'/>
600 600 %if c.repo_changesets:
601 601 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
602 602 %endif
603 603 </div>
604 604 </div>
605 605
606 606 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now