##// END OF EJS Templates
summary: don't load size on container expand, only on manual action....
marcink -
r3334:6301d8bb default
parent child Browse files
Show More
@@ -1,203 +1,203 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2015-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
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 Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20 import time
21 21 import errno
22 22 import logging
23 23
24 24 import gevent
25 25
26 26 from dogpile.cache.backends import memory as memory_backend
27 27 from dogpile.cache.backends import file as file_backend
28 28 from dogpile.cache.backends import redis as redis_backend
29 29 from dogpile.cache.backends.file import NO_VALUE, compat, FileLock
30 30 from dogpile.cache.util import memoized_property
31 31
32 32 from rhodecode.lib.memory_lru_dict import LRUDict, LRUDictDebug
33 33
34 34
35 35 _default_max_size = 1024
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 class LRUMemoryBackend(memory_backend.MemoryBackend):
41 41 pickle_values = False
42 42
43 43 def __init__(self, arguments):
44 44 max_size = arguments.pop('max_size', _default_max_size)
45 45
46 46 LRUDictClass = LRUDict
47 47 if arguments.pop('log_key_count', None):
48 48 LRUDictClass = LRUDictDebug
49 49
50 50 arguments['cache_dict'] = LRUDictClass(max_size)
51 51 super(LRUMemoryBackend, self).__init__(arguments)
52 52
53 53 def delete(self, key):
54 54 try:
55 55 del self._cache[key]
56 56 except KeyError:
57 57 # we don't care if key isn't there at deletion
58 58 pass
59 59
60 60 def delete_multi(self, keys):
61 61 for key in keys:
62 62 self.delete(key)
63 63
64 64
65 65 class Serializer(object):
66 66 def _dumps(self, value, safe=False):
67 67 try:
68 68 return compat.pickle.dumps(value)
69 69 except Exception:
70 70 if safe:
71 71 return NO_VALUE
72 72 else:
73 73 raise
74 74
75 75 def _loads(self, value, safe=True):
76 76 try:
77 77 return compat.pickle.loads(value)
78 78 except Exception:
79 79 if safe:
80 80 return NO_VALUE
81 81 else:
82 82 raise
83 83
84 84
85 85 class CustomLockFactory(FileLock):
86 86
87 87 @memoized_property
88 88 def _module(self):
89 89 import fcntl
90 90 flock_org = fcntl.flock
91 91
92 92 def gevent_flock(fd, operation):
93 93 """
94 94 Gevent compatible flock
95 95 """
96 96 # set non-blocking, this will cause an exception if we cannot acquire a lock
97 97 operation |= fcntl.LOCK_NB
98 98 start_lock_time = time.time()
99 timeout = 60 * 5 # 5min
99 timeout = 60 * 15 # 15min
100 100 while True:
101 101 try:
102 102 flock_org(fd, operation)
103 103 # lock has been acquired
104 104 break
105 105 except (OSError, IOError) as e:
106 106 # raise on other errors than Resource temporarily unavailable
107 107 if e.errno != errno.EAGAIN:
108 108 raise
109 109 elif (time.time() - start_lock_time) > timeout:
110 110 # waited to much time on a lock, better fail than loop for ever
111 111 log.error('Failed to acquire lock on `%s` after waiting %ss',
112 112 self.filename, timeout)
113 113 raise
114 114 wait_timeout = 0.03
115 115 log.debug('Failed to acquire lock on `%s`, retry in %ss',
116 116 self.filename, wait_timeout)
117 117 gevent.sleep(wait_timeout)
118 118
119 119 fcntl.flock = gevent_flock
120 120 return fcntl
121 121
122 122
123 123 class FileNamespaceBackend(Serializer, file_backend.DBMBackend):
124 124
125 125 def __init__(self, arguments):
126 126 arguments['lock_factory'] = CustomLockFactory
127 127 super(FileNamespaceBackend, self).__init__(arguments)
128 128
129 129 def list_keys(self, prefix=''):
130 130 def cond(v):
131 131 if not prefix:
132 132 return True
133 133
134 134 if v.startswith(prefix):
135 135 return True
136 136 return False
137 137
138 138 with self._dbm_file(True) as dbm:
139 139
140 140 return filter(cond, dbm.keys())
141 141
142 142 def get_store(self):
143 143 return self.filename
144 144
145 145 def get(self, key):
146 146 with self._dbm_file(False) as dbm:
147 147 if hasattr(dbm, 'get'):
148 148 value = dbm.get(key, NO_VALUE)
149 149 else:
150 150 # gdbm objects lack a .get method
151 151 try:
152 152 value = dbm[key]
153 153 except KeyError:
154 154 value = NO_VALUE
155 155 if value is not NO_VALUE:
156 156 value = self._loads(value)
157 157 return value
158 158
159 159 def set(self, key, value):
160 160 with self._dbm_file(True) as dbm:
161 161 dbm[key] = self._dumps(value)
162 162
163 163 def set_multi(self, mapping):
164 164 with self._dbm_file(True) as dbm:
165 165 for key, value in mapping.items():
166 166 dbm[key] = self._dumps(value)
167 167
168 168
169 169 class RedisPickleBackend(Serializer, redis_backend.RedisBackend):
170 170 def list_keys(self, prefix=''):
171 171 if prefix:
172 172 prefix = prefix + '*'
173 173 return self.client.keys(prefix)
174 174
175 175 def get_store(self):
176 176 return self.client.connection_pool
177 177
178 178 def get(self, key):
179 179 value = self.client.get(key)
180 180 if value is None:
181 181 return NO_VALUE
182 182 return self._loads(value)
183 183
184 184 def set(self, key, value):
185 185 if self.redis_expiration_time:
186 186 self.client.setex(key, self.redis_expiration_time,
187 187 self._dumps(value))
188 188 else:
189 189 self.client.set(key, self._dumps(value))
190 190
191 191 def set_multi(self, mapping):
192 192 mapping = dict(
193 193 (k, self._dumps(v))
194 194 for k, v in mapping.items()
195 195 )
196 196
197 197 if not self.redis_expiration_time:
198 198 self.client.mset(mapping)
199 199 else:
200 200 pipe = self.client.pipeline()
201 201 for key, value in mapping.items():
202 202 pipe.setex(key, self.redis_expiration_time, value)
203 203 pipe.execute()
@@ -1,578 +1,579 b''
1 1 // # Copyright (C) 2010-2018 RhodeCode GmbH
2 2 // #
3 3 // # This program is free software: you can redistribute it and/or modify
4 4 // # it under the terms of the GNU Affero General Public License, version 3
5 5 // # (only), as published by the Free Software Foundation.
6 6 // #
7 7 // # This program is distributed in the hope that it will be useful,
8 8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 // # GNU General Public License for more details.
11 11 // #
12 12 // # You should have received a copy of the GNU Affero General Public License
13 13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 // #
15 15 // # This program is dual-licensed. If you wish to learn more about the
16 16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 /**
20 20 RhodeCode JS Files
21 21 **/
22 22
23 23 if (typeof console == "undefined" || typeof console.log == "undefined"){
24 24 console = { log: function() {} }
25 25 }
26 26
27 27 // TODO: move the following function to submodules
28 28
29 29 /**
30 30 * show more
31 31 */
32 32 var show_more_event = function(){
33 33 $('table .show_more').click(function(e) {
34 34 var cid = e.target.id.substring(1);
35 35 var button = $(this);
36 36 if (button.hasClass('open')) {
37 37 $('#'+cid).hide();
38 38 button.removeClass('open');
39 39 } else {
40 40 $('#'+cid).show();
41 41 button.addClass('open one');
42 42 }
43 43 });
44 44 };
45 45
46 46 var compare_radio_buttons = function(repo_name, compare_ref_type){
47 47 $('#compare_action').on('click', function(e){
48 48 e.preventDefault();
49 49
50 50 var source = $('input[name=compare_source]:checked').val();
51 51 var target = $('input[name=compare_target]:checked').val();
52 52 if(source && target){
53 53 var url_data = {
54 54 repo_name: repo_name,
55 55 source_ref: source,
56 56 source_ref_type: compare_ref_type,
57 57 target_ref: target,
58 58 target_ref_type: compare_ref_type,
59 59 merge: 1
60 60 };
61 61 window.location = pyroutes.url('repo_compare', url_data);
62 62 }
63 63 });
64 64 $('.compare-radio-button').on('click', function(e){
65 65 var source = $('input[name=compare_source]:checked').val();
66 66 var target = $('input[name=compare_target]:checked').val();
67 67 if(source && target){
68 68 $('#compare_action').removeAttr("disabled");
69 69 $('#compare_action').removeClass("disabled");
70 70 }
71 71 })
72 72 };
73 73
74 74 var showRepoSize = function(target, repo_name, commit_id, callback) {
75 75 var container = $('#' + target);
76 76 var url = pyroutes.url('repo_stats',
77 77 {"repo_name": repo_name, "commit_id": commit_id});
78 78
79 container.show();
79 80 if (!container.hasClass('loaded')) {
80 81 $.ajax({url: url})
81 82 .complete(function (data) {
82 83 var responseJSON = data.responseJSON;
83 84 container.addClass('loaded');
84 85 container.html(responseJSON.size);
85 86 callback(responseJSON.code_stats)
86 87 })
87 88 .fail(function (data) {
88 89 console.log('failed to load repo stats');
89 90 });
90 91 }
91 92
92 93 };
93 94
94 95 var showRepoStats = function(target, data){
95 96 var container = $('#' + target);
96 97
97 98 if (container.hasClass('loaded')) {
98 99 return
99 100 }
100 101
101 102 var total = 0;
102 103 var no_data = true;
103 104 var tbl = document.createElement('table');
104 105 tbl.setAttribute('class', 'trending_language_tbl');
105 106
106 107 $.each(data, function(key, val){
107 108 total += val.count;
108 109 });
109 110
110 111 var sortedStats = [];
111 112 for (var obj in data){
112 113 sortedStats.push([obj, data[obj]])
113 114 }
114 115 var sortedData = sortedStats.sort(function (a, b) {
115 116 return b[1].count - a[1].count
116 117 });
117 118 var cnt = 0;
118 119 $.each(sortedData, function(idx, val){
119 120 cnt += 1;
120 121 no_data = false;
121 122
122 123 var hide = cnt > 2;
123 124 var tr = document.createElement('tr');
124 125 if (hide) {
125 126 tr.setAttribute('style', 'display:none');
126 127 tr.setAttribute('class', 'stats_hidden');
127 128 }
128 129
129 130 var key = val[0];
130 131 var obj = {"desc": val[1].desc, "count": val[1].count};
131 132
132 133 var percentage = Math.round((obj.count / total * 100), 2);
133 134
134 135 var td1 = document.createElement('td');
135 136 td1.width = 300;
136 137 var trending_language_label = document.createElement('div');
137 138 trending_language_label.innerHTML = obj.desc + " (.{0})".format(key);
138 139 td1.appendChild(trending_language_label);
139 140
140 141 var td2 = document.createElement('td');
141 142 var trending_language = document.createElement('div');
142 143 var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count);
143 144
144 145 trending_language.title = key + " " + nr_files;
145 146
146 147 trending_language.innerHTML = "<span>" + percentage + "% " + nr_files
147 148 + "</span><b>" + percentage + "% " + nr_files + "</b>";
148 149
149 150 trending_language.setAttribute("class", 'trending_language');
150 151 $('b', trending_language)[0].style.width = percentage + "%";
151 152 td2.appendChild(trending_language);
152 153
153 154 tr.appendChild(td1);
154 155 tr.appendChild(td2);
155 156 tbl.appendChild(tr);
156 157 if (cnt == 3) {
157 158 var show_more = document.createElement('tr');
158 159 var td = document.createElement('td');
159 160 lnk = document.createElement('a');
160 161
161 162 lnk.href = '#';
162 163 lnk.innerHTML = _gettext('Show more');
163 164 lnk.id = 'code_stats_show_more';
164 165 td.appendChild(lnk);
165 166
166 167 show_more.appendChild(td);
167 168 show_more.appendChild(document.createElement('td'));
168 169 tbl.appendChild(show_more);
169 170 }
170 171 });
171 172
172 173 $(container).html(tbl);
173 174 $(container).addClass('loaded');
174 175
175 176 $('#code_stats_show_more').on('click', function (e) {
176 177 e.preventDefault();
177 178 $('.stats_hidden').each(function (idx) {
178 179 $(this).css("display", "");
179 180 });
180 181 $('#code_stats_show_more').hide();
181 182 });
182 183
183 184 };
184 185
185 186 // returns a node from given html;
186 187 var fromHTML = function(html){
187 188 var _html = document.createElement('element');
188 189 _html.innerHTML = html;
189 190 return _html;
190 191 };
191 192
192 193 // Toggle Collapsable Content
193 194 function collapsableContent() {
194 195
195 196 $('.collapsable-content').not('.no-hide').hide();
196 197
197 198 $('.btn-collapse').unbind(); //in case we've been here before
198 199 $('.btn-collapse').click(function() {
199 200 var button = $(this);
200 201 var togglename = $(this).data("toggle");
201 202 $('.collapsable-content[data-toggle='+togglename+']').toggle();
202 203 if ($(this).html()=="Show Less")
203 204 $(this).html("Show More");
204 205 else
205 206 $(this).html("Show Less");
206 207 });
207 208 };
208 209
209 210 var timeagoActivate = function() {
210 211 $("time.timeago").timeago();
211 212 };
212 213
213 214
214 215 var clipboardActivate = function() {
215 216 /*
216 217 *
217 218 * <i class="tooltip icon-plus clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
218 219 * */
219 220 var clipboard = new ClipboardJS('.clipboard-action');
220 221
221 222 clipboard.on('success', function(e) {
222 223 var callback = function () {
223 224 $(e.trigger).animate({'opacity': 1.00}, 200)
224 225 };
225 226 $(e.trigger).animate({'opacity': 0.15}, 200, callback);
226 227 e.clearSelection();
227 228 });
228 229 };
229 230
230 231
231 232 // Formatting values in a Select2 dropdown of commit references
232 233 var formatSelect2SelectionRefs = function(commit_ref){
233 234 var tmpl = '';
234 235 if (!commit_ref.text || commit_ref.type === 'sha'){
235 236 return commit_ref.text;
236 237 }
237 238 if (commit_ref.type === 'branch'){
238 239 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
239 240 } else if (commit_ref.type === 'tag'){
240 241 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
241 242 } else if (commit_ref.type === 'book'){
242 243 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
243 244 }
244 245 return tmpl.concat(escapeHtml(commit_ref.text));
245 246 };
246 247
247 248 // takes a given html element and scrolls it down offset pixels
248 249 function offsetScroll(element, offset) {
249 250 setTimeout(function() {
250 251 var location = element.offset().top;
251 252 // some browsers use body, some use html
252 253 $('html, body').animate({ scrollTop: (location - offset) });
253 254 }, 100);
254 255 }
255 256
256 257 // scroll an element `percent`% from the top of page in `time` ms
257 258 function scrollToElement(element, percent, time) {
258 259 percent = (percent === undefined ? 25 : percent);
259 260 time = (time === undefined ? 100 : time);
260 261
261 262 var $element = $(element);
262 263 if ($element.length == 0) {
263 264 throw('Cannot scroll to {0}'.format(element))
264 265 }
265 266 var elOffset = $element.offset().top;
266 267 var elHeight = $element.height();
267 268 var windowHeight = $(window).height();
268 269 var offset = elOffset;
269 270 if (elHeight < windowHeight) {
270 271 offset = elOffset - ((windowHeight / (100 / percent)) - (elHeight / 2));
271 272 }
272 273 setTimeout(function() {
273 274 $('html, body').animate({ scrollTop: offset});
274 275 }, time);
275 276 }
276 277
277 278 /**
278 279 * global hooks after DOM is loaded
279 280 */
280 281 $(document).ready(function() {
281 282 firefoxAnchorFix();
282 283
283 284 $('.navigation a.menulink').on('click', function(e){
284 285 var menuitem = $(this).parent('li');
285 286 if (menuitem.hasClass('open')) {
286 287 menuitem.removeClass('open');
287 288 } else {
288 289 menuitem.addClass('open');
289 290 $(document).on('click', function(event) {
290 291 if (!$(event.target).closest(menuitem).length) {
291 292 menuitem.removeClass('open');
292 293 }
293 294 });
294 295 }
295 296 });
296 297
297 298 $('body').on('click', '.cb-lineno a', function(event) {
298 299 function sortNumber(a,b) {
299 300 return a - b;
300 301 }
301 302
302 303 var lineNo = $(this).data('lineNo');
303 304 var lineName = $(this).attr('name');
304 305
305 306 if (lineNo) {
306 307 var prevLine = $('.cb-line-selected a').data('lineNo');
307 308
308 309 // on shift, we do a range selection, if we got previous line
309 310 if (event.shiftKey && prevLine !== undefined) {
310 311 var prevLine = parseInt(prevLine);
311 312 var nextLine = parseInt(lineNo);
312 313 var pos = [prevLine, nextLine].sort(sortNumber);
313 314 var anchor = '#L{0}-{1}'.format(pos[0], pos[1]);
314 315
315 316 // single click
316 317 } else {
317 318 var nextLine = parseInt(lineNo);
318 319 var pos = [nextLine, nextLine];
319 320 var anchor = '#L{0}'.format(pos[0]);
320 321
321 322 }
322 323 // highlight
323 324 var range = [];
324 325 for (var i = pos[0]; i <= pos[1]; i++) {
325 326 range.push(i);
326 327 }
327 328 // clear old selected lines
328 329 $('.cb-line-selected').removeClass('cb-line-selected');
329 330
330 331 $.each(range, function (i, lineNo) {
331 332 var line_td = $('td.cb-lineno#L' + lineNo);
332 333
333 334 if (line_td.length) {
334 335 line_td.addClass('cb-line-selected'); // line number td
335 336 line_td.prev().addClass('cb-line-selected'); // line data
336 337 line_td.next().addClass('cb-line-selected'); // line content
337 338 }
338 339 });
339 340
340 341 } else if (lineName !== undefined) { // lineName only occurs in diffs
341 342 // clear old selected lines
342 343 $('td.cb-line-selected').removeClass('cb-line-selected');
343 344 var anchor = '#{0}'.format(lineName);
344 345 var diffmode = templateContext.session_attrs.diffmode || "sideside";
345 346
346 347 if (diffmode === "unified") {
347 348 $(this).closest('tr').find('td').addClass('cb-line-selected');
348 349 } else {
349 350 var activeTd = $(this).closest('td');
350 351 activeTd.addClass('cb-line-selected');
351 352 activeTd.next('td').addClass('cb-line-selected');
352 353 }
353 354
354 355 }
355 356
356 357 // Replace URL without jumping to it if browser supports.
357 358 // Default otherwise
358 359 if (history.pushState && anchor !== undefined) {
359 360 var new_location = location.href.rstrip('#');
360 361 if (location.hash) {
361 362 // location without hash
362 363 new_location = new_location.replace(location.hash, "");
363 364 }
364 365
365 366 // Make new anchor url
366 367 new_location = new_location + anchor;
367 368 history.pushState(true, document.title, new_location);
368 369
369 370 return false;
370 371 }
371 372
372 373 });
373 374
374 375 $('.collapse_file').on('click', function(e) {
375 376 e.stopPropagation();
376 377 if ($(e.target).is('a')) { return; }
377 378 var node = $(e.delegateTarget).first();
378 379 var icon = $($(node.children().first()).children().first());
379 380 var id = node.attr('fid');
380 381 var target = $('#'+id);
381 382 var tr = $('#tr_'+id);
382 383 var diff = $('#diff_'+id);
383 384 if(node.hasClass('expand_file')){
384 385 node.removeClass('expand_file');
385 386 icon.removeClass('expand_file_icon');
386 387 node.addClass('collapse_file');
387 388 icon.addClass('collapse_file_icon');
388 389 diff.show();
389 390 tr.show();
390 391 target.show();
391 392 } else {
392 393 node.removeClass('collapse_file');
393 394 icon.removeClass('collapse_file_icon');
394 395 node.addClass('expand_file');
395 396 icon.addClass('expand_file_icon');
396 397 diff.hide();
397 398 tr.hide();
398 399 target.hide();
399 400 }
400 401 });
401 402
402 403 $('#expand_all_files').click(function() {
403 404 $('.expand_file').each(function() {
404 405 var node = $(this);
405 406 var icon = $($(node.children().first()).children().first());
406 407 var id = $(this).attr('fid');
407 408 var target = $('#'+id);
408 409 var tr = $('#tr_'+id);
409 410 var diff = $('#diff_'+id);
410 411 node.removeClass('expand_file');
411 412 icon.removeClass('expand_file_icon');
412 413 node.addClass('collapse_file');
413 414 icon.addClass('collapse_file_icon');
414 415 diff.show();
415 416 tr.show();
416 417 target.show();
417 418 });
418 419 });
419 420
420 421 $('#collapse_all_files').click(function() {
421 422 $('.collapse_file').each(function() {
422 423 var node = $(this);
423 424 var icon = $($(node.children().first()).children().first());
424 425 var id = $(this).attr('fid');
425 426 var target = $('#'+id);
426 427 var tr = $('#tr_'+id);
427 428 var diff = $('#diff_'+id);
428 429 node.removeClass('collapse_file');
429 430 icon.removeClass('collapse_file_icon');
430 431 node.addClass('expand_file');
431 432 icon.addClass('expand_file_icon');
432 433 diff.hide();
433 434 tr.hide();
434 435 target.hide();
435 436 });
436 437 });
437 438
438 439 // Mouse over behavior for comments and line selection
439 440
440 441 // Select the line that comes from the url anchor
441 442 // At the time of development, Chrome didn't seem to support jquery's :target
442 443 // element, so I had to scroll manually
443 444
444 445 if (location.hash) {
445 446 var result = splitDelimitedHash(location.hash);
446 447 var loc = result.loc;
447 448 if (loc.length > 1) {
448 449
449 450 var highlightable_line_tds = [];
450 451
451 452 // source code line format
452 453 var page_highlights = loc.substring(
453 454 loc.indexOf('#') + 1).split('L');
454 455
455 456 if (page_highlights.length > 1) {
456 457 var highlight_ranges = page_highlights[1].split(",");
457 458 var h_lines = [];
458 459 for (var pos in highlight_ranges) {
459 460 var _range = highlight_ranges[pos].split('-');
460 461 if (_range.length === 2) {
461 462 var start = parseInt(_range[0]);
462 463 var end = parseInt(_range[1]);
463 464 if (start < end) {
464 465 for (var i = start; i <= end; i++) {
465 466 h_lines.push(i);
466 467 }
467 468 }
468 469 }
469 470 else {
470 471 h_lines.push(parseInt(highlight_ranges[pos]));
471 472 }
472 473 }
473 474 for (pos in h_lines) {
474 475 var line_td = $('td.cb-lineno#L' + h_lines[pos]);
475 476 if (line_td.length) {
476 477 highlightable_line_tds.push(line_td);
477 478 }
478 479 }
479 480 }
480 481
481 482 // now check a direct id reference (diff page)
482 483 if ($(loc).length && $(loc).hasClass('cb-lineno')) {
483 484 highlightable_line_tds.push($(loc));
484 485 }
485 486 $.each(highlightable_line_tds, function (i, $td) {
486 487 $td.addClass('cb-line-selected'); // line number td
487 488 $td.prev().addClass('cb-line-selected'); // line data
488 489 $td.next().addClass('cb-line-selected'); // line content
489 490 });
490 491
491 492 if (highlightable_line_tds.length) {
492 493 var $first_line_td = highlightable_line_tds[0];
493 494 scrollToElement($first_line_td);
494 495 $.Topic('/ui/plugins/code/anchor_focus').prepareOrPublish({
495 496 td: $first_line_td,
496 497 remainder: result.remainder
497 498 });
498 499 }
499 500 }
500 501 }
501 502 collapsableContent();
502 503 });
503 504
504 505 var feedLifetimeOptions = function(query, initialData){
505 506 var data = {results: []};
506 507 var isQuery = typeof query.term !== 'undefined';
507 508
508 509 var section = _gettext('Lifetime');
509 510 var children = [];
510 511
511 512 //filter results
512 513 $.each(initialData.results, function(idx, value) {
513 514
514 515 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
515 516 children.push({
516 517 'id': this.id,
517 518 'text': this.text
518 519 })
519 520 }
520 521
521 522 });
522 523 data.results.push({
523 524 'text': section,
524 525 'children': children
525 526 });
526 527
527 528 if (isQuery) {
528 529
529 530 var now = moment.utc();
530 531
531 532 var parseQuery = function(entry, now){
532 533 var fmt = 'DD/MM/YYYY H:mm';
533 534 var parsed = moment.utc(entry, fmt);
534 535 var diffInMin = parsed.diff(now, 'minutes');
535 536
536 537 if (diffInMin > 0){
537 538 return {
538 539 id: diffInMin,
539 540 text: parsed.format(fmt)
540 541 }
541 542 } else {
542 543 return {
543 544 id: undefined,
544 545 text: parsed.format('DD/MM/YYYY') + ' ' + _gettext('date not in future')
545 546 }
546 547 }
547 548
548 549
549 550 };
550 551
551 552 data.results.push({
552 553 'text': _gettext('Specified expiration date'),
553 554 'children': [{
554 555 'id': parseQuery(query.term, now).id,
555 556 'text': parseQuery(query.term, now).text
556 557 }]
557 558 });
558 559 }
559 560
560 561 query.callback(data);
561 562 };
562 563
563 564
564 565 var storeUserSessionAttr = function (key, val) {
565 566
566 567 var postData = {
567 568 'key': key,
568 569 'val': val,
569 570 'csrf_token': CSRF_TOKEN
570 571 };
571 572
572 573 var success = function(o) {
573 574 return true
574 575 };
575 576
576 577 ajaxPOST(pyroutes.url('store_user_session_value'), postData, success);
577 578 return false;
578 579 };
@@ -1,217 +1,231 b''
1 1 <%def name="refs_counters(branches, closed_branches, tags, bookmarks)">
2 2 <span class="branchtag tag">
3 3 <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
4 4 <i class="icon-branch"></i>${_ungettext(
5 5 '%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}</a>
6 6 </span>
7 7
8 8 %if closed_branches:
9 9 <span class="branchtag tag">
10 10 <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
11 11 <i class="icon-branch"></i>${_ungettext(
12 12 '%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}</a>
13 13 </span>
14 14 %endif
15 15
16 16 <span class="tagtag tag">
17 17 <a href="${h.route_path('tags_home',repo_name=c.repo_name)}" class="childs">
18 18 <i class="icon-tag"></i>${_ungettext(
19 19 '%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}</a>
20 20 </span>
21 21
22 22 %if bookmarks:
23 23 <span class="booktag tag">
24 24 <a href="${h.route_path('bookmarks_home',repo_name=c.repo_name)}" class="childs">
25 25 <i class="icon-bookmark"></i>${_ungettext(
26 26 '%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}</a>
27 27 </span>
28 28 %endif
29 29 </%def>
30 30
31 31 <%def name="summary_detail(breadcrumbs_links, show_downloads=True)">
32 32 <% summary = lambda n:{False:'summary-short'}.get(n) %>
33 33
34 34 <div id="summary-menu-stats" class="summary-detail">
35 35 <div class="summary-detail-header">
36 36 <div class="breadcrumbs files_location">
37 37 <h4>
38 38 ${breadcrumbs_links}
39 39 </h4>
40 40 </div>
41 41 <div id="summary_details_expand" class="btn-collapse" data-toggle="summary-details">
42 42 ${_('Show More')}
43 43 </div>
44 44 </div>
45 45
46 46 <div class="fieldset">
47 47
48 48 <div class="left-clone">
49 49 <select id="clone_option" name="clone_option">
50 50 <option value="http" selected="selected">HTTP</option>
51 51 <option value="http_id">HTTP UID</option>
52 52 % if c.ssh_enabled:
53 53 <option value="ssh">SSH</option>
54 54 % endif
55 55 </select>
56 56 </div>
57 57 <div class="right-clone">
58 58 <%
59 59 maybe_disabled = ''
60 60 if h.is_svn_without_proxy(c.rhodecode_db_repo):
61 61 maybe_disabled = 'disabled'
62 62 %>
63 63
64 64 <span id="clone_option_http">
65 65 <input type="text" class="input-monospace clone_url_input" ${maybe_disabled} readonly="readonly" value="${c.clone_repo_url}"/>
66 66 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${c.clone_repo_url}" title="${_('Copy the clone url')}"></i>
67 67 </span>
68 68
69 69 <span style="display: none;" id="clone_option_http_id">
70 70 <input type="text" class="input-monospace clone_url_input" ${maybe_disabled} readonly="readonly" value="${c.clone_repo_url_id}"/>
71 71 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${c.clone_repo_url_id}" title="${_('Copy the clone by id url')}"></i>
72 72 </span>
73 73
74 74 <span style="display: none;" id="clone_option_ssh">
75 75 <input type="text" class="input-monospace clone_url_input" ${maybe_disabled} readonly="readonly" value="${c.clone_repo_url_ssh}"/>
76 76 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${c.clone_repo_url_ssh}" title="${_('Copy the clone by ssh url')}"></i>
77 77 </span>
78 78
79 79 % if maybe_disabled:
80 80 <p class="help-block">${_('SVN Protocol is disabled. To enable it, see the')} <a href="${h.route_url('enterprise_svn_setup')}" target="_blank">${_('documentation here')}</a>.</p>
81 81 % endif
82 82
83 83 </div>
84 84 </div>
85 85
86 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
86 <div class="fieldset">
87 87 <div class="left-label-summary">
88 ${_('Information')}:
88 &nbsp;
89 89 </div>
90 90 <div class="right-content">
91 91 <div class="commit-info">
92 92 <div class="tags">
93 93 <% commit_rev = c.rhodecode_db_repo.changeset_cache.get('revision') %>
94 94 % if c.rhodecode_repo:
95 95 ${refs_counters(
96 96 c.rhodecode_repo.branches,
97 97 c.rhodecode_repo.branches_closed,
98 98 c.rhodecode_repo.tags,
99 99 c.rhodecode_repo.bookmarks)}
100 100 % else:
101 101 ## missing requirements can make c.rhodecode_repo None
102 102 ${refs_counters([], [], [], [])}
103 103 % endif
104 104
105 105 ## commits
106 106 <span class="tag">
107 107 % if commit_rev == -1:
108 ${_ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
108 ${_ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}}
109 109 % else:
110 110 <a href="${h.route_path('repo_changelog', repo_name=c.repo_name)}">
111 ${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
111 ${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>
112 112 % endif
113 113 </span>
114 114
115 115 ## forks
116 116 <span class="tag">
117 117 <a title="${_('Number of Repository Forks')}" href="${h.route_path('repo_forks_show_all', repo_name=c.repo_name)}">
118 ${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>,
118 ${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>
119 119 </span>
120 120
121 ## repo size
122 % if commit_rev == -1:
123 <span class="stats-bullet">0 B</span>
124 % else:
125 <span class="stats-bullet" id="repo_size_container">
126 ${_('Calculating Repository Size...')}
127 </span>
128 % endif
121 </div>
122 </div>
123 </div>
124 </div>
129 125
126 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
127 <div class="left-label-summary">
128 ${_('Repository size')}:
129 </div>
130 <div class="right-content">
131 <div class="commit-info">
132 <div class="tags">
133 ## repo size
134 % if commit_rev == -1:
135 <span class="stats-bullet">0 B</span>
136 % else:
137 <span>
138 <a href="#showSize" onclick="calculateSize(); $(this).hide(); return false" id="show-repo-size">Show repository size</a>
139 </span>
140 <span class="stats-bullet" id="repo_size_container" style="display:none">
141 ${_('Calculating Repository Size...')}
142 </span>
143 % endif
130 144 </div>
131 145 </div>
132 146 </div>
133 147 </div>
134 148
135 149 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
136 150 <div class="left-label-summary">
137 151 ${_('Description')}:
138 152 </div>
139 153 <div class="right-content">
140 154 <div class="input ${summary(c.show_stats)}">
141 155 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
142 156 ${dt.repo_desc(c.rhodecode_db_repo.description_safe, c.visual.stylify_metatags)}
143 157 </div>
144 158 </div>
145 159 </div>
146 160
147 161 % if show_downloads:
148 162 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
149 163 <div class="left-label-summary">
150 164 ${_('Downloads')}:
151 165 </div>
152 166 <div class="right-content">
153 167 <div class="input ${summary(c.show_stats)} downloads">
154 168 % if c.rhodecode_repo and len(c.rhodecode_repo.commit_ids) == 0:
155 169 <span class="disabled">
156 170 ${_('There are no downloads yet')}
157 171 </span>
158 172 % elif not c.enable_downloads:
159 173 <span class="disabled">
160 174 ${_('Downloads are disabled for this repository')}.
161 175 </span>
162 176 % if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
163 177 ${h.link_to(_('Enable downloads'),h.route_path('edit_repo',repo_name=c.repo_name, _anchor='repo_enable_downloads'))}
164 178 % endif
165 179 % else:
166 180 <span class="enabled">
167 181 <a id="archive_link" class="btn btn-small" href="${h.route_path('repo_archivefile',repo_name=c.rhodecode_db_repo.repo_name,fname='tip.zip')}">
168 182 <i class="icon-archive"></i> tip.zip
169 183 ## replaced by some JS on select
170 184 </a>
171 185 </span>
172 186 ${h.hidden('download_options')}
173 187 % endif
174 188 </div>
175 189 </div>
176 190 </div>
177 191 % endif
178 192
179 193 ## Statistics
180 194 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
181 195 <div class="left-label-summary">
182 196 ${_('Statistics')}:
183 197 </div>
184 198 <div class="right-content">
185 199 <div class="input ${summary(c.show_stats)} statistics">
186 200 % if c.show_stats:
187 201 <div id="lang_stats" class="enabled">
188 202 ${_('Calculating Code Statistics...')}
189 203 </div>
190 204 % else:
191 205 <span class="disabled">
192 206 ${_('Statistics are disabled for this repository')}.
193 207 </span>
194 208 % if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
195 209 ${h.link_to(_('Enable statistics'),h.route_path('edit_repo',repo_name=c.repo_name, _anchor='repo_enable_statistics'))}
196 210 % endif
197 211 % endif
198 212 </div>
199 213
200 214 </div>
201 215 </div>
202 216
203 217 </div><!--end summary-detail-->
204 218 </%def>
205 219
206 220 <%def name="summary_stats(gravatar_function)">
207 221 <div class="sidebar-right">
208 222 <div class="summary-detail-header">
209 223 <h4 class="item">
210 224 ${_('Owner')}
211 225 </h4>
212 226 </div>
213 227 <div class="sidebar-right-content">
214 228 ${gravatar_function(c.rhodecode_db_repo.user.email, 16)}
215 229 </div>
216 230 </div><!--end sidebar-right-->
217 231 </%def>
@@ -1,129 +1,125 b''
1 1 <%inherit file="/summary/summary_base.mako"/>
2 2
3 3 <%namespace name="components" file="/summary/components.mako"/>
4 4
5 5
6 6 <%def name="menu_bar_subnav()">
7 7 ${self.repo_menu(active='summary')}
8 8 </%def>
9 9
10 10 <%def name="main()">
11 11
12 12 <div class="title">
13 13 ${self.repo_page_title(c.rhodecode_db_repo)}
14 14 <ul class="links icon-only-links block-right">
15 15 <li>
16 16 %if c.rhodecode_user.username != h.DEFAULT_USER:
17 17 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_name, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}"><i class="icon-rss-sign"></i></a>
18 18 %else:
19 19 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_name)}" title="${_('RSS Feed')}"><i class="icon-rss-sign"></i></a>
20 20 %endif
21 21 </li>
22 22 </ul>
23 23 </div>
24 24
25 25 <div id="repo-summary" class="summary">
26 26 ${components.summary_detail(breadcrumbs_links=self.breadcrumbs_links(), show_downloads=True)}
27 27 ${components.summary_stats(gravatar_function=self.gravatar_with_user)}
28 28 </div><!--end repo-summary-->
29 29
30 30
31 31 <div class="box" >
32 32 %if not c.repo_commits:
33 33 <div class="title">
34 34 <h3>${_('Quick start')}</h3>
35 35 </div>
36 36 %endif
37 37 <div class="table">
38 38 <div id="shortlog_data">
39 39 <%include file='summary_commits.mako'/>
40 40 </div>
41 41 </div>
42 42 </div>
43 43
44 44 %if c.readme_data:
45 45 <div id="readme" class="anchor">
46 46 <div class="box" >
47 47 <div class="title" title="${h.tooltip(_('Readme file from commit %s:%s') % (c.rhodecode_db_repo.landing_rev[0], c.rhodecode_db_repo.landing_rev[1]))}">
48 48 <h3 class="breadcrumbs">
49 49 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.landing_rev[1],f_path=c.readme_file)}">${c.readme_file}</a>
50 50 </h3>
51 51 </div>
52 52 <div class="readme codeblock">
53 53 <div class="readme_box">
54 54 ${c.readme_data|n}
55 55 </div>
56 56 </div>
57 57 </div>
58 58 </div>
59 59 %endif
60 60
61 61 <script type="text/javascript">
62 62 $(document).ready(function(){
63 63
64 64 var showCloneField = function(clone_url_format){
65 65 $.each(['http', 'http_id', 'ssh'], function (idx, val) {
66 66 if(val === clone_url_format){
67 67 $('#clone_option_' + val).show();
68 68 $('#clone_option').val(val)
69 69 } else {
70 70 $('#clone_option_' + val).hide();
71 71 }
72 72 });
73 73 };
74 74 // default taken from session
75 75 showCloneField(templateContext.session_attrs.clone_url_format);
76 76
77 77 $('#clone_option').on('change', function(e) {
78 78 var selected = $(this).val();
79 79
80 80 storeUserSessionAttr('rc_user_session_attr.clone_url_format', selected);
81 81 showCloneField(selected)
82 82 });
83 83
84 84 var initialCommitData = {
85 85 id: null,
86 86 text: 'tip',
87 87 type: 'tag',
88 88 raw_id: null,
89 89 files_url: null
90 90 };
91 91
92 92 select2RefSwitcher('#download_options', initialCommitData);
93 93
94 94 // on change of download options
95 95 $('#download_options').on('change', function(e) {
96 96 // format of Object {text: "v0.0.3", type: "tag", id: "rev"}
97 97 var ext = '.zip';
98 98 var selected_cs = e.added;
99 99 var fname = e.added.raw_id + ext;
100 100 var href = pyroutes.url('repo_archivefile', {'repo_name': templateContext.repo_name, 'fname':fname});
101 101 // set new label
102 102 $('#archive_link').html('<i class="icon-archive"></i> {0}{1}'.format(escapeHtml(e.added.text), ext));
103 103
104 104 // set new url to button,
105 105 $('#archive_link').attr('href', href)
106 106 });
107 107
108 108
109 // load details on summary page expand
110 $('#summary_details_expand').on('click', function() {
109 // calculate size of repository
110 calculateSize = function () {
111 111
112 112 var callback = function (data) {
113 113 % if c.show_stats:
114 114 showRepoStats('lang_stats', data);
115 115 % endif
116 116 };
117 117
118 showRepoSize(
119 'repo_size_container',
120 templateContext.repo_name,
121 templateContext.repo_landing_commit,
122 callback);
118 showRepoSize('repo_size_container', templateContext.repo_name, templateContext.repo_landing_commit, callback);
123 119
124 })
120 }
125 121
126 122 })
127 123 </script>
128 124
129 125 </%def>
General Comments 0
You need to be logged in to leave comments. Login now