##// END OF EJS Templates
pull-requests: expose TODO box in dedicated panel...
marcink -
r4140:eb578430 default
parent child Browse files
Show More
@@ -1,94 +1,104 b''
1 //--- RESETS ---//
1 //--- RESETS ---//
2 :focus { outline: none; }
2 :focus { outline: none; }
3 a { cursor: pointer; }
3 a { cursor: pointer; }
4
4
5 //--- clearfix --//
5 //--- clearfix --//
6 .clearfix {
6 .clearfix {
7 &:before,
7 &:before,
8 &:after {
8 &:after {
9 content:"";
9 content:"";
10 width: 100%;
10 width: 100%;
11 clear: both;
11 clear: both;
12 float: left;
12 float: left;
13 }
13 }
14 }
14 }
15
15
16 .clearinner:after { /* clears all floating divs inside a block */
16 .clearinner:after { /* clears all floating divs inside a block */
17 content: "";
17 content: "";
18 display: table;
18 display: table;
19 clear: both;
19 clear: both;
20 }
20 }
21
21
22 .js-template { /* mark a template for javascript use */
22 .js-template { /* mark a template for javascript use */
23 display: none;
23 display: none;
24 }
24 }
25
25
26 .linebreak {
26 .linebreak {
27 display: block;
27 display: block;
28 }
28 }
29
29
30 .clear-both {
30 .clear-both {
31 clear: both;
31 clear: both;
32 }
32 }
33
33
34 .pull-right {
34 .pull-right {
35 float: right !important;
35 float: right !important;
36 }
36 }
37
37
38 .pull-left {
38 .pull-left {
39 float: left !important;
39 float: left !important;
40 }
40 }
41
41
42 .block-left {
42 .block-left {
43 float: left;
43 float: left;
44 }
44 }
45
45
46 .block-right {
46 .block-right {
47 float: right;
47 float: right;
48 clear: right;
48 clear: right;
49
49
50 li {
50 li {
51 list-style-type: none;
51 list-style-type: none;
52 }
52 }
53 }
53 }
54
54
55 .noselect {
56 -webkit-touch-callout: none; /* iOS Safari */
57 -webkit-user-select: none; /* Safari */
58 -khtml-user-select: none; /* Konqueror HTML */
59 -moz-user-select: none; /* Firefox */
60 -ms-user-select: none; /* Internet Explorer/Edge */
61 user-select: none; /* Non-prefixed version, currently
62 supported by Chrome and Opera */
63 }
64
55 //--- DEVICE-SPECIFIC CLASSES ---------------//
65 //--- DEVICE-SPECIFIC CLASSES ---------------//
56 //regular tablet and up
66 //regular tablet and up
57 @media (min-width:768px) {
67 @media (min-width:768px) {
58 .no-mobile {
68 .no-mobile {
59 display: block;
69 display: block;
60 }
70 }
61 .mobile-only {
71 .mobile-only {
62 display: none;
72 display: none;
63 }
73 }
64 }
74 }
65 //small tablet and phone
75 //small tablet and phone
66 @media (max-width:767px) {
76 @media (max-width:767px) {
67 .mobile-only {
77 .mobile-only {
68 display: block;
78 display: block;
69 }
79 }
70 .no-mobile {
80 .no-mobile {
71 display: none;
81 display: none;
72 }
82 }
73 }
83 }
74
84
75 //--- STICKY FOOTER ---//
85 //--- STICKY FOOTER ---//
76 html, body {
86 html, body {
77 height: 100%;
87 height: 100%;
78 margin: 0;
88 margin: 0;
79 }
89 }
80 .outerwrapper {
90 .outerwrapper {
81 height: 100%;
91 height: 100%;
82 min-height: 100%;
92 min-height: 100%;
83 margin: 0;
93 margin: 0;
84 padding-bottom: 3em; /* must be equal to footer height */
94 padding-bottom: 3em; /* must be equal to footer height */
85 }
95 }
86 .outerwrapper:after{
96 .outerwrapper:after{
87 content:" ";
97 content:" ";
88 }
98 }
89 #footer {
99 #footer {
90 clear: both;
100 clear: both;
91 position: relative;
101 position: relative;
92 height: 3em; /* footer height */
102 height: 3em; /* footer height */
93 margin: -3em 0 0; /* must be equal to footer height */
103 margin: -3em 0 0; /* must be equal to footer height */
94 }
104 }
@@ -1,2985 +1,3037 b''
1 //Primary CSS
1 //Primary CSS
2
2
3 //--- IMPORTS ------------------//
3 //--- IMPORTS ------------------//
4
4
5 @import 'helpers';
5 @import 'helpers';
6 @import 'mixins';
6 @import 'mixins';
7 @import 'rcicons';
7 @import 'rcicons';
8 @import 'variables';
8 @import 'variables';
9 @import 'bootstrap-variables';
9 @import 'bootstrap-variables';
10 @import 'form-bootstrap';
10 @import 'form-bootstrap';
11 @import 'codemirror';
11 @import 'codemirror';
12 @import 'legacy_code_styles';
12 @import 'legacy_code_styles';
13 @import 'readme-box';
13 @import 'readme-box';
14 @import 'progress-bar';
14 @import 'progress-bar';
15
15
16 @import 'type';
16 @import 'type';
17 @import 'alerts';
17 @import 'alerts';
18 @import 'buttons';
18 @import 'buttons';
19 @import 'tags';
19 @import 'tags';
20 @import 'code-block';
20 @import 'code-block';
21 @import 'examples';
21 @import 'examples';
22 @import 'login';
22 @import 'login';
23 @import 'main-content';
23 @import 'main-content';
24 @import 'select2';
24 @import 'select2';
25 @import 'comments';
25 @import 'comments';
26 @import 'panels-bootstrap';
26 @import 'panels-bootstrap';
27 @import 'panels';
27 @import 'panels';
28 @import 'deform';
28 @import 'deform';
29 @import 'tooltips';
29 @import 'tooltips';
30
30
31 //--- BASE ------------------//
31 //--- BASE ------------------//
32 .noscript-error {
32 .noscript-error {
33 top: 0;
33 top: 0;
34 left: 0;
34 left: 0;
35 width: 100%;
35 width: 100%;
36 z-index: 101;
36 z-index: 101;
37 text-align: center;
37 text-align: center;
38 font-size: 120%;
38 font-size: 120%;
39 color: white;
39 color: white;
40 background-color: @alert2;
40 background-color: @alert2;
41 padding: 5px 0 5px 0;
41 padding: 5px 0 5px 0;
42 font-weight: @text-semibold-weight;
42 font-weight: @text-semibold-weight;
43 font-family: @text-semibold;
43 font-family: @text-semibold;
44 }
44 }
45
45
46 html {
46 html {
47 display: table;
47 display: table;
48 height: 100%;
48 height: 100%;
49 width: 100%;
49 width: 100%;
50 }
50 }
51
51
52 body {
52 body {
53 display: table-cell;
53 display: table-cell;
54 width: 100%;
54 width: 100%;
55 }
55 }
56
56
57 //--- LAYOUT ------------------//
57 //--- LAYOUT ------------------//
58
58
59 .hidden{
59 .hidden{
60 display: none !important;
60 display: none !important;
61 }
61 }
62
62
63 .box{
63 .box{
64 float: left;
64 float: left;
65 width: 100%;
65 width: 100%;
66 }
66 }
67
67
68 .browser-header {
68 .browser-header {
69 clear: both;
69 clear: both;
70 }
70 }
71 .main {
71 .main {
72 clear: both;
72 clear: both;
73 padding:0 0 @pagepadding;
73 padding:0 0 @pagepadding;
74 height: auto;
74 height: auto;
75
75
76 &:after { //clearfix
76 &:after { //clearfix
77 content:"";
77 content:"";
78 clear:both;
78 clear:both;
79 width:100%;
79 width:100%;
80 display:block;
80 display:block;
81 }
81 }
82 }
82 }
83
83
84 .action-link{
84 .action-link{
85 margin-left: @padding;
85 margin-left: @padding;
86 padding-left: @padding;
86 padding-left: @padding;
87 border-left: @border-thickness solid @border-default-color;
87 border-left: @border-thickness solid @border-default-color;
88 }
88 }
89
89
90 input + .action-link, .action-link.first{
90 input + .action-link, .action-link.first{
91 border-left: none;
91 border-left: none;
92 }
92 }
93
93
94 .action-link.last{
94 .action-link.last{
95 margin-right: @padding;
95 margin-right: @padding;
96 padding-right: @padding;
96 padding-right: @padding;
97 }
97 }
98
98
99 .action-link.active,
99 .action-link.active,
100 .action-link.active a{
100 .action-link.active a{
101 color: @grey4;
101 color: @grey4;
102 }
102 }
103
103
104 .action-link.disabled {
104 .action-link.disabled {
105 color: @grey4;
105 color: @grey4;
106 cursor: inherit;
106 cursor: inherit;
107 }
107 }
108
108
109
109
110 .clipboard-action {
110 .clipboard-action {
111 cursor: pointer;
111 cursor: pointer;
112 margin-left: 5px;
112 margin-left: 5px;
113
113
114 &:not(.no-grey) {
114 &:not(.no-grey) {
115
115
116 &:hover {
116 &:hover {
117 color: @grey2;
117 color: @grey2;
118 }
118 }
119 color: @grey4;
119 color: @grey4;
120 }
120 }
121 }
121 }
122
122
123 ul.simple-list{
123 ul.simple-list{
124 list-style: none;
124 list-style: none;
125 margin: 0;
125 margin: 0;
126 padding: 0;
126 padding: 0;
127 }
127 }
128
128
129 .main-content {
129 .main-content {
130 padding-bottom: @pagepadding;
130 padding-bottom: @pagepadding;
131 }
131 }
132
132
133 .wide-mode-wrapper {
133 .wide-mode-wrapper {
134 max-width:4000px !important;
134 max-width:4000px !important;
135 }
135 }
136
136
137 .wrapper {
137 .wrapper {
138 position: relative;
138 position: relative;
139 max-width: @wrapper-maxwidth;
139 max-width: @wrapper-maxwidth;
140 margin: 0 auto;
140 margin: 0 auto;
141 }
141 }
142
142
143 #content {
143 #content {
144 clear: both;
144 clear: both;
145 padding: 0 @contentpadding;
145 padding: 0 @contentpadding;
146 }
146 }
147
147
148 .advanced-settings-fields{
148 .advanced-settings-fields{
149 input{
149 input{
150 margin-left: @textmargin;
150 margin-left: @textmargin;
151 margin-right: @padding/2;
151 margin-right: @padding/2;
152 }
152 }
153 }
153 }
154
154
155 .cs_files_title {
155 .cs_files_title {
156 margin: @pagepadding 0 0;
156 margin: @pagepadding 0 0;
157 }
157 }
158
158
159 input.inline[type="file"] {
159 input.inline[type="file"] {
160 display: inline;
160 display: inline;
161 }
161 }
162
162
163 .error_page {
163 .error_page {
164 margin: 10% auto;
164 margin: 10% auto;
165
165
166 h1 {
166 h1 {
167 color: @grey2;
167 color: @grey2;
168 }
168 }
169
169
170 .alert {
170 .alert {
171 margin: @padding 0;
171 margin: @padding 0;
172 }
172 }
173
173
174 .error-branding {
174 .error-branding {
175 color: @grey4;
175 color: @grey4;
176 font-weight: @text-semibold-weight;
176 font-weight: @text-semibold-weight;
177 font-family: @text-semibold;
177 font-family: @text-semibold;
178 }
178 }
179
179
180 .error_message {
180 .error_message {
181 font-family: @text-regular;
181 font-family: @text-regular;
182 }
182 }
183
183
184 .sidebar {
184 .sidebar {
185 min-height: 275px;
185 min-height: 275px;
186 margin: 0;
186 margin: 0;
187 padding: 0 0 @sidebarpadding @sidebarpadding;
187 padding: 0 0 @sidebarpadding @sidebarpadding;
188 border: none;
188 border: none;
189 }
189 }
190
190
191 .main-content {
191 .main-content {
192 position: relative;
192 position: relative;
193 margin: 0 @sidebarpadding @sidebarpadding;
193 margin: 0 @sidebarpadding @sidebarpadding;
194 padding: 0 0 0 @sidebarpadding;
194 padding: 0 0 0 @sidebarpadding;
195 border-left: @border-thickness solid @grey5;
195 border-left: @border-thickness solid @grey5;
196
196
197 @media (max-width:767px) {
197 @media (max-width:767px) {
198 clear: both;
198 clear: both;
199 width: 100%;
199 width: 100%;
200 margin: 0;
200 margin: 0;
201 border: none;
201 border: none;
202 }
202 }
203 }
203 }
204
204
205 .inner-column {
205 .inner-column {
206 float: left;
206 float: left;
207 width: 29.75%;
207 width: 29.75%;
208 min-height: 150px;
208 min-height: 150px;
209 margin: @sidebarpadding 2% 0 0;
209 margin: @sidebarpadding 2% 0 0;
210 padding: 0 2% 0 0;
210 padding: 0 2% 0 0;
211 border-right: @border-thickness solid @grey5;
211 border-right: @border-thickness solid @grey5;
212
212
213 @media (max-width:767px) {
213 @media (max-width:767px) {
214 clear: both;
214 clear: both;
215 width: 100%;
215 width: 100%;
216 border: none;
216 border: none;
217 }
217 }
218
218
219 ul {
219 ul {
220 padding-left: 1.25em;
220 padding-left: 1.25em;
221 }
221 }
222
222
223 &:last-child {
223 &:last-child {
224 margin: @sidebarpadding 0 0;
224 margin: @sidebarpadding 0 0;
225 border: none;
225 border: none;
226 }
226 }
227
227
228 h4 {
228 h4 {
229 margin: 0 0 @padding;
229 margin: 0 0 @padding;
230 font-weight: @text-semibold-weight;
230 font-weight: @text-semibold-weight;
231 font-family: @text-semibold;
231 font-family: @text-semibold;
232 }
232 }
233 }
233 }
234 }
234 }
235 .error-page-logo {
235 .error-page-logo {
236 width: 130px;
236 width: 130px;
237 height: 160px;
237 height: 160px;
238 }
238 }
239
239
240 // HEADER
240 // HEADER
241 .header {
241 .header {
242
242
243 // TODO: johbo: Fix login pages, so that they work without a min-height
243 // TODO: johbo: Fix login pages, so that they work without a min-height
244 // for the header and then remove the min-height. I chose a smaller value
244 // for the header and then remove the min-height. I chose a smaller value
245 // intentionally here to avoid rendering issues in the main navigation.
245 // intentionally here to avoid rendering issues in the main navigation.
246 min-height: 49px;
246 min-height: 49px;
247 min-width: 1024px;
247 min-width: 1024px;
248
248
249 position: relative;
249 position: relative;
250 vertical-align: bottom;
250 vertical-align: bottom;
251 padding: 0 @header-padding;
251 padding: 0 @header-padding;
252 background-color: @grey1;
252 background-color: @grey1;
253 color: @grey5;
253 color: @grey5;
254
254
255 .title {
255 .title {
256 overflow: visible;
256 overflow: visible;
257 }
257 }
258
258
259 &:before,
259 &:before,
260 &:after {
260 &:after {
261 content: "";
261 content: "";
262 clear: both;
262 clear: both;
263 width: 100%;
263 width: 100%;
264 }
264 }
265
265
266 // TODO: johbo: Avoids breaking "Repositories" chooser
266 // TODO: johbo: Avoids breaking "Repositories" chooser
267 .select2-container .select2-choice .select2-arrow {
267 .select2-container .select2-choice .select2-arrow {
268 display: none;
268 display: none;
269 }
269 }
270 }
270 }
271
271
272 #header-inner {
272 #header-inner {
273 &.title {
273 &.title {
274 margin: 0;
274 margin: 0;
275 }
275 }
276 &:before,
276 &:before,
277 &:after {
277 &:after {
278 content: "";
278 content: "";
279 clear: both;
279 clear: both;
280 }
280 }
281 }
281 }
282
282
283 // Gists
283 // Gists
284 #files_data {
284 #files_data {
285 clear: both; //for firefox
285 clear: both; //for firefox
286 padding-top: 10px;
286 padding-top: 10px;
287 }
287 }
288
288
289 #gistid {
289 #gistid {
290 margin-right: @padding;
290 margin-right: @padding;
291 }
291 }
292
292
293 // Global Settings Editor
293 // Global Settings Editor
294 .textarea.editor {
294 .textarea.editor {
295 float: left;
295 float: left;
296 position: relative;
296 position: relative;
297 max-width: @texteditor-width;
297 max-width: @texteditor-width;
298
298
299 select {
299 select {
300 position: absolute;
300 position: absolute;
301 top:10px;
301 top:10px;
302 right:0;
302 right:0;
303 }
303 }
304
304
305 .CodeMirror {
305 .CodeMirror {
306 margin: 0;
306 margin: 0;
307 }
307 }
308
308
309 .help-block {
309 .help-block {
310 margin: 0 0 @padding;
310 margin: 0 0 @padding;
311 padding:.5em;
311 padding:.5em;
312 background-color: @grey6;
312 background-color: @grey6;
313 &.pre-formatting {
313 &.pre-formatting {
314 white-space: pre;
314 white-space: pre;
315 }
315 }
316 }
316 }
317 }
317 }
318
318
319 ul.auth_plugins {
319 ul.auth_plugins {
320 margin: @padding 0 @padding @legend-width;
320 margin: @padding 0 @padding @legend-width;
321 padding: 0;
321 padding: 0;
322
322
323 li {
323 li {
324 margin-bottom: @padding;
324 margin-bottom: @padding;
325 line-height: 1em;
325 line-height: 1em;
326 list-style-type: none;
326 list-style-type: none;
327
327
328 .auth_buttons .btn {
328 .auth_buttons .btn {
329 margin-right: @padding;
329 margin-right: @padding;
330 }
330 }
331
331
332 }
332 }
333 }
333 }
334
334
335
335
336 // My Account PR list
336 // My Account PR list
337
337
338 #show_closed {
338 #show_closed {
339 margin: 0 1em 0 0;
339 margin: 0 1em 0 0;
340 }
340 }
341
341
342 #pull_request_list_table {
342 #pull_request_list_table {
343 .closed {
343 .closed {
344 background-color: @grey6;
344 background-color: @grey6;
345 }
345 }
346
346
347 .state-creating,
347 .state-creating,
348 .state-updating,
348 .state-updating,
349 .state-merging
349 .state-merging
350 {
350 {
351 background-color: @grey6;
351 background-color: @grey6;
352 }
352 }
353
353
354 .td-status {
354 .td-status {
355 padding-left: .5em;
355 padding-left: .5em;
356 }
356 }
357 .log-container .truncate {
357 .log-container .truncate {
358 height: 2.75em;
358 height: 2.75em;
359 white-space: pre-line;
359 white-space: pre-line;
360 }
360 }
361 table.rctable .user {
361 table.rctable .user {
362 padding-left: 0;
362 padding-left: 0;
363 }
363 }
364 table.rctable {
364 table.rctable {
365 td.td-description,
365 td.td-description,
366 .rc-user {
366 .rc-user {
367 min-width: auto;
367 min-width: auto;
368 }
368 }
369 }
369 }
370 }
370 }
371
371
372 // Pull Requests
372 // Pull Requests
373
373
374 .pullrequests_section_head {
374 .pullrequests_section_head {
375 display: block;
375 display: block;
376 clear: both;
376 clear: both;
377 margin: @padding 0;
377 margin: @padding 0;
378 font-weight: @text-bold-weight;
378 font-weight: @text-bold-weight;
379 font-family: @text-bold;
379 font-family: @text-bold;
380 }
380 }
381
381
382 .pr-commit-flow {
382 .pr-commit-flow {
383 position: relative;
383 position: relative;
384 font-weight: 600;
384 font-weight: 600;
385
385
386 .tag {
386 .tag {
387 display: inline-block;
387 display: inline-block;
388 margin: 0 1em .5em 0;
388 margin: 0 1em .5em 0;
389 }
389 }
390
390
391 .clone-url {
391 .clone-url {
392 display: inline-block;
392 display: inline-block;
393 margin: 0 0 .5em 0;
393 margin: 0 0 .5em 0;
394 padding: 0;
394 padding: 0;
395 line-height: 1.2em;
395 line-height: 1.2em;
396 }
396 }
397 }
397 }
398
398
399 .pr-mergeinfo {
399 .pr-mergeinfo {
400 min-width: 95% !important;
400 min-width: 95% !important;
401 padding: 0 !important;
401 padding: 0 !important;
402 border: 0;
402 border: 0;
403 }
403 }
404 .pr-mergeinfo-copy {
404 .pr-mergeinfo-copy {
405 padding: 0 0;
405 padding: 0 0;
406 }
406 }
407
407
408 .pr-pullinfo {
408 .pr-pullinfo {
409 min-width: 95% !important;
409 min-width: 95% !important;
410 padding: 0 !important;
410 padding: 0 !important;
411 border: 0;
411 border: 0;
412 }
412 }
413 .pr-pullinfo-copy {
413 .pr-pullinfo-copy {
414 padding: 0 0;
414 padding: 0 0;
415 }
415 }
416
416
417 .pr-title-input {
417 .pr-title-input {
418 width: 80%;
418 width: 80%;
419 font-size: 1em;
419 font-size: 1em;
420 margin: 0 0 4px 0;
420 margin: 0 0 4px 0;
421 padding: 0;
421 padding: 0;
422 line-height: 1.7em;
422 line-height: 1.7em;
423 color: @text-color;
423 color: @text-color;
424 letter-spacing: .02em;
424 letter-spacing: .02em;
425 font-weight: @text-bold-weight;
425 font-weight: @text-bold-weight;
426 font-family: @text-bold;
426 font-family: @text-bold;
427
427
428 &:hover {
428 &:hover {
429 box-shadow: none;
429 box-shadow: none;
430 }
430 }
431 }
431 }
432
432
433 #pr-title {
433 #pr-title {
434 input {
434 input {
435 border: 1px transparent;
435 border: 1px transparent;
436 color: black;
436 color: black;
437 opacity: 1
437 opacity: 1;
438 background: #fff;
438 }
439 }
439 }
440 }
440
441
441 .pr-title-closed-tag {
442 .pr-title-closed-tag {
442 font-size: 16px;
443 font-size: 16px;
443 }
444 }
444
445
445 #pr-desc {
446 #pr-desc {
446 padding: 10px 0;
447 padding: 10px 0;
447
448
448 .markdown-block {
449 .markdown-block {
449 padding: 0;
450 padding: 0;
450 margin-bottom: -30px;
451 margin-bottom: -30px;
451 }
452 }
452 }
453 }
453
454
454 #pullrequest_title {
455 #pullrequest_title {
455 width: 100%;
456 width: 100%;
456 box-sizing: border-box;
457 box-sizing: border-box;
457 }
458 }
458
459
459 #pr_open_message {
460 #pr_open_message {
460 border: @border-thickness solid #fff;
461 border: @border-thickness solid #fff;
461 border-radius: @border-radius;
462 border-radius: @border-radius;
462 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
463 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
463 text-align: left;
464 text-align: left;
464 overflow: hidden;
465 overflow: hidden;
465 }
466 }
466
467
467 .pr-details-title {
468 .pr-details-title {
468 height: 16px
469 height: 16px
469 }
470 }
470
471
471 .pr-details-title-author-pref {
472 .pr-details-title-author-pref {
472 padding-right: 10px
473 padding-right: 10px
473 }
474 }
474
475
475 .label-pr-detail {
476 .label-pr-detail {
476 display: table-cell;
477 display: table-cell;
477 width: 120px;
478 width: 120px;
478 padding-top: 7.5px;
479 padding-top: 7.5px;
479 padding-bottom: 7.5px;
480 padding-bottom: 7.5px;
480 padding-right: 7.5px;
481 padding-right: 7.5px;
481 }
482 }
482
483
483 .source-details ul {
484 .source-details ul {
484 padding: 10px 16px;
485 padding: 10px 16px;
485 }
486 }
486
487
487 .source-details-action {
488 .source-details-action {
488 color: @grey4;
489 color: @grey4;
489 font-size: 11px
490 font-size: 11px
490 }
491 }
491
492
492 .pr-submit-button {
493 .pr-submit-button {
493 float: right;
494 float: right;
494 margin: 0 0 0 5px;
495 margin: 0 0 0 5px;
495 }
496 }
496
497
497 .pr-spacing-container {
498 .pr-spacing-container {
498 padding: 20px;
499 padding: 20px;
499 clear: both
500 clear: both
500 }
501 }
501
502
502 #pr-description-input {
503 #pr-description-input {
503 margin-bottom: 0;
504 margin-bottom: 0;
504 }
505 }
505
506
506 .pr-description-label {
507 .pr-description-label {
507 vertical-align: top;
508 vertical-align: top;
508 }
509 }
509
510
511 #open_edit_pullrequest {
512 padding: 0;
513 }
514
510 #close_edit_pullrequest {
515 #close_edit_pullrequest {
511 padding-left: 1em
516
512 }
517 }
513
518
514 #delete_pullrequest {
519 #delete_pullrequest {
515 clear: inherit;
520 clear: inherit;
516 padding: 0
521
522 form {
523 display: inline;
524 }
525
517 }
526 }
518
527
519 .perms_section_head {
528 .perms_section_head {
520 min-width: 625px;
529 min-width: 625px;
521
530
522 h2 {
531 h2 {
523 margin-bottom: 0;
532 margin-bottom: 0;
524 }
533 }
525
534
526 .label-checkbox {
535 .label-checkbox {
527 float: left;
536 float: left;
528 }
537 }
529
538
530 &.field {
539 &.field {
531 margin: @space 0 @padding;
540 margin: @space 0 @padding;
532 }
541 }
533
542
534 &:first-child.field {
543 &:first-child.field {
535 margin-top: 0;
544 margin-top: 0;
536
545
537 .label {
546 .label {
538 margin-top: 0;
547 margin-top: 0;
539 padding-top: 0;
548 padding-top: 0;
540 }
549 }
541
550
542 .radios {
551 .radios {
543 padding-top: 0;
552 padding-top: 0;
544 }
553 }
545 }
554 }
546
555
547 .radios {
556 .radios {
548 position: relative;
557 position: relative;
549 width: 505px;
558 width: 505px;
550 }
559 }
551 }
560 }
552
561
553 //--- MODULES ------------------//
562 //--- MODULES ------------------//
554
563
555
564
556 // Server Announcement
565 // Server Announcement
557 #server-announcement {
566 #server-announcement {
558 width: 95%;
567 width: 95%;
559 margin: @padding auto;
568 margin: @padding auto;
560 padding: @padding;
569 padding: @padding;
561 border-width: 2px;
570 border-width: 2px;
562 border-style: solid;
571 border-style: solid;
563 .border-radius(2px);
572 .border-radius(2px);
564 font-weight: @text-bold-weight;
573 font-weight: @text-bold-weight;
565 font-family: @text-bold;
574 font-family: @text-bold;
566
575
567 &.info { border-color: @alert4; background-color: @alert4-inner; }
576 &.info { border-color: @alert4; background-color: @alert4-inner; }
568 &.warning { border-color: @alert3; background-color: @alert3-inner; }
577 &.warning { border-color: @alert3; background-color: @alert3-inner; }
569 &.error { border-color: @alert2; background-color: @alert2-inner; }
578 &.error { border-color: @alert2; background-color: @alert2-inner; }
570 &.success { border-color: @alert1; background-color: @alert1-inner; }
579 &.success { border-color: @alert1; background-color: @alert1-inner; }
571 &.neutral { border-color: @grey3; background-color: @grey6; }
580 &.neutral { border-color: @grey3; background-color: @grey6; }
572 }
581 }
573
582
574 // Fixed Sidebar Column
583 // Fixed Sidebar Column
575 .sidebar-col-wrapper {
584 .sidebar-col-wrapper {
576 padding-left: @sidebar-all-width;
585 padding-left: @sidebar-all-width;
577
586
578 .sidebar {
587 .sidebar {
579 width: @sidebar-width;
588 width: @sidebar-width;
580 margin-left: -@sidebar-all-width;
589 margin-left: -@sidebar-all-width;
581 }
590 }
582 }
591 }
583
592
584 .sidebar-col-wrapper.scw-small {
593 .sidebar-col-wrapper.scw-small {
585 padding-left: @sidebar-small-all-width;
594 padding-left: @sidebar-small-all-width;
586
595
587 .sidebar {
596 .sidebar {
588 width: @sidebar-small-width;
597 width: @sidebar-small-width;
589 margin-left: -@sidebar-small-all-width;
598 margin-left: -@sidebar-small-all-width;
590 }
599 }
591 }
600 }
592
601
593
602
594 // FOOTER
603 // FOOTER
595 #footer {
604 #footer {
596 padding: 0;
605 padding: 0;
597 text-align: center;
606 text-align: center;
598 vertical-align: middle;
607 vertical-align: middle;
599 color: @grey2;
608 color: @grey2;
600 font-size: 11px;
609 font-size: 11px;
601
610
602 p {
611 p {
603 margin: 0;
612 margin: 0;
604 padding: 1em;
613 padding: 1em;
605 line-height: 1em;
614 line-height: 1em;
606 }
615 }
607
616
608 .server-instance { //server instance
617 .server-instance { //server instance
609 display: none;
618 display: none;
610 }
619 }
611
620
612 .title {
621 .title {
613 float: none;
622 float: none;
614 margin: 0 auto;
623 margin: 0 auto;
615 }
624 }
616 }
625 }
617
626
618 button.close {
627 button.close {
619 padding: 0;
628 padding: 0;
620 cursor: pointer;
629 cursor: pointer;
621 background: transparent;
630 background: transparent;
622 border: 0;
631 border: 0;
623 .box-shadow(none);
632 .box-shadow(none);
624 -webkit-appearance: none;
633 -webkit-appearance: none;
625 }
634 }
626
635
627 .close {
636 .close {
628 float: right;
637 float: right;
629 font-size: 21px;
638 font-size: 21px;
630 font-family: @text-bootstrap;
639 font-family: @text-bootstrap;
631 line-height: 1em;
640 line-height: 1em;
632 font-weight: bold;
641 font-weight: bold;
633 color: @grey2;
642 color: @grey2;
634
643
635 &:hover,
644 &:hover,
636 &:focus {
645 &:focus {
637 color: @grey1;
646 color: @grey1;
638 text-decoration: none;
647 text-decoration: none;
639 cursor: pointer;
648 cursor: pointer;
640 }
649 }
641 }
650 }
642
651
643 // GRID
652 // GRID
644 .sorting,
653 .sorting,
645 .sorting_desc,
654 .sorting_desc,
646 .sorting_asc {
655 .sorting_asc {
647 cursor: pointer;
656 cursor: pointer;
648 }
657 }
649 .sorting_desc:after {
658 .sorting_desc:after {
650 content: "\00A0\25B2";
659 content: "\00A0\25B2";
651 font-size: .75em;
660 font-size: .75em;
652 }
661 }
653 .sorting_asc:after {
662 .sorting_asc:after {
654 content: "\00A0\25BC";
663 content: "\00A0\25BC";
655 font-size: .68em;
664 font-size: .68em;
656 }
665 }
657
666
658
667
659 .user_auth_tokens {
668 .user_auth_tokens {
660
669
661 &.truncate {
670 &.truncate {
662 white-space: nowrap;
671 white-space: nowrap;
663 overflow: hidden;
672 overflow: hidden;
664 text-overflow: ellipsis;
673 text-overflow: ellipsis;
665 }
674 }
666
675
667 .fields .field .input {
676 .fields .field .input {
668 margin: 0;
677 margin: 0;
669 }
678 }
670
679
671 input#description {
680 input#description {
672 width: 100px;
681 width: 100px;
673 margin: 0;
682 margin: 0;
674 }
683 }
675
684
676 .drop-menu {
685 .drop-menu {
677 // TODO: johbo: Remove this, should work out of the box when
686 // TODO: johbo: Remove this, should work out of the box when
678 // having multiple inputs inline
687 // having multiple inputs inline
679 margin: 0 0 0 5px;
688 margin: 0 0 0 5px;
680 }
689 }
681 }
690 }
682 #user_list_table {
691 #user_list_table {
683 .closed {
692 .closed {
684 background-color: @grey6;
693 background-color: @grey6;
685 }
694 }
686 }
695 }
687
696
688
697
689 input, textarea {
698 input, textarea {
690 &.disabled {
699 &.disabled {
691 opacity: .5;
700 opacity: .5;
692 }
701 }
693
702
694 &:hover {
703 &:hover {
695 border-color: @grey3;
704 border-color: @grey3;
696 box-shadow: @button-shadow;
705 box-shadow: @button-shadow;
697 }
706 }
698
707
699 &:focus {
708 &:focus {
700 border-color: @rcblue;
709 border-color: @rcblue;
701 box-shadow: @button-shadow;
710 box-shadow: @button-shadow;
702 }
711 }
703 }
712 }
704
713
705 // remove extra padding in firefox
714 // remove extra padding in firefox
706 input::-moz-focus-inner { border:0; padding:0 }
715 input::-moz-focus-inner { border:0; padding:0 }
707
716
708 .adjacent input {
717 .adjacent input {
709 margin-bottom: @padding;
718 margin-bottom: @padding;
710 }
719 }
711
720
712 .permissions_boxes {
721 .permissions_boxes {
713 display: block;
722 display: block;
714 }
723 }
715
724
716 //FORMS
725 //FORMS
717
726
718 .medium-inline,
727 .medium-inline,
719 input#description.medium-inline {
728 input#description.medium-inline {
720 display: inline;
729 display: inline;
721 width: @medium-inline-input-width;
730 width: @medium-inline-input-width;
722 min-width: 100px;
731 min-width: 100px;
723 }
732 }
724
733
725 select {
734 select {
726 //reset
735 //reset
727 -webkit-appearance: none;
736 -webkit-appearance: none;
728 -moz-appearance: none;
737 -moz-appearance: none;
729
738
730 display: inline-block;
739 display: inline-block;
731 height: 28px;
740 height: 28px;
732 width: auto;
741 width: auto;
733 margin: 0 @padding @padding 0;
742 margin: 0 @padding @padding 0;
734 padding: 0 18px 0 8px;
743 padding: 0 18px 0 8px;
735 line-height:1em;
744 line-height:1em;
736 font-size: @basefontsize;
745 font-size: @basefontsize;
737 border: @border-thickness solid @grey5;
746 border: @border-thickness solid @grey5;
738 border-radius: @border-radius;
747 border-radius: @border-radius;
739 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
748 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
740 color: @grey4;
749 color: @grey4;
741 box-shadow: @button-shadow;
750 box-shadow: @button-shadow;
742
751
743 &:after {
752 &:after {
744 content: "\00A0\25BE";
753 content: "\00A0\25BE";
745 }
754 }
746
755
747 &:focus, &:hover {
756 &:focus, &:hover {
748 outline: none;
757 outline: none;
749 border-color: @grey4;
758 border-color: @grey4;
750 color: @rcdarkblue;
759 color: @rcdarkblue;
751 }
760 }
752 }
761 }
753
762
754 option {
763 option {
755 &:focus {
764 &:focus {
756 outline: none;
765 outline: none;
757 }
766 }
758 }
767 }
759
768
760 input,
769 input,
761 textarea {
770 textarea {
762 padding: @input-padding;
771 padding: @input-padding;
763 border: @input-border-thickness solid @border-highlight-color;
772 border: @input-border-thickness solid @border-highlight-color;
764 .border-radius (@border-radius);
773 .border-radius (@border-radius);
765 font-family: @text-light;
774 font-family: @text-light;
766 font-size: @basefontsize;
775 font-size: @basefontsize;
767
776
768 &.input-sm {
777 &.input-sm {
769 padding: 5px;
778 padding: 5px;
770 }
779 }
771
780
772 &#description {
781 &#description {
773 min-width: @input-description-minwidth;
782 min-width: @input-description-minwidth;
774 min-height: 1em;
783 min-height: 1em;
775 padding: 10px;
784 padding: 10px;
776 }
785 }
777 }
786 }
778
787
779 .field-sm {
788 .field-sm {
780 input,
789 input,
781 textarea {
790 textarea {
782 padding: 5px;
791 padding: 5px;
783 }
792 }
784 }
793 }
785
794
786 textarea {
795 textarea {
787 display: block;
796 display: block;
788 clear: both;
797 clear: both;
789 width: 100%;
798 width: 100%;
790 min-height: 100px;
799 min-height: 100px;
791 margin-bottom: @padding;
800 margin-bottom: @padding;
792 .box-sizing(border-box);
801 .box-sizing(border-box);
793 overflow: auto;
802 overflow: auto;
794 }
803 }
795
804
796 label {
805 label {
797 font-family: @text-light;
806 font-family: @text-light;
798 }
807 }
799
808
800 // GRAVATARS
809 // GRAVATARS
801 // centers gravatar on username to the right
810 // centers gravatar on username to the right
802
811
803 .gravatar {
812 .gravatar {
804 display: inline;
813 display: inline;
805 min-width: 16px;
814 min-width: 16px;
806 min-height: 16px;
815 min-height: 16px;
807 margin: -5px 0;
816 margin: -5px 0;
808 padding: 0;
817 padding: 0;
809 line-height: 1em;
818 line-height: 1em;
810 box-sizing: content-box;
819 box-sizing: content-box;
811 border-radius: 50%;
820 border-radius: 50%;
812
821
813 &.gravatar-large {
822 &.gravatar-large {
814 margin: -0.5em .25em -0.5em 0;
823 margin: -0.5em .25em -0.5em 0;
815 }
824 }
816
825
817 & + .user {
826 & + .user {
818 display: inline;
827 display: inline;
819 margin: 0;
828 margin: 0;
820 padding: 0 0 0 .17em;
829 padding: 0 0 0 .17em;
821 line-height: 1em;
830 line-height: 1em;
822 }
831 }
832
833 & + .no-margin {
834 margin: 0
835 }
836
823 }
837 }
824
838
825 .user-inline-data {
839 .user-inline-data {
826 display: inline-block;
840 display: inline-block;
827 float: left;
841 float: left;
828 padding-left: .5em;
842 padding-left: .5em;
829 line-height: 1.3em;
843 line-height: 1.3em;
830 }
844 }
831
845
832 .rc-user { // gravatar + user wrapper
846 .rc-user { // gravatar + user wrapper
833 float: left;
847 float: left;
834 position: relative;
848 position: relative;
835 min-width: 100px;
849 min-width: 100px;
836 max-width: 200px;
850 max-width: 200px;
837 min-height: (@gravatar-size + @border-thickness * 2); // account for border
851 min-height: (@gravatar-size + @border-thickness * 2); // account for border
838 display: block;
852 display: block;
839 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
853 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
840
854
841
855
842 .gravatar {
856 .gravatar {
843 display: block;
857 display: block;
844 position: absolute;
858 position: absolute;
845 top: 0;
859 top: 0;
846 left: 0;
860 left: 0;
847 min-width: @gravatar-size;
861 min-width: @gravatar-size;
848 min-height: @gravatar-size;
862 min-height: @gravatar-size;
849 margin: 0;
863 margin: 0;
850 }
864 }
851
865
852 .user {
866 .user {
853 display: block;
867 display: block;
854 max-width: 175px;
868 max-width: 175px;
855 padding-top: 2px;
869 padding-top: 2px;
856 overflow: hidden;
870 overflow: hidden;
857 text-overflow: ellipsis;
871 text-overflow: ellipsis;
858 }
872 }
859 }
873 }
860
874
861 .gist-gravatar,
875 .gist-gravatar,
862 .journal_container {
876 .journal_container {
863 .gravatar-large {
877 .gravatar-large {
864 margin: 0 .5em -10px 0;
878 margin: 0 .5em -10px 0;
865 }
879 }
866 }
880 }
867
881
868 .gist-type-fields {
882 .gist-type-fields {
869 line-height: 30px;
883 line-height: 30px;
870 height: 30px;
884 height: 30px;
871
885
872 .gist-type-fields-wrapper {
886 .gist-type-fields-wrapper {
873 vertical-align: middle;
887 vertical-align: middle;
874 display: inline-block;
888 display: inline-block;
875 line-height: 25px;
889 line-height: 25px;
876 }
890 }
877 }
891 }
878
892
879 // ADMIN SETTINGS
893 // ADMIN SETTINGS
880
894
881 // Tag Patterns
895 // Tag Patterns
882 .tag_patterns {
896 .tag_patterns {
883 .tag_input {
897 .tag_input {
884 margin-bottom: @padding;
898 margin-bottom: @padding;
885 }
899 }
886 }
900 }
887
901
888 .locked_input {
902 .locked_input {
889 position: relative;
903 position: relative;
890
904
891 input {
905 input {
892 display: inline;
906 display: inline;
893 margin: 3px 5px 0px 0px;
907 margin: 3px 5px 0px 0px;
894 }
908 }
895
909
896 br {
910 br {
897 display: none;
911 display: none;
898 }
912 }
899
913
900 .error-message {
914 .error-message {
901 float: left;
915 float: left;
902 width: 100%;
916 width: 100%;
903 }
917 }
904
918
905 .lock_input_button {
919 .lock_input_button {
906 display: inline;
920 display: inline;
907 }
921 }
908
922
909 .help-block {
923 .help-block {
910 clear: both;
924 clear: both;
911 }
925 }
912 }
926 }
913
927
914 // Notifications
928 // Notifications
915
929
916 .notifications_buttons {
930 .notifications_buttons {
917 margin: 0 0 @space 0;
931 margin: 0 0 @space 0;
918 padding: 0;
932 padding: 0;
919
933
920 .btn {
934 .btn {
921 display: inline-block;
935 display: inline-block;
922 }
936 }
923 }
937 }
924
938
925 .notification-list {
939 .notification-list {
926
940
927 div {
941 div {
928 vertical-align: middle;
942 vertical-align: middle;
929 }
943 }
930
944
931 .container {
945 .container {
932 display: block;
946 display: block;
933 margin: 0 0 @padding 0;
947 margin: 0 0 @padding 0;
934 }
948 }
935
949
936 .delete-notifications {
950 .delete-notifications {
937 margin-left: @padding;
951 margin-left: @padding;
938 text-align: right;
952 text-align: right;
939 cursor: pointer;
953 cursor: pointer;
940 }
954 }
941
955
942 .read-notifications {
956 .read-notifications {
943 margin-left: @padding/2;
957 margin-left: @padding/2;
944 text-align: right;
958 text-align: right;
945 width: 35px;
959 width: 35px;
946 cursor: pointer;
960 cursor: pointer;
947 }
961 }
948
962
949 .icon-minus-sign {
963 .icon-minus-sign {
950 color: @alert2;
964 color: @alert2;
951 }
965 }
952
966
953 .icon-ok-sign {
967 .icon-ok-sign {
954 color: @alert1;
968 color: @alert1;
955 }
969 }
956 }
970 }
957
971
958 .user_settings {
972 .user_settings {
959 float: left;
973 float: left;
960 clear: both;
974 clear: both;
961 display: block;
975 display: block;
962 width: 100%;
976 width: 100%;
963
977
964 .gravatar_box {
978 .gravatar_box {
965 margin-bottom: @padding;
979 margin-bottom: @padding;
966
980
967 &:after {
981 &:after {
968 content: " ";
982 content: " ";
969 clear: both;
983 clear: both;
970 width: 100%;
984 width: 100%;
971 }
985 }
972 }
986 }
973
987
974 .fields .field {
988 .fields .field {
975 clear: both;
989 clear: both;
976 }
990 }
977 }
991 }
978
992
979 .advanced_settings {
993 .advanced_settings {
980 margin-bottom: @space;
994 margin-bottom: @space;
981
995
982 .help-block {
996 .help-block {
983 margin-left: 0;
997 margin-left: 0;
984 }
998 }
985
999
986 button + .help-block {
1000 button + .help-block {
987 margin-top: @padding;
1001 margin-top: @padding;
988 }
1002 }
989 }
1003 }
990
1004
991 // admin settings radio buttons and labels
1005 // admin settings radio buttons and labels
992 .label-2 {
1006 .label-2 {
993 float: left;
1007 float: left;
994 width: @label2-width;
1008 width: @label2-width;
995
1009
996 label {
1010 label {
997 color: @grey1;
1011 color: @grey1;
998 }
1012 }
999 }
1013 }
1000 .checkboxes {
1014 .checkboxes {
1001 float: left;
1015 float: left;
1002 width: @checkboxes-width;
1016 width: @checkboxes-width;
1003 margin-bottom: @padding;
1017 margin-bottom: @padding;
1004
1018
1005 .checkbox {
1019 .checkbox {
1006 width: 100%;
1020 width: 100%;
1007
1021
1008 label {
1022 label {
1009 margin: 0;
1023 margin: 0;
1010 padding: 0;
1024 padding: 0;
1011 }
1025 }
1012 }
1026 }
1013
1027
1014 .checkbox + .checkbox {
1028 .checkbox + .checkbox {
1015 display: inline-block;
1029 display: inline-block;
1016 }
1030 }
1017
1031
1018 label {
1032 label {
1019 margin-right: 1em;
1033 margin-right: 1em;
1020 }
1034 }
1021 }
1035 }
1022
1036
1023 // CHANGELOG
1037 // CHANGELOG
1024 .container_header {
1038 .container_header {
1025 float: left;
1039 float: left;
1026 display: block;
1040 display: block;
1027 width: 100%;
1041 width: 100%;
1028 margin: @padding 0 @padding;
1042 margin: @padding 0 @padding;
1029
1043
1030 #filter_changelog {
1044 #filter_changelog {
1031 float: left;
1045 float: left;
1032 margin-right: @padding;
1046 margin-right: @padding;
1033 }
1047 }
1034
1048
1035 .breadcrumbs_light {
1049 .breadcrumbs_light {
1036 display: inline-block;
1050 display: inline-block;
1037 }
1051 }
1038 }
1052 }
1039
1053
1040 .info_box {
1054 .info_box {
1041 float: right;
1055 float: right;
1042 }
1056 }
1043
1057
1044
1058
1045
1059
1046 #graph_content{
1060 #graph_content{
1047
1061
1048 // adjust for table headers so that graph renders properly
1062 // adjust for table headers so that graph renders properly
1049 // #graph_nodes padding - table cell padding
1063 // #graph_nodes padding - table cell padding
1050 padding-top: (@space - (@basefontsize * 2.4));
1064 padding-top: (@space - (@basefontsize * 2.4));
1051
1065
1052 &.graph_full_width {
1066 &.graph_full_width {
1053 width: 100%;
1067 width: 100%;
1054 max-width: 100%;
1068 max-width: 100%;
1055 }
1069 }
1056 }
1070 }
1057
1071
1058 #graph {
1072 #graph {
1059
1073
1060 .pagination-left {
1074 .pagination-left {
1061 float: left;
1075 float: left;
1062 clear: both;
1076 clear: both;
1063 }
1077 }
1064
1078
1065 .log-container {
1079 .log-container {
1066 max-width: 345px;
1080 max-width: 345px;
1067
1081
1068 .message{
1082 .message{
1069 max-width: 340px;
1083 max-width: 340px;
1070 }
1084 }
1071 }
1085 }
1072
1086
1073 .graph-col-wrapper {
1087 .graph-col-wrapper {
1074
1088
1075 #graph_nodes {
1089 #graph_nodes {
1076 width: 100px;
1090 width: 100px;
1077 position: absolute;
1091 position: absolute;
1078 left: 70px;
1092 left: 70px;
1079 z-index: -1;
1093 z-index: -1;
1080 }
1094 }
1081 }
1095 }
1082
1096
1083 .load-more-commits {
1097 .load-more-commits {
1084 text-align: center;
1098 text-align: center;
1085 }
1099 }
1086 .load-more-commits:hover {
1100 .load-more-commits:hover {
1087 background-color: @grey7;
1101 background-color: @grey7;
1088 }
1102 }
1089 .load-more-commits {
1103 .load-more-commits {
1090 a {
1104 a {
1091 display: block;
1105 display: block;
1092 }
1106 }
1093 }
1107 }
1094 }
1108 }
1095
1109
1096 .obsolete-toggle {
1110 .obsolete-toggle {
1097 line-height: 30px;
1111 line-height: 30px;
1098 margin-left: -15px;
1112 margin-left: -15px;
1099 }
1113 }
1100
1114
1101 #rev_range_container, #rev_range_clear, #rev_range_more {
1115 #rev_range_container, #rev_range_clear, #rev_range_more {
1102 margin-top: -5px;
1116 margin-top: -5px;
1103 margin-bottom: -5px;
1117 margin-bottom: -5px;
1104 }
1118 }
1105
1119
1106 #filter_changelog {
1120 #filter_changelog {
1107 float: left;
1121 float: left;
1108 }
1122 }
1109
1123
1110
1124
1111 //--- THEME ------------------//
1125 //--- THEME ------------------//
1112
1126
1113 #logo {
1127 #logo {
1114 float: left;
1128 float: left;
1115 margin: 9px 0 0 0;
1129 margin: 9px 0 0 0;
1116
1130
1117 .header {
1131 .header {
1118 background-color: transparent;
1132 background-color: transparent;
1119 }
1133 }
1120
1134
1121 a {
1135 a {
1122 display: inline-block;
1136 display: inline-block;
1123 }
1137 }
1124
1138
1125 img {
1139 img {
1126 height:30px;
1140 height:30px;
1127 }
1141 }
1128 }
1142 }
1129
1143
1130 .logo-wrapper {
1144 .logo-wrapper {
1131 float:left;
1145 float:left;
1132 }
1146 }
1133
1147
1134 .branding {
1148 .branding {
1135 float: left;
1149 float: left;
1136 padding: 9px 2px;
1150 padding: 9px 2px;
1137 line-height: 1em;
1151 line-height: 1em;
1138 font-size: @navigation-fontsize;
1152 font-size: @navigation-fontsize;
1139
1153
1140 a {
1154 a {
1141 color: @grey5
1155 color: @grey5
1142 }
1156 }
1143 @media screen and (max-width: 1200px) {
1157 @media screen and (max-width: 1200px) {
1144 display: none;
1158 display: none;
1145 }
1159 }
1146 }
1160 }
1147
1161
1148 img {
1162 img {
1149 border: none;
1163 border: none;
1150 outline: none;
1164 outline: none;
1151 }
1165 }
1152 user-profile-header
1166 user-profile-header
1153 label {
1167 label {
1154
1168
1155 input[type="checkbox"] {
1169 input[type="checkbox"] {
1156 margin-right: 1em;
1170 margin-right: 1em;
1157 }
1171 }
1158 input[type="radio"] {
1172 input[type="radio"] {
1159 margin-right: 1em;
1173 margin-right: 1em;
1160 }
1174 }
1161 }
1175 }
1162
1176
1163 .review-status {
1177 .review-status {
1164 &.under_review {
1178 &.under_review {
1165 color: @alert3;
1179 color: @alert3;
1166 }
1180 }
1167 &.approved {
1181 &.approved {
1168 color: @alert1;
1182 color: @alert1;
1169 }
1183 }
1170 &.rejected,
1184 &.rejected,
1171 &.forced_closed{
1185 &.forced_closed{
1172 color: @alert2;
1186 color: @alert2;
1173 }
1187 }
1174 &.not_reviewed {
1188 &.not_reviewed {
1175 color: @grey5;
1189 color: @grey5;
1176 }
1190 }
1177 }
1191 }
1178
1192
1179 .review-status-under_review {
1193 .review-status-under_review {
1180 color: @alert3;
1194 color: @alert3;
1181 }
1195 }
1182 .status-tag-under_review {
1196 .status-tag-under_review {
1183 border-color: @alert3;
1197 border-color: @alert3;
1184 }
1198 }
1185
1199
1186 .review-status-approved {
1200 .review-status-approved {
1187 color: @alert1;
1201 color: @alert1;
1188 }
1202 }
1189 .status-tag-approved {
1203 .status-tag-approved {
1190 border-color: @alert1;
1204 border-color: @alert1;
1191 }
1205 }
1192
1206
1193 .review-status-rejected,
1207 .review-status-rejected,
1194 .review-status-forced_closed {
1208 .review-status-forced_closed {
1195 color: @alert2;
1209 color: @alert2;
1196 }
1210 }
1197 .status-tag-rejected,
1211 .status-tag-rejected,
1198 .status-tag-forced_closed {
1212 .status-tag-forced_closed {
1199 border-color: @alert2;
1213 border-color: @alert2;
1200 }
1214 }
1201
1215
1202 .review-status-not_reviewed {
1216 .review-status-not_reviewed {
1203 color: @grey5;
1217 color: @grey5;
1204 }
1218 }
1205 .status-tag-not_reviewed {
1219 .status-tag-not_reviewed {
1206 border-color: @grey5;
1220 border-color: @grey5;
1207 }
1221 }
1208
1222
1209 .test_pattern_preview {
1223 .test_pattern_preview {
1210 margin: @space 0;
1224 margin: @space 0;
1211
1225
1212 p {
1226 p {
1213 margin-bottom: 0;
1227 margin-bottom: 0;
1214 border-bottom: @border-thickness solid @border-default-color;
1228 border-bottom: @border-thickness solid @border-default-color;
1215 color: @grey3;
1229 color: @grey3;
1216 }
1230 }
1217
1231
1218 .btn {
1232 .btn {
1219 margin-bottom: @padding;
1233 margin-bottom: @padding;
1220 }
1234 }
1221 }
1235 }
1222 #test_pattern_result {
1236 #test_pattern_result {
1223 display: none;
1237 display: none;
1224 &:extend(pre);
1238 &:extend(pre);
1225 padding: .9em;
1239 padding: .9em;
1226 color: @grey3;
1240 color: @grey3;
1227 background-color: @grey7;
1241 background-color: @grey7;
1228 border-right: @border-thickness solid @border-default-color;
1242 border-right: @border-thickness solid @border-default-color;
1229 border-bottom: @border-thickness solid @border-default-color;
1243 border-bottom: @border-thickness solid @border-default-color;
1230 border-left: @border-thickness solid @border-default-color;
1244 border-left: @border-thickness solid @border-default-color;
1231 }
1245 }
1232
1246
1233 #repo_vcs_settings {
1247 #repo_vcs_settings {
1234 #inherit_overlay_vcs_default {
1248 #inherit_overlay_vcs_default {
1235 display: none;
1249 display: none;
1236 }
1250 }
1237 #inherit_overlay_vcs_custom {
1251 #inherit_overlay_vcs_custom {
1238 display: custom;
1252 display: custom;
1239 }
1253 }
1240 &.inherited {
1254 &.inherited {
1241 #inherit_overlay_vcs_default {
1255 #inherit_overlay_vcs_default {
1242 display: block;
1256 display: block;
1243 }
1257 }
1244 #inherit_overlay_vcs_custom {
1258 #inherit_overlay_vcs_custom {
1245 display: none;
1259 display: none;
1246 }
1260 }
1247 }
1261 }
1248 }
1262 }
1249
1263
1250 .issue-tracker-link {
1264 .issue-tracker-link {
1251 color: @rcblue;
1265 color: @rcblue;
1252 }
1266 }
1253
1267
1254 // Issue Tracker Table Show/Hide
1268 // Issue Tracker Table Show/Hide
1255 #repo_issue_tracker {
1269 #repo_issue_tracker {
1256 #inherit_overlay {
1270 #inherit_overlay {
1257 display: none;
1271 display: none;
1258 }
1272 }
1259 #custom_overlay {
1273 #custom_overlay {
1260 display: custom;
1274 display: custom;
1261 }
1275 }
1262 &.inherited {
1276 &.inherited {
1263 #inherit_overlay {
1277 #inherit_overlay {
1264 display: block;
1278 display: block;
1265 }
1279 }
1266 #custom_overlay {
1280 #custom_overlay {
1267 display: none;
1281 display: none;
1268 }
1282 }
1269 }
1283 }
1270 }
1284 }
1271 table.issuetracker {
1285 table.issuetracker {
1272 &.readonly {
1286 &.readonly {
1273 tr, td {
1287 tr, td {
1274 color: @grey3;
1288 color: @grey3;
1275 }
1289 }
1276 }
1290 }
1277 .edit {
1291 .edit {
1278 display: none;
1292 display: none;
1279 }
1293 }
1280 .editopen {
1294 .editopen {
1281 .edit {
1295 .edit {
1282 display: inline;
1296 display: inline;
1283 }
1297 }
1284 .entry {
1298 .entry {
1285 display: none;
1299 display: none;
1286 }
1300 }
1287 }
1301 }
1288 tr td.td-action {
1302 tr td.td-action {
1289 min-width: 117px;
1303 min-width: 117px;
1290 }
1304 }
1291 td input {
1305 td input {
1292 max-width: none;
1306 max-width: none;
1293 min-width: 30px;
1307 min-width: 30px;
1294 width: 80%;
1308 width: 80%;
1295 }
1309 }
1296 .issuetracker_pref input {
1310 .issuetracker_pref input {
1297 width: 40%;
1311 width: 40%;
1298 }
1312 }
1299 input.edit_issuetracker_update {
1313 input.edit_issuetracker_update {
1300 margin-right: 0;
1314 margin-right: 0;
1301 width: auto;
1315 width: auto;
1302 }
1316 }
1303 }
1317 }
1304
1318
1305 table.integrations {
1319 table.integrations {
1306 .td-icon {
1320 .td-icon {
1307 width: 20px;
1321 width: 20px;
1308 .integration-icon {
1322 .integration-icon {
1309 height: 20px;
1323 height: 20px;
1310 width: 20px;
1324 width: 20px;
1311 }
1325 }
1312 }
1326 }
1313 }
1327 }
1314
1328
1315 .integrations {
1329 .integrations {
1316 a.integration-box {
1330 a.integration-box {
1317 color: @text-color;
1331 color: @text-color;
1318 &:hover {
1332 &:hover {
1319 .panel {
1333 .panel {
1320 background: #fbfbfb;
1334 background: #fbfbfb;
1321 }
1335 }
1322 }
1336 }
1323 .integration-icon {
1337 .integration-icon {
1324 width: 30px;
1338 width: 30px;
1325 height: 30px;
1339 height: 30px;
1326 margin-right: 20px;
1340 margin-right: 20px;
1327 float: left;
1341 float: left;
1328 }
1342 }
1329
1343
1330 .panel-body {
1344 .panel-body {
1331 padding: 10px;
1345 padding: 10px;
1332 }
1346 }
1333 .panel {
1347 .panel {
1334 margin-bottom: 10px;
1348 margin-bottom: 10px;
1335 }
1349 }
1336 h2 {
1350 h2 {
1337 display: inline-block;
1351 display: inline-block;
1338 margin: 0;
1352 margin: 0;
1339 min-width: 140px;
1353 min-width: 140px;
1340 }
1354 }
1341 }
1355 }
1342 a.integration-box.dummy-integration {
1356 a.integration-box.dummy-integration {
1343 color: @grey4
1357 color: @grey4
1344 }
1358 }
1345 }
1359 }
1346
1360
1347 //Permissions Settings
1361 //Permissions Settings
1348 #add_perm {
1362 #add_perm {
1349 margin: 0 0 @padding;
1363 margin: 0 0 @padding;
1350 cursor: pointer;
1364 cursor: pointer;
1351 }
1365 }
1352
1366
1353 .perm_ac {
1367 .perm_ac {
1354 input {
1368 input {
1355 width: 95%;
1369 width: 95%;
1356 }
1370 }
1357 }
1371 }
1358
1372
1359 .autocomplete-suggestions {
1373 .autocomplete-suggestions {
1360 width: auto !important; // overrides autocomplete.js
1374 width: auto !important; // overrides autocomplete.js
1361 min-width: 278px;
1375 min-width: 278px;
1362 margin: 0;
1376 margin: 0;
1363 border: @border-thickness solid @grey5;
1377 border: @border-thickness solid @grey5;
1364 border-radius: @border-radius;
1378 border-radius: @border-radius;
1365 color: @grey2;
1379 color: @grey2;
1366 background-color: white;
1380 background-color: white;
1367 }
1381 }
1368
1382
1369 .autocomplete-qfilter-suggestions {
1383 .autocomplete-qfilter-suggestions {
1370 width: auto !important; // overrides autocomplete.js
1384 width: auto !important; // overrides autocomplete.js
1371 max-height: 100% !important;
1385 max-height: 100% !important;
1372 min-width: 376px;
1386 min-width: 376px;
1373 margin: 0;
1387 margin: 0;
1374 border: @border-thickness solid @grey5;
1388 border: @border-thickness solid @grey5;
1375 color: @grey2;
1389 color: @grey2;
1376 background-color: white;
1390 background-color: white;
1377 }
1391 }
1378
1392
1379 .autocomplete-selected {
1393 .autocomplete-selected {
1380 background: #F0F0F0;
1394 background: #F0F0F0;
1381 }
1395 }
1382
1396
1383 .ac-container-wrap {
1397 .ac-container-wrap {
1384 margin: 0;
1398 margin: 0;
1385 padding: 8px;
1399 padding: 8px;
1386 border-bottom: @border-thickness solid @grey5;
1400 border-bottom: @border-thickness solid @grey5;
1387 list-style-type: none;
1401 list-style-type: none;
1388 cursor: pointer;
1402 cursor: pointer;
1389
1403
1390 &:hover {
1404 &:hover {
1391 background-color: @grey7;
1405 background-color: @grey7;
1392 }
1406 }
1393
1407
1394 img {
1408 img {
1395 height: @gravatar-size;
1409 height: @gravatar-size;
1396 width: @gravatar-size;
1410 width: @gravatar-size;
1397 margin-right: 1em;
1411 margin-right: 1em;
1398 }
1412 }
1399
1413
1400 strong {
1414 strong {
1401 font-weight: normal;
1415 font-weight: normal;
1402 }
1416 }
1403 }
1417 }
1404
1418
1405 // Settings Dropdown
1419 // Settings Dropdown
1406 .user-menu .container {
1420 .user-menu .container {
1407 padding: 0 4px;
1421 padding: 0 4px;
1408 margin: 0;
1422 margin: 0;
1409 }
1423 }
1410
1424
1411 .user-menu .gravatar {
1425 .user-menu .gravatar {
1412 cursor: pointer;
1426 cursor: pointer;
1413 }
1427 }
1414
1428
1415 .codeblock {
1429 .codeblock {
1416 margin-bottom: @padding;
1430 margin-bottom: @padding;
1417 clear: both;
1431 clear: both;
1418
1432
1419 .stats {
1433 .stats {
1420 overflow: hidden;
1434 overflow: hidden;
1421 }
1435 }
1422
1436
1423 .message{
1437 .message{
1424 textarea{
1438 textarea{
1425 margin: 0;
1439 margin: 0;
1426 }
1440 }
1427 }
1441 }
1428
1442
1429 .code-header {
1443 .code-header {
1430 .stats {
1444 .stats {
1431 line-height: 2em;
1445 line-height: 2em;
1432
1446
1433 .revision_id {
1447 .revision_id {
1434 margin-left: 0;
1448 margin-left: 0;
1435 }
1449 }
1436 .buttons {
1450 .buttons {
1437 padding-right: 0;
1451 padding-right: 0;
1438 }
1452 }
1439 }
1453 }
1440
1454
1441 .item{
1455 .item{
1442 margin-right: 0.5em;
1456 margin-right: 0.5em;
1443 }
1457 }
1444 }
1458 }
1445
1459
1446 #editor_container {
1460 #editor_container {
1447 position: relative;
1461 position: relative;
1448 margin: @padding 10px;
1462 margin: @padding 10px;
1449 }
1463 }
1450 }
1464 }
1451
1465
1452 #file_history_container {
1466 #file_history_container {
1453 display: none;
1467 display: none;
1454 }
1468 }
1455
1469
1456 .file-history-inner {
1470 .file-history-inner {
1457 margin-bottom: 10px;
1471 margin-bottom: 10px;
1458 }
1472 }
1459
1473
1460 // Pull Requests
1474 // Pull Requests
1461 .summary-details {
1475 .summary-details {
1462 width: 72%;
1476 width: 72%;
1463 }
1477 }
1464 .pr-summary {
1478 .pr-summary {
1465 border-bottom: @border-thickness solid @grey5;
1479 border-bottom: @border-thickness solid @grey5;
1466 margin-bottom: @space;
1480 margin-bottom: @space;
1467 }
1481 }
1468 .reviewers-title {
1482 .reviewers-title {
1469 width: 25%;
1483 width: 25%;
1470 min-width: 200px;
1484 min-width: 200px;
1471 }
1485 }
1472 .reviewers {
1486 .reviewers {
1473 width: 25%;
1487 width: 25%;
1474 min-width: 200px;
1488 min-width: 200px;
1475 }
1489 }
1476 .reviewers ul li {
1490 .reviewers ul li {
1477 position: relative;
1491 position: relative;
1478 width: 100%;
1492 width: 100%;
1479 padding-bottom: 8px;
1493 padding-bottom: 8px;
1480 list-style-type: none;
1494 list-style-type: none;
1481 }
1495 }
1482
1496
1483 .reviewer_entry {
1497 .reviewer_entry {
1484 min-height: 55px;
1498 min-height: 55px;
1485 }
1499 }
1486
1500
1487 .reviewers_member {
1501 .reviewers_member {
1488 width: 100%;
1502 width: 100%;
1489 overflow: auto;
1503 overflow: auto;
1490 }
1504 }
1491 .reviewer_reason {
1505 .reviewer_reason {
1492 padding-left: 20px;
1506 padding-left: 20px;
1493 line-height: 1.5em;
1507 line-height: 1.5em;
1494 }
1508 }
1495 .reviewer_status {
1509 .reviewer_status {
1496 display: inline-block;
1510 display: inline-block;
1497 width: 25px;
1511 width: 25px;
1498 min-width: 25px;
1512 min-width: 25px;
1499 height: 1.2em;
1513 height: 1.2em;
1500 line-height: 1em;
1514 line-height: 1em;
1501 }
1515 }
1502
1516
1503 .reviewer_name {
1517 .reviewer_name {
1504 display: inline-block;
1518 display: inline-block;
1505 max-width: 83%;
1519 max-width: 83%;
1506 padding-right: 20px;
1520 padding-right: 20px;
1507 vertical-align: middle;
1521 vertical-align: middle;
1508 line-height: 1;
1522 line-height: 1;
1509
1523
1510 .rc-user {
1524 .rc-user {
1511 min-width: 0;
1525 min-width: 0;
1512 margin: -2px 1em 0 0;
1526 margin: -2px 1em 0 0;
1513 }
1527 }
1514
1528
1515 .reviewer {
1529 .reviewer {
1516 float: left;
1530 float: left;
1517 }
1531 }
1518 }
1532 }
1519
1533
1520 .reviewer_member_mandatory {
1534 .reviewer_member_mandatory {
1521 position: absolute;
1535 position: absolute;
1522 left: 15px;
1536 left: 15px;
1523 top: 8px;
1537 top: 8px;
1524 width: 16px;
1538 width: 16px;
1525 font-size: 11px;
1539 font-size: 11px;
1526 margin: 0;
1540 margin: 0;
1527 padding: 0;
1541 padding: 0;
1528 color: black;
1542 color: black;
1529 }
1543 }
1530
1544
1531 .reviewer_member_mandatory_remove,
1545 .reviewer_member_mandatory_remove,
1532 .reviewer_member_remove {
1546 .reviewer_member_remove {
1533 position: absolute;
1547 position: absolute;
1534 right: 0;
1548 right: 0;
1535 top: 0;
1549 top: 0;
1536 width: 16px;
1550 width: 16px;
1537 margin-bottom: 10px;
1551 margin-bottom: 10px;
1538 padding: 0;
1552 padding: 0;
1539 color: black;
1553 color: black;
1540 }
1554 }
1541
1555
1542 .reviewer_member_mandatory_remove {
1556 .reviewer_member_mandatory_remove {
1543 color: @grey4;
1557 color: @grey4;
1544 }
1558 }
1545
1559
1546 .reviewer_member_status {
1560 .reviewer_member_status {
1547 margin-top: 5px;
1561 margin-top: 5px;
1548 }
1562 }
1549 .pr-summary #summary{
1563 .pr-summary #summary{
1550 width: 100%;
1564 width: 100%;
1551 }
1565 }
1552 .pr-summary .action_button:hover {
1566 .pr-summary .action_button:hover {
1553 border: 0;
1567 border: 0;
1554 cursor: pointer;
1568 cursor: pointer;
1555 }
1569 }
1556 .pr-details-title {
1570 .pr-details-title {
1557 padding-bottom: 8px;
1571 padding-bottom: 8px;
1558 border-bottom: @border-thickness solid @grey5;
1572 border-bottom: @border-thickness solid @grey5;
1559
1573
1560 .action_button.disabled {
1574 .action_button.disabled {
1561 color: @grey4;
1575 color: @grey4;
1562 cursor: inherit;
1576 cursor: inherit;
1563 }
1577 }
1564 .action_button {
1578 .action_button {
1565 color: @rcblue;
1579 color: @rcblue;
1566 }
1580 }
1567 }
1581 }
1568 .pr-details-content {
1582 .pr-details-content {
1569 margin-top: @textmargin;
1583 margin-top: @textmargin - 5;
1570 margin-bottom: @textmargin;
1584 margin-bottom: @textmargin - 5;
1571 }
1585 }
1572
1586
1573 .pr-reviewer-rules {
1587 .pr-reviewer-rules {
1574 padding: 10px 0px 20px 0px;
1588 padding: 10px 0px 20px 0px;
1575 }
1589 }
1576
1590
1591 .todo-resolved {
1592 text-decoration: line-through;
1593 }
1594
1595 .todo-table {
1596 width: 100%;
1597
1598 td {
1599 padding: 5px 0px;
1600 }
1601
1602 .td-todo-number {
1603 text-align: left;
1604 white-space: nowrap;
1605 width: 15%;
1606 }
1607
1608 .td-todo-gravatar {
1609 width: 5%;
1610
1611 img {
1612 margin: -3px 0;
1613 }
1614 }
1615
1616 }
1617
1618 .todo-comment-text-wrapper {
1619 display: inline-grid;
1620 }
1621
1622 .todo-comment-text {
1623 margin-left: 5px;
1624 white-space: nowrap;
1625 overflow: hidden;
1626 text-overflow: ellipsis;
1627 }
1628
1577 .group_members {
1629 .group_members {
1578 margin-top: 0;
1630 margin-top: 0;
1579 padding: 0;
1631 padding: 0;
1580 list-style: outside none none;
1632 list-style: outside none none;
1581
1633
1582 img {
1634 img {
1583 height: @gravatar-size;
1635 height: @gravatar-size;
1584 width: @gravatar-size;
1636 width: @gravatar-size;
1585 margin-right: .5em;
1637 margin-right: .5em;
1586 margin-left: 3px;
1638 margin-left: 3px;
1587 }
1639 }
1588
1640
1589 .to-delete {
1641 .to-delete {
1590 .user {
1642 .user {
1591 text-decoration: line-through;
1643 text-decoration: line-through;
1592 }
1644 }
1593 }
1645 }
1594 }
1646 }
1595
1647
1596 .compare_view_commits_title {
1648 .compare_view_commits_title {
1597 .disabled {
1649 .disabled {
1598 cursor: inherit;
1650 cursor: inherit;
1599 &:hover{
1651 &:hover{
1600 background-color: inherit;
1652 background-color: inherit;
1601 color: inherit;
1653 color: inherit;
1602 }
1654 }
1603 }
1655 }
1604 }
1656 }
1605
1657
1606 .subtitle-compare {
1658 .subtitle-compare {
1607 margin: -15px 0px 0px 0px;
1659 margin: -15px 0px 0px 0px;
1608 }
1660 }
1609
1661
1610 // new entry in group_members
1662 // new entry in group_members
1611 .td-author-new-entry {
1663 .td-author-new-entry {
1612 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1664 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1613 }
1665 }
1614
1666
1615 .usergroup_member_remove {
1667 .usergroup_member_remove {
1616 width: 16px;
1668 width: 16px;
1617 margin-bottom: 10px;
1669 margin-bottom: 10px;
1618 padding: 0;
1670 padding: 0;
1619 color: black !important;
1671 color: black !important;
1620 cursor: pointer;
1672 cursor: pointer;
1621 }
1673 }
1622
1674
1623 .reviewer_ac .ac-input {
1675 .reviewer_ac .ac-input {
1624 width: 92%;
1676 width: 92%;
1625 margin-bottom: 1em;
1677 margin-bottom: 1em;
1626 }
1678 }
1627
1679
1628 .compare_view_commits tr{
1680 .compare_view_commits tr{
1629 height: 20px;
1681 height: 20px;
1630 }
1682 }
1631 .compare_view_commits td {
1683 .compare_view_commits td {
1632 vertical-align: top;
1684 vertical-align: top;
1633 padding-top: 10px;
1685 padding-top: 10px;
1634 }
1686 }
1635 .compare_view_commits .author {
1687 .compare_view_commits .author {
1636 margin-left: 5px;
1688 margin-left: 5px;
1637 }
1689 }
1638
1690
1639 .compare_view_commits {
1691 .compare_view_commits {
1640 .color-a {
1692 .color-a {
1641 color: @alert1;
1693 color: @alert1;
1642 }
1694 }
1643
1695
1644 .color-c {
1696 .color-c {
1645 color: @color3;
1697 color: @color3;
1646 }
1698 }
1647
1699
1648 .color-r {
1700 .color-r {
1649 color: @color5;
1701 color: @color5;
1650 }
1702 }
1651
1703
1652 .color-a-bg {
1704 .color-a-bg {
1653 background-color: @alert1;
1705 background-color: @alert1;
1654 }
1706 }
1655
1707
1656 .color-c-bg {
1708 .color-c-bg {
1657 background-color: @alert3;
1709 background-color: @alert3;
1658 }
1710 }
1659
1711
1660 .color-r-bg {
1712 .color-r-bg {
1661 background-color: @alert2;
1713 background-color: @alert2;
1662 }
1714 }
1663
1715
1664 .color-a-border {
1716 .color-a-border {
1665 border: 1px solid @alert1;
1717 border: 1px solid @alert1;
1666 }
1718 }
1667
1719
1668 .color-c-border {
1720 .color-c-border {
1669 border: 1px solid @alert3;
1721 border: 1px solid @alert3;
1670 }
1722 }
1671
1723
1672 .color-r-border {
1724 .color-r-border {
1673 border: 1px solid @alert2;
1725 border: 1px solid @alert2;
1674 }
1726 }
1675
1727
1676 .commit-change-indicator {
1728 .commit-change-indicator {
1677 width: 15px;
1729 width: 15px;
1678 height: 15px;
1730 height: 15px;
1679 position: relative;
1731 position: relative;
1680 left: 15px;
1732 left: 15px;
1681 }
1733 }
1682
1734
1683 .commit-change-content {
1735 .commit-change-content {
1684 text-align: center;
1736 text-align: center;
1685 vertical-align: middle;
1737 vertical-align: middle;
1686 line-height: 15px;
1738 line-height: 15px;
1687 }
1739 }
1688 }
1740 }
1689
1741
1690 .compare_view_filepath {
1742 .compare_view_filepath {
1691 color: @grey1;
1743 color: @grey1;
1692 }
1744 }
1693
1745
1694 .show_more {
1746 .show_more {
1695 display: inline-block;
1747 display: inline-block;
1696 width: 0;
1748 width: 0;
1697 height: 0;
1749 height: 0;
1698 vertical-align: middle;
1750 vertical-align: middle;
1699 content: "";
1751 content: "";
1700 border: 4px solid;
1752 border: 4px solid;
1701 border-right-color: transparent;
1753 border-right-color: transparent;
1702 border-bottom-color: transparent;
1754 border-bottom-color: transparent;
1703 border-left-color: transparent;
1755 border-left-color: transparent;
1704 font-size: 0;
1756 font-size: 0;
1705 }
1757 }
1706
1758
1707 .journal_more .show_more {
1759 .journal_more .show_more {
1708 display: inline;
1760 display: inline;
1709
1761
1710 &:after {
1762 &:after {
1711 content: none;
1763 content: none;
1712 }
1764 }
1713 }
1765 }
1714
1766
1715 .compare_view_commits .collapse_commit:after {
1767 .compare_view_commits .collapse_commit:after {
1716 cursor: pointer;
1768 cursor: pointer;
1717 content: "\00A0\25B4";
1769 content: "\00A0\25B4";
1718 margin-left: -3px;
1770 margin-left: -3px;
1719 font-size: 17px;
1771 font-size: 17px;
1720 color: @grey4;
1772 color: @grey4;
1721 }
1773 }
1722
1774
1723 .diff_links {
1775 .diff_links {
1724 margin-left: 8px;
1776 margin-left: 8px;
1725 }
1777 }
1726
1778
1727 #pull_request_overview {
1779 #pull_request_overview {
1728 div.ancestor {
1780 div.ancestor {
1729 margin: -33px 0;
1781 margin: -33px 0;
1730 }
1782 }
1731 }
1783 }
1732
1784
1733 div.ancestor {
1785 div.ancestor {
1734 line-height: 33px;
1786 line-height: 33px;
1735 }
1787 }
1736
1788
1737 .cs_icon_td input[type="checkbox"] {
1789 .cs_icon_td input[type="checkbox"] {
1738 display: none;
1790 display: none;
1739 }
1791 }
1740
1792
1741 .cs_icon_td .expand_file_icon:after {
1793 .cs_icon_td .expand_file_icon:after {
1742 cursor: pointer;
1794 cursor: pointer;
1743 content: "\00A0\25B6";
1795 content: "\00A0\25B6";
1744 font-size: 12px;
1796 font-size: 12px;
1745 color: @grey4;
1797 color: @grey4;
1746 }
1798 }
1747
1799
1748 .cs_icon_td .collapse_file_icon:after {
1800 .cs_icon_td .collapse_file_icon:after {
1749 cursor: pointer;
1801 cursor: pointer;
1750 content: "\00A0\25BC";
1802 content: "\00A0\25BC";
1751 font-size: 12px;
1803 font-size: 12px;
1752 color: @grey4;
1804 color: @grey4;
1753 }
1805 }
1754
1806
1755 /*new binary
1807 /*new binary
1756 NEW_FILENODE = 1
1808 NEW_FILENODE = 1
1757 DEL_FILENODE = 2
1809 DEL_FILENODE = 2
1758 MOD_FILENODE = 3
1810 MOD_FILENODE = 3
1759 RENAMED_FILENODE = 4
1811 RENAMED_FILENODE = 4
1760 COPIED_FILENODE = 5
1812 COPIED_FILENODE = 5
1761 CHMOD_FILENODE = 6
1813 CHMOD_FILENODE = 6
1762 BIN_FILENODE = 7
1814 BIN_FILENODE = 7
1763 */
1815 */
1764 .cs_files_expand {
1816 .cs_files_expand {
1765 font-size: @basefontsize + 5px;
1817 font-size: @basefontsize + 5px;
1766 line-height: 1.8em;
1818 line-height: 1.8em;
1767 float: right;
1819 float: right;
1768 }
1820 }
1769
1821
1770 .cs_files_expand span{
1822 .cs_files_expand span{
1771 color: @rcblue;
1823 color: @rcblue;
1772 cursor: pointer;
1824 cursor: pointer;
1773 }
1825 }
1774 .cs_files {
1826 .cs_files {
1775 clear: both;
1827 clear: both;
1776 padding-bottom: @padding;
1828 padding-bottom: @padding;
1777
1829
1778 .cur_cs {
1830 .cur_cs {
1779 margin: 10px 2px;
1831 margin: 10px 2px;
1780 font-weight: bold;
1832 font-weight: bold;
1781 }
1833 }
1782
1834
1783 .node {
1835 .node {
1784 float: left;
1836 float: left;
1785 }
1837 }
1786
1838
1787 .changes {
1839 .changes {
1788 float: right;
1840 float: right;
1789 color: white;
1841 color: white;
1790 font-size: @basefontsize - 4px;
1842 font-size: @basefontsize - 4px;
1791 margin-top: 4px;
1843 margin-top: 4px;
1792 opacity: 0.6;
1844 opacity: 0.6;
1793 filter: Alpha(opacity=60); /* IE8 and earlier */
1845 filter: Alpha(opacity=60); /* IE8 and earlier */
1794
1846
1795 .added {
1847 .added {
1796 background-color: @alert1;
1848 background-color: @alert1;
1797 float: left;
1849 float: left;
1798 text-align: center;
1850 text-align: center;
1799 }
1851 }
1800
1852
1801 .deleted {
1853 .deleted {
1802 background-color: @alert2;
1854 background-color: @alert2;
1803 float: left;
1855 float: left;
1804 text-align: center;
1856 text-align: center;
1805 }
1857 }
1806
1858
1807 .bin {
1859 .bin {
1808 background-color: @alert1;
1860 background-color: @alert1;
1809 text-align: center;
1861 text-align: center;
1810 }
1862 }
1811
1863
1812 /*new binary*/
1864 /*new binary*/
1813 .bin.bin1 {
1865 .bin.bin1 {
1814 background-color: @alert1;
1866 background-color: @alert1;
1815 text-align: center;
1867 text-align: center;
1816 }
1868 }
1817
1869
1818 /*deleted binary*/
1870 /*deleted binary*/
1819 .bin.bin2 {
1871 .bin.bin2 {
1820 background-color: @alert2;
1872 background-color: @alert2;
1821 text-align: center;
1873 text-align: center;
1822 }
1874 }
1823
1875
1824 /*mod binary*/
1876 /*mod binary*/
1825 .bin.bin3 {
1877 .bin.bin3 {
1826 background-color: @grey2;
1878 background-color: @grey2;
1827 text-align: center;
1879 text-align: center;
1828 }
1880 }
1829
1881
1830 /*rename file*/
1882 /*rename file*/
1831 .bin.bin4 {
1883 .bin.bin4 {
1832 background-color: @alert4;
1884 background-color: @alert4;
1833 text-align: center;
1885 text-align: center;
1834 }
1886 }
1835
1887
1836 /*copied file*/
1888 /*copied file*/
1837 .bin.bin5 {
1889 .bin.bin5 {
1838 background-color: @alert4;
1890 background-color: @alert4;
1839 text-align: center;
1891 text-align: center;
1840 }
1892 }
1841
1893
1842 /*chmod file*/
1894 /*chmod file*/
1843 .bin.bin6 {
1895 .bin.bin6 {
1844 background-color: @grey2;
1896 background-color: @grey2;
1845 text-align: center;
1897 text-align: center;
1846 }
1898 }
1847 }
1899 }
1848 }
1900 }
1849
1901
1850 .cs_files .cs_added, .cs_files .cs_A,
1902 .cs_files .cs_added, .cs_files .cs_A,
1851 .cs_files .cs_added, .cs_files .cs_M,
1903 .cs_files .cs_added, .cs_files .cs_M,
1852 .cs_files .cs_added, .cs_files .cs_D {
1904 .cs_files .cs_added, .cs_files .cs_D {
1853 height: 16px;
1905 height: 16px;
1854 padding-right: 10px;
1906 padding-right: 10px;
1855 margin-top: 7px;
1907 margin-top: 7px;
1856 text-align: left;
1908 text-align: left;
1857 }
1909 }
1858
1910
1859 .cs_icon_td {
1911 .cs_icon_td {
1860 min-width: 16px;
1912 min-width: 16px;
1861 width: 16px;
1913 width: 16px;
1862 }
1914 }
1863
1915
1864 .pull-request-merge {
1916 .pull-request-merge {
1865 border: 1px solid @grey5;
1917 border: 1px solid @grey5;
1866 padding: 10px 0px 20px;
1918 padding: 10px 0px 20px;
1867 margin-top: 10px;
1919 margin-top: 10px;
1868 margin-bottom: 20px;
1920 margin-bottom: 20px;
1869 }
1921 }
1870
1922
1871 .pull-request-merge-refresh {
1923 .pull-request-merge-refresh {
1872 margin: 2px 7px;
1924 margin: 2px 7px;
1873 a {
1925 a {
1874 color: @grey3;
1926 color: @grey3;
1875 }
1927 }
1876 }
1928 }
1877
1929
1878 .pull-request-merge ul {
1930 .pull-request-merge ul {
1879 padding: 0px 0px;
1931 padding: 0px 0px;
1880 }
1932 }
1881
1933
1882 .pull-request-merge li {
1934 .pull-request-merge li {
1883 list-style-type: none;
1935 list-style-type: none;
1884 }
1936 }
1885
1937
1886 .pull-request-merge .pull-request-wrap {
1938 .pull-request-merge .pull-request-wrap {
1887 height: auto;
1939 height: auto;
1888 padding: 0px 0px;
1940 padding: 0px 0px;
1889 text-align: right;
1941 text-align: right;
1890 }
1942 }
1891
1943
1892 .pull-request-merge span {
1944 .pull-request-merge span {
1893 margin-right: 5px;
1945 margin-right: 5px;
1894 }
1946 }
1895
1947
1896 .pull-request-merge-actions {
1948 .pull-request-merge-actions {
1897 min-height: 30px;
1949 min-height: 30px;
1898 padding: 0px 0px;
1950 padding: 0px 0px;
1899 }
1951 }
1900
1952
1901 .pull-request-merge-info {
1953 .pull-request-merge-info {
1902 padding: 0px 5px 5px 0px;
1954 padding: 0px 5px 5px 0px;
1903 }
1955 }
1904
1956
1905 .merge-status {
1957 .merge-status {
1906 margin-right: 5px;
1958 margin-right: 5px;
1907 }
1959 }
1908
1960
1909 .merge-message {
1961 .merge-message {
1910 font-size: 1.2em
1962 font-size: 1.2em
1911 }
1963 }
1912
1964
1913 .merge-message.success i,
1965 .merge-message.success i,
1914 .merge-icon.success i {
1966 .merge-icon.success i {
1915 color:@alert1;
1967 color:@alert1;
1916 }
1968 }
1917
1969
1918 .merge-message.warning i,
1970 .merge-message.warning i,
1919 .merge-icon.warning i {
1971 .merge-icon.warning i {
1920 color: @alert3;
1972 color: @alert3;
1921 }
1973 }
1922
1974
1923 .merge-message.error i,
1975 .merge-message.error i,
1924 .merge-icon.error i {
1976 .merge-icon.error i {
1925 color:@alert2;
1977 color:@alert2;
1926 }
1978 }
1927
1979
1928 .pr-versions {
1980 .pr-versions {
1929 font-size: 1.1em;
1981 font-size: 1.1em;
1930 padding: 7.5px;
1982 padding: 7.5px;
1931
1983
1932 table {
1984 table {
1933
1985
1934 }
1986 }
1935
1987
1936 td {
1988 td {
1937 line-height: 15px;
1989 line-height: 15px;
1938 }
1990 }
1939
1991
1940 .compare-radio-button {
1992 .compare-radio-button {
1941 position: relative;
1993 position: relative;
1942 top: -3px;
1994 top: -3px;
1943 }
1995 }
1944 }
1996 }
1945
1997
1946
1998
1947 #close_pull_request {
1999 #close_pull_request {
1948 margin-right: 0px;
2000 margin-right: 0px;
1949 }
2001 }
1950
2002
1951 .empty_data {
2003 .empty_data {
1952 color: @grey4;
2004 color: @grey4;
1953 }
2005 }
1954
2006
1955 #changeset_compare_view_content {
2007 #changeset_compare_view_content {
1956 clear: both;
2008 clear: both;
1957 width: 100%;
2009 width: 100%;
1958 box-sizing: border-box;
2010 box-sizing: border-box;
1959 .border-radius(@border-radius);
2011 .border-radius(@border-radius);
1960
2012
1961 .help-block {
2013 .help-block {
1962 margin: @padding 0;
2014 margin: @padding 0;
1963 color: @text-color;
2015 color: @text-color;
1964 &.pre-formatting {
2016 &.pre-formatting {
1965 white-space: pre;
2017 white-space: pre;
1966 }
2018 }
1967 }
2019 }
1968
2020
1969 .empty_data {
2021 .empty_data {
1970 margin: @padding 0;
2022 margin: @padding 0;
1971 }
2023 }
1972
2024
1973 .alert {
2025 .alert {
1974 margin-bottom: @space;
2026 margin-bottom: @space;
1975 }
2027 }
1976 }
2028 }
1977
2029
1978 .table_disp {
2030 .table_disp {
1979 .status {
2031 .status {
1980 width: auto;
2032 width: auto;
1981 }
2033 }
1982 }
2034 }
1983
2035
1984
2036
1985 .creation_in_progress {
2037 .creation_in_progress {
1986 color: @grey4
2038 color: @grey4
1987 }
2039 }
1988
2040
1989 .status_box_menu {
2041 .status_box_menu {
1990 margin: 0;
2042 margin: 0;
1991 }
2043 }
1992
2044
1993 .notification-table{
2045 .notification-table{
1994 margin-bottom: @space;
2046 margin-bottom: @space;
1995 display: table;
2047 display: table;
1996 width: 100%;
2048 width: 100%;
1997
2049
1998 .container{
2050 .container{
1999 display: table-row;
2051 display: table-row;
2000
2052
2001 .notification-header{
2053 .notification-header{
2002 border-bottom: @border-thickness solid @border-default-color;
2054 border-bottom: @border-thickness solid @border-default-color;
2003 }
2055 }
2004
2056
2005 .notification-subject{
2057 .notification-subject{
2006 display: table-cell;
2058 display: table-cell;
2007 }
2059 }
2008 }
2060 }
2009 }
2061 }
2010
2062
2011 // Notifications
2063 // Notifications
2012 .notification-header{
2064 .notification-header{
2013 display: table;
2065 display: table;
2014 width: 100%;
2066 width: 100%;
2015 padding: floor(@basefontsize/2) 0;
2067 padding: floor(@basefontsize/2) 0;
2016 line-height: 1em;
2068 line-height: 1em;
2017
2069
2018 .desc, .delete-notifications, .read-notifications{
2070 .desc, .delete-notifications, .read-notifications{
2019 display: table-cell;
2071 display: table-cell;
2020 text-align: left;
2072 text-align: left;
2021 }
2073 }
2022
2074
2023 .delete-notifications, .read-notifications{
2075 .delete-notifications, .read-notifications{
2024 width: 35px;
2076 width: 35px;
2025 min-width: 35px; //fixes when only one button is displayed
2077 min-width: 35px; //fixes when only one button is displayed
2026 }
2078 }
2027 }
2079 }
2028
2080
2029 .notification-body {
2081 .notification-body {
2030 .markdown-block,
2082 .markdown-block,
2031 .rst-block {
2083 .rst-block {
2032 padding: @padding 0;
2084 padding: @padding 0;
2033 }
2085 }
2034
2086
2035 .notification-subject {
2087 .notification-subject {
2036 padding: @textmargin 0;
2088 padding: @textmargin 0;
2037 border-bottom: @border-thickness solid @border-default-color;
2089 border-bottom: @border-thickness solid @border-default-color;
2038 }
2090 }
2039 }
2091 }
2040
2092
2041
2093
2042 .notifications_buttons{
2094 .notifications_buttons{
2043 float: right;
2095 float: right;
2044 }
2096 }
2045
2097
2046 #notification-status{
2098 #notification-status{
2047 display: inline;
2099 display: inline;
2048 }
2100 }
2049
2101
2050 // Repositories
2102 // Repositories
2051
2103
2052 #summary.fields{
2104 #summary.fields{
2053 display: table;
2105 display: table;
2054
2106
2055 .field{
2107 .field{
2056 display: table-row;
2108 display: table-row;
2057
2109
2058 .label-summary{
2110 .label-summary{
2059 display: table-cell;
2111 display: table-cell;
2060 min-width: @label-summary-minwidth;
2112 min-width: @label-summary-minwidth;
2061 padding-top: @padding/2;
2113 padding-top: @padding/2;
2062 padding-bottom: @padding/2;
2114 padding-bottom: @padding/2;
2063 padding-right: @padding/2;
2115 padding-right: @padding/2;
2064 }
2116 }
2065
2117
2066 .input{
2118 .input{
2067 display: table-cell;
2119 display: table-cell;
2068 padding: @padding/2;
2120 padding: @padding/2;
2069
2121
2070 input{
2122 input{
2071 min-width: 29em;
2123 min-width: 29em;
2072 padding: @padding/4;
2124 padding: @padding/4;
2073 }
2125 }
2074 }
2126 }
2075 .statistics, .downloads{
2127 .statistics, .downloads{
2076 .disabled{
2128 .disabled{
2077 color: @grey4;
2129 color: @grey4;
2078 }
2130 }
2079 }
2131 }
2080 }
2132 }
2081 }
2133 }
2082
2134
2083 #summary{
2135 #summary{
2084 width: 70%;
2136 width: 70%;
2085 }
2137 }
2086
2138
2087
2139
2088 // Journal
2140 // Journal
2089 .journal.title {
2141 .journal.title {
2090 h5 {
2142 h5 {
2091 float: left;
2143 float: left;
2092 margin: 0;
2144 margin: 0;
2093 width: 70%;
2145 width: 70%;
2094 }
2146 }
2095
2147
2096 ul {
2148 ul {
2097 float: right;
2149 float: right;
2098 display: inline-block;
2150 display: inline-block;
2099 margin: 0;
2151 margin: 0;
2100 width: 30%;
2152 width: 30%;
2101 text-align: right;
2153 text-align: right;
2102
2154
2103 li {
2155 li {
2104 display: inline;
2156 display: inline;
2105 font-size: @journal-fontsize;
2157 font-size: @journal-fontsize;
2106 line-height: 1em;
2158 line-height: 1em;
2107
2159
2108 list-style-type: none;
2160 list-style-type: none;
2109 }
2161 }
2110 }
2162 }
2111 }
2163 }
2112
2164
2113 .filterexample {
2165 .filterexample {
2114 position: absolute;
2166 position: absolute;
2115 top: 95px;
2167 top: 95px;
2116 left: @contentpadding;
2168 left: @contentpadding;
2117 color: @rcblue;
2169 color: @rcblue;
2118 font-size: 11px;
2170 font-size: 11px;
2119 font-family: @text-regular;
2171 font-family: @text-regular;
2120 cursor: help;
2172 cursor: help;
2121
2173
2122 &:hover {
2174 &:hover {
2123 color: @rcdarkblue;
2175 color: @rcdarkblue;
2124 }
2176 }
2125
2177
2126 @media (max-width:768px) {
2178 @media (max-width:768px) {
2127 position: relative;
2179 position: relative;
2128 top: auto;
2180 top: auto;
2129 left: auto;
2181 left: auto;
2130 display: block;
2182 display: block;
2131 }
2183 }
2132 }
2184 }
2133
2185
2134
2186
2135 #journal{
2187 #journal{
2136 margin-bottom: @space;
2188 margin-bottom: @space;
2137
2189
2138 .journal_day{
2190 .journal_day{
2139 margin-bottom: @textmargin/2;
2191 margin-bottom: @textmargin/2;
2140 padding-bottom: @textmargin/2;
2192 padding-bottom: @textmargin/2;
2141 font-size: @journal-fontsize;
2193 font-size: @journal-fontsize;
2142 border-bottom: @border-thickness solid @border-default-color;
2194 border-bottom: @border-thickness solid @border-default-color;
2143 }
2195 }
2144
2196
2145 .journal_container{
2197 .journal_container{
2146 margin-bottom: @space;
2198 margin-bottom: @space;
2147
2199
2148 .journal_user{
2200 .journal_user{
2149 display: inline-block;
2201 display: inline-block;
2150 }
2202 }
2151 .journal_action_container{
2203 .journal_action_container{
2152 display: block;
2204 display: block;
2153 margin-top: @textmargin;
2205 margin-top: @textmargin;
2154
2206
2155 div{
2207 div{
2156 display: inline;
2208 display: inline;
2157 }
2209 }
2158
2210
2159 div.journal_action_params{
2211 div.journal_action_params{
2160 display: block;
2212 display: block;
2161 }
2213 }
2162
2214
2163 div.journal_repo:after{
2215 div.journal_repo:after{
2164 content: "\A";
2216 content: "\A";
2165 white-space: pre;
2217 white-space: pre;
2166 }
2218 }
2167
2219
2168 div.date{
2220 div.date{
2169 display: block;
2221 display: block;
2170 margin-bottom: @textmargin;
2222 margin-bottom: @textmargin;
2171 }
2223 }
2172 }
2224 }
2173 }
2225 }
2174 }
2226 }
2175
2227
2176 // Files
2228 // Files
2177 .edit-file-title {
2229 .edit-file-title {
2178 font-size: 16px;
2230 font-size: 16px;
2179
2231
2180 .title-heading {
2232 .title-heading {
2181 padding: 2px;
2233 padding: 2px;
2182 }
2234 }
2183 }
2235 }
2184
2236
2185 .edit-file-fieldset {
2237 .edit-file-fieldset {
2186 margin: @sidebarpadding 0;
2238 margin: @sidebarpadding 0;
2187
2239
2188 .fieldset {
2240 .fieldset {
2189 .left-label {
2241 .left-label {
2190 width: 13%;
2242 width: 13%;
2191 }
2243 }
2192 .right-content {
2244 .right-content {
2193 width: 87%;
2245 width: 87%;
2194 max-width: 100%;
2246 max-width: 100%;
2195 }
2247 }
2196 .filename-label {
2248 .filename-label {
2197 margin-top: 13px;
2249 margin-top: 13px;
2198 }
2250 }
2199 .commit-message-label {
2251 .commit-message-label {
2200 margin-top: 4px;
2252 margin-top: 4px;
2201 }
2253 }
2202 .file-upload-input {
2254 .file-upload-input {
2203 input {
2255 input {
2204 display: none;
2256 display: none;
2205 }
2257 }
2206 margin-top: 10px;
2258 margin-top: 10px;
2207 }
2259 }
2208 .file-upload-label {
2260 .file-upload-label {
2209 margin-top: 10px;
2261 margin-top: 10px;
2210 }
2262 }
2211 p {
2263 p {
2212 margin-top: 5px;
2264 margin-top: 5px;
2213 }
2265 }
2214
2266
2215 }
2267 }
2216 .custom-path-link {
2268 .custom-path-link {
2217 margin-left: 5px;
2269 margin-left: 5px;
2218 }
2270 }
2219 #commit {
2271 #commit {
2220 resize: vertical;
2272 resize: vertical;
2221 }
2273 }
2222 }
2274 }
2223
2275
2224 .delete-file-preview {
2276 .delete-file-preview {
2225 max-height: 250px;
2277 max-height: 250px;
2226 }
2278 }
2227
2279
2228 .new-file,
2280 .new-file,
2229 #filter_activate,
2281 #filter_activate,
2230 #filter_deactivate {
2282 #filter_deactivate {
2231 float: right;
2283 float: right;
2232 margin: 0 0 0 10px;
2284 margin: 0 0 0 10px;
2233 }
2285 }
2234
2286
2235 .file-upload-transaction-wrapper {
2287 .file-upload-transaction-wrapper {
2236 margin-top: 57px;
2288 margin-top: 57px;
2237 clear: both;
2289 clear: both;
2238 }
2290 }
2239
2291
2240 .file-upload-transaction-wrapper .error {
2292 .file-upload-transaction-wrapper .error {
2241 color: @color5;
2293 color: @color5;
2242 }
2294 }
2243
2295
2244 .file-upload-transaction {
2296 .file-upload-transaction {
2245 min-height: 200px;
2297 min-height: 200px;
2246 padding: 54px;
2298 padding: 54px;
2247 border: 1px solid @grey5;
2299 border: 1px solid @grey5;
2248 text-align: center;
2300 text-align: center;
2249 clear: both;
2301 clear: both;
2250 }
2302 }
2251
2303
2252 .file-upload-transaction i {
2304 .file-upload-transaction i {
2253 font-size: 48px
2305 font-size: 48px
2254 }
2306 }
2255
2307
2256 h3.files_location{
2308 h3.files_location{
2257 line-height: 2.4em;
2309 line-height: 2.4em;
2258 }
2310 }
2259
2311
2260 .browser-nav {
2312 .browser-nav {
2261 width: 100%;
2313 width: 100%;
2262 display: table;
2314 display: table;
2263 margin-bottom: 20px;
2315 margin-bottom: 20px;
2264
2316
2265 .info_box {
2317 .info_box {
2266 float: left;
2318 float: left;
2267 display: inline-table;
2319 display: inline-table;
2268 height: 2.5em;
2320 height: 2.5em;
2269
2321
2270 .browser-cur-rev, .info_box_elem {
2322 .browser-cur-rev, .info_box_elem {
2271 display: table-cell;
2323 display: table-cell;
2272 vertical-align: middle;
2324 vertical-align: middle;
2273 }
2325 }
2274
2326
2275 .drop-menu {
2327 .drop-menu {
2276 margin: 0 10px;
2328 margin: 0 10px;
2277 }
2329 }
2278
2330
2279 .info_box_elem {
2331 .info_box_elem {
2280 border-top: @border-thickness solid @grey5;
2332 border-top: @border-thickness solid @grey5;
2281 border-bottom: @border-thickness solid @grey5;
2333 border-bottom: @border-thickness solid @grey5;
2282 box-shadow: @button-shadow;
2334 box-shadow: @button-shadow;
2283
2335
2284 #at_rev, a {
2336 #at_rev, a {
2285 padding: 0.6em 0.4em;
2337 padding: 0.6em 0.4em;
2286 margin: 0;
2338 margin: 0;
2287 .box-shadow(none);
2339 .box-shadow(none);
2288 border: 0;
2340 border: 0;
2289 height: 12px;
2341 height: 12px;
2290 color: @grey2;
2342 color: @grey2;
2291 }
2343 }
2292
2344
2293 input#at_rev {
2345 input#at_rev {
2294 max-width: 50px;
2346 max-width: 50px;
2295 text-align: center;
2347 text-align: center;
2296 }
2348 }
2297
2349
2298 &.previous {
2350 &.previous {
2299 border: @border-thickness solid @grey5;
2351 border: @border-thickness solid @grey5;
2300 border-top-left-radius: @border-radius;
2352 border-top-left-radius: @border-radius;
2301 border-bottom-left-radius: @border-radius;
2353 border-bottom-left-radius: @border-radius;
2302
2354
2303 &:hover {
2355 &:hover {
2304 border-color: @grey4;
2356 border-color: @grey4;
2305 }
2357 }
2306
2358
2307 .disabled {
2359 .disabled {
2308 color: @grey5;
2360 color: @grey5;
2309 cursor: not-allowed;
2361 cursor: not-allowed;
2310 opacity: 0.5;
2362 opacity: 0.5;
2311 }
2363 }
2312 }
2364 }
2313
2365
2314 &.next {
2366 &.next {
2315 border: @border-thickness solid @grey5;
2367 border: @border-thickness solid @grey5;
2316 border-top-right-radius: @border-radius;
2368 border-top-right-radius: @border-radius;
2317 border-bottom-right-radius: @border-radius;
2369 border-bottom-right-radius: @border-radius;
2318
2370
2319 &:hover {
2371 &:hover {
2320 border-color: @grey4;
2372 border-color: @grey4;
2321 }
2373 }
2322
2374
2323 .disabled {
2375 .disabled {
2324 color: @grey5;
2376 color: @grey5;
2325 cursor: not-allowed;
2377 cursor: not-allowed;
2326 opacity: 0.5;
2378 opacity: 0.5;
2327 }
2379 }
2328 }
2380 }
2329 }
2381 }
2330
2382
2331 .browser-cur-rev {
2383 .browser-cur-rev {
2332
2384
2333 span{
2385 span{
2334 margin: 0;
2386 margin: 0;
2335 color: @rcblue;
2387 color: @rcblue;
2336 height: 12px;
2388 height: 12px;
2337 display: inline-block;
2389 display: inline-block;
2338 padding: 0.7em 1em ;
2390 padding: 0.7em 1em ;
2339 border: @border-thickness solid @rcblue;
2391 border: @border-thickness solid @rcblue;
2340 margin-right: @padding;
2392 margin-right: @padding;
2341 }
2393 }
2342 }
2394 }
2343
2395
2344 }
2396 }
2345
2397
2346 .select-index-number {
2398 .select-index-number {
2347 margin: 0 0 0 20px;
2399 margin: 0 0 0 20px;
2348 color: @grey3;
2400 color: @grey3;
2349 }
2401 }
2350
2402
2351 .search_activate {
2403 .search_activate {
2352 display: table-cell;
2404 display: table-cell;
2353 vertical-align: middle;
2405 vertical-align: middle;
2354
2406
2355 input, label{
2407 input, label{
2356 margin: 0;
2408 margin: 0;
2357 padding: 0;
2409 padding: 0;
2358 }
2410 }
2359
2411
2360 input{
2412 input{
2361 margin-left: @textmargin;
2413 margin-left: @textmargin;
2362 }
2414 }
2363
2415
2364 }
2416 }
2365 }
2417 }
2366
2418
2367 .browser-cur-rev{
2419 .browser-cur-rev{
2368 margin-bottom: @textmargin;
2420 margin-bottom: @textmargin;
2369 }
2421 }
2370
2422
2371 #node_filter_box_loading{
2423 #node_filter_box_loading{
2372 .info_text;
2424 .info_text;
2373 }
2425 }
2374
2426
2375 .browser-search {
2427 .browser-search {
2376 margin: -25px 0px 5px 0px;
2428 margin: -25px 0px 5px 0px;
2377 }
2429 }
2378
2430
2379 .files-quick-filter {
2431 .files-quick-filter {
2380 float: right;
2432 float: right;
2381 width: 180px;
2433 width: 180px;
2382 position: relative;
2434 position: relative;
2383 }
2435 }
2384
2436
2385 .files-filter-box {
2437 .files-filter-box {
2386 display: flex;
2438 display: flex;
2387 padding: 0px;
2439 padding: 0px;
2388 border-radius: 3px;
2440 border-radius: 3px;
2389 margin-bottom: 0;
2441 margin-bottom: 0;
2390
2442
2391 a {
2443 a {
2392 border: none !important;
2444 border: none !important;
2393 }
2445 }
2394
2446
2395 li {
2447 li {
2396 list-style-type: none
2448 list-style-type: none
2397 }
2449 }
2398 }
2450 }
2399
2451
2400 .files-filter-box-path {
2452 .files-filter-box-path {
2401 line-height: 33px;
2453 line-height: 33px;
2402 padding: 0;
2454 padding: 0;
2403 width: 20px;
2455 width: 20px;
2404 position: absolute;
2456 position: absolute;
2405 z-index: 11;
2457 z-index: 11;
2406 left: 5px;
2458 left: 5px;
2407 }
2459 }
2408
2460
2409 .files-filter-box-input {
2461 .files-filter-box-input {
2410 margin-right: 0;
2462 margin-right: 0;
2411
2463
2412 input {
2464 input {
2413 border: 1px solid @white;
2465 border: 1px solid @white;
2414 padding-left: 25px;
2466 padding-left: 25px;
2415 width: 145px;
2467 width: 145px;
2416
2468
2417 &:hover {
2469 &:hover {
2418 border-color: @grey6;
2470 border-color: @grey6;
2419 }
2471 }
2420
2472
2421 &:focus {
2473 &:focus {
2422 border-color: @grey5;
2474 border-color: @grey5;
2423 }
2475 }
2424 }
2476 }
2425 }
2477 }
2426
2478
2427 .browser-result{
2479 .browser-result{
2428 td a{
2480 td a{
2429 margin-left: 0.5em;
2481 margin-left: 0.5em;
2430 display: inline-block;
2482 display: inline-block;
2431
2483
2432 em {
2484 em {
2433 font-weight: @text-bold-weight;
2485 font-weight: @text-bold-weight;
2434 font-family: @text-bold;
2486 font-family: @text-bold;
2435 }
2487 }
2436 }
2488 }
2437 }
2489 }
2438
2490
2439 .browser-highlight{
2491 .browser-highlight{
2440 background-color: @grey5-alpha;
2492 background-color: @grey5-alpha;
2441 }
2493 }
2442
2494
2443
2495
2444 .edit-file-fieldset #location,
2496 .edit-file-fieldset #location,
2445 .edit-file-fieldset #filename {
2497 .edit-file-fieldset #filename {
2446 display: flex;
2498 display: flex;
2447 width: -moz-available; /* WebKit-based browsers will ignore this. */
2499 width: -moz-available; /* WebKit-based browsers will ignore this. */
2448 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2500 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2449 width: fill-available;
2501 width: fill-available;
2450 border: 0;
2502 border: 0;
2451 }
2503 }
2452
2504
2453 .path-items {
2505 .path-items {
2454 display: flex;
2506 display: flex;
2455 padding: 0;
2507 padding: 0;
2456 border: 1px solid #eeeeee;
2508 border: 1px solid #eeeeee;
2457 width: 100%;
2509 width: 100%;
2458 float: left;
2510 float: left;
2459
2511
2460 .breadcrumb-path {
2512 .breadcrumb-path {
2461 line-height: 30px;
2513 line-height: 30px;
2462 padding: 0 4px;
2514 padding: 0 4px;
2463 white-space: nowrap;
2515 white-space: nowrap;
2464 }
2516 }
2465
2517
2466 .location-path {
2518 .location-path {
2467 width: -moz-available; /* WebKit-based browsers will ignore this. */
2519 width: -moz-available; /* WebKit-based browsers will ignore this. */
2468 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2520 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2469 width: fill-available;
2521 width: fill-available;
2470
2522
2471 .file-name-input {
2523 .file-name-input {
2472 padding: 0.5em 0;
2524 padding: 0.5em 0;
2473 }
2525 }
2474
2526
2475 }
2527 }
2476
2528
2477 ul {
2529 ul {
2478 display: flex;
2530 display: flex;
2479 margin: 0;
2531 margin: 0;
2480 padding: 0;
2532 padding: 0;
2481 width: 100%;
2533 width: 100%;
2482 }
2534 }
2483
2535
2484 li {
2536 li {
2485 list-style-type: none;
2537 list-style-type: none;
2486 }
2538 }
2487
2539
2488 }
2540 }
2489
2541
2490 .editor-items {
2542 .editor-items {
2491 height: 40px;
2543 height: 40px;
2492 margin: 10px 0 -17px 10px;
2544 margin: 10px 0 -17px 10px;
2493
2545
2494 .editor-action {
2546 .editor-action {
2495 cursor: pointer;
2547 cursor: pointer;
2496 }
2548 }
2497
2549
2498 .editor-action.active {
2550 .editor-action.active {
2499 border-bottom: 2px solid #5C5C5C;
2551 border-bottom: 2px solid #5C5C5C;
2500 }
2552 }
2501
2553
2502 li {
2554 li {
2503 list-style-type: none;
2555 list-style-type: none;
2504 }
2556 }
2505 }
2557 }
2506
2558
2507 .edit-file-fieldset .message textarea {
2559 .edit-file-fieldset .message textarea {
2508 border: 1px solid #eeeeee;
2560 border: 1px solid #eeeeee;
2509 }
2561 }
2510
2562
2511 #files_data .codeblock {
2563 #files_data .codeblock {
2512 background-color: #F5F5F5;
2564 background-color: #F5F5F5;
2513 }
2565 }
2514
2566
2515 #editor_preview {
2567 #editor_preview {
2516 background: white;
2568 background: white;
2517 }
2569 }
2518
2570
2519 .show-editor {
2571 .show-editor {
2520 padding: 10px;
2572 padding: 10px;
2521 background-color: white;
2573 background-color: white;
2522
2574
2523 }
2575 }
2524
2576
2525 .show-preview {
2577 .show-preview {
2526 padding: 10px;
2578 padding: 10px;
2527 background-color: white;
2579 background-color: white;
2528 border-left: 1px solid #eeeeee;
2580 border-left: 1px solid #eeeeee;
2529 }
2581 }
2530 // quick filter
2582 // quick filter
2531 .grid-quick-filter {
2583 .grid-quick-filter {
2532 float: right;
2584 float: right;
2533 position: relative;
2585 position: relative;
2534 }
2586 }
2535
2587
2536 .grid-filter-box {
2588 .grid-filter-box {
2537 display: flex;
2589 display: flex;
2538 padding: 0px;
2590 padding: 0px;
2539 border-radius: 3px;
2591 border-radius: 3px;
2540 margin-bottom: 0;
2592 margin-bottom: 0;
2541
2593
2542 a {
2594 a {
2543 border: none !important;
2595 border: none !important;
2544 }
2596 }
2545
2597
2546 li {
2598 li {
2547 list-style-type: none
2599 list-style-type: none
2548 }
2600 }
2549 }
2601 }
2550
2602
2551 .grid-filter-box-icon {
2603 .grid-filter-box-icon {
2552 line-height: 33px;
2604 line-height: 33px;
2553 padding: 0;
2605 padding: 0;
2554 width: 20px;
2606 width: 20px;
2555 position: absolute;
2607 position: absolute;
2556 z-index: 11;
2608 z-index: 11;
2557 left: 5px;
2609 left: 5px;
2558 }
2610 }
2559
2611
2560 .grid-filter-box-input {
2612 .grid-filter-box-input {
2561 margin-right: 0;
2613 margin-right: 0;
2562
2614
2563 input {
2615 input {
2564 border: 1px solid @white;
2616 border: 1px solid @white;
2565 padding-left: 25px;
2617 padding-left: 25px;
2566 width: 145px;
2618 width: 145px;
2567
2619
2568 &:hover {
2620 &:hover {
2569 border-color: @grey6;
2621 border-color: @grey6;
2570 }
2622 }
2571
2623
2572 &:focus {
2624 &:focus {
2573 border-color: @grey5;
2625 border-color: @grey5;
2574 }
2626 }
2575 }
2627 }
2576 }
2628 }
2577
2629
2578
2630
2579
2631
2580 // Search
2632 // Search
2581
2633
2582 .search-form{
2634 .search-form{
2583 #q {
2635 #q {
2584 width: @search-form-width;
2636 width: @search-form-width;
2585 }
2637 }
2586 .fields{
2638 .fields{
2587 margin: 0 0 @space;
2639 margin: 0 0 @space;
2588 }
2640 }
2589
2641
2590 label{
2642 label{
2591 display: inline-block;
2643 display: inline-block;
2592 margin-right: @textmargin;
2644 margin-right: @textmargin;
2593 padding-top: 0.25em;
2645 padding-top: 0.25em;
2594 }
2646 }
2595
2647
2596
2648
2597 .results{
2649 .results{
2598 clear: both;
2650 clear: both;
2599 margin: 0 0 @padding;
2651 margin: 0 0 @padding;
2600 }
2652 }
2601
2653
2602 .search-tags {
2654 .search-tags {
2603 padding: 5px 0;
2655 padding: 5px 0;
2604 }
2656 }
2605 }
2657 }
2606
2658
2607 div.search-feedback-items {
2659 div.search-feedback-items {
2608 display: inline-block;
2660 display: inline-block;
2609 }
2661 }
2610
2662
2611 div.search-code-body {
2663 div.search-code-body {
2612 background-color: #ffffff; padding: 5px 0 5px 10px;
2664 background-color: #ffffff; padding: 5px 0 5px 10px;
2613 pre {
2665 pre {
2614 .match { background-color: #faffa6;}
2666 .match { background-color: #faffa6;}
2615 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2667 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2616 }
2668 }
2617 }
2669 }
2618
2670
2619 .expand_commit.search {
2671 .expand_commit.search {
2620 .show_more.open {
2672 .show_more.open {
2621 height: auto;
2673 height: auto;
2622 max-height: none;
2674 max-height: none;
2623 }
2675 }
2624 }
2676 }
2625
2677
2626 .search-results {
2678 .search-results {
2627
2679
2628 h2 {
2680 h2 {
2629 margin-bottom: 0;
2681 margin-bottom: 0;
2630 }
2682 }
2631 .codeblock {
2683 .codeblock {
2632 border: none;
2684 border: none;
2633 background: transparent;
2685 background: transparent;
2634 }
2686 }
2635
2687
2636 .codeblock-header {
2688 .codeblock-header {
2637 border: none;
2689 border: none;
2638 background: transparent;
2690 background: transparent;
2639 }
2691 }
2640
2692
2641 .code-body {
2693 .code-body {
2642 border: @border-thickness solid @grey6;
2694 border: @border-thickness solid @grey6;
2643 .border-radius(@border-radius);
2695 .border-radius(@border-radius);
2644 }
2696 }
2645
2697
2646 .td-commit {
2698 .td-commit {
2647 &:extend(pre);
2699 &:extend(pre);
2648 border-bottom: @border-thickness solid @border-default-color;
2700 border-bottom: @border-thickness solid @border-default-color;
2649 }
2701 }
2650
2702
2651 .message {
2703 .message {
2652 height: auto;
2704 height: auto;
2653 max-width: 350px;
2705 max-width: 350px;
2654 white-space: normal;
2706 white-space: normal;
2655 text-overflow: initial;
2707 text-overflow: initial;
2656 overflow: visible;
2708 overflow: visible;
2657
2709
2658 .match { background-color: #faffa6;}
2710 .match { background-color: #faffa6;}
2659 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2711 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2660 }
2712 }
2661
2713
2662 .path {
2714 .path {
2663 border-bottom: none !important;
2715 border-bottom: none !important;
2664 border-left: 1px solid @grey6 !important;
2716 border-left: 1px solid @grey6 !important;
2665 border-right: 1px solid @grey6 !important;
2717 border-right: 1px solid @grey6 !important;
2666 }
2718 }
2667 }
2719 }
2668
2720
2669 table.rctable td.td-search-results div {
2721 table.rctable td.td-search-results div {
2670 max-width: 100%;
2722 max-width: 100%;
2671 }
2723 }
2672
2724
2673 #tip-box, .tip-box{
2725 #tip-box, .tip-box{
2674 padding: @menupadding/2;
2726 padding: @menupadding/2;
2675 display: block;
2727 display: block;
2676 border: @border-thickness solid @border-highlight-color;
2728 border: @border-thickness solid @border-highlight-color;
2677 .border-radius(@border-radius);
2729 .border-radius(@border-radius);
2678 background-color: white;
2730 background-color: white;
2679 z-index: 99;
2731 z-index: 99;
2680 white-space: pre-wrap;
2732 white-space: pre-wrap;
2681 }
2733 }
2682
2734
2683 #linktt {
2735 #linktt {
2684 width: 79px;
2736 width: 79px;
2685 }
2737 }
2686
2738
2687 #help_kb .modal-content{
2739 #help_kb .modal-content{
2688 max-width: 750px;
2740 max-width: 750px;
2689 margin: 10% auto;
2741 margin: 10% auto;
2690
2742
2691 table{
2743 table{
2692 td,th{
2744 td,th{
2693 border-bottom: none;
2745 border-bottom: none;
2694 line-height: 2.5em;
2746 line-height: 2.5em;
2695 }
2747 }
2696 th{
2748 th{
2697 padding-bottom: @textmargin/2;
2749 padding-bottom: @textmargin/2;
2698 }
2750 }
2699 td.keys{
2751 td.keys{
2700 text-align: center;
2752 text-align: center;
2701 }
2753 }
2702 }
2754 }
2703
2755
2704 .block-left{
2756 .block-left{
2705 width: 45%;
2757 width: 45%;
2706 margin-right: 5%;
2758 margin-right: 5%;
2707 }
2759 }
2708 .modal-footer{
2760 .modal-footer{
2709 clear: both;
2761 clear: both;
2710 }
2762 }
2711 .key.tag{
2763 .key.tag{
2712 padding: 0.5em;
2764 padding: 0.5em;
2713 background-color: @rcblue;
2765 background-color: @rcblue;
2714 color: white;
2766 color: white;
2715 border-color: @rcblue;
2767 border-color: @rcblue;
2716 .box-shadow(none);
2768 .box-shadow(none);
2717 }
2769 }
2718 }
2770 }
2719
2771
2720
2772
2721
2773
2722 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2774 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2723
2775
2724 @import 'statistics-graph';
2776 @import 'statistics-graph';
2725 @import 'tables';
2777 @import 'tables';
2726 @import 'forms';
2778 @import 'forms';
2727 @import 'diff';
2779 @import 'diff';
2728 @import 'summary';
2780 @import 'summary';
2729 @import 'navigation';
2781 @import 'navigation';
2730
2782
2731 //--- SHOW/HIDE SECTIONS --//
2783 //--- SHOW/HIDE SECTIONS --//
2732
2784
2733 .btn-collapse {
2785 .btn-collapse {
2734 float: right;
2786 float: right;
2735 text-align: right;
2787 text-align: right;
2736 font-family: @text-light;
2788 font-family: @text-light;
2737 font-size: @basefontsize;
2789 font-size: @basefontsize;
2738 cursor: pointer;
2790 cursor: pointer;
2739 border: none;
2791 border: none;
2740 color: @rcblue;
2792 color: @rcblue;
2741 }
2793 }
2742
2794
2743 table.rctable,
2795 table.rctable,
2744 table.dataTable {
2796 table.dataTable {
2745 .btn-collapse {
2797 .btn-collapse {
2746 float: right;
2798 float: right;
2747 text-align: right;
2799 text-align: right;
2748 }
2800 }
2749 }
2801 }
2750
2802
2751 table.rctable {
2803 table.rctable {
2752 &.permissions {
2804 &.permissions {
2753
2805
2754 th.td-owner {
2806 th.td-owner {
2755 padding: 0;
2807 padding: 0;
2756 }
2808 }
2757
2809
2758 th {
2810 th {
2759 font-weight: normal;
2811 font-weight: normal;
2760 padding: 0 5px;
2812 padding: 0 5px;
2761 }
2813 }
2762
2814
2763 }
2815 }
2764 }
2816 }
2765
2817
2766
2818
2767 // TODO: johbo: Fix for IE10, this avoids that we see a border
2819 // TODO: johbo: Fix for IE10, this avoids that we see a border
2768 // and padding around checkboxes and radio boxes. Move to the right place,
2820 // and padding around checkboxes and radio boxes. Move to the right place,
2769 // or better: Remove this once we did the form refactoring.
2821 // or better: Remove this once we did the form refactoring.
2770 input[type=checkbox],
2822 input[type=checkbox],
2771 input[type=radio] {
2823 input[type=radio] {
2772 padding: 0;
2824 padding: 0;
2773 border: none;
2825 border: none;
2774 }
2826 }
2775
2827
2776 .toggle-ajax-spinner{
2828 .toggle-ajax-spinner{
2777 height: 16px;
2829 height: 16px;
2778 width: 16px;
2830 width: 16px;
2779 }
2831 }
2780
2832
2781
2833
2782 .markup-form .clearfix {
2834 .markup-form .clearfix {
2783 .border-radius(@border-radius);
2835 .border-radius(@border-radius);
2784 margin: 0px;
2836 margin: 0px;
2785 }
2837 }
2786
2838
2787 .markup-form-area {
2839 .markup-form-area {
2788 padding: 8px 12px;
2840 padding: 8px 12px;
2789 border: 1px solid @grey4;
2841 border: 1px solid @grey4;
2790 .border-radius(@border-radius);
2842 .border-radius(@border-radius);
2791 }
2843 }
2792
2844
2793 .markup-form-area-header .nav-links {
2845 .markup-form-area-header .nav-links {
2794 display: flex;
2846 display: flex;
2795 flex-flow: row wrap;
2847 flex-flow: row wrap;
2796 -webkit-flex-flow: row wrap;
2848 -webkit-flex-flow: row wrap;
2797 width: 100%;
2849 width: 100%;
2798 }
2850 }
2799
2851
2800 .markup-form-area-footer {
2852 .markup-form-area-footer {
2801 display: flex;
2853 display: flex;
2802 }
2854 }
2803
2855
2804 .markup-form-area-footer .toolbar {
2856 .markup-form-area-footer .toolbar {
2805
2857
2806 }
2858 }
2807
2859
2808 // markup Form
2860 // markup Form
2809 div.markup-form {
2861 div.markup-form {
2810 margin-top: 20px;
2862 margin-top: 20px;
2811 }
2863 }
2812
2864
2813 .markup-form strong {
2865 .markup-form strong {
2814 display: block;
2866 display: block;
2815 margin-bottom: 15px;
2867 margin-bottom: 15px;
2816 }
2868 }
2817
2869
2818 .markup-form textarea {
2870 .markup-form textarea {
2819 width: 100%;
2871 width: 100%;
2820 height: 100px;
2872 height: 100px;
2821 font-family: @text-monospace;
2873 font-family: @text-monospace;
2822 }
2874 }
2823
2875
2824 form.markup-form {
2876 form.markup-form {
2825 margin-top: 10px;
2877 margin-top: 10px;
2826 margin-left: 10px;
2878 margin-left: 10px;
2827 }
2879 }
2828
2880
2829 .markup-form .comment-block-ta,
2881 .markup-form .comment-block-ta,
2830 .markup-form .preview-box {
2882 .markup-form .preview-box {
2831 .border-radius(@border-radius);
2883 .border-radius(@border-radius);
2832 .box-sizing(border-box);
2884 .box-sizing(border-box);
2833 background-color: white;
2885 background-color: white;
2834 }
2886 }
2835
2887
2836 .markup-form .preview-box.unloaded {
2888 .markup-form .preview-box.unloaded {
2837 height: 50px;
2889 height: 50px;
2838 text-align: center;
2890 text-align: center;
2839 padding: 20px;
2891 padding: 20px;
2840 background-color: white;
2892 background-color: white;
2841 }
2893 }
2842
2894
2843
2895
2844 .dropzone-wrapper {
2896 .dropzone-wrapper {
2845 border: 1px solid @grey5;
2897 border: 1px solid @grey5;
2846 padding: 20px;
2898 padding: 20px;
2847 }
2899 }
2848
2900
2849 .dropzone,
2901 .dropzone,
2850 .dropzone-pure {
2902 .dropzone-pure {
2851 border: 2px dashed @grey5;
2903 border: 2px dashed @grey5;
2852 border-radius: 5px;
2904 border-radius: 5px;
2853 background: white;
2905 background: white;
2854 min-height: 200px;
2906 min-height: 200px;
2855 padding: 54px;
2907 padding: 54px;
2856
2908
2857 .dz-message {
2909 .dz-message {
2858 font-weight: 700;
2910 font-weight: 700;
2859 text-align: center;
2911 text-align: center;
2860 margin: 2em 0;
2912 margin: 2em 0;
2861 }
2913 }
2862
2914
2863 }
2915 }
2864
2916
2865 .dz-preview {
2917 .dz-preview {
2866 margin: 10px 0 !important;
2918 margin: 10px 0 !important;
2867 position: relative;
2919 position: relative;
2868 vertical-align: top;
2920 vertical-align: top;
2869 padding: 10px;
2921 padding: 10px;
2870 border-bottom: 1px solid @grey5;
2922 border-bottom: 1px solid @grey5;
2871 }
2923 }
2872
2924
2873 .dz-filename {
2925 .dz-filename {
2874 font-weight: 700;
2926 font-weight: 700;
2875 float: left;
2927 float: left;
2876 }
2928 }
2877
2929
2878 .dz-sending {
2930 .dz-sending {
2879 float: right;
2931 float: right;
2880 }
2932 }
2881
2933
2882 .dz-response {
2934 .dz-response {
2883 clear: both
2935 clear: both
2884 }
2936 }
2885
2937
2886 .dz-filename-size {
2938 .dz-filename-size {
2887 float: right
2939 float: right
2888 }
2940 }
2889
2941
2890 .dz-error-message {
2942 .dz-error-message {
2891 color: @alert2;
2943 color: @alert2;
2892 padding-top: 10px;
2944 padding-top: 10px;
2893 clear: both;
2945 clear: both;
2894 }
2946 }
2895
2947
2896
2948
2897 .user-hovercard {
2949 .user-hovercard {
2898 padding: 5px;
2950 padding: 5px;
2899 }
2951 }
2900
2952
2901 .user-hovercard-icon {
2953 .user-hovercard-icon {
2902 display: inline;
2954 display: inline;
2903 padding: 0;
2955 padding: 0;
2904 box-sizing: content-box;
2956 box-sizing: content-box;
2905 border-radius: 50%;
2957 border-radius: 50%;
2906 float: left;
2958 float: left;
2907 }
2959 }
2908
2960
2909 .user-hovercard-name {
2961 .user-hovercard-name {
2910 float: right;
2962 float: right;
2911 vertical-align: top;
2963 vertical-align: top;
2912 padding-left: 10px;
2964 padding-left: 10px;
2913 min-width: 150px;
2965 min-width: 150px;
2914 }
2966 }
2915
2967
2916 .user-hovercard-bio {
2968 .user-hovercard-bio {
2917 clear: both;
2969 clear: both;
2918 padding-top: 10px;
2970 padding-top: 10px;
2919 }
2971 }
2920
2972
2921 .user-hovercard-header {
2973 .user-hovercard-header {
2922 clear: both;
2974 clear: both;
2923 min-height: 10px;
2975 min-height: 10px;
2924 }
2976 }
2925
2977
2926 .user-hovercard-footer {
2978 .user-hovercard-footer {
2927 clear: both;
2979 clear: both;
2928 min-height: 10px;
2980 min-height: 10px;
2929 }
2981 }
2930
2982
2931 .user-group-hovercard {
2983 .user-group-hovercard {
2932 padding: 5px;
2984 padding: 5px;
2933 }
2985 }
2934
2986
2935 .user-group-hovercard-icon {
2987 .user-group-hovercard-icon {
2936 display: inline;
2988 display: inline;
2937 padding: 0;
2989 padding: 0;
2938 box-sizing: content-box;
2990 box-sizing: content-box;
2939 border-radius: 50%;
2991 border-radius: 50%;
2940 float: left;
2992 float: left;
2941 }
2993 }
2942
2994
2943 .user-group-hovercard-name {
2995 .user-group-hovercard-name {
2944 float: left;
2996 float: left;
2945 vertical-align: top;
2997 vertical-align: top;
2946 padding-left: 10px;
2998 padding-left: 10px;
2947 min-width: 150px;
2999 min-width: 150px;
2948 }
3000 }
2949
3001
2950 .user-group-hovercard-icon i {
3002 .user-group-hovercard-icon i {
2951 border: 1px solid @grey4;
3003 border: 1px solid @grey4;
2952 border-radius: 4px;
3004 border-radius: 4px;
2953 }
3005 }
2954
3006
2955 .user-group-hovercard-bio {
3007 .user-group-hovercard-bio {
2956 clear: both;
3008 clear: both;
2957 padding-top: 10px;
3009 padding-top: 10px;
2958 line-height: 1.0em;
3010 line-height: 1.0em;
2959 }
3011 }
2960
3012
2961 .user-group-hovercard-header {
3013 .user-group-hovercard-header {
2962 clear: both;
3014 clear: both;
2963 min-height: 10px;
3015 min-height: 10px;
2964 }
3016 }
2965
3017
2966 .user-group-hovercard-footer {
3018 .user-group-hovercard-footer {
2967 clear: both;
3019 clear: both;
2968 min-height: 10px;
3020 min-height: 10px;
2969 }
3021 }
2970
3022
2971 .pr-hovercard-header {
3023 .pr-hovercard-header {
2972 clear: both;
3024 clear: both;
2973 display: block;
3025 display: block;
2974 line-height: 20px;
3026 line-height: 20px;
2975 }
3027 }
2976
3028
2977 .pr-hovercard-user {
3029 .pr-hovercard-user {
2978 display: flex;
3030 display: flex;
2979 align-items: center;
3031 align-items: center;
2980 padding-left: 5px;
3032 padding-left: 5px;
2981 }
3033 }
2982
3034
2983 .pr-hovercard-title {
3035 .pr-hovercard-title {
2984 padding-top: 5px;
3036 padding-top: 5px;
2985 } No newline at end of file
3037 }
@@ -1,929 +1,931 b''
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 var firefoxAnchorFix = function() {
19 var firefoxAnchorFix = function() {
20 // hack to make anchor links behave properly on firefox, in our inline
20 // hack to make anchor links behave properly on firefox, in our inline
21 // comments generation when comments are injected firefox is misbehaving
21 // comments generation when comments are injected firefox is misbehaving
22 // when jumping to anchor links
22 // when jumping to anchor links
23 if (location.href.indexOf('#') > -1) {
23 if (location.href.indexOf('#') > -1) {
24 location.href += '';
24 location.href += '';
25 }
25 }
26 };
26 };
27
27
28 var linkifyComments = function(comments) {
28 var linkifyComments = function(comments) {
29 var firstCommentId = null;
29 var firstCommentId = null;
30 if (comments) {
30 if (comments) {
31 firstCommentId = $(comments[0]).data('comment-id');
31 firstCommentId = $(comments[0]).data('comment-id');
32 }
32 }
33
33
34 if (firstCommentId){
34 if (firstCommentId){
35 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
35 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
36 }
36 }
37 };
37 };
38
38
39 var bindToggleButtons = function() {
39 var bindToggleButtons = function() {
40 $('.comment-toggle').on('click', function() {
40 $('.comment-toggle').on('click', function() {
41 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
41 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
42 });
42 });
43 };
43 };
44
44
45
45
46
46
47 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
47 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
48 failHandler = failHandler || function() {};
48 failHandler = failHandler || function() {};
49 postData = toQueryString(postData);
49 postData = toQueryString(postData);
50 var request = $.ajax({
50 var request = $.ajax({
51 url: url,
51 url: url,
52 type: 'POST',
52 type: 'POST',
53 data: postData,
53 data: postData,
54 headers: {'X-PARTIAL-XHR': true}
54 headers: {'X-PARTIAL-XHR': true}
55 })
55 })
56 .done(function (data) {
56 .done(function (data) {
57 successHandler(data);
57 successHandler(data);
58 })
58 })
59 .fail(function (data, textStatus, errorThrown) {
59 .fail(function (data, textStatus, errorThrown) {
60 failHandler(data, textStatus, errorThrown)
60 failHandler(data, textStatus, errorThrown)
61 });
61 });
62 return request;
62 return request;
63 };
63 };
64
64
65
65
66
66
67
67
68 /* Comment form for main and inline comments */
68 /* Comment form for main and inline comments */
69 (function(mod) {
69 (function(mod) {
70
70
71 if (typeof exports == "object" && typeof module == "object") {
71 if (typeof exports == "object" && typeof module == "object") {
72 // CommonJS
72 // CommonJS
73 module.exports = mod();
73 module.exports = mod();
74 }
74 }
75 else {
75 else {
76 // Plain browser env
76 // Plain browser env
77 (this || window).CommentForm = mod();
77 (this || window).CommentForm = mod();
78 }
78 }
79
79
80 })(function() {
80 })(function() {
81 "use strict";
81 "use strict";
82
82
83 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId) {
83 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId) {
84 if (!(this instanceof CommentForm)) {
84 if (!(this instanceof CommentForm)) {
85 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId);
85 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId);
86 }
86 }
87
87
88 // bind the element instance to our Form
88 // bind the element instance to our Form
89 $(formElement).get(0).CommentForm = this;
89 $(formElement).get(0).CommentForm = this;
90
90
91 this.withLineNo = function(selector) {
91 this.withLineNo = function(selector) {
92 var lineNo = this.lineNo;
92 var lineNo = this.lineNo;
93 if (lineNo === undefined) {
93 if (lineNo === undefined) {
94 return selector
94 return selector
95 } else {
95 } else {
96 return selector + '_' + lineNo;
96 return selector + '_' + lineNo;
97 }
97 }
98 };
98 };
99
99
100 this.commitId = commitId;
100 this.commitId = commitId;
101 this.pullRequestId = pullRequestId;
101 this.pullRequestId = pullRequestId;
102 this.lineNo = lineNo;
102 this.lineNo = lineNo;
103 this.initAutocompleteActions = initAutocompleteActions;
103 this.initAutocompleteActions = initAutocompleteActions;
104
104
105 this.previewButton = this.withLineNo('#preview-btn');
105 this.previewButton = this.withLineNo('#preview-btn');
106 this.previewContainer = this.withLineNo('#preview-container');
106 this.previewContainer = this.withLineNo('#preview-container');
107
107
108 this.previewBoxSelector = this.withLineNo('#preview-box');
108 this.previewBoxSelector = this.withLineNo('#preview-box');
109
109
110 this.editButton = this.withLineNo('#edit-btn');
110 this.editButton = this.withLineNo('#edit-btn');
111 this.editContainer = this.withLineNo('#edit-container');
111 this.editContainer = this.withLineNo('#edit-container');
112 this.cancelButton = this.withLineNo('#cancel-btn');
112 this.cancelButton = this.withLineNo('#cancel-btn');
113 this.commentType = this.withLineNo('#comment_type');
113 this.commentType = this.withLineNo('#comment_type');
114
114
115 this.resolvesId = null;
115 this.resolvesId = null;
116 this.resolvesActionId = null;
116 this.resolvesActionId = null;
117
117
118 this.closesPr = '#close_pull_request';
118 this.closesPr = '#close_pull_request';
119
119
120 this.cmBox = this.withLineNo('#text');
120 this.cmBox = this.withLineNo('#text');
121 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
121 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
122
122
123 this.statusChange = this.withLineNo('#change_status');
123 this.statusChange = this.withLineNo('#change_status');
124
124
125 this.submitForm = formElement;
125 this.submitForm = formElement;
126 this.submitButton = $(this.submitForm).find('input[type="submit"]');
126 this.submitButton = $(this.submitForm).find('input[type="submit"]');
127 this.submitButtonText = this.submitButton.val();
127 this.submitButtonText = this.submitButton.val();
128
128
129 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
129 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
130 {'repo_name': templateContext.repo_name,
130 {'repo_name': templateContext.repo_name,
131 'commit_id': templateContext.commit_data.commit_id});
131 'commit_id': templateContext.commit_data.commit_id});
132
132
133 if (resolvesCommentId){
133 if (resolvesCommentId){
134 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
134 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
135 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
135 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
136 $(this.commentType).prop('disabled', true);
136 $(this.commentType).prop('disabled', true);
137 $(this.commentType).addClass('disabled');
137 $(this.commentType).addClass('disabled');
138
138
139 // disable select
139 // disable select
140 setTimeout(function() {
140 setTimeout(function() {
141 $(self.statusChange).select2('readonly', true);
141 $(self.statusChange).select2('readonly', true);
142 }, 10);
142 }, 10);
143
143
144 var resolvedInfo = (
144 var resolvedInfo = (
145 '<li class="resolve-action">' +
145 '<li class="resolve-action">' +
146 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
146 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
147 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
147 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
148 '</li>'
148 '</li>'
149 ).format(resolvesCommentId, _gettext('resolve comment'));
149 ).format(resolvesCommentId, _gettext('resolve comment'));
150 $(resolvedInfo).insertAfter($(this.commentType).parent());
150 $(resolvedInfo).insertAfter($(this.commentType).parent());
151 }
151 }
152
152
153 // based on commitId, or pullRequestId decide where do we submit
153 // based on commitId, or pullRequestId decide where do we submit
154 // out data
154 // out data
155 if (this.commitId){
155 if (this.commitId){
156 this.submitUrl = pyroutes.url('repo_commit_comment_create',
156 this.submitUrl = pyroutes.url('repo_commit_comment_create',
157 {'repo_name': templateContext.repo_name,
157 {'repo_name': templateContext.repo_name,
158 'commit_id': this.commitId});
158 'commit_id': this.commitId});
159 this.selfUrl = pyroutes.url('repo_commit',
159 this.selfUrl = pyroutes.url('repo_commit',
160 {'repo_name': templateContext.repo_name,
160 {'repo_name': templateContext.repo_name,
161 'commit_id': this.commitId});
161 'commit_id': this.commitId});
162
162
163 } else if (this.pullRequestId) {
163 } else if (this.pullRequestId) {
164 this.submitUrl = pyroutes.url('pullrequest_comment_create',
164 this.submitUrl = pyroutes.url('pullrequest_comment_create',
165 {'repo_name': templateContext.repo_name,
165 {'repo_name': templateContext.repo_name,
166 'pull_request_id': this.pullRequestId});
166 'pull_request_id': this.pullRequestId});
167 this.selfUrl = pyroutes.url('pullrequest_show',
167 this.selfUrl = pyroutes.url('pullrequest_show',
168 {'repo_name': templateContext.repo_name,
168 {'repo_name': templateContext.repo_name,
169 'pull_request_id': this.pullRequestId});
169 'pull_request_id': this.pullRequestId});
170
170
171 } else {
171 } else {
172 throw new Error(
172 throw new Error(
173 'CommentForm requires pullRequestId, or commitId to be specified.')
173 'CommentForm requires pullRequestId, or commitId to be specified.')
174 }
174 }
175
175
176 // FUNCTIONS and helpers
176 // FUNCTIONS and helpers
177 var self = this;
177 var self = this;
178
178
179 this.isInline = function(){
179 this.isInline = function(){
180 return this.lineNo && this.lineNo != 'general';
180 return this.lineNo && this.lineNo != 'general';
181 };
181 };
182
182
183 this.getCmInstance = function(){
183 this.getCmInstance = function(){
184 return this.cm
184 return this.cm
185 };
185 };
186
186
187 this.setPlaceholder = function(placeholder) {
187 this.setPlaceholder = function(placeholder) {
188 var cm = this.getCmInstance();
188 var cm = this.getCmInstance();
189 if (cm){
189 if (cm){
190 cm.setOption('placeholder', placeholder);
190 cm.setOption('placeholder', placeholder);
191 }
191 }
192 };
192 };
193
193
194 this.getCommentStatus = function() {
194 this.getCommentStatus = function() {
195 return $(this.submitForm).find(this.statusChange).val();
195 return $(this.submitForm).find(this.statusChange).val();
196 };
196 };
197 this.getCommentType = function() {
197 this.getCommentType = function() {
198 return $(this.submitForm).find(this.commentType).val();
198 return $(this.submitForm).find(this.commentType).val();
199 };
199 };
200
200
201 this.getResolvesId = function() {
201 this.getResolvesId = function() {
202 return $(this.submitForm).find(this.resolvesId).val() || null;
202 return $(this.submitForm).find(this.resolvesId).val() || null;
203 };
203 };
204
204
205 this.getClosePr = function() {
205 this.getClosePr = function() {
206 return $(this.submitForm).find(this.closesPr).val() || null;
206 return $(this.submitForm).find(this.closesPr).val() || null;
207 };
207 };
208
208
209 this.markCommentResolved = function(resolvedCommentId){
209 this.markCommentResolved = function(resolvedCommentId){
210 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
210 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolved').show();
211 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
211 $('#comment-label-{0}'.format(resolvedCommentId)).find('.resolve').hide();
212 };
212 };
213
213
214 this.isAllowedToSubmit = function() {
214 this.isAllowedToSubmit = function() {
215 return !$(this.submitButton).prop('disabled');
215 return !$(this.submitButton).prop('disabled');
216 };
216 };
217
217
218 this.initStatusChangeSelector = function(){
218 this.initStatusChangeSelector = function(){
219 var formatChangeStatus = function(state, escapeMarkup) {
219 var formatChangeStatus = function(state, escapeMarkup) {
220 var originalOption = state.element;
220 var originalOption = state.element;
221 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
221 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
222 return tmpl
222 return tmpl
223 };
223 };
224 var formatResult = function(result, container, query, escapeMarkup) {
224 var formatResult = function(result, container, query, escapeMarkup) {
225 return formatChangeStatus(result, escapeMarkup);
225 return formatChangeStatus(result, escapeMarkup);
226 };
226 };
227
227
228 var formatSelection = function(data, container, escapeMarkup) {
228 var formatSelection = function(data, container, escapeMarkup) {
229 return formatChangeStatus(data, escapeMarkup);
229 return formatChangeStatus(data, escapeMarkup);
230 };
230 };
231
231
232 $(this.submitForm).find(this.statusChange).select2({
232 $(this.submitForm).find(this.statusChange).select2({
233 placeholder: _gettext('Status Review'),
233 placeholder: _gettext('Status Review'),
234 formatResult: formatResult,
234 formatResult: formatResult,
235 formatSelection: formatSelection,
235 formatSelection: formatSelection,
236 containerCssClass: "drop-menu status_box_menu",
236 containerCssClass: "drop-menu status_box_menu",
237 dropdownCssClass: "drop-menu-dropdown",
237 dropdownCssClass: "drop-menu-dropdown",
238 dropdownAutoWidth: true,
238 dropdownAutoWidth: true,
239 minimumResultsForSearch: -1
239 minimumResultsForSearch: -1
240 });
240 });
241 $(this.submitForm).find(this.statusChange).on('change', function() {
241 $(this.submitForm).find(this.statusChange).on('change', function() {
242 var status = self.getCommentStatus();
242 var status = self.getCommentStatus();
243
243
244 if (status && !self.isInline()) {
244 if (status && !self.isInline()) {
245 $(self.submitButton).prop('disabled', false);
245 $(self.submitButton).prop('disabled', false);
246 }
246 }
247
247
248 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
248 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
249 self.setPlaceholder(placeholderText)
249 self.setPlaceholder(placeholderText)
250 })
250 })
251 };
251 };
252
252
253 // reset the comment form into it's original state
253 // reset the comment form into it's original state
254 this.resetCommentFormState = function(content) {
254 this.resetCommentFormState = function(content) {
255 content = content || '';
255 content = content || '';
256
256
257 $(this.editContainer).show();
257 $(this.editContainer).show();
258 $(this.editButton).parent().addClass('active');
258 $(this.editButton).parent().addClass('active');
259
259
260 $(this.previewContainer).hide();
260 $(this.previewContainer).hide();
261 $(this.previewButton).parent().removeClass('active');
261 $(this.previewButton).parent().removeClass('active');
262
262
263 this.setActionButtonsDisabled(true);
263 this.setActionButtonsDisabled(true);
264 self.cm.setValue(content);
264 self.cm.setValue(content);
265 self.cm.setOption("readOnly", false);
265 self.cm.setOption("readOnly", false);
266
266
267 if (this.resolvesId) {
267 if (this.resolvesId) {
268 // destroy the resolve action
268 // destroy the resolve action
269 $(this.resolvesId).parent().remove();
269 $(this.resolvesId).parent().remove();
270 }
270 }
271 // reset closingPR flag
271 // reset closingPR flag
272 $('.close-pr-input').remove();
272 $('.close-pr-input').remove();
273
273
274 $(this.statusChange).select2('readonly', false);
274 $(this.statusChange).select2('readonly', false);
275 };
275 };
276
276
277 this.globalSubmitSuccessCallback = function(){
277 this.globalSubmitSuccessCallback = function(){
278 // default behaviour is to call GLOBAL hook, if it's registered.
278 // default behaviour is to call GLOBAL hook, if it's registered.
279 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
279 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
280 commentFormGlobalSubmitSuccessCallback()
280 commentFormGlobalSubmitSuccessCallback()
281 }
281 }
282 };
282 };
283
283
284 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
284 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
285 return _submitAjaxPOST(url, postData, successHandler, failHandler);
285 return _submitAjaxPOST(url, postData, successHandler, failHandler);
286 };
286 };
287
287
288 // overwrite a submitHandler, we need to do it for inline comments
288 // overwrite a submitHandler, we need to do it for inline comments
289 this.setHandleFormSubmit = function(callback) {
289 this.setHandleFormSubmit = function(callback) {
290 this.handleFormSubmit = callback;
290 this.handleFormSubmit = callback;
291 };
291 };
292
292
293 // overwrite a submitSuccessHandler
293 // overwrite a submitSuccessHandler
294 this.setGlobalSubmitSuccessCallback = function(callback) {
294 this.setGlobalSubmitSuccessCallback = function(callback) {
295 this.globalSubmitSuccessCallback = callback;
295 this.globalSubmitSuccessCallback = callback;
296 };
296 };
297
297
298 // default handler for for submit for main comments
298 // default handler for for submit for main comments
299 this.handleFormSubmit = function() {
299 this.handleFormSubmit = function() {
300 var text = self.cm.getValue();
300 var text = self.cm.getValue();
301 var status = self.getCommentStatus();
301 var status = self.getCommentStatus();
302 var commentType = self.getCommentType();
302 var commentType = self.getCommentType();
303 var resolvesCommentId = self.getResolvesId();
303 var resolvesCommentId = self.getResolvesId();
304 var closePullRequest = self.getClosePr();
304 var closePullRequest = self.getClosePr();
305
305
306 if (text === "" && !status) {
306 if (text === "" && !status) {
307 return;
307 return;
308 }
308 }
309
309
310 var excludeCancelBtn = false;
310 var excludeCancelBtn = false;
311 var submitEvent = true;
311 var submitEvent = true;
312 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
312 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
313 self.cm.setOption("readOnly", true);
313 self.cm.setOption("readOnly", true);
314
314
315 var postData = {
315 var postData = {
316 'text': text,
316 'text': text,
317 'changeset_status': status,
317 'changeset_status': status,
318 'comment_type': commentType,
318 'comment_type': commentType,
319 'csrf_token': CSRF_TOKEN
319 'csrf_token': CSRF_TOKEN
320 };
320 };
321
321
322 if (resolvesCommentId) {
322 if (resolvesCommentId) {
323 postData['resolves_comment_id'] = resolvesCommentId;
323 postData['resolves_comment_id'] = resolvesCommentId;
324 }
324 }
325
325
326 if (closePullRequest) {
326 if (closePullRequest) {
327 postData['close_pull_request'] = true;
327 postData['close_pull_request'] = true;
328 }
328 }
329
329
330 var submitSuccessCallback = function(o) {
330 var submitSuccessCallback = function(o) {
331 // reload page if we change status for single commit.
331 // reload page if we change status for single commit.
332 if (status && self.commitId) {
332 if (status && self.commitId) {
333 location.reload(true);
333 location.reload(true);
334 } else {
334 } else {
335 $('#injected_page_comments').append(o.rendered_text);
335 $('#injected_page_comments').append(o.rendered_text);
336 self.resetCommentFormState();
336 self.resetCommentFormState();
337 timeagoActivate();
337 timeagoActivate();
338 tooltipActivate();
338 tooltipActivate();
339
339
340 // mark visually which comment was resolved
340 // mark visually which comment was resolved
341 if (resolvesCommentId) {
341 if (resolvesCommentId) {
342 self.markCommentResolved(resolvesCommentId);
342 self.markCommentResolved(resolvesCommentId);
343 }
343 }
344 }
344 }
345
345
346 // run global callback on submit
346 // run global callback on submit
347 self.globalSubmitSuccessCallback();
347 self.globalSubmitSuccessCallback();
348
348
349 };
349 };
350 var submitFailCallback = function(data) {
350 var submitFailCallback = function(data) {
351 alert(
351 alert(
352 "Error while submitting comment.\n" +
352 "Error while submitting comment.\n" +
353 "Error code {0} ({1}).".format(data.status, data.statusText)
353 "Error code {0} ({1}).".format(data.status, data.statusText)
354 );
354 );
355 self.resetCommentFormState(text);
355 self.resetCommentFormState(text);
356 };
356 };
357 self.submitAjaxPOST(
357 self.submitAjaxPOST(
358 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
358 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
359 };
359 };
360
360
361 this.previewSuccessCallback = function(o) {
361 this.previewSuccessCallback = function(o) {
362 $(self.previewBoxSelector).html(o);
362 $(self.previewBoxSelector).html(o);
363 $(self.previewBoxSelector).removeClass('unloaded');
363 $(self.previewBoxSelector).removeClass('unloaded');
364
364
365 // swap buttons, making preview active
365 // swap buttons, making preview active
366 $(self.previewButton).parent().addClass('active');
366 $(self.previewButton).parent().addClass('active');
367 $(self.editButton).parent().removeClass('active');
367 $(self.editButton).parent().removeClass('active');
368
368
369 // unlock buttons
369 // unlock buttons
370 self.setActionButtonsDisabled(false);
370 self.setActionButtonsDisabled(false);
371 };
371 };
372
372
373 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
373 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
374 excludeCancelBtn = excludeCancelBtn || false;
374 excludeCancelBtn = excludeCancelBtn || false;
375 submitEvent = submitEvent || false;
375 submitEvent = submitEvent || false;
376
376
377 $(this.editButton).prop('disabled', state);
377 $(this.editButton).prop('disabled', state);
378 $(this.previewButton).prop('disabled', state);
378 $(this.previewButton).prop('disabled', state);
379
379
380 if (!excludeCancelBtn) {
380 if (!excludeCancelBtn) {
381 $(this.cancelButton).prop('disabled', state);
381 $(this.cancelButton).prop('disabled', state);
382 }
382 }
383
383
384 var submitState = state;
384 var submitState = state;
385 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
385 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
386 // if the value of commit review status is set, we allow
386 // if the value of commit review status is set, we allow
387 // submit button, but only on Main form, isInline means inline
387 // submit button, but only on Main form, isInline means inline
388 submitState = false
388 submitState = false
389 }
389 }
390
390
391 $(this.submitButton).prop('disabled', submitState);
391 $(this.submitButton).prop('disabled', submitState);
392 if (submitEvent) {
392 if (submitEvent) {
393 $(this.submitButton).val(_gettext('Submitting...'));
393 $(this.submitButton).val(_gettext('Submitting...'));
394 } else {
394 } else {
395 $(this.submitButton).val(this.submitButtonText);
395 $(this.submitButton).val(this.submitButtonText);
396 }
396 }
397
397
398 };
398 };
399
399
400 // lock preview/edit/submit buttons on load, but exclude cancel button
400 // lock preview/edit/submit buttons on load, but exclude cancel button
401 var excludeCancelBtn = true;
401 var excludeCancelBtn = true;
402 this.setActionButtonsDisabled(true, excludeCancelBtn);
402 this.setActionButtonsDisabled(true, excludeCancelBtn);
403
403
404 // anonymous users don't have access to initialized CM instance
404 // anonymous users don't have access to initialized CM instance
405 if (this.cm !== undefined){
405 if (this.cm !== undefined){
406 this.cm.on('change', function(cMirror) {
406 this.cm.on('change', function(cMirror) {
407 if (cMirror.getValue() === "") {
407 if (cMirror.getValue() === "") {
408 self.setActionButtonsDisabled(true, excludeCancelBtn)
408 self.setActionButtonsDisabled(true, excludeCancelBtn)
409 } else {
409 } else {
410 self.setActionButtonsDisabled(false, excludeCancelBtn)
410 self.setActionButtonsDisabled(false, excludeCancelBtn)
411 }
411 }
412 });
412 });
413 }
413 }
414
414
415 $(this.editButton).on('click', function(e) {
415 $(this.editButton).on('click', function(e) {
416 e.preventDefault();
416 e.preventDefault();
417
417
418 $(self.previewButton).parent().removeClass('active');
418 $(self.previewButton).parent().removeClass('active');
419 $(self.previewContainer).hide();
419 $(self.previewContainer).hide();
420
420
421 $(self.editButton).parent().addClass('active');
421 $(self.editButton).parent().addClass('active');
422 $(self.editContainer).show();
422 $(self.editContainer).show();
423
423
424 });
424 });
425
425
426 $(this.previewButton).on('click', function(e) {
426 $(this.previewButton).on('click', function(e) {
427 e.preventDefault();
427 e.preventDefault();
428 var text = self.cm.getValue();
428 var text = self.cm.getValue();
429
429
430 if (text === "") {
430 if (text === "") {
431 return;
431 return;
432 }
432 }
433
433
434 var postData = {
434 var postData = {
435 'text': text,
435 'text': text,
436 'renderer': templateContext.visual.default_renderer,
436 'renderer': templateContext.visual.default_renderer,
437 'csrf_token': CSRF_TOKEN
437 'csrf_token': CSRF_TOKEN
438 };
438 };
439
439
440 // lock ALL buttons on preview
440 // lock ALL buttons on preview
441 self.setActionButtonsDisabled(true);
441 self.setActionButtonsDisabled(true);
442
442
443 $(self.previewBoxSelector).addClass('unloaded');
443 $(self.previewBoxSelector).addClass('unloaded');
444 $(self.previewBoxSelector).html(_gettext('Loading ...'));
444 $(self.previewBoxSelector).html(_gettext('Loading ...'));
445
445
446 $(self.editContainer).hide();
446 $(self.editContainer).hide();
447 $(self.previewContainer).show();
447 $(self.previewContainer).show();
448
448
449 // by default we reset state of comment preserving the text
449 // by default we reset state of comment preserving the text
450 var previewFailCallback = function(data){
450 var previewFailCallback = function(data){
451 alert(
451 alert(
452 "Error while preview of comment.\n" +
452 "Error while preview of comment.\n" +
453 "Error code {0} ({1}).".format(data.status, data.statusText)
453 "Error code {0} ({1}).".format(data.status, data.statusText)
454 );
454 );
455 self.resetCommentFormState(text)
455 self.resetCommentFormState(text)
456 };
456 };
457 self.submitAjaxPOST(
457 self.submitAjaxPOST(
458 self.previewUrl, postData, self.previewSuccessCallback,
458 self.previewUrl, postData, self.previewSuccessCallback,
459 previewFailCallback);
459 previewFailCallback);
460
460
461 $(self.previewButton).parent().addClass('active');
461 $(self.previewButton).parent().addClass('active');
462 $(self.editButton).parent().removeClass('active');
462 $(self.editButton).parent().removeClass('active');
463 });
463 });
464
464
465 $(this.submitForm).submit(function(e) {
465 $(this.submitForm).submit(function(e) {
466 e.preventDefault();
466 e.preventDefault();
467 var allowedToSubmit = self.isAllowedToSubmit();
467 var allowedToSubmit = self.isAllowedToSubmit();
468 if (!allowedToSubmit){
468 if (!allowedToSubmit){
469 return false;
469 return false;
470 }
470 }
471 self.handleFormSubmit();
471 self.handleFormSubmit();
472 });
472 });
473
473
474 }
474 }
475
475
476 return CommentForm;
476 return CommentForm;
477 });
477 });
478
478
479 /* comments controller */
479 /* comments controller */
480 var CommentsController = function() {
480 var CommentsController = function() {
481 var mainComment = '#text';
481 var mainComment = '#text';
482 var self = this;
482 var self = this;
483
483
484 this.cancelComment = function(node) {
484 this.cancelComment = function(node) {
485 var $node = $(node);
485 var $node = $(node);
486 var $td = $node.closest('td');
486 var $td = $node.closest('td');
487 $node.closest('.comment-inline-form').remove();
487 $node.closest('.comment-inline-form').remove();
488 return false;
488 return false;
489 };
489 };
490
490
491 this.getLineNumber = function(node) {
491 this.getLineNumber = function(node) {
492 var $node = $(node);
492 var $node = $(node);
493 var lineNo = $node.closest('td').attr('data-line-no');
493 var lineNo = $node.closest('td').attr('data-line-no');
494 if (lineNo === undefined && $node.data('commentInline')){
494 if (lineNo === undefined && $node.data('commentInline')){
495 lineNo = $node.data('commentLineNo')
495 lineNo = $node.data('commentLineNo')
496 }
496 }
497
497
498 return lineNo
498 return lineNo
499 };
499 };
500
500
501 this.scrollToComment = function(node, offset, outdated) {
501 this.scrollToComment = function(node, offset, outdated) {
502 if (offset === undefined) {
502 if (offset === undefined) {
503 offset = 0;
503 offset = 0;
504 }
504 }
505 var outdated = outdated || false;
505 var outdated = outdated || false;
506 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
506 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
507
507
508 if (!node) {
508 if (!node) {
509 node = $('.comment-selected');
509 node = $('.comment-selected');
510 if (!node.length) {
510 if (!node.length) {
511 node = $('comment-current')
511 node = $('comment-current')
512 }
512 }
513 }
513 }
514
514 $wrapper = $(node).closest('div.comment');
515 $wrapper = $(node).closest('div.comment');
515 $comment = $(node).closest(klass);
516 $comments = $(klass);
517
516
518 // show hidden comment when referenced.
517 // show hidden comment when referenced.
519 if (!$wrapper.is(':visible')){
518 if (!$wrapper.is(':visible')){
520 $wrapper.show();
519 $wrapper.show();
521 }
520 }
522
521
522 $comment = $(node).closest(klass);
523 $comments = $(klass);
524
523 $('.comment-selected').removeClass('comment-selected');
525 $('.comment-selected').removeClass('comment-selected');
524
526
525 var nextIdx = $(klass).index($comment) + offset;
527 var nextIdx = $(klass).index($comment) + offset;
526 if (nextIdx >= $comments.length) {
528 if (nextIdx >= $comments.length) {
527 nextIdx = 0;
529 nextIdx = 0;
528 }
530 }
529 var $next = $(klass).eq(nextIdx);
531 var $next = $(klass).eq(nextIdx);
530
532
531 var $cb = $next.closest('.cb');
533 var $cb = $next.closest('.cb');
532 $cb.removeClass('cb-collapsed');
534 $cb.removeClass('cb-collapsed');
533
535
534 var $filediffCollapseState = $cb.closest('.filediff').prev();
536 var $filediffCollapseState = $cb.closest('.filediff').prev();
535 $filediffCollapseState.prop('checked', false);
537 $filediffCollapseState.prop('checked', false);
536 $next.addClass('comment-selected');
538 $next.addClass('comment-selected');
537 scrollToElement($next);
539 scrollToElement($next);
538 return false;
540 return false;
539 };
541 };
540
542
541 this.nextComment = function(node) {
543 this.nextComment = function(node) {
542 return self.scrollToComment(node, 1);
544 return self.scrollToComment(node, 1);
543 };
545 };
544
546
545 this.prevComment = function(node) {
547 this.prevComment = function(node) {
546 return self.scrollToComment(node, -1);
548 return self.scrollToComment(node, -1);
547 };
549 };
548
550
549 this.nextOutdatedComment = function(node) {
551 this.nextOutdatedComment = function(node) {
550 return self.scrollToComment(node, 1, true);
552 return self.scrollToComment(node, 1, true);
551 };
553 };
552
554
553 this.prevOutdatedComment = function(node) {
555 this.prevOutdatedComment = function(node) {
554 return self.scrollToComment(node, -1, true);
556 return self.scrollToComment(node, -1, true);
555 };
557 };
556
558
557 this.deleteComment = function(node) {
559 this.deleteComment = function(node) {
558 if (!confirm(_gettext('Delete this comment?'))) {
560 if (!confirm(_gettext('Delete this comment?'))) {
559 return false;
561 return false;
560 }
562 }
561 var $node = $(node);
563 var $node = $(node);
562 var $td = $node.closest('td');
564 var $td = $node.closest('td');
563 var $comment = $node.closest('.comment');
565 var $comment = $node.closest('.comment');
564 var comment_id = $comment.attr('data-comment-id');
566 var comment_id = $comment.attr('data-comment-id');
565 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
567 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
566 var postData = {
568 var postData = {
567 'csrf_token': CSRF_TOKEN
569 'csrf_token': CSRF_TOKEN
568 };
570 };
569
571
570 $comment.addClass('comment-deleting');
572 $comment.addClass('comment-deleting');
571 $comment.hide('fast');
573 $comment.hide('fast');
572
574
573 var success = function(response) {
575 var success = function(response) {
574 $comment.remove();
576 $comment.remove();
575 return false;
577 return false;
576 };
578 };
577 var failure = function(data, textStatus, xhr) {
579 var failure = function(data, textStatus, xhr) {
578 alert("error processing request: " + textStatus);
580 alert("error processing request: " + textStatus);
579 $comment.show('fast');
581 $comment.show('fast');
580 $comment.removeClass('comment-deleting');
582 $comment.removeClass('comment-deleting');
581 return false;
583 return false;
582 };
584 };
583 ajaxPOST(url, postData, success, failure);
585 ajaxPOST(url, postData, success, failure);
584 };
586 };
585
587
586 this.toggleWideMode = function (node) {
588 this.toggleWideMode = function (node) {
587 if ($('#content').hasClass('wrapper')) {
589 if ($('#content').hasClass('wrapper')) {
588 $('#content').removeClass("wrapper");
590 $('#content').removeClass("wrapper");
589 $('#content').addClass("wide-mode-wrapper");
591 $('#content').addClass("wide-mode-wrapper");
590 $(node).addClass('btn-success');
592 $(node).addClass('btn-success');
591 return true
593 return true
592 } else {
594 } else {
593 $('#content').removeClass("wide-mode-wrapper");
595 $('#content').removeClass("wide-mode-wrapper");
594 $('#content').addClass("wrapper");
596 $('#content').addClass("wrapper");
595 $(node).removeClass('btn-success');
597 $(node).removeClass('btn-success');
596 return false
598 return false
597 }
599 }
598
600
599 };
601 };
600
602
601 this.toggleComments = function(node, show) {
603 this.toggleComments = function(node, show) {
602 var $filediff = $(node).closest('.filediff');
604 var $filediff = $(node).closest('.filediff');
603 if (show === true) {
605 if (show === true) {
604 $filediff.removeClass('hide-comments');
606 $filediff.removeClass('hide-comments');
605 } else if (show === false) {
607 } else if (show === false) {
606 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
608 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
607 $filediff.addClass('hide-comments');
609 $filediff.addClass('hide-comments');
608 } else {
610 } else {
609 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
611 $filediff.find('.hide-line-comments').removeClass('hide-line-comments');
610 $filediff.toggleClass('hide-comments');
612 $filediff.toggleClass('hide-comments');
611 }
613 }
612 return false;
614 return false;
613 };
615 };
614
616
615 this.toggleLineComments = function(node) {
617 this.toggleLineComments = function(node) {
616 self.toggleComments(node, true);
618 self.toggleComments(node, true);
617 var $node = $(node);
619 var $node = $(node);
618 // mark outdated comments as visible before the toggle;
620 // mark outdated comments as visible before the toggle;
619 $(node.closest('tr')).find('.comment-outdated').show();
621 $(node.closest('tr')).find('.comment-outdated').show();
620 $node.closest('tr').toggleClass('hide-line-comments');
622 $node.closest('tr').toggleClass('hide-line-comments');
621 };
623 };
622
624
623 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId){
625 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId){
624 var pullRequestId = templateContext.pull_request_data.pull_request_id;
626 var pullRequestId = templateContext.pull_request_data.pull_request_id;
625 var commitId = templateContext.commit_data.commit_id;
627 var commitId = templateContext.commit_data.commit_id;
626
628
627 var commentForm = new CommentForm(
629 var commentForm = new CommentForm(
628 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId);
630 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId);
629 var cm = commentForm.getCmInstance();
631 var cm = commentForm.getCmInstance();
630
632
631 if (resolvesCommentId){
633 if (resolvesCommentId){
632 var placeholderText = _gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
634 var placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
633 }
635 }
634
636
635 setTimeout(function() {
637 setTimeout(function() {
636 // callbacks
638 // callbacks
637 if (cm !== undefined) {
639 if (cm !== undefined) {
638 commentForm.setPlaceholder(placeholderText);
640 commentForm.setPlaceholder(placeholderText);
639 if (commentForm.isInline()) {
641 if (commentForm.isInline()) {
640 cm.focus();
642 cm.focus();
641 cm.refresh();
643 cm.refresh();
642 }
644 }
643 }
645 }
644 }, 10);
646 }, 10);
645
647
646 // trigger scrolldown to the resolve comment, since it might be away
648 // trigger scrolldown to the resolve comment, since it might be away
647 // from the clicked
649 // from the clicked
648 if (resolvesCommentId){
650 if (resolvesCommentId){
649 var actionNode = $(commentForm.resolvesActionId).offset();
651 var actionNode = $(commentForm.resolvesActionId).offset();
650
652
651 setTimeout(function() {
653 setTimeout(function() {
652 if (actionNode) {
654 if (actionNode) {
653 $('body, html').animate({scrollTop: actionNode.top}, 10);
655 $('body, html').animate({scrollTop: actionNode.top}, 10);
654 }
656 }
655 }, 100);
657 }, 100);
656 }
658 }
657
659
658 // add dropzone support
660 // add dropzone support
659 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
661 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
660 var renderer = templateContext.visual.default_renderer;
662 var renderer = templateContext.visual.default_renderer;
661 if (renderer == 'rst') {
663 if (renderer == 'rst') {
662 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
664 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
663 if (isRendered){
665 if (isRendered){
664 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
666 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
665 }
667 }
666 } else if (renderer == 'markdown') {
668 } else if (renderer == 'markdown') {
667 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
669 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
668 if (isRendered){
670 if (isRendered){
669 attachmentUrl = '!' + attachmentUrl;
671 attachmentUrl = '!' + attachmentUrl;
670 }
672 }
671 } else {
673 } else {
672 var attachmentUrl = '{}'.format(attachmentStoreUrl);
674 var attachmentUrl = '{}'.format(attachmentStoreUrl);
673 }
675 }
674 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
676 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
675
677
676 return false;
678 return false;
677 };
679 };
678
680
679 //see: https://www.dropzonejs.com/#configuration
681 //see: https://www.dropzonejs.com/#configuration
680 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
682 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
681 {'repo_name': templateContext.repo_name,
683 {'repo_name': templateContext.repo_name,
682 'commit_id': templateContext.commit_data.commit_id})
684 'commit_id': templateContext.commit_data.commit_id})
683
685
684 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
686 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
685 if (previewTmpl !== undefined){
687 if (previewTmpl !== undefined){
686 var selectLink = $(formElement).find('.pick-attachment').get(0);
688 var selectLink = $(formElement).find('.pick-attachment').get(0);
687 $(formElement).find('.comment-attachment-uploader').dropzone({
689 $(formElement).find('.comment-attachment-uploader').dropzone({
688 url: storeUrl,
690 url: storeUrl,
689 headers: {"X-CSRF-Token": CSRF_TOKEN},
691 headers: {"X-CSRF-Token": CSRF_TOKEN},
690 paramName: function () {
692 paramName: function () {
691 return "attachment"
693 return "attachment"
692 }, // The name that will be used to transfer the file
694 }, // The name that will be used to transfer the file
693 clickable: selectLink,
695 clickable: selectLink,
694 parallelUploads: 1,
696 parallelUploads: 1,
695 maxFiles: 10,
697 maxFiles: 10,
696 maxFilesize: templateContext.attachment_store.max_file_size_mb,
698 maxFilesize: templateContext.attachment_store.max_file_size_mb,
697 uploadMultiple: false,
699 uploadMultiple: false,
698 autoProcessQueue: true, // if false queue will not be processed automatically.
700 autoProcessQueue: true, // if false queue will not be processed automatically.
699 createImageThumbnails: false,
701 createImageThumbnails: false,
700 previewTemplate: previewTmpl.innerHTML,
702 previewTemplate: previewTmpl.innerHTML,
701
703
702 accept: function (file, done) {
704 accept: function (file, done) {
703 done();
705 done();
704 },
706 },
705 init: function () {
707 init: function () {
706
708
707 this.on("sending", function (file, xhr, formData) {
709 this.on("sending", function (file, xhr, formData) {
708 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
710 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
709 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
711 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
710 });
712 });
711
713
712 this.on("success", function (file, response) {
714 this.on("success", function (file, response) {
713 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
715 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
714 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
716 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
715
717
716 var isRendered = false;
718 var isRendered = false;
717 var ext = file.name.split('.').pop();
719 var ext = file.name.split('.').pop();
718 var imageExts = templateContext.attachment_store.image_ext;
720 var imageExts = templateContext.attachment_store.image_ext;
719 if (imageExts.indexOf(ext) !== -1){
721 if (imageExts.indexOf(ext) !== -1){
720 isRendered = true;
722 isRendered = true;
721 }
723 }
722
724
723 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
725 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
724 });
726 });
725
727
726 this.on("error", function (file, errorMessage, xhr) {
728 this.on("error", function (file, errorMessage, xhr) {
727 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
729 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
728
730
729 var error = null;
731 var error = null;
730
732
731 if (xhr !== undefined){
733 if (xhr !== undefined){
732 var httpStatus = xhr.status + " " + xhr.statusText;
734 var httpStatus = xhr.status + " " + xhr.statusText;
733 if (xhr !== undefined && xhr.status >= 500) {
735 if (xhr !== undefined && xhr.status >= 500) {
734 error = httpStatus;
736 error = httpStatus;
735 }
737 }
736 }
738 }
737
739
738 if (error === null) {
740 if (error === null) {
739 error = errorMessage.error || errorMessage || httpStatus;
741 error = errorMessage.error || errorMessage || httpStatus;
740 }
742 }
741 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
743 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
742
744
743 });
745 });
744 }
746 }
745 });
747 });
746 }
748 }
747 return commentForm;
749 return commentForm;
748 };
750 };
749
751
750 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
752 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
751
753
752 var tmpl = $('#cb-comment-general-form-template').html();
754 var tmpl = $('#cb-comment-general-form-template').html();
753 tmpl = tmpl.format(null, 'general');
755 tmpl = tmpl.format(null, 'general');
754 var $form = $(tmpl);
756 var $form = $(tmpl);
755
757
756 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
758 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
757 var curForm = $formPlaceholder.find('form');
759 var curForm = $formPlaceholder.find('form');
758 if (curForm){
760 if (curForm){
759 curForm.remove();
761 curForm.remove();
760 }
762 }
761 $formPlaceholder.append($form);
763 $formPlaceholder.append($form);
762
764
763 var _form = $($form[0]);
765 var _form = $($form[0]);
764 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
766 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
765 var commentForm = this.createCommentForm(
767 var commentForm = this.createCommentForm(
766 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId);
768 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId);
767 commentForm.initStatusChangeSelector();
769 commentForm.initStatusChangeSelector();
768
770
769 return commentForm;
771 return commentForm;
770 };
772 };
771
773
772 this.createComment = function(node, resolutionComment) {
774 this.createComment = function(node, resolutionComment) {
773 var resolvesCommentId = resolutionComment || null;
775 var resolvesCommentId = resolutionComment || null;
774 var $node = $(node);
776 var $node = $(node);
775 var $td = $node.closest('td');
777 var $td = $node.closest('td');
776 var $form = $td.find('.comment-inline-form');
778 var $form = $td.find('.comment-inline-form');
777
779
778 if (!$form.length) {
780 if (!$form.length) {
779
781
780 var $filediff = $node.closest('.filediff');
782 var $filediff = $node.closest('.filediff');
781 $filediff.removeClass('hide-comments');
783 $filediff.removeClass('hide-comments');
782 var f_path = $filediff.attr('data-f-path');
784 var f_path = $filediff.attr('data-f-path');
783 var lineno = self.getLineNumber(node);
785 var lineno = self.getLineNumber(node);
784 // create a new HTML from template
786 // create a new HTML from template
785 var tmpl = $('#cb-comment-inline-form-template').html();
787 var tmpl = $('#cb-comment-inline-form-template').html();
786 tmpl = tmpl.format(escapeHtml(f_path), lineno);
788 tmpl = tmpl.format(escapeHtml(f_path), lineno);
787 $form = $(tmpl);
789 $form = $(tmpl);
788
790
789 var $comments = $td.find('.inline-comments');
791 var $comments = $td.find('.inline-comments');
790 if (!$comments.length) {
792 if (!$comments.length) {
791 $comments = $(
793 $comments = $(
792 $('#cb-comments-inline-container-template').html());
794 $('#cb-comments-inline-container-template').html());
793 $td.append($comments);
795 $td.append($comments);
794 }
796 }
795
797
796 $td.find('.cb-comment-add-button').before($form);
798 $td.find('.cb-comment-add-button').before($form);
797
799
798 var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno);
800 var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno);
799 var _form = $($form[0]).find('form');
801 var _form = $($form[0]).find('form');
800 var autocompleteActions = ['as_note', 'as_todo'];
802 var autocompleteActions = ['as_note', 'as_todo'];
801 var commentForm = this.createCommentForm(
803 var commentForm = this.createCommentForm(
802 _form, lineno, placeholderText, autocompleteActions, resolvesCommentId);
804 _form, lineno, placeholderText, autocompleteActions, resolvesCommentId);
803
805
804 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
806 $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
805 form: _form,
807 form: _form,
806 parent: $td[0],
808 parent: $td[0],
807 lineno: lineno,
809 lineno: lineno,
808 f_path: f_path}
810 f_path: f_path}
809 );
811 );
810
812
811 // set a CUSTOM submit handler for inline comments.
813 // set a CUSTOM submit handler for inline comments.
812 commentForm.setHandleFormSubmit(function(o) {
814 commentForm.setHandleFormSubmit(function(o) {
813 var text = commentForm.cm.getValue();
815 var text = commentForm.cm.getValue();
814 var commentType = commentForm.getCommentType();
816 var commentType = commentForm.getCommentType();
815 var resolvesCommentId = commentForm.getResolvesId();
817 var resolvesCommentId = commentForm.getResolvesId();
816
818
817 if (text === "") {
819 if (text === "") {
818 return;
820 return;
819 }
821 }
820
822
821 if (lineno === undefined) {
823 if (lineno === undefined) {
822 alert('missing line !');
824 alert('missing line !');
823 return;
825 return;
824 }
826 }
825 if (f_path === undefined) {
827 if (f_path === undefined) {
826 alert('missing file path !');
828 alert('missing file path !');
827 return;
829 return;
828 }
830 }
829
831
830 var excludeCancelBtn = false;
832 var excludeCancelBtn = false;
831 var submitEvent = true;
833 var submitEvent = true;
832 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
834 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
833 commentForm.cm.setOption("readOnly", true);
835 commentForm.cm.setOption("readOnly", true);
834 var postData = {
836 var postData = {
835 'text': text,
837 'text': text,
836 'f_path': f_path,
838 'f_path': f_path,
837 'line': lineno,
839 'line': lineno,
838 'comment_type': commentType,
840 'comment_type': commentType,
839 'csrf_token': CSRF_TOKEN
841 'csrf_token': CSRF_TOKEN
840 };
842 };
841 if (resolvesCommentId){
843 if (resolvesCommentId){
842 postData['resolves_comment_id'] = resolvesCommentId;
844 postData['resolves_comment_id'] = resolvesCommentId;
843 }
845 }
844
846
845 var submitSuccessCallback = function(json_data) {
847 var submitSuccessCallback = function(json_data) {
846 $form.remove();
848 $form.remove();
847 try {
849 try {
848 var html = json_data.rendered_text;
850 var html = json_data.rendered_text;
849 var lineno = json_data.line_no;
851 var lineno = json_data.line_no;
850 var target_id = json_data.target_id;
852 var target_id = json_data.target_id;
851
853
852 $comments.find('.cb-comment-add-button').before(html);
854 $comments.find('.cb-comment-add-button').before(html);
853
855
854 //mark visually which comment was resolved
856 //mark visually which comment was resolved
855 if (resolvesCommentId) {
857 if (resolvesCommentId) {
856 commentForm.markCommentResolved(resolvesCommentId);
858 commentForm.markCommentResolved(resolvesCommentId);
857 }
859 }
858
860
859 // run global callback on submit
861 // run global callback on submit
860 commentForm.globalSubmitSuccessCallback();
862 commentForm.globalSubmitSuccessCallback();
861
863
862 } catch (e) {
864 } catch (e) {
863 console.error(e);
865 console.error(e);
864 }
866 }
865
867
866 // re trigger the linkification of next/prev navigation
868 // re trigger the linkification of next/prev navigation
867 linkifyComments($('.inline-comment-injected'));
869 linkifyComments($('.inline-comment-injected'));
868 timeagoActivate();
870 timeagoActivate();
869 tooltipActivate();
871 tooltipActivate();
870
872
871 if (window.updateSticky !== undefined) {
873 if (window.updateSticky !== undefined) {
872 // potentially our comments change the active window size, so we
874 // potentially our comments change the active window size, so we
873 // notify sticky elements
875 // notify sticky elements
874 updateSticky()
876 updateSticky()
875 }
877 }
876
878
877 commentForm.setActionButtonsDisabled(false);
879 commentForm.setActionButtonsDisabled(false);
878
880
879 };
881 };
880 var submitFailCallback = function(data){
882 var submitFailCallback = function(data){
881 alert(
883 alert(
882 "Error while submitting comment.\n" +
884 "Error while submitting comment.\n" +
883 "Error code {0} ({1}).".format(data.status, data.statusText)
885 "Error code {0} ({1}).".format(data.status, data.statusText)
884 );
886 );
885 commentForm.resetCommentFormState(text)
887 commentForm.resetCommentFormState(text)
886 };
888 };
887 commentForm.submitAjaxPOST(
889 commentForm.submitAjaxPOST(
888 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
890 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
889 });
891 });
890 }
892 }
891
893
892 $form.addClass('comment-inline-form-open');
894 $form.addClass('comment-inline-form-open');
893 };
895 };
894
896
895 this.createResolutionComment = function(commentId){
897 this.createResolutionComment = function(commentId){
896 // hide the trigger text
898 // hide the trigger text
897 $('#resolve-comment-{0}'.format(commentId)).hide();
899 $('#resolve-comment-{0}'.format(commentId)).hide();
898
900
899 var comment = $('#comment-'+commentId);
901 var comment = $('#comment-'+commentId);
900 var commentData = comment.data();
902 var commentData = comment.data();
901 if (commentData.commentInline) {
903 if (commentData.commentInline) {
902 this.createComment(comment, commentId)
904 this.createComment(comment, commentId)
903 } else {
905 } else {
904 Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
906 Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
905 }
907 }
906
908
907 return false;
909 return false;
908 };
910 };
909
911
910 this.submitResolution = function(commentId){
912 this.submitResolution = function(commentId){
911 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
913 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
912 var commentForm = form.get(0).CommentForm;
914 var commentForm = form.get(0).CommentForm;
913
915
914 var cm = commentForm.getCmInstance();
916 var cm = commentForm.getCmInstance();
915 var renderer = templateContext.visual.default_renderer;
917 var renderer = templateContext.visual.default_renderer;
916 if (renderer == 'rst'){
918 if (renderer == 'rst'){
917 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
919 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
918 } else if (renderer == 'markdown') {
920 } else if (renderer == 'markdown') {
919 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
921 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
920 } else {
922 } else {
921 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
923 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
922 }
924 }
923
925
924 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
926 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
925 form.submit();
927 form.submit();
926 return false;
928 return false;
927 };
929 };
928
930
929 };
931 };
@@ -1,1139 +1,1140 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%!
3 <%!
4 ## base64 filter e.g ${ example | base64 }
4 ## base64 filter e.g ${ example | base64 }
5 def base64(text):
5 def base64(text):
6 import base64
6 import base64
7 from rhodecode.lib.helpers import safe_str
7 from rhodecode.lib.helpers import safe_str
8 return base64.encodestring(safe_str(text))
8 return base64.encodestring(safe_str(text))
9 %>
9 %>
10
10
11 <%inherit file="root.mako"/>
11 <%inherit file="root.mako"/>
12
12
13 <%include file="/ejs_templates/templates.html"/>
13 <%include file="/ejs_templates/templates.html"/>
14
14
15 <div class="outerwrapper">
15 <div class="outerwrapper">
16 <!-- HEADER -->
16 <!-- HEADER -->
17 <div class="header">
17 <div class="header">
18 <div id="header-inner" class="wrapper">
18 <div id="header-inner" class="wrapper">
19 <div id="logo">
19 <div id="logo">
20 <div class="logo-wrapper">
20 <div class="logo-wrapper">
21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
22 </div>
22 </div>
23 % if c.rhodecode_name:
23 % if c.rhodecode_name:
24 <div class="branding">
24 <div class="branding">
25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
26 </div>
26 </div>
27 % endif
27 % endif
28 </div>
28 </div>
29 <!-- MENU BAR NAV -->
29 <!-- MENU BAR NAV -->
30 ${self.menu_bar_nav()}
30 ${self.menu_bar_nav()}
31 <!-- END MENU BAR NAV -->
31 <!-- END MENU BAR NAV -->
32 </div>
32 </div>
33 </div>
33 </div>
34 ${self.menu_bar_subnav()}
34 ${self.menu_bar_subnav()}
35 <!-- END HEADER -->
35 <!-- END HEADER -->
36
36
37 <!-- CONTENT -->
37 <!-- CONTENT -->
38 <div id="content" class="wrapper">
38 <div id="content" class="wrapper">
39
39
40 <rhodecode-toast id="notifications"></rhodecode-toast>
40 <rhodecode-toast id="notifications"></rhodecode-toast>
41
41
42 <div class="main">
42 <div class="main">
43 ${next.main()}
43 ${next.main()}
44 </div>
44 </div>
45 </div>
45 </div>
46 <!-- END CONTENT -->
46 <!-- END CONTENT -->
47
47
48 </div>
48 </div>
49 <!-- FOOTER -->
49 <!-- FOOTER -->
50 <div id="footer">
50 <div id="footer">
51 <div id="footer-inner" class="title wrapper">
51 <div id="footer-inner" class="title wrapper">
52 <div>
52 <div>
53 <p class="footer-link-right">
53 <p class="footer-link-right">
54 % if c.visual.show_version:
54 % if c.visual.show_version:
55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
56 % endif
56 % endif
57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
58 % if c.visual.rhodecode_support_url:
58 % if c.visual.rhodecode_support_url:
59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
60 % endif
60 % endif
61 </p>
61 </p>
62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
63 <p class="server-instance" style="display:${sid}">
63 <p class="server-instance" style="display:${sid}">
64 ## display hidden instance ID if specially defined
64 ## display hidden instance ID if specially defined
65 % if c.rhodecode_instanceid:
65 % if c.rhodecode_instanceid:
66 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
66 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
67 % endif
67 % endif
68 </p>
68 </p>
69 </div>
69 </div>
70 </div>
70 </div>
71 </div>
71 </div>
72
72
73 <!-- END FOOTER -->
73 <!-- END FOOTER -->
74
74
75 ### MAKO DEFS ###
75 ### MAKO DEFS ###
76
76
77 <%def name="menu_bar_subnav()">
77 <%def name="menu_bar_subnav()">
78 </%def>
78 </%def>
79
79
80 <%def name="breadcrumbs(class_='breadcrumbs')">
80 <%def name="breadcrumbs(class_='breadcrumbs')">
81 <div class="${class_}">
81 <div class="${class_}">
82 ${self.breadcrumbs_links()}
82 ${self.breadcrumbs_links()}
83 </div>
83 </div>
84 </%def>
84 </%def>
85
85
86 <%def name="admin_menu(active=None)">
86 <%def name="admin_menu(active=None)">
87
87
88 <div id="context-bar">
88 <div id="context-bar">
89 <div class="wrapper">
89 <div class="wrapper">
90 <div class="title">
90 <div class="title">
91 <div class="title-content">
91 <div class="title-content">
92 <div class="title-main">
92 <div class="title-main">
93 % if c.is_super_admin:
93 % if c.is_super_admin:
94 ${_('Super-admin Panel')}
94 ${_('Super-admin Panel')}
95 % else:
95 % else:
96 ${_('Delegated Admin Panel')}
96 ${_('Delegated Admin Panel')}
97 % endif
97 % endif
98 </div>
98 </div>
99 </div>
99 </div>
100 </div>
100 </div>
101
101
102 <ul id="context-pages" class="navigation horizontal-list">
102 <ul id="context-pages" class="navigation horizontal-list">
103
103
104 ## super-admin case
104 ## super-admin case
105 % if c.is_super_admin:
105 % if c.is_super_admin:
106 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
106 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
107 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
107 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
108 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
108 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
109 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
109 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
110 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
110 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
111 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
111 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
112 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
112 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
113 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
113 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
114 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
114 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
115 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
115 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
116
116
117 ## delegated admin
117 ## delegated admin
118 % elif c.is_delegated_admin:
118 % elif c.is_delegated_admin:
119 <%
119 <%
120 repositories=c.auth_user.repositories_admin or c.can_create_repo
120 repositories=c.auth_user.repositories_admin or c.can_create_repo
121 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
121 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
122 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
122 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
123 %>
123 %>
124
124
125 %if repositories:
125 %if repositories:
126 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
126 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
127 %endif
127 %endif
128 %if repository_groups:
128 %if repository_groups:
129 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
129 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
130 %endif
130 %endif
131 %if user_groups:
131 %if user_groups:
132 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
132 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
133 %endif
133 %endif
134 % endif
134 % endif
135 </ul>
135 </ul>
136
136
137 </div>
137 </div>
138 <div class="clear"></div>
138 <div class="clear"></div>
139 </div>
139 </div>
140 </%def>
140 </%def>
141
141
142 <%def name="dt_info_panel(elements)">
142 <%def name="dt_info_panel(elements)">
143 <dl class="dl-horizontal">
143 <dl class="dl-horizontal">
144 %for dt, dd, title, show_items in elements:
144 %for dt, dd, title, show_items in elements:
145 <dt>${dt}:</dt>
145 <dt>${dt}:</dt>
146 <dd title="${h.tooltip(title)}">
146 <dd title="${h.tooltip(title)}">
147 %if callable(dd):
147 %if callable(dd):
148 ## allow lazy evaluation of elements
148 ## allow lazy evaluation of elements
149 ${dd()}
149 ${dd()}
150 %else:
150 %else:
151 ${dd}
151 ${dd}
152 %endif
152 %endif
153 %if show_items:
153 %if show_items:
154 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
154 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
155 %endif
155 %endif
156 </dd>
156 </dd>
157
157
158 %if show_items:
158 %if show_items:
159 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
159 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
160 %for item in show_items:
160 %for item in show_items:
161 <dt></dt>
161 <dt></dt>
162 <dd>${item}</dd>
162 <dd>${item}</dd>
163 %endfor
163 %endfor
164 </div>
164 </div>
165 %endif
165 %endif
166
166
167 %endfor
167 %endfor
168 </dl>
168 </dl>
169 </%def>
169 </%def>
170
170
171 <%def name="tr_info_entry(element)">
171 <%def name="tr_info_entry(element)">
172 <% key, val, title, show_items = element %>
172 <% key, val, title, show_items = element %>
173
173
174 <tr>
174 <tr>
175 <td style="vertical-align: top">${key}</td>
175 <td style="vertical-align: top">${key}</td>
176 <td title="${h.tooltip(title)}">
176 <td title="${h.tooltip(title)}">
177 %if callable(val):
177 %if callable(val):
178 ## allow lazy evaluation of elements
178 ## allow lazy evaluation of elements
179 ${val()}
179 ${val()}
180 %else:
180 %else:
181 ${val}
181 ${val}
182 %endif
182 %endif
183 %if show_items:
183 %if show_items:
184 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
184 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
185 % for item in show_items:
185 % for item in show_items:
186 <dt></dt>
186 <dt></dt>
187 <dd>${item}</dd>
187 <dd>${item}</dd>
188 % endfor
188 % endfor
189 </div>
189 </div>
190 %endif
190 %endif
191 </td>
191 </td>
192 <td style="vertical-align: top">
192 <td style="vertical-align: top">
193 %if show_items:
193 %if show_items:
194 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
194 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
195 %endif
195 %endif
196 </td>
196 </td>
197 </tr>
197 </tr>
198
198
199 </%def>
199 </%def>
200
200
201 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None)">
201 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None, extra_class=None)">
202 <%
202 <%
203 if size > 16:
203 if size > 16:
204 gravatar_class = ['gravatar','gravatar-large']
204 gravatar_class = ['gravatar','gravatar-large']
205 else:
205 else:
206 gravatar_class = ['gravatar']
206 gravatar_class = ['gravatar']
207
207
208 data_hovercard_url = ''
208 data_hovercard_url = ''
209 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
209 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
210
210
211 if tooltip:
211 if tooltip:
212 gravatar_class += ['tooltip-hovercard']
212 gravatar_class += ['tooltip-hovercard']
213
213 if extra_class:
214 gravatar_class += extra_class
214 if tooltip and user:
215 if tooltip and user:
215 if user.username == h.DEFAULT_USER:
216 if user.username == h.DEFAULT_USER:
216 gravatar_class.pop(-1)
217 gravatar_class.pop(-1)
217 else:
218 else:
218 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
219 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
219 gravatar_class = ' '.join(gravatar_class)
220 gravatar_class = ' '.join(gravatar_class)
220
221
221 %>
222 %>
222 <%doc>
223 <%doc>
223 TODO: johbo: For now we serve double size images to make it smooth
224 TODO: johbo: For now we serve double size images to make it smooth
224 for retina. This is how it worked until now. Should be replaced
225 for retina. This is how it worked until now. Should be replaced
225 with a better solution at some point.
226 with a better solution at some point.
226 </%doc>
227 </%doc>
227
228
228 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
229 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
229 </%def>
230 </%def>
230
231
231
232
232 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)">
233 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)">
233 <%
234 <%
234 email = h.email_or_none(contact)
235 email = h.email_or_none(contact)
235 rc_user = h.discover_user(contact)
236 rc_user = h.discover_user(contact)
236 %>
237 %>
237
238
238 <div class="rc-user">
239 <div class="rc-user">
239 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
240 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
240 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
241 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
241 </div>
242 </div>
242 </%def>
243 </%def>
243
244
244
245
245 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
246 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
246 <%
247 <%
247 if (size > 16):
248 if (size > 16):
248 gravatar_class = 'icon-user-group-alt'
249 gravatar_class = 'icon-user-group-alt'
249 else:
250 else:
250 gravatar_class = 'icon-user-group-alt'
251 gravatar_class = 'icon-user-group-alt'
251
252
252 if tooltip:
253 if tooltip:
253 gravatar_class += ' tooltip-hovercard'
254 gravatar_class += ' tooltip-hovercard'
254
255
255 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
256 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
256 %>
257 %>
257 <%doc>
258 <%doc>
258 TODO: johbo: For now we serve double size images to make it smooth
259 TODO: johbo: For now we serve double size images to make it smooth
259 for retina. This is how it worked until now. Should be replaced
260 for retina. This is how it worked until now. Should be replaced
260 with a better solution at some point.
261 with a better solution at some point.
261 </%doc>
262 </%doc>
262
263
263 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
264 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
264 </%def>
265 </%def>
265
266
266 <%def name="repo_page_title(repo_instance)">
267 <%def name="repo_page_title(repo_instance)">
267 <div class="title-content repo-title">
268 <div class="title-content repo-title">
268
269
269 <div class="title-main">
270 <div class="title-main">
270 ## SVN/HG/GIT icons
271 ## SVN/HG/GIT icons
271 %if h.is_hg(repo_instance):
272 %if h.is_hg(repo_instance):
272 <i class="icon-hg"></i>
273 <i class="icon-hg"></i>
273 %endif
274 %endif
274 %if h.is_git(repo_instance):
275 %if h.is_git(repo_instance):
275 <i class="icon-git"></i>
276 <i class="icon-git"></i>
276 %endif
277 %endif
277 %if h.is_svn(repo_instance):
278 %if h.is_svn(repo_instance):
278 <i class="icon-svn"></i>
279 <i class="icon-svn"></i>
279 %endif
280 %endif
280
281
281 ## public/private
282 ## public/private
282 %if repo_instance.private:
283 %if repo_instance.private:
283 <i class="icon-repo-private"></i>
284 <i class="icon-repo-private"></i>
284 %else:
285 %else:
285 <i class="icon-repo-public"></i>
286 <i class="icon-repo-public"></i>
286 %endif
287 %endif
287
288
288 ## repo name with group name
289 ## repo name with group name
289 ${h.breadcrumb_repo_link(repo_instance)}
290 ${h.breadcrumb_repo_link(repo_instance)}
290
291
291 ## Context Actions
292 ## Context Actions
292 <div class="pull-right">
293 <div class="pull-right">
293 %if c.rhodecode_user.username != h.DEFAULT_USER:
294 %if c.rhodecode_user.username != h.DEFAULT_USER:
294 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
295 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
295
296
296 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
297 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
297 % if c.repository_is_user_following:
298 % if c.repository_is_user_following:
298 <i class="icon-eye-off"></i>${_('Unwatch')}
299 <i class="icon-eye-off"></i>${_('Unwatch')}
299 % else:
300 % else:
300 <i class="icon-eye"></i>${_('Watch')}
301 <i class="icon-eye"></i>${_('Watch')}
301 % endif
302 % endif
302
303
303 </a>
304 </a>
304 %else:
305 %else:
305 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
306 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
306 %endif
307 %endif
307 </div>
308 </div>
308
309
309 </div>
310 </div>
310
311
311 ## FORKED
312 ## FORKED
312 %if repo_instance.fork:
313 %if repo_instance.fork:
313 <p class="discreet">
314 <p class="discreet">
314 <i class="icon-code-fork"></i> ${_('Fork of')}
315 <i class="icon-code-fork"></i> ${_('Fork of')}
315 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
316 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
316 </p>
317 </p>
317 %endif
318 %endif
318
319
319 ## IMPORTED FROM REMOTE
320 ## IMPORTED FROM REMOTE
320 %if repo_instance.clone_uri:
321 %if repo_instance.clone_uri:
321 <p class="discreet">
322 <p class="discreet">
322 <i class="icon-code-fork"></i> ${_('Clone from')}
323 <i class="icon-code-fork"></i> ${_('Clone from')}
323 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
324 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
324 </p>
325 </p>
325 %endif
326 %endif
326
327
327 ## LOCKING STATUS
328 ## LOCKING STATUS
328 %if repo_instance.locked[0]:
329 %if repo_instance.locked[0]:
329 <p class="locking_locked discreet">
330 <p class="locking_locked discreet">
330 <i class="icon-repo-lock"></i>
331 <i class="icon-repo-lock"></i>
331 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
332 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
332 </p>
333 </p>
333 %elif repo_instance.enable_locking:
334 %elif repo_instance.enable_locking:
334 <p class="locking_unlocked discreet">
335 <p class="locking_unlocked discreet">
335 <i class="icon-repo-unlock"></i>
336 <i class="icon-repo-unlock"></i>
336 ${_('Repository not locked. Pull repository to lock it.')}
337 ${_('Repository not locked. Pull repository to lock it.')}
337 </p>
338 </p>
338 %endif
339 %endif
339
340
340 </div>
341 </div>
341 </%def>
342 </%def>
342
343
343 <%def name="repo_menu(active=None)">
344 <%def name="repo_menu(active=None)">
344 <%
345 <%
345 ## determine if we have "any" option available
346 ## determine if we have "any" option available
346 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
347 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
347 has_actions = can_lock
348 has_actions = can_lock
348
349
349 %>
350 %>
350 % if c.rhodecode_db_repo.archived:
351 % if c.rhodecode_db_repo.archived:
351 <div class="alert alert-warning text-center">
352 <div class="alert alert-warning text-center">
352 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
353 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
353 </div>
354 </div>
354 % endif
355 % endif
355
356
356 <!--- REPO CONTEXT BAR -->
357 <!--- REPO CONTEXT BAR -->
357 <div id="context-bar">
358 <div id="context-bar">
358 <div class="wrapper">
359 <div class="wrapper">
359
360
360 <div class="title">
361 <div class="title">
361 ${self.repo_page_title(c.rhodecode_db_repo)}
362 ${self.repo_page_title(c.rhodecode_db_repo)}
362 </div>
363 </div>
363
364
364 <ul id="context-pages" class="navigation horizontal-list">
365 <ul id="context-pages" class="navigation horizontal-list">
365 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
366 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
366 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
367 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
367 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
368 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
368 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
369 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
369
370
370 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
371 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
371 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
372 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
372 <li class="${h.is_active('showpullrequest', active)}">
373 <li class="${h.is_active('showpullrequest', active)}">
373 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
374 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
374 <div class="menulabel">
375 <div class="menulabel">
375 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
376 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
376 </div>
377 </div>
377 </a>
378 </a>
378 </li>
379 </li>
379 %endif
380 %endif
380
381
381 <li class="${h.is_active('artifacts', active)}">
382 <li class="${h.is_active('artifacts', active)}">
382 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
383 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
383 <div class="menulabel">
384 <div class="menulabel">
384 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
385 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
385 </div>
386 </div>
386 </a>
387 </a>
387 </li>
388 </li>
388
389
389 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
390 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
390 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
391 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
391 %endif
392 %endif
392
393
393 <li class="${h.is_active('options', active)}">
394 <li class="${h.is_active('options', active)}">
394 % if has_actions:
395 % if has_actions:
395 <a class="menulink dropdown">
396 <a class="menulink dropdown">
396 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
397 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
397 </a>
398 </a>
398 <ul class="submenu">
399 <ul class="submenu">
399 %if can_lock:
400 %if can_lock:
400 %if c.rhodecode_db_repo.locked[0]:
401 %if c.rhodecode_db_repo.locked[0]:
401 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
402 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
402 %else:
403 %else:
403 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
404 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
404 %endif
405 %endif
405 %endif
406 %endif
406 </ul>
407 </ul>
407 % else:
408 % else:
408 <a class="menulink disabled">
409 <a class="menulink disabled">
409 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
410 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
410 </a>
411 </a>
411 % endif
412 % endif
412 </li>
413 </li>
413
414
414 </ul>
415 </ul>
415 </div>
416 </div>
416 <div class="clear"></div>
417 <div class="clear"></div>
417 </div>
418 </div>
418
419
419 <!--- REPO END CONTEXT BAR -->
420 <!--- REPO END CONTEXT BAR -->
420
421
421 </%def>
422 </%def>
422
423
423 <%def name="repo_group_page_title(repo_group_instance)">
424 <%def name="repo_group_page_title(repo_group_instance)">
424 <div class="title-content">
425 <div class="title-content">
425 <div class="title-main">
426 <div class="title-main">
426 ## Repository Group icon
427 ## Repository Group icon
427 <i class="icon-repo-group"></i>
428 <i class="icon-repo-group"></i>
428
429
429 ## repo name with group name
430 ## repo name with group name
430 ${h.breadcrumb_repo_group_link(repo_group_instance)}
431 ${h.breadcrumb_repo_group_link(repo_group_instance)}
431 </div>
432 </div>
432
433
433 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
434 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
434 <div class="repo-group-desc discreet">
435 <div class="repo-group-desc discreet">
435 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
436 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
436 </div>
437 </div>
437
438
438 </div>
439 </div>
439 </%def>
440 </%def>
440
441
441
442
442 <%def name="repo_group_menu(active=None)">
443 <%def name="repo_group_menu(active=None)">
443 <%
444 <%
444 gr_name = c.repo_group.group_name if c.repo_group else None
445 gr_name = c.repo_group.group_name if c.repo_group else None
445 # create repositories with write permission on group is set to true
446 # create repositories with write permission on group is set to true
446 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
447 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
447
448
448 %>
449 %>
449
450
450
451
451 <!--- REPO GROUP CONTEXT BAR -->
452 <!--- REPO GROUP CONTEXT BAR -->
452 <div id="context-bar">
453 <div id="context-bar">
453 <div class="wrapper">
454 <div class="wrapper">
454 <div class="title">
455 <div class="title">
455 ${self.repo_group_page_title(c.repo_group)}
456 ${self.repo_group_page_title(c.repo_group)}
456 </div>
457 </div>
457
458
458 <ul id="context-pages" class="navigation horizontal-list">
459 <ul id="context-pages" class="navigation horizontal-list">
459 <li class="${h.is_active('home', active)}">
460 <li class="${h.is_active('home', active)}">
460 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
461 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
461 </li>
462 </li>
462 % if c.is_super_admin or group_admin:
463 % if c.is_super_admin or group_admin:
463 <li class="${h.is_active('settings', active)}">
464 <li class="${h.is_active('settings', active)}">
464 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
465 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
465 </li>
466 </li>
466 % endif
467 % endif
467
468
468 </ul>
469 </ul>
469 </div>
470 </div>
470 <div class="clear"></div>
471 <div class="clear"></div>
471 </div>
472 </div>
472
473
473 <!--- REPO GROUP CONTEXT BAR -->
474 <!--- REPO GROUP CONTEXT BAR -->
474
475
475 </%def>
476 </%def>
476
477
477
478
478 <%def name="usermenu(active=False)">
479 <%def name="usermenu(active=False)">
479 <%
480 <%
480 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
481 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
481
482
482 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
483 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
483 # create repositories with write permission on group is set to true
484 # create repositories with write permission on group is set to true
484
485
485 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
486 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
486 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
487 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
487 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
488 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
488 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
489 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
489
490
490 can_create_repos = c.is_super_admin or c.can_create_repo
491 can_create_repos = c.is_super_admin or c.can_create_repo
491 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
492 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
492
493
493 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
494 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
494 can_create_repo_groups_in_group = c.is_super_admin or group_admin
495 can_create_repo_groups_in_group = c.is_super_admin or group_admin
495 %>
496 %>
496
497
497 % if not_anonymous:
498 % if not_anonymous:
498 <%
499 <%
499 default_target_group = dict()
500 default_target_group = dict()
500 if c.rhodecode_user.personal_repo_group:
501 if c.rhodecode_user.personal_repo_group:
501 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
502 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
502 %>
503 %>
503
504
504 ## create action
505 ## create action
505 <li>
506 <li>
506 <a href="#create-actions" onclick="return false;" class="menulink childs">
507 <a href="#create-actions" onclick="return false;" class="menulink childs">
507 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
508 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
508 </a>
509 </a>
509
510
510 <div class="action-menu submenu">
511 <div class="action-menu submenu">
511
512
512 <ol>
513 <ol>
513 ## scope of within a repository
514 ## scope of within a repository
514 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
515 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
515 <li class="submenu-title">${_('This Repository')}</li>
516 <li class="submenu-title">${_('This Repository')}</li>
516 <li>
517 <li>
517 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
518 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
518 </li>
519 </li>
519 % if can_fork:
520 % if can_fork:
520 <li>
521 <li>
521 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
522 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
522 </li>
523 </li>
523 % endif
524 % endif
524 % endif
525 % endif
525
526
526 ## scope of within repository groups
527 ## scope of within repository groups
527 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
528 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
528 <li class="submenu-title">${_('This Repository Group')}</li>
529 <li class="submenu-title">${_('This Repository Group')}</li>
529
530
530 % if can_create_repos_in_group:
531 % if can_create_repos_in_group:
531 <li>
532 <li>
532 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
533 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
533 </li>
534 </li>
534 % endif
535 % endif
535
536
536 % if can_create_repo_groups_in_group:
537 % if can_create_repo_groups_in_group:
537 <li>
538 <li>
538 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
539 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
539 </li>
540 </li>
540 % endif
541 % endif
541 % endif
542 % endif
542
543
543 ## personal group
544 ## personal group
544 % if c.rhodecode_user.personal_repo_group:
545 % if c.rhodecode_user.personal_repo_group:
545 <li class="submenu-title">Personal Group</li>
546 <li class="submenu-title">Personal Group</li>
546
547
547 <li>
548 <li>
548 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
549 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
549 </li>
550 </li>
550
551
551 <li>
552 <li>
552 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
553 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
553 </li>
554 </li>
554 % endif
555 % endif
555
556
556 ## Global actions
557 ## Global actions
557 <li class="submenu-title">RhodeCode</li>
558 <li class="submenu-title">RhodeCode</li>
558 % if can_create_repos:
559 % if can_create_repos:
559 <li>
560 <li>
560 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
561 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
561 </li>
562 </li>
562 % endif
563 % endif
563
564
564 % if can_create_repo_groups:
565 % if can_create_repo_groups:
565 <li>
566 <li>
566 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
567 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
567 </li>
568 </li>
568 % endif
569 % endif
569
570
570 <li>
571 <li>
571 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
572 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
572 </li>
573 </li>
573
574
574 </ol>
575 </ol>
575
576
576 </div>
577 </div>
577 </li>
578 </li>
578
579
579 ## notifications
580 ## notifications
580 <li>
581 <li>
581 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
582 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
582 ${c.unread_notifications}
583 ${c.unread_notifications}
583 </a>
584 </a>
584 </li>
585 </li>
585 % endif
586 % endif
586
587
587 ## USER MENU
588 ## USER MENU
588 <li id="quick_login_li" class="${'active' if active else ''}">
589 <li id="quick_login_li" class="${'active' if active else ''}">
589 % if c.rhodecode_user.username == h.DEFAULT_USER:
590 % if c.rhodecode_user.username == h.DEFAULT_USER:
590 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
591 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
591 ${gravatar(c.rhodecode_user.email, 20)}
592 ${gravatar(c.rhodecode_user.email, 20)}
592 <span class="user">
593 <span class="user">
593 <span>${_('Sign in')}</span>
594 <span>${_('Sign in')}</span>
594 </span>
595 </span>
595 </a>
596 </a>
596 % else:
597 % else:
597 ## logged in user
598 ## logged in user
598 <a id="quick_login_link" class="menulink childs">
599 <a id="quick_login_link" class="menulink childs">
599 ${gravatar(c.rhodecode_user.email, 20)}
600 ${gravatar(c.rhodecode_user.email, 20)}
600 <span class="user">
601 <span class="user">
601 <span class="menu_link_user">${c.rhodecode_user.username}</span>
602 <span class="menu_link_user">${c.rhodecode_user.username}</span>
602 <div class="show_more"></div>
603 <div class="show_more"></div>
603 </span>
604 </span>
604 </a>
605 </a>
605 ## subnav with menu for logged in user
606 ## subnav with menu for logged in user
606 <div class="user-menu submenu">
607 <div class="user-menu submenu">
607 <div id="quick_login">
608 <div id="quick_login">
608 %if c.rhodecode_user.username != h.DEFAULT_USER:
609 %if c.rhodecode_user.username != h.DEFAULT_USER:
609 <div class="">
610 <div class="">
610 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
611 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
611 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
612 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
612 <div class="email">${c.rhodecode_user.email}</div>
613 <div class="email">${c.rhodecode_user.email}</div>
613 </div>
614 </div>
614 <div class="">
615 <div class="">
615 <ol class="links">
616 <ol class="links">
616 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
617 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
617 % if c.rhodecode_user.personal_repo_group:
618 % if c.rhodecode_user.personal_repo_group:
618 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
619 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
619 % endif
620 % endif
620 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
621 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
621
622
622 % if c.debug_style:
623 % if c.debug_style:
623 <li>
624 <li>
624 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
625 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
625 <div class="menulabel">${_('[Style]')}</div>
626 <div class="menulabel">${_('[Style]')}</div>
626 </a>
627 </a>
627 </li>
628 </li>
628 % endif
629 % endif
629
630
630 ## bookmark-items
631 ## bookmark-items
631 <li class="bookmark-items">
632 <li class="bookmark-items">
632 ${_('Bookmarks')}
633 ${_('Bookmarks')}
633 <div class="pull-right">
634 <div class="pull-right">
634 <a href="${h.route_path('my_account_bookmarks')}">
635 <a href="${h.route_path('my_account_bookmarks')}">
635
636
636 <i class="icon-cog"></i>
637 <i class="icon-cog"></i>
637 </a>
638 </a>
638 </div>
639 </div>
639 </li>
640 </li>
640 % if not c.bookmark_items:
641 % if not c.bookmark_items:
641 <li>
642 <li>
642 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
643 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
643 </li>
644 </li>
644 % endif
645 % endif
645 % for item in c.bookmark_items:
646 % for item in c.bookmark_items:
646 <li>
647 <li>
647 % if item.repository:
648 % if item.repository:
648 <div>
649 <div>
649 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
650 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
650 <code>${item.position}</code>
651 <code>${item.position}</code>
651 % if item.repository.repo_type == 'hg':
652 % if item.repository.repo_type == 'hg':
652 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
653 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
653 % elif item.repository.repo_type == 'git':
654 % elif item.repository.repo_type == 'git':
654 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
655 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
655 % elif item.repository.repo_type == 'svn':
656 % elif item.repository.repo_type == 'svn':
656 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
657 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
657 % endif
658 % endif
658 ${(item.title or h.shorter(item.repository.repo_name, 30))}
659 ${(item.title or h.shorter(item.repository.repo_name, 30))}
659 </a>
660 </a>
660 </div>
661 </div>
661 % elif item.repository_group:
662 % elif item.repository_group:
662 <div>
663 <div>
663 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
664 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
664 <code>${item.position}</code>
665 <code>${item.position}</code>
665 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
666 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
666 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
667 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
667 </a>
668 </a>
668 </div>
669 </div>
669 % else:
670 % else:
670 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
671 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
671 <code>${item.position}</code>
672 <code>${item.position}</code>
672 ${item.title}
673 ${item.title}
673 </a>
674 </a>
674 % endif
675 % endif
675 </li>
676 </li>
676 % endfor
677 % endfor
677
678
678 <li class="logout">
679 <li class="logout">
679 ${h.secure_form(h.route_path('logout'), request=request)}
680 ${h.secure_form(h.route_path('logout'), request=request)}
680 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
681 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
681 ${h.end_form()}
682 ${h.end_form()}
682 </li>
683 </li>
683 </ol>
684 </ol>
684 </div>
685 </div>
685 %endif
686 %endif
686 </div>
687 </div>
687 </div>
688 </div>
688
689
689 % endif
690 % endif
690 </li>
691 </li>
691 </%def>
692 </%def>
692
693
693 <%def name="menu_items(active=None)">
694 <%def name="menu_items(active=None)">
694
695
695 <ul id="quick" class="main_nav navigation horizontal-list">
696 <ul id="quick" class="main_nav navigation horizontal-list">
696 ## notice box for important system messages
697 ## notice box for important system messages
697 <li style="display: none">
698 <li style="display: none">
698 <a class="notice-box" href="#openNotice" onclick="return false">
699 <a class="notice-box" href="#openNotice" onclick="return false">
699 <div class="menulabel-notice" >
700 <div class="menulabel-notice" >
700 0
701 0
701 </div>
702 </div>
702 </a>
703 </a>
703 </li>
704 </li>
704
705
705 ## Main filter
706 ## Main filter
706 <li>
707 <li>
707 <div class="menulabel main_filter_box">
708 <div class="menulabel main_filter_box">
708 <div class="main_filter_input_box">
709 <div class="main_filter_input_box">
709 <ul class="searchItems">
710 <ul class="searchItems">
710
711
711 <li class="searchTag searchTagIcon">
712 <li class="searchTag searchTagIcon">
712 <i class="icon-search"></i>
713 <i class="icon-search"></i>
713 </li>
714 </li>
714
715
715 % if c.template_context['search_context']['repo_id']:
716 % if c.template_context['search_context']['repo_id']:
716 <li class="searchTag searchTagFilter searchTagHidable" >
717 <li class="searchTag searchTagFilter searchTagHidable" >
717 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
718 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
718 <span class="tag">
719 <span class="tag">
719 This repo
720 This repo
720 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
721 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
721 </span>
722 </span>
722 ##</a>
723 ##</a>
723 </li>
724 </li>
724 % elif c.template_context['search_context']['repo_group_id']:
725 % elif c.template_context['search_context']['repo_group_id']:
725 <li class="searchTag searchTagFilter searchTagHidable">
726 <li class="searchTag searchTagFilter searchTagHidable">
726 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
727 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
727 <span class="tag">
728 <span class="tag">
728 This group
729 This group
729 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
730 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
730 </span>
731 </span>
731 ##</a>
732 ##</a>
732 </li>
733 </li>
733 % endif
734 % endif
734
735
735 <li class="searchTagInput">
736 <li class="searchTagInput">
736 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
737 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
737 </li>
738 </li>
738 <li class="searchTag searchTagHelp">
739 <li class="searchTag searchTagHelp">
739 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
740 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
740 </li>
741 </li>
741 </ul>
742 </ul>
742 </div>
743 </div>
743 </div>
744 </div>
744
745
745 <div id="main_filter_help" style="display: none">
746 <div id="main_filter_help" style="display: none">
746 - Use '/' key to quickly access this field.
747 - Use '/' key to quickly access this field.
747
748
748 - Enter a name of repository, or repository group for quick search.
749 - Enter a name of repository, or repository group for quick search.
749
750
750 - Prefix query to allow special search:
751 - Prefix query to allow special search:
751
752
752 user:admin, to search for usernames, always global
753 user:admin, to search for usernames, always global
753
754
754 user_group:devops, to search for user groups, always global
755 user_group:devops, to search for user groups, always global
755
756
756 commit:efced4, to search for commits, scoped to repositories or groups
757 commit:efced4, to search for commits, scoped to repositories or groups
757
758
758 file:models.py, to search for file paths, scoped to repositories or groups
759 file:models.py, to search for file paths, scoped to repositories or groups
759
760
760 % if c.template_context['search_context']['repo_id']:
761 % if c.template_context['search_context']['repo_id']:
761 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
762 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
762 % elif c.template_context['search_context']['repo_group_id']:
763 % elif c.template_context['search_context']['repo_group_id']:
763 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
764 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
764 % else:
765 % else:
765 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
766 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
766 % endif
767 % endif
767 </div>
768 </div>
768 </li>
769 </li>
769
770
770 ## ROOT MENU
771 ## ROOT MENU
771 <li class="${h.is_active('home', active)}">
772 <li class="${h.is_active('home', active)}">
772 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
773 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
773 <div class="menulabel">${_('Home')}</div>
774 <div class="menulabel">${_('Home')}</div>
774 </a>
775 </a>
775 </li>
776 </li>
776
777
777 %if c.rhodecode_user.username != h.DEFAULT_USER:
778 %if c.rhodecode_user.username != h.DEFAULT_USER:
778 <li class="${h.is_active('journal', active)}">
779 <li class="${h.is_active('journal', active)}">
779 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
780 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
780 <div class="menulabel">${_('Journal')}</div>
781 <div class="menulabel">${_('Journal')}</div>
781 </a>
782 </a>
782 </li>
783 </li>
783 %else:
784 %else:
784 <li class="${h.is_active('journal', active)}">
785 <li class="${h.is_active('journal', active)}">
785 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
786 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
786 <div class="menulabel">${_('Public journal')}</div>
787 <div class="menulabel">${_('Public journal')}</div>
787 </a>
788 </a>
788 </li>
789 </li>
789 %endif
790 %endif
790
791
791 <li class="${h.is_active('gists', active)}">
792 <li class="${h.is_active('gists', active)}">
792 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
793 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
793 <div class="menulabel">${_('Gists')}</div>
794 <div class="menulabel">${_('Gists')}</div>
794 </a>
795 </a>
795 </li>
796 </li>
796
797
797 % if c.is_super_admin or c.is_delegated_admin:
798 % if c.is_super_admin or c.is_delegated_admin:
798 <li class="${h.is_active('admin', active)}">
799 <li class="${h.is_active('admin', active)}">
799 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
800 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
800 <div class="menulabel">${_('Admin')} </div>
801 <div class="menulabel">${_('Admin')} </div>
801 </a>
802 </a>
802 </li>
803 </li>
803 % endif
804 % endif
804
805
805 ## render extra user menu
806 ## render extra user menu
806 ${usermenu(active=(active=='my_account'))}
807 ${usermenu(active=(active=='my_account'))}
807
808
808 </ul>
809 </ul>
809
810
810 <script type="text/javascript">
811 <script type="text/javascript">
811 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
812 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
812
813
813 var formatRepoResult = function(result, container, query, escapeMarkup) {
814 var formatRepoResult = function(result, container, query, escapeMarkup) {
814 return function(data, escapeMarkup) {
815 return function(data, escapeMarkup) {
815 if (!data.repo_id){
816 if (!data.repo_id){
816 return data.text; // optgroup text Repositories
817 return data.text; // optgroup text Repositories
817 }
818 }
818
819
819 var tmpl = '';
820 var tmpl = '';
820 var repoType = data['repo_type'];
821 var repoType = data['repo_type'];
821 var repoName = data['text'];
822 var repoName = data['text'];
822
823
823 if(data && data.type == 'repo'){
824 if(data && data.type == 'repo'){
824 if(repoType === 'hg'){
825 if(repoType === 'hg'){
825 tmpl += '<i class="icon-hg"></i> ';
826 tmpl += '<i class="icon-hg"></i> ';
826 }
827 }
827 else if(repoType === 'git'){
828 else if(repoType === 'git'){
828 tmpl += '<i class="icon-git"></i> ';
829 tmpl += '<i class="icon-git"></i> ';
829 }
830 }
830 else if(repoType === 'svn'){
831 else if(repoType === 'svn'){
831 tmpl += '<i class="icon-svn"></i> ';
832 tmpl += '<i class="icon-svn"></i> ';
832 }
833 }
833 if(data['private']){
834 if(data['private']){
834 tmpl += '<i class="icon-lock" ></i> ';
835 tmpl += '<i class="icon-lock" ></i> ';
835 }
836 }
836 else if(visualShowPublicIcon){
837 else if(visualShowPublicIcon){
837 tmpl += '<i class="icon-unlock-alt"></i> ';
838 tmpl += '<i class="icon-unlock-alt"></i> ';
838 }
839 }
839 }
840 }
840 tmpl += escapeMarkup(repoName);
841 tmpl += escapeMarkup(repoName);
841 return tmpl;
842 return tmpl;
842
843
843 }(result, escapeMarkup);
844 }(result, escapeMarkup);
844 };
845 };
845
846
846 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
847 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
847 return function(data, escapeMarkup) {
848 return function(data, escapeMarkup) {
848 if (!data.repo_group_id){
849 if (!data.repo_group_id){
849 return data.text; // optgroup text Repositories
850 return data.text; // optgroup text Repositories
850 }
851 }
851
852
852 var tmpl = '';
853 var tmpl = '';
853 var repoGroupName = data['text'];
854 var repoGroupName = data['text'];
854
855
855 if(data){
856 if(data){
856
857
857 tmpl += '<i class="icon-repo-group"></i> ';
858 tmpl += '<i class="icon-repo-group"></i> ';
858
859
859 }
860 }
860 tmpl += escapeMarkup(repoGroupName);
861 tmpl += escapeMarkup(repoGroupName);
861 return tmpl;
862 return tmpl;
862
863
863 }(result, escapeMarkup);
864 }(result, escapeMarkup);
864 };
865 };
865
866
866 var escapeRegExChars = function (value) {
867 var escapeRegExChars = function (value) {
867 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
868 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
868 };
869 };
869
870
870 var getRepoIcon = function(repo_type) {
871 var getRepoIcon = function(repo_type) {
871 if (repo_type === 'hg') {
872 if (repo_type === 'hg') {
872 return '<i class="icon-hg"></i> ';
873 return '<i class="icon-hg"></i> ';
873 }
874 }
874 else if (repo_type === 'git') {
875 else if (repo_type === 'git') {
875 return '<i class="icon-git"></i> ';
876 return '<i class="icon-git"></i> ';
876 }
877 }
877 else if (repo_type === 'svn') {
878 else if (repo_type === 'svn') {
878 return '<i class="icon-svn"></i> ';
879 return '<i class="icon-svn"></i> ';
879 }
880 }
880 return ''
881 return ''
881 };
882 };
882
883
883 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
884 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
884
885
885 if (value.split(':').length === 2) {
886 if (value.split(':').length === 2) {
886 value = value.split(':')[1]
887 value = value.split(':')[1]
887 }
888 }
888
889
889 var searchType = data['type'];
890 var searchType = data['type'];
890 var searchSubType = data['subtype'];
891 var searchSubType = data['subtype'];
891 var valueDisplay = data['value_display'];
892 var valueDisplay = data['value_display'];
892 var valueIcon = data['value_icon'];
893 var valueIcon = data['value_icon'];
893
894
894 var pattern = '(' + escapeRegExChars(value) + ')';
895 var pattern = '(' + escapeRegExChars(value) + ')';
895
896
896 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
897 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
897
898
898 // highlight match
899 // highlight match
899 if (searchType != 'text') {
900 if (searchType != 'text') {
900 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
901 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
901 }
902 }
902
903
903 var icon = '';
904 var icon = '';
904
905
905 if (searchType === 'hint') {
906 if (searchType === 'hint') {
906 icon += '<i class="icon-repo-group"></i> ';
907 icon += '<i class="icon-repo-group"></i> ';
907 }
908 }
908 // full text search/hints
909 // full text search/hints
909 else if (searchType === 'search') {
910 else if (searchType === 'search') {
910 if (valueIcon === undefined) {
911 if (valueIcon === undefined) {
911 icon += '<i class="icon-more"></i> ';
912 icon += '<i class="icon-more"></i> ';
912 } else {
913 } else {
913 icon += valueIcon + ' ';
914 icon += valueIcon + ' ';
914 }
915 }
915
916
916 if (searchSubType !== undefined && searchSubType == 'repo') {
917 if (searchSubType !== undefined && searchSubType == 'repo') {
917 valueDisplay += '<div class="pull-right tag">repository</div>';
918 valueDisplay += '<div class="pull-right tag">repository</div>';
918 }
919 }
919 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
920 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
920 valueDisplay += '<div class="pull-right tag">repo group</div>';
921 valueDisplay += '<div class="pull-right tag">repo group</div>';
921 }
922 }
922 }
923 }
923 // repository
924 // repository
924 else if (searchType === 'repo') {
925 else if (searchType === 'repo') {
925
926
926 var repoIcon = getRepoIcon(data['repo_type']);
927 var repoIcon = getRepoIcon(data['repo_type']);
927 icon += repoIcon;
928 icon += repoIcon;
928
929
929 if (data['private']) {
930 if (data['private']) {
930 icon += '<i class="icon-lock" ></i> ';
931 icon += '<i class="icon-lock" ></i> ';
931 }
932 }
932 else if (visualShowPublicIcon) {
933 else if (visualShowPublicIcon) {
933 icon += '<i class="icon-unlock-alt"></i> ';
934 icon += '<i class="icon-unlock-alt"></i> ';
934 }
935 }
935 }
936 }
936 // repository groups
937 // repository groups
937 else if (searchType === 'repo_group') {
938 else if (searchType === 'repo_group') {
938 icon += '<i class="icon-repo-group"></i> ';
939 icon += '<i class="icon-repo-group"></i> ';
939 }
940 }
940 // user group
941 // user group
941 else if (searchType === 'user_group') {
942 else if (searchType === 'user_group') {
942 icon += '<i class="icon-group"></i> ';
943 icon += '<i class="icon-group"></i> ';
943 }
944 }
944 // user
945 // user
945 else if (searchType === 'user') {
946 else if (searchType === 'user') {
946 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
947 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
947 }
948 }
948 // commit
949 // commit
949 else if (searchType === 'commit') {
950 else if (searchType === 'commit') {
950 var repo_data = data['repo_data'];
951 var repo_data = data['repo_data'];
951 var repoIcon = getRepoIcon(repo_data['repository_type']);
952 var repoIcon = getRepoIcon(repo_data['repository_type']);
952 if (repoIcon) {
953 if (repoIcon) {
953 icon += repoIcon;
954 icon += repoIcon;
954 } else {
955 } else {
955 icon += '<i class="icon-tag"></i>';
956 icon += '<i class="icon-tag"></i>';
956 }
957 }
957 }
958 }
958 // file
959 // file
959 else if (searchType === 'file') {
960 else if (searchType === 'file') {
960 var repo_data = data['repo_data'];
961 var repo_data = data['repo_data'];
961 var repoIcon = getRepoIcon(repo_data['repository_type']);
962 var repoIcon = getRepoIcon(repo_data['repository_type']);
962 if (repoIcon) {
963 if (repoIcon) {
963 icon += repoIcon;
964 icon += repoIcon;
964 } else {
965 } else {
965 icon += '<i class="icon-tag"></i>';
966 icon += '<i class="icon-tag"></i>';
966 }
967 }
967 }
968 }
968 // generic text
969 // generic text
969 else if (searchType === 'text') {
970 else if (searchType === 'text') {
970 icon = '';
971 icon = '';
971 }
972 }
972
973
973 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
974 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
974 return tmpl.format(icon, valueDisplay);
975 return tmpl.format(icon, valueDisplay);
975 };
976 };
976
977
977 var handleSelect = function(element, suggestion) {
978 var handleSelect = function(element, suggestion) {
978 if (suggestion.type === "hint") {
979 if (suggestion.type === "hint") {
979 // we skip action
980 // we skip action
980 $('#main_filter').focus();
981 $('#main_filter').focus();
981 }
982 }
982 else if (suggestion.type === "text") {
983 else if (suggestion.type === "text") {
983 // we skip action
984 // we skip action
984 $('#main_filter').focus();
985 $('#main_filter').focus();
985
986
986 } else {
987 } else {
987 window.location = suggestion['url'];
988 window.location = suggestion['url'];
988 }
989 }
989 };
990 };
990
991
991 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
992 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
992 if (queryLowerCase.split(':').length === 2) {
993 if (queryLowerCase.split(':').length === 2) {
993 queryLowerCase = queryLowerCase.split(':')[1]
994 queryLowerCase = queryLowerCase.split(':')[1]
994 }
995 }
995 if (suggestion.type === "text") {
996 if (suggestion.type === "text") {
996 // special case we don't want to "skip" display for
997 // special case we don't want to "skip" display for
997 return true
998 return true
998 }
999 }
999 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
1000 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
1000 };
1001 };
1001
1002
1002 var cleanContext = {
1003 var cleanContext = {
1003 repo_view_type: null,
1004 repo_view_type: null,
1004
1005
1005 repo_id: null,
1006 repo_id: null,
1006 repo_name: "",
1007 repo_name: "",
1007
1008
1008 repo_group_id: null,
1009 repo_group_id: null,
1009 repo_group_name: null
1010 repo_group_name: null
1010 };
1011 };
1011 var removeGoToFilter = function () {
1012 var removeGoToFilter = function () {
1012 $('.searchTagHidable').hide();
1013 $('.searchTagHidable').hide();
1013 $('#main_filter').autocomplete(
1014 $('#main_filter').autocomplete(
1014 'setOptions', {params:{search_context: cleanContext}});
1015 'setOptions', {params:{search_context: cleanContext}});
1015 };
1016 };
1016
1017
1017 $('#main_filter').autocomplete({
1018 $('#main_filter').autocomplete({
1018 serviceUrl: pyroutes.url('goto_switcher_data'),
1019 serviceUrl: pyroutes.url('goto_switcher_data'),
1019 params: {
1020 params: {
1020 "search_context": templateContext.search_context
1021 "search_context": templateContext.search_context
1021 },
1022 },
1022 minChars:2,
1023 minChars:2,
1023 maxHeight:400,
1024 maxHeight:400,
1024 deferRequestBy: 300, //miliseconds
1025 deferRequestBy: 300, //miliseconds
1025 tabDisabled: true,
1026 tabDisabled: true,
1026 autoSelectFirst: false,
1027 autoSelectFirst: false,
1027 containerClass: 'autocomplete-qfilter-suggestions',
1028 containerClass: 'autocomplete-qfilter-suggestions',
1028 formatResult: autocompleteMainFilterFormatResult,
1029 formatResult: autocompleteMainFilterFormatResult,
1029 lookupFilter: autocompleteMainFilterResult,
1030 lookupFilter: autocompleteMainFilterResult,
1030 onSelect: function (element, suggestion) {
1031 onSelect: function (element, suggestion) {
1031 handleSelect(element, suggestion);
1032 handleSelect(element, suggestion);
1032 return false;
1033 return false;
1033 },
1034 },
1034 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1035 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1035 if (jqXHR !== 'abort') {
1036 if (jqXHR !== 'abort') {
1036 alert("Error during search.\nError code: {0}".format(textStatus));
1037 alert("Error during search.\nError code: {0}".format(textStatus));
1037 window.location = '';
1038 window.location = '';
1038 }
1039 }
1039 },
1040 },
1040 onSearchStart: function (params) {
1041 onSearchStart: function (params) {
1041 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1042 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1042 },
1043 },
1043 onSearchComplete: function (query, suggestions) {
1044 onSearchComplete: function (query, suggestions) {
1044 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1045 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1045 },
1046 },
1046 });
1047 });
1047
1048
1048 showMainFilterBox = function () {
1049 showMainFilterBox = function () {
1049 $('#main_filter_help').toggle();
1050 $('#main_filter_help').toggle();
1050 };
1051 };
1051
1052
1052 $('#main_filter').on('keydown.autocomplete', function (e) {
1053 $('#main_filter').on('keydown.autocomplete', function (e) {
1053
1054
1054 var BACKSPACE = 8;
1055 var BACKSPACE = 8;
1055 var el = $(e.currentTarget);
1056 var el = $(e.currentTarget);
1056 if(e.which === BACKSPACE){
1057 if(e.which === BACKSPACE){
1057 var inputVal = el.val();
1058 var inputVal = el.val();
1058 if (inputVal === ""){
1059 if (inputVal === ""){
1059 removeGoToFilter()
1060 removeGoToFilter()
1060 }
1061 }
1061 }
1062 }
1062 });
1063 });
1063
1064
1064 </script>
1065 </script>
1065 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1066 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1066 </%def>
1067 </%def>
1067
1068
1068 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1069 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1069 <div class="modal-dialog">
1070 <div class="modal-dialog">
1070 <div class="modal-content">
1071 <div class="modal-content">
1071 <div class="modal-header">
1072 <div class="modal-header">
1072 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1073 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1073 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1074 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1074 </div>
1075 </div>
1075 <div class="modal-body">
1076 <div class="modal-body">
1076 <div class="block-left">
1077 <div class="block-left">
1077 <table class="keyboard-mappings">
1078 <table class="keyboard-mappings">
1078 <tbody>
1079 <tbody>
1079 <tr>
1080 <tr>
1080 <th></th>
1081 <th></th>
1081 <th>${_('Site-wide shortcuts')}</th>
1082 <th>${_('Site-wide shortcuts')}</th>
1082 </tr>
1083 </tr>
1083 <%
1084 <%
1084 elems = [
1085 elems = [
1085 ('/', 'Use quick search box'),
1086 ('/', 'Use quick search box'),
1086 ('g h', 'Goto home page'),
1087 ('g h', 'Goto home page'),
1087 ('g g', 'Goto my private gists page'),
1088 ('g g', 'Goto my private gists page'),
1088 ('g G', 'Goto my public gists page'),
1089 ('g G', 'Goto my public gists page'),
1089 ('g 0-9', 'Goto bookmarked items from 0-9'),
1090 ('g 0-9', 'Goto bookmarked items from 0-9'),
1090 ('n r', 'New repository page'),
1091 ('n r', 'New repository page'),
1091 ('n g', 'New gist page'),
1092 ('n g', 'New gist page'),
1092 ]
1093 ]
1093 %>
1094 %>
1094 %for key, desc in elems:
1095 %for key, desc in elems:
1095 <tr>
1096 <tr>
1096 <td class="keys">
1097 <td class="keys">
1097 <span class="key tag">${key}</span>
1098 <span class="key tag">${key}</span>
1098 </td>
1099 </td>
1099 <td>${desc}</td>
1100 <td>${desc}</td>
1100 </tr>
1101 </tr>
1101 %endfor
1102 %endfor
1102 </tbody>
1103 </tbody>
1103 </table>
1104 </table>
1104 </div>
1105 </div>
1105 <div class="block-left">
1106 <div class="block-left">
1106 <table class="keyboard-mappings">
1107 <table class="keyboard-mappings">
1107 <tbody>
1108 <tbody>
1108 <tr>
1109 <tr>
1109 <th></th>
1110 <th></th>
1110 <th>${_('Repositories')}</th>
1111 <th>${_('Repositories')}</th>
1111 </tr>
1112 </tr>
1112 <%
1113 <%
1113 elems = [
1114 elems = [
1114 ('g s', 'Goto summary page'),
1115 ('g s', 'Goto summary page'),
1115 ('g c', 'Goto changelog page'),
1116 ('g c', 'Goto changelog page'),
1116 ('g f', 'Goto files page'),
1117 ('g f', 'Goto files page'),
1117 ('g F', 'Goto files page with file search activated'),
1118 ('g F', 'Goto files page with file search activated'),
1118 ('g p', 'Goto pull requests page'),
1119 ('g p', 'Goto pull requests page'),
1119 ('g o', 'Goto repository settings'),
1120 ('g o', 'Goto repository settings'),
1120 ('g O', 'Goto repository access permissions settings'),
1121 ('g O', 'Goto repository access permissions settings'),
1121 ]
1122 ]
1122 %>
1123 %>
1123 %for key, desc in elems:
1124 %for key, desc in elems:
1124 <tr>
1125 <tr>
1125 <td class="keys">
1126 <td class="keys">
1126 <span class="key tag">${key}</span>
1127 <span class="key tag">${key}</span>
1127 </td>
1128 </td>
1128 <td>${desc}</td>
1129 <td>${desc}</td>
1129 </tr>
1130 </tr>
1130 %endfor
1131 %endfor
1131 </tbody>
1132 </tbody>
1132 </table>
1133 </table>
1133 </div>
1134 </div>
1134 </div>
1135 </div>
1135 <div class="modal-footer">
1136 <div class="modal-footer">
1136 </div>
1137 </div>
1137 </div><!-- /.modal-content -->
1138 </div><!-- /.modal-content -->
1138 </div><!-- /.modal-dialog -->
1139 </div><!-- /.modal-dialog -->
1139 </div><!-- /.modal -->
1140 </div><!-- /.modal -->
@@ -1,1178 +1,1181 b''
1 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
1 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
2
2
3 <%def name="diff_line_anchor(commit, filename, line, type)"><%
3 <%def name="diff_line_anchor(commit, filename, line, type)"><%
4 return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
4 return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
5 %></%def>
5 %></%def>
6
6
7 <%def name="action_class(action)">
7 <%def name="action_class(action)">
8 <%
8 <%
9 return {
9 return {
10 '-': 'cb-deletion',
10 '-': 'cb-deletion',
11 '+': 'cb-addition',
11 '+': 'cb-addition',
12 ' ': 'cb-context',
12 ' ': 'cb-context',
13 }.get(action, 'cb-empty')
13 }.get(action, 'cb-empty')
14 %>
14 %>
15 </%def>
15 </%def>
16
16
17 <%def name="op_class(op_id)">
17 <%def name="op_class(op_id)">
18 <%
18 <%
19 return {
19 return {
20 DEL_FILENODE: 'deletion', # file deleted
20 DEL_FILENODE: 'deletion', # file deleted
21 BIN_FILENODE: 'warning' # binary diff hidden
21 BIN_FILENODE: 'warning' # binary diff hidden
22 }.get(op_id, 'addition')
22 }.get(op_id, 'addition')
23 %>
23 %>
24 </%def>
24 </%def>
25
25
26
26
27
27
28 <%def name="render_diffset(diffset, commit=None,
28 <%def name="render_diffset(diffset, commit=None,
29
29
30 # collapse all file diff entries when there are more than this amount of files in the diff
30 # collapse all file diff entries when there are more than this amount of files in the diff
31 collapse_when_files_over=20,
31 collapse_when_files_over=20,
32
32
33 # collapse lines in the diff when more than this amount of lines changed in the file diff
33 # collapse lines in the diff when more than this amount of lines changed in the file diff
34 lines_changed_limit=500,
34 lines_changed_limit=500,
35
35
36 # add a ruler at to the output
36 # add a ruler at to the output
37 ruler_at_chars=0,
37 ruler_at_chars=0,
38
38
39 # show inline comments
39 # show inline comments
40 use_comments=False,
40 use_comments=False,
41
41
42 # disable new comments
42 # disable new comments
43 disable_new_comments=False,
43 disable_new_comments=False,
44
44
45 # special file-comments that were deleted in previous versions
45 # special file-comments that were deleted in previous versions
46 # it's used for showing outdated comments for deleted files in a PR
46 # it's used for showing outdated comments for deleted files in a PR
47 deleted_files_comments=None,
47 deleted_files_comments=None,
48
48
49 # for cache purpose
49 # for cache purpose
50 inline_comments=None,
50 inline_comments=None,
51
51
52 # additional menu for PRs
52 # additional menu for PRs
53 pull_request_menu=None
53 pull_request_menu=None,
54
55 # show/hide todo next to comments
56 show_todos=True,
54
57
55 )">
58 )">
56
59
57 <%
60 <%
58 diffset_container_id = h.md5(diffset.target_ref)
61 diffset_container_id = h.md5(diffset.target_ref)
59 collapse_all = len(diffset.files) > collapse_when_files_over
62 collapse_all = len(diffset.files) > collapse_when_files_over
60 %>
63 %>
61
64
62 %if use_comments:
65 %if use_comments:
63 <div id="cb-comments-inline-container-template" class="js-template">
66 <div id="cb-comments-inline-container-template" class="js-template">
64 ${inline_comments_container([], inline_comments)}
67 ${inline_comments_container([], inline_comments)}
65 </div>
68 </div>
66 <div class="js-template" id="cb-comment-inline-form-template">
69 <div class="js-template" id="cb-comment-inline-form-template">
67 <div class="comment-inline-form ac">
70 <div class="comment-inline-form ac">
68
71
69 %if c.rhodecode_user.username != h.DEFAULT_USER:
72 %if c.rhodecode_user.username != h.DEFAULT_USER:
70 ## render template for inline comments
73 ## render template for inline comments
71 ${commentblock.comment_form(form_type='inline')}
74 ${commentblock.comment_form(form_type='inline')}
72 %else:
75 %else:
73 ${h.form('', class_='inline-form comment-form-login', method='get')}
76 ${h.form('', class_='inline-form comment-form-login', method='get')}
74 <div class="pull-left">
77 <div class="pull-left">
75 <div class="comment-help pull-right">
78 <div class="comment-help pull-right">
76 ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
79 ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
77 </div>
80 </div>
78 </div>
81 </div>
79 <div class="comment-button pull-right">
82 <div class="comment-button pull-right">
80 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
83 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
81 ${_('Cancel')}
84 ${_('Cancel')}
82 </button>
85 </button>
83 </div>
86 </div>
84 <div class="clearfix"></div>
87 <div class="clearfix"></div>
85 ${h.end_form()}
88 ${h.end_form()}
86 %endif
89 %endif
87 </div>
90 </div>
88 </div>
91 </div>
89
92
90 %endif
93 %endif
91
94
92 %if c.user_session_attrs["diffmode"] == 'sideside':
95 %if c.user_session_attrs["diffmode"] == 'sideside':
93 <style>
96 <style>
94 .wrapper {
97 .wrapper {
95 max-width: 1600px !important;
98 max-width: 1600px !important;
96 }
99 }
97 </style>
100 </style>
98 %endif
101 %endif
99
102
100 %if ruler_at_chars:
103 %if ruler_at_chars:
101 <style>
104 <style>
102 .diff table.cb .cb-content:after {
105 .diff table.cb .cb-content:after {
103 content: "";
106 content: "";
104 border-left: 1px solid blue;
107 border-left: 1px solid blue;
105 position: absolute;
108 position: absolute;
106 top: 0;
109 top: 0;
107 height: 18px;
110 height: 18px;
108 opacity: .2;
111 opacity: .2;
109 z-index: 10;
112 z-index: 10;
110 //## +5 to account for diff action (+/-)
113 //## +5 to account for diff action (+/-)
111 left: ${ruler_at_chars + 5}ch;
114 left: ${ruler_at_chars + 5}ch;
112 </style>
115 </style>
113 %endif
116 %endif
114
117
115 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
118 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
116
119
117 <div style="height: 20px; line-height: 20px">
120 <div style="height: 20px; line-height: 20px">
118 ## expand/collapse action
121 ## expand/collapse action
119 <div class="pull-left">
122 <div class="pull-left">
120 <a class="${'collapsed' if collapse_all else ''}" href="#expand-files" onclick="toggleExpand(this, '${diffset_container_id}'); return false">
123 <a class="${'collapsed' if collapse_all else ''}" href="#expand-files" onclick="toggleExpand(this, '${diffset_container_id}'); return false">
121 % if collapse_all:
124 % if collapse_all:
122 <i class="icon-plus-squared-alt icon-no-margin"></i>${_('Expand all files')}
125 <i class="icon-plus-squared-alt icon-no-margin"></i>${_('Expand all files')}
123 % else:
126 % else:
124 <i class="icon-minus-squared-alt icon-no-margin"></i>${_('Collapse all files')}
127 <i class="icon-minus-squared-alt icon-no-margin"></i>${_('Collapse all files')}
125 % endif
128 % endif
126 </a>
129 </a>
127
130
128 </div>
131 </div>
129
132
130 ## todos
133 ## todos
131 % if getattr(c, 'at_version', None):
134 % if show_todos and getattr(c, 'at_version', None):
132 <div class="pull-right">
135 <div class="pull-right">
133 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
136 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
134 ${_('not available in this view')}
137 ${_('not available in this view')}
135 </div>
138 </div>
136 % else:
139 % elif show_todos:
137 <div class="pull-right">
140 <div class="pull-right">
138 <div class="comments-number" style="padding-left: 10px">
141 <div class="comments-number" style="padding-left: 10px">
139 % if hasattr(c, 'unresolved_comments') and hasattr(c, 'resolved_comments'):
142 % if hasattr(c, 'unresolved_comments') and hasattr(c, 'resolved_comments'):
140 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
143 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
141 % if c.unresolved_comments:
144 % if c.unresolved_comments:
142 <a href="#show-todos" onclick="$('#todo-box').toggle(); return false">
145 <a href="#show-todos" onclick="$('#todo-box').toggle(); return false">
143 ${_('{} unresolved').format(len(c.unresolved_comments))}
146 ${_('{} unresolved').format(len(c.unresolved_comments))}
144 </a>
147 </a>
145 % else:
148 % else:
146 ${_('0 unresolved')}
149 ${_('0 unresolved')}
147 % endif
150 % endif
148
151
149 ${_('{} Resolved').format(len(c.resolved_comments))}
152 ${_('{} Resolved').format(len(c.resolved_comments))}
150 % endif
153 % endif
151 </div>
154 </div>
152 </div>
155 </div>
153 % endif
156 % endif
154
157
155 ## comments
158 ## comments
156 <div class="pull-right">
159 <div class="pull-right">
157 <div class="comments-number" style="padding-left: 10px">
160 <div class="comments-number" style="padding-left: 10px">
158 % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
161 % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
159 <i class="icon-comment" style="color: #949494">COMMENTS:</i>
162 <i class="icon-comment" style="color: #949494">COMMENTS:</i>
160 % if c.comments:
163 % if c.comments:
161 <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
164 <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
162 % else:
165 % else:
163 ${_('0 General')}
166 ${_('0 General')}
164 % endif
167 % endif
165
168
166 % if c.inline_cnt:
169 % if c.inline_cnt:
167 <a href="#" onclick="return Rhodecode.comments.nextComment();"
170 <a href="#" onclick="return Rhodecode.comments.nextComment();"
168 id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
171 id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
169 </a>
172 </a>
170 % else:
173 % else:
171 ${_('0 Inline')}
174 ${_('0 Inline')}
172 % endif
175 % endif
173 % endif
176 % endif
174
177
175 % if pull_request_menu:
178 % if pull_request_menu:
176 <%
179 <%
177 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
180 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
178 %>
181 %>
179
182
180 % if outdated_comm_count_ver:
183 % if outdated_comm_count_ver:
181 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
184 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
182 (${_("{} Outdated").format(outdated_comm_count_ver)})
185 (${_("{} Outdated").format(outdated_comm_count_ver)})
183 </a>
186 </a>
184 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
187 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
185 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
188 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
186 % else:
189 % else:
187 (${_("{} Outdated").format(outdated_comm_count_ver)})
190 (${_("{} Outdated").format(outdated_comm_count_ver)})
188 % endif
191 % endif
189
192
190 % endif
193 % endif
191
194
192 </div>
195 </div>
193 </div>
196 </div>
194
197
195 </div>
198 </div>
196
199
197 % if diffset.limited_diff:
200 % if diffset.limited_diff:
198 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
201 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
199 <h2 class="clearinner">
202 <h2 class="clearinner">
200 ${_('The requested changes are too big and content was truncated.')}
203 ${_('The requested changes are too big and content was truncated.')}
201 <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
204 <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
202 </h2>
205 </h2>
203 </div>
206 </div>
204 ## commit range header for each individual diff
207 ## commit range header for each individual diff
205 % elif commit and hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1:
208 % elif commit and hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1:
206 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
209 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
207 <div class="clearinner">
210 <div class="clearinner">
208 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
211 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
209 </div>
212 </div>
210 </div>
213 </div>
211 % endif
214 % endif
212
215
213 <div id="todo-box">
216 <div id="todo-box">
214 % if hasattr(c, 'unresolved_comments') and c.unresolved_comments:
217 % if hasattr(c, 'unresolved_comments') and c.unresolved_comments:
215 % for co in c.unresolved_comments:
218 % for co in c.unresolved_comments:
216 <a class="permalink" href="#comment-${co.comment_id}"
219 <a class="permalink" href="#comment-${co.comment_id}"
217 onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'))">
220 onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'))">
218 <i class="icon-flag-filled-red"></i>
221 <i class="icon-flag-filled-red"></i>
219 ${co.comment_id}</a>${('' if loop.last else ',')}
222 ${co.comment_id}</a>${('' if loop.last else ',')}
220 % endfor
223 % endfor
221 % endif
224 % endif
222 </div>
225 </div>
223 %if diffset.has_hidden_changes:
226 %if diffset.has_hidden_changes:
224 <p class="empty_data">${_('Some changes may be hidden')}</p>
227 <p class="empty_data">${_('Some changes may be hidden')}</p>
225 %elif not diffset.files:
228 %elif not diffset.files:
226 <p class="empty_data">${_('No files')}</p>
229 <p class="empty_data">${_('No files')}</p>
227 %endif
230 %endif
228
231
229 <div class="filediffs">
232 <div class="filediffs">
230
233
231 ## initial value could be marked as False later on
234 ## initial value could be marked as False later on
232 <% over_lines_changed_limit = False %>
235 <% over_lines_changed_limit = False %>
233 %for i, filediff in enumerate(diffset.files):
236 %for i, filediff in enumerate(diffset.files):
234
237
235 <%
238 <%
236 lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted']
239 lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted']
237 over_lines_changed_limit = lines_changed > lines_changed_limit
240 over_lines_changed_limit = lines_changed > lines_changed_limit
238 %>
241 %>
239 ## anchor with support of sticky header
242 ## anchor with support of sticky header
240 <div class="anchor" id="a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></div>
243 <div class="anchor" id="a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></div>
241
244
242 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="updateSticky();">
245 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="updateSticky();">
243 <div
246 <div
244 class="filediff"
247 class="filediff"
245 data-f-path="${filediff.patch['filename']}"
248 data-f-path="${filediff.patch['filename']}"
246 data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}"
249 data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}"
247 >
250 >
248 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
251 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
249 <div class="filediff-collapse-indicator icon-"></div>
252 <div class="filediff-collapse-indicator icon-"></div>
250 ${diff_ops(filediff)}
253 ${diff_ops(filediff)}
251 </label>
254 </label>
252
255
253 ${diff_menu(filediff, use_comments=use_comments)}
256 ${diff_menu(filediff, use_comments=use_comments)}
254 <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
257 <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
255
258
256 ## new/deleted/empty content case
259 ## new/deleted/empty content case
257 % if not filediff.hunks:
260 % if not filediff.hunks:
258 ## Comment container, on "fakes" hunk that contains all data to render comments
261 ## Comment container, on "fakes" hunk that contains all data to render comments
259 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments)}
262 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments)}
260 % endif
263 % endif
261
264
262 %if filediff.limited_diff:
265 %if filediff.limited_diff:
263 <tr class="cb-warning cb-collapser">
266 <tr class="cb-warning cb-collapser">
264 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
267 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
265 ${_('The requested commit or file is too big and content was truncated.')} <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
268 ${_('The requested commit or file is too big and content was truncated.')} <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
266 </td>
269 </td>
267 </tr>
270 </tr>
268 %else:
271 %else:
269 %if over_lines_changed_limit:
272 %if over_lines_changed_limit:
270 <tr class="cb-warning cb-collapser">
273 <tr class="cb-warning cb-collapser">
271 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
274 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
272 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
275 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
273 <a href="#" class="cb-expand"
276 <a href="#" class="cb-expand"
274 onclick="$(this).closest('table').removeClass('cb-collapsed'); updateSticky(); return false;">${_('Show them')}
277 onclick="$(this).closest('table').removeClass('cb-collapsed'); updateSticky(); return false;">${_('Show them')}
275 </a>
278 </a>
276 <a href="#" class="cb-collapse"
279 <a href="#" class="cb-collapse"
277 onclick="$(this).closest('table').addClass('cb-collapsed'); updateSticky(); return false;">${_('Hide them')}
280 onclick="$(this).closest('table').addClass('cb-collapsed'); updateSticky(); return false;">${_('Hide them')}
278 </a>
281 </a>
279 </td>
282 </td>
280 </tr>
283 </tr>
281 %endif
284 %endif
282 %endif
285 %endif
283
286
284 % for hunk in filediff.hunks:
287 % for hunk in filediff.hunks:
285 <tr class="cb-hunk">
288 <tr class="cb-hunk">
286 <td ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=3' or '')}>
289 <td ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=3' or '')}>
287 ## TODO: dan: add ajax loading of more context here
290 ## TODO: dan: add ajax loading of more context here
288 ## <a href="#">
291 ## <a href="#">
289 <i class="icon-more"></i>
292 <i class="icon-more"></i>
290 ## </a>
293 ## </a>
291 </td>
294 </td>
292 <td ${(c.user_session_attrs["diffmode"] == 'sideside' and 'colspan=5' or '')}>
295 <td ${(c.user_session_attrs["diffmode"] == 'sideside' and 'colspan=5' or '')}>
293 @@
296 @@
294 -${hunk.source_start},${hunk.source_length}
297 -${hunk.source_start},${hunk.source_length}
295 +${hunk.target_start},${hunk.target_length}
298 +${hunk.target_start},${hunk.target_length}
296 ${hunk.section_header}
299 ${hunk.section_header}
297 </td>
300 </td>
298 </tr>
301 </tr>
299 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments)}
302 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments)}
300 % endfor
303 % endfor
301
304
302 <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %>
305 <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %>
303
306
304 ## outdated comments that do not fit into currently displayed lines
307 ## outdated comments that do not fit into currently displayed lines
305 % for lineno, comments in unmatched_comments.items():
308 % for lineno, comments in unmatched_comments.items():
306
309
307 %if c.user_session_attrs["diffmode"] == 'unified':
310 %if c.user_session_attrs["diffmode"] == 'unified':
308 % if loop.index == 0:
311 % if loop.index == 0:
309 <tr class="cb-hunk">
312 <tr class="cb-hunk">
310 <td colspan="3"></td>
313 <td colspan="3"></td>
311 <td>
314 <td>
312 <div>
315 <div>
313 ${_('Unmatched inline comments below')}
316 ${_('Unmatched/outdated inline comments below')}
314 </div>
317 </div>
315 </td>
318 </td>
316 </tr>
319 </tr>
317 % endif
320 % endif
318 <tr class="cb-line">
321 <tr class="cb-line">
319 <td class="cb-data cb-context"></td>
322 <td class="cb-data cb-context"></td>
320 <td class="cb-lineno cb-context"></td>
323 <td class="cb-lineno cb-context"></td>
321 <td class="cb-lineno cb-context"></td>
324 <td class="cb-lineno cb-context"></td>
322 <td class="cb-content cb-context">
325 <td class="cb-content cb-context">
323 ${inline_comments_container(comments, inline_comments)}
326 ${inline_comments_container(comments, inline_comments)}
324 </td>
327 </td>
325 </tr>
328 </tr>
326 %elif c.user_session_attrs["diffmode"] == 'sideside':
329 %elif c.user_session_attrs["diffmode"] == 'sideside':
327 % if loop.index == 0:
330 % if loop.index == 0:
328 <tr class="cb-comment-info">
331 <tr class="cb-comment-info">
329 <td colspan="2"></td>
332 <td colspan="2"></td>
330 <td class="cb-line">
333 <td class="cb-line">
331 <div>
334 <div>
332 ${_('Unmatched inline comments below')}
335 ${_('Unmatched/outdated inline comments below')}
333 </div>
336 </div>
334 </td>
337 </td>
335 <td colspan="2"></td>
338 <td colspan="2"></td>
336 <td class="cb-line">
339 <td class="cb-line">
337 <div>
340 <div>
338 ${_('Unmatched comments below')}
341 ${_('Unmatched/outdated comments below')}
339 </div>
342 </div>
340 </td>
343 </td>
341 </tr>
344 </tr>
342 % endif
345 % endif
343 <tr class="cb-line">
346 <tr class="cb-line">
344 <td class="cb-data cb-context"></td>
347 <td class="cb-data cb-context"></td>
345 <td class="cb-lineno cb-context"></td>
348 <td class="cb-lineno cb-context"></td>
346 <td class="cb-content cb-context">
349 <td class="cb-content cb-context">
347 % if lineno.startswith('o'):
350 % if lineno.startswith('o'):
348 ${inline_comments_container(comments, inline_comments)}
351 ${inline_comments_container(comments, inline_comments)}
349 % endif
352 % endif
350 </td>
353 </td>
351
354
352 <td class="cb-data cb-context"></td>
355 <td class="cb-data cb-context"></td>
353 <td class="cb-lineno cb-context"></td>
356 <td class="cb-lineno cb-context"></td>
354 <td class="cb-content cb-context">
357 <td class="cb-content cb-context">
355 % if lineno.startswith('n'):
358 % if lineno.startswith('n'):
356 ${inline_comments_container(comments, inline_comments)}
359 ${inline_comments_container(comments, inline_comments)}
357 % endif
360 % endif
358 </td>
361 </td>
359 </tr>
362 </tr>
360 %endif
363 %endif
361
364
362 % endfor
365 % endfor
363
366
364 </table>
367 </table>
365 </div>
368 </div>
366 %endfor
369 %endfor
367
370
368 ## outdated comments that are made for a file that has been deleted
371 ## outdated comments that are made for a file that has been deleted
369 % for filename, comments_dict in (deleted_files_comments or {}).items():
372 % for filename, comments_dict in (deleted_files_comments or {}).items():
370
373
371 <%
374 <%
372 display_state = 'display: none'
375 display_state = 'display: none'
373 open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False]
376 open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False]
374 if open_comments_in_file:
377 if open_comments_in_file:
375 display_state = ''
378 display_state = ''
376 fid = str(id(filename))
379 fid = str(id(filename))
377 %>
380 %>
378 <div class="filediffs filediff-outdated" style="${display_state}">
381 <div class="filediffs filediff-outdated" style="${display_state}">
379 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="updateSticky();">
382 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="updateSticky();">
380 <div class="filediff" data-f-path="${filename}" id="a_${h.FID(fid, filename)}">
383 <div class="filediff" data-f-path="${filename}" id="a_${h.FID(fid, filename)}">
381 <label for="filediff-collapse-${id(filename)}" class="filediff-heading">
384 <label for="filediff-collapse-${id(filename)}" class="filediff-heading">
382 <div class="filediff-collapse-indicator icon-"></div>
385 <div class="filediff-collapse-indicator icon-"></div>
383
386
384 <span class="pill">
387 <span class="pill">
385 ## file was deleted
388 ## file was deleted
386 ${filename}
389 ${filename}
387 </span>
390 </span>
388 <span class="pill-group pull-left" >
391 <span class="pill-group pull-left" >
389 ## file op, doesn't need translation
392 ## file op, doesn't need translation
390 <span class="pill" op="removed">removed in this version</span>
393 <span class="pill" op="removed">removed in this version</span>
391 </span>
394 </span>
392 <a class="pill filediff-anchor" href="#a_${h.FID(fid, filename)}">ΒΆ</a>
395 <a class="pill filediff-anchor" href="#a_${h.FID(fid, filename)}">ΒΆ</a>
393 <span class="pill-group pull-right">
396 <span class="pill-group pull-right">
394 <span class="pill" op="deleted">-${comments_dict['stats']}</span>
397 <span class="pill" op="deleted">-${comments_dict['stats']}</span>
395 </span>
398 </span>
396 </label>
399 </label>
397
400
398 <table class="cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
401 <table class="cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
399 <tr>
402 <tr>
400 % if c.user_session_attrs["diffmode"] == 'unified':
403 % if c.user_session_attrs["diffmode"] == 'unified':
401 <td></td>
404 <td></td>
402 %endif
405 %endif
403
406
404 <td></td>
407 <td></td>
405 <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=5')}>
408 <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=5')}>
406 ${_('File was deleted in this version. There are still outdated/unresolved comments attached to it.')}
409 ${_('File was deleted in this version. There are still outdated/unresolved comments attached to it.')}
407 </td>
410 </td>
408 </tr>
411 </tr>
409 %if c.user_session_attrs["diffmode"] == 'unified':
412 %if c.user_session_attrs["diffmode"] == 'unified':
410 <tr class="cb-line">
413 <tr class="cb-line">
411 <td class="cb-data cb-context"></td>
414 <td class="cb-data cb-context"></td>
412 <td class="cb-lineno cb-context"></td>
415 <td class="cb-lineno cb-context"></td>
413 <td class="cb-lineno cb-context"></td>
416 <td class="cb-lineno cb-context"></td>
414 <td class="cb-content cb-context">
417 <td class="cb-content cb-context">
415 ${inline_comments_container(comments_dict['comments'], inline_comments)}
418 ${inline_comments_container(comments_dict['comments'], inline_comments)}
416 </td>
419 </td>
417 </tr>
420 </tr>
418 %elif c.user_session_attrs["diffmode"] == 'sideside':
421 %elif c.user_session_attrs["diffmode"] == 'sideside':
419 <tr class="cb-line">
422 <tr class="cb-line">
420 <td class="cb-data cb-context"></td>
423 <td class="cb-data cb-context"></td>
421 <td class="cb-lineno cb-context"></td>
424 <td class="cb-lineno cb-context"></td>
422 <td class="cb-content cb-context"></td>
425 <td class="cb-content cb-context"></td>
423
426
424 <td class="cb-data cb-context"></td>
427 <td class="cb-data cb-context"></td>
425 <td class="cb-lineno cb-context"></td>
428 <td class="cb-lineno cb-context"></td>
426 <td class="cb-content cb-context">
429 <td class="cb-content cb-context">
427 ${inline_comments_container(comments_dict['comments'], inline_comments)}
430 ${inline_comments_container(comments_dict['comments'], inline_comments)}
428 </td>
431 </td>
429 </tr>
432 </tr>
430 %endif
433 %endif
431 </table>
434 </table>
432 </div>
435 </div>
433 </div>
436 </div>
434 % endfor
437 % endfor
435
438
436 </div>
439 </div>
437 </div>
440 </div>
438 </%def>
441 </%def>
439
442
440 <%def name="diff_ops(filediff)">
443 <%def name="diff_ops(filediff)">
441 <%
444 <%
442 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
445 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
443 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
446 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
444 %>
447 %>
445 <span class="pill">
448 <span class="pill">
446 <i class="icon-file-text"></i>
449 <i class="icon-file-text"></i>
447 %if filediff.source_file_path and filediff.target_file_path:
450 %if filediff.source_file_path and filediff.target_file_path:
448 %if filediff.source_file_path != filediff.target_file_path:
451 %if filediff.source_file_path != filediff.target_file_path:
449 ## file was renamed, or copied
452 ## file was renamed, or copied
450 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
453 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
451 ${filediff.target_file_path} β¬… <del>${filediff.source_file_path}</del>
454 ${filediff.target_file_path} β¬… <del>${filediff.source_file_path}</del>
452 <% final_path = filediff.target_file_path %>
455 <% final_path = filediff.target_file_path %>
453 %elif COPIED_FILENODE in filediff.patch['stats']['ops']:
456 %elif COPIED_FILENODE in filediff.patch['stats']['ops']:
454 ${filediff.target_file_path} β¬… ${filediff.source_file_path}
457 ${filediff.target_file_path} β¬… ${filediff.source_file_path}
455 <% final_path = filediff.target_file_path %>
458 <% final_path = filediff.target_file_path %>
456 %endif
459 %endif
457 %else:
460 %else:
458 ## file was modified
461 ## file was modified
459 ${filediff.source_file_path}
462 ${filediff.source_file_path}
460 <% final_path = filediff.source_file_path %>
463 <% final_path = filediff.source_file_path %>
461 %endif
464 %endif
462 %else:
465 %else:
463 %if filediff.source_file_path:
466 %if filediff.source_file_path:
464 ## file was deleted
467 ## file was deleted
465 ${filediff.source_file_path}
468 ${filediff.source_file_path}
466 <% final_path = filediff.source_file_path %>
469 <% final_path = filediff.source_file_path %>
467 %else:
470 %else:
468 ## file was added
471 ## file was added
469 ${filediff.target_file_path}
472 ${filediff.target_file_path}
470 <% final_path = filediff.target_file_path %>
473 <% final_path = filediff.target_file_path %>
471 %endif
474 %endif
472 %endif
475 %endif
473 <i style="color: #aaa" class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy the full path')}" onclick="return false;"></i>
476 <i style="color: #aaa" class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy the full path')}" onclick="return false;"></i>
474 </span>
477 </span>
475 ## anchor link
478 ## anchor link
476 <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}">ΒΆ</a>
479 <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}">ΒΆ</a>
477
480
478 <span class="pill-group pull-right">
481 <span class="pill-group pull-right">
479
482
480 ## ops pills
483 ## ops pills
481 %if filediff.limited_diff:
484 %if filediff.limited_diff:
482 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
485 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
483 %endif
486 %endif
484
487
485 %if NEW_FILENODE in filediff.patch['stats']['ops']:
488 %if NEW_FILENODE in filediff.patch['stats']['ops']:
486 <span class="pill" op="created">created</span>
489 <span class="pill" op="created">created</span>
487 %if filediff['target_mode'].startswith('120'):
490 %if filediff['target_mode'].startswith('120'):
488 <span class="pill" op="symlink">symlink</span>
491 <span class="pill" op="symlink">symlink</span>
489 %else:
492 %else:
490 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
493 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
491 %endif
494 %endif
492 %endif
495 %endif
493
496
494 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
497 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
495 <span class="pill" op="renamed">renamed</span>
498 <span class="pill" op="renamed">renamed</span>
496 %endif
499 %endif
497
500
498 %if COPIED_FILENODE in filediff.patch['stats']['ops']:
501 %if COPIED_FILENODE in filediff.patch['stats']['ops']:
499 <span class="pill" op="copied">copied</span>
502 <span class="pill" op="copied">copied</span>
500 %endif
503 %endif
501
504
502 %if DEL_FILENODE in filediff.patch['stats']['ops']:
505 %if DEL_FILENODE in filediff.patch['stats']['ops']:
503 <span class="pill" op="removed">removed</span>
506 <span class="pill" op="removed">removed</span>
504 %endif
507 %endif
505
508
506 %if CHMOD_FILENODE in filediff.patch['stats']['ops']:
509 %if CHMOD_FILENODE in filediff.patch['stats']['ops']:
507 <span class="pill" op="mode">
510 <span class="pill" op="mode">
508 ${nice_mode(filediff['source_mode'])} ➑ ${nice_mode(filediff['target_mode'])}
511 ${nice_mode(filediff['source_mode'])} ➑ ${nice_mode(filediff['target_mode'])}
509 </span>
512 </span>
510 %endif
513 %endif
511
514
512 %if BIN_FILENODE in filediff.patch['stats']['ops']:
515 %if BIN_FILENODE in filediff.patch['stats']['ops']:
513 <span class="pill" op="binary">binary</span>
516 <span class="pill" op="binary">binary</span>
514 %if MOD_FILENODE in filediff.patch['stats']['ops']:
517 %if MOD_FILENODE in filediff.patch['stats']['ops']:
515 <span class="pill" op="modified">modified</span>
518 <span class="pill" op="modified">modified</span>
516 %endif
519 %endif
517 %endif
520 %endif
518
521
519 <span class="pill" op="added">${('+' if filediff.patch['stats']['added'] else '')}${filediff.patch['stats']['added']}</span>
522 <span class="pill" op="added">${('+' if filediff.patch['stats']['added'] else '')}${filediff.patch['stats']['added']}</span>
520 <span class="pill" op="deleted">${((h.safe_int(filediff.patch['stats']['deleted']) or 0) * -1)}</span>
523 <span class="pill" op="deleted">${((h.safe_int(filediff.patch['stats']['deleted']) or 0) * -1)}</span>
521
524
522 </span>
525 </span>
523
526
524 </%def>
527 </%def>
525
528
526 <%def name="nice_mode(filemode)">
529 <%def name="nice_mode(filemode)">
527 ${(filemode.startswith('100') and filemode[3:] or filemode)}
530 ${(filemode.startswith('100') and filemode[3:] or filemode)}
528 </%def>
531 </%def>
529
532
530 <%def name="diff_menu(filediff, use_comments=False)">
533 <%def name="diff_menu(filediff, use_comments=False)">
531 <div class="filediff-menu">
534 <div class="filediff-menu">
532
535
533 %if filediff.diffset.source_ref:
536 %if filediff.diffset.source_ref:
534
537
535 ## FILE BEFORE CHANGES
538 ## FILE BEFORE CHANGES
536 %if filediff.operation in ['D', 'M']:
539 %if filediff.operation in ['D', 'M']:
537 <a
540 <a
538 class="tooltip"
541 class="tooltip"
539 href="${h.route_path('repo_files',repo_name=filediff.diffset.target_repo_name,commit_id=filediff.diffset.source_ref,f_path=filediff.source_file_path)}"
542 href="${h.route_path('repo_files',repo_name=filediff.diffset.target_repo_name,commit_id=filediff.diffset.source_ref,f_path=filediff.source_file_path)}"
540 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
543 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
541 >
544 >
542 ${_('Show file before')}
545 ${_('Show file before')}
543 </a> |
546 </a> |
544 %else:
547 %else:
545 <span
548 <span
546 class="tooltip"
549 class="tooltip"
547 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
550 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
548 >
551 >
549 ${_('Show file before')}
552 ${_('Show file before')}
550 </span> |
553 </span> |
551 %endif
554 %endif
552
555
553 ## FILE AFTER CHANGES
556 ## FILE AFTER CHANGES
554 %if filediff.operation in ['A', 'M']:
557 %if filediff.operation in ['A', 'M']:
555 <a
558 <a
556 class="tooltip"
559 class="tooltip"
557 href="${h.route_path('repo_files',repo_name=filediff.diffset.source_repo_name,commit_id=filediff.diffset.target_ref,f_path=filediff.target_file_path)}"
560 href="${h.route_path('repo_files',repo_name=filediff.diffset.source_repo_name,commit_id=filediff.diffset.target_ref,f_path=filediff.target_file_path)}"
558 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
561 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
559 >
562 >
560 ${_('Show file after')}
563 ${_('Show file after')}
561 </a>
564 </a>
562 %else:
565 %else:
563 <span
566 <span
564 class="tooltip"
567 class="tooltip"
565 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
568 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
566 >
569 >
567 ${_('Show file after')}
570 ${_('Show file after')}
568 </span>
571 </span>
569 %endif
572 %endif
570
573
571 % if use_comments:
574 % if use_comments:
572 |
575 |
573 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
576 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
574 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
577 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
575 </a>
578 </a>
576 % endif
579 % endif
577
580
578 %endif
581 %endif
579
582
580 </div>
583 </div>
581 </%def>
584 </%def>
582
585
583
586
584 <%def name="inline_comments_container(comments, inline_comments)">
587 <%def name="inline_comments_container(comments, inline_comments)">
585 <div class="inline-comments">
588 <div class="inline-comments">
586 %for comment in comments:
589 %for comment in comments:
587 ${commentblock.comment_block(comment, inline=True)}
590 ${commentblock.comment_block(comment, inline=True)}
588 %endfor
591 %endfor
589 % if comments and comments[-1].outdated:
592 % if comments and comments[-1].outdated:
590 <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}">
593 <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}">
591 ${_('Add another comment')}
594 ${_('Add another comment')}
592 </span>
595 </span>
593 % else:
596 % else:
594 <span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button">
597 <span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button">
595 ${_('Add another comment')}
598 ${_('Add another comment')}
596 </span>
599 </span>
597 % endif
600 % endif
598
601
599 </div>
602 </div>
600 </%def>
603 </%def>
601
604
602 <%!
605 <%!
603 def get_comments_for(diff_type, comments, filename, line_version, line_number):
606 def get_comments_for(diff_type, comments, filename, line_version, line_number):
604 if hasattr(filename, 'unicode_path'):
607 if hasattr(filename, 'unicode_path'):
605 filename = filename.unicode_path
608 filename = filename.unicode_path
606
609
607 if not isinstance(filename, (unicode, str)):
610 if not isinstance(filename, (unicode, str)):
608 return None
611 return None
609
612
610 line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12
613 line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12
611
614
612 if comments and filename in comments:
615 if comments and filename in comments:
613 file_comments = comments[filename]
616 file_comments = comments[filename]
614 if line_key in file_comments:
617 if line_key in file_comments:
615 data = file_comments.pop(line_key)
618 data = file_comments.pop(line_key)
616 return data
619 return data
617 %>
620 %>
618
621
619 <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None)">
622 <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None)">
620 %for i, line in enumerate(hunk.sideside):
623 %for i, line in enumerate(hunk.sideside):
621 <%
624 <%
622 old_line_anchor, new_line_anchor = None, None
625 old_line_anchor, new_line_anchor = None, None
623
626
624 if line.original.lineno:
627 if line.original.lineno:
625 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o')
628 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o')
626 if line.modified.lineno:
629 if line.modified.lineno:
627 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n')
630 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n')
628 %>
631 %>
629
632
630 <tr class="cb-line">
633 <tr class="cb-line">
631 <td class="cb-data ${action_class(line.original.action)}"
634 <td class="cb-data ${action_class(line.original.action)}"
632 data-line-no="${line.original.lineno}"
635 data-line-no="${line.original.lineno}"
633 >
636 >
634 <div>
637 <div>
635
638
636 <% line_old_comments = None %>
639 <% line_old_comments = None %>
637 %if line.original.get_comment_args:
640 %if line.original.get_comment_args:
638 <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %>
641 <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %>
639 %endif
642 %endif
640 %if line_old_comments:
643 %if line_old_comments:
641 <% has_outdated = any([x.outdated for x in line_old_comments]) %>
644 <% has_outdated = any([x.outdated for x in line_old_comments]) %>
642 % if has_outdated:
645 % if has_outdated:
643 <i title="${_('comments including outdated')}:${len(line_old_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
646 <i title="${_('comments including outdated')}:${len(line_old_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
644 % else:
647 % else:
645 <i title="${_('comments')}: ${len(line_old_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
648 <i title="${_('comments')}: ${len(line_old_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
646 % endif
649 % endif
647 %endif
650 %endif
648 </div>
651 </div>
649 </td>
652 </td>
650 <td class="cb-lineno ${action_class(line.original.action)}"
653 <td class="cb-lineno ${action_class(line.original.action)}"
651 data-line-no="${line.original.lineno}"
654 data-line-no="${line.original.lineno}"
652 %if old_line_anchor:
655 %if old_line_anchor:
653 id="${old_line_anchor}"
656 id="${old_line_anchor}"
654 %endif
657 %endif
655 >
658 >
656 %if line.original.lineno:
659 %if line.original.lineno:
657 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
660 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
658 %endif
661 %endif
659 </td>
662 </td>
660 <td class="cb-content ${action_class(line.original.action)}"
663 <td class="cb-content ${action_class(line.original.action)}"
661 data-line-no="o${line.original.lineno}"
664 data-line-no="o${line.original.lineno}"
662 >
665 >
663 %if use_comments and line.original.lineno:
666 %if use_comments and line.original.lineno:
664 ${render_add_comment_button()}
667 ${render_add_comment_button()}
665 %endif
668 %endif
666 <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span>
669 <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span>
667
670
668 %if use_comments and line.original.lineno and line_old_comments:
671 %if use_comments and line.original.lineno and line_old_comments:
669 ${inline_comments_container(line_old_comments, inline_comments)}
672 ${inline_comments_container(line_old_comments, inline_comments)}
670 %endif
673 %endif
671
674
672 </td>
675 </td>
673 <td class="cb-data ${action_class(line.modified.action)}"
676 <td class="cb-data ${action_class(line.modified.action)}"
674 data-line-no="${line.modified.lineno}"
677 data-line-no="${line.modified.lineno}"
675 >
678 >
676 <div>
679 <div>
677
680
678 %if line.modified.get_comment_args:
681 %if line.modified.get_comment_args:
679 <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %>
682 <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %>
680 %else:
683 %else:
681 <% line_new_comments = None%>
684 <% line_new_comments = None%>
682 %endif
685 %endif
683 %if line_new_comments:
686 %if line_new_comments:
684 <% has_outdated = any([x.outdated for x in line_new_comments]) %>
687 <% has_outdated = any([x.outdated for x in line_new_comments]) %>
685 % if has_outdated:
688 % if has_outdated:
686 <i title="${_('comments including outdated')}:${len(line_new_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
689 <i title="${_('comments including outdated')}:${len(line_new_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
687 % else:
690 % else:
688 <i title="${_('comments')}: ${len(line_new_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
691 <i title="${_('comments')}: ${len(line_new_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
689 % endif
692 % endif
690 %endif
693 %endif
691 </div>
694 </div>
692 </td>
695 </td>
693 <td class="cb-lineno ${action_class(line.modified.action)}"
696 <td class="cb-lineno ${action_class(line.modified.action)}"
694 data-line-no="${line.modified.lineno}"
697 data-line-no="${line.modified.lineno}"
695 %if new_line_anchor:
698 %if new_line_anchor:
696 id="${new_line_anchor}"
699 id="${new_line_anchor}"
697 %endif
700 %endif
698 >
701 >
699 %if line.modified.lineno:
702 %if line.modified.lineno:
700 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
703 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
701 %endif
704 %endif
702 </td>
705 </td>
703 <td class="cb-content ${action_class(line.modified.action)}"
706 <td class="cb-content ${action_class(line.modified.action)}"
704 data-line-no="n${line.modified.lineno}"
707 data-line-no="n${line.modified.lineno}"
705 >
708 >
706 %if use_comments and line.modified.lineno:
709 %if use_comments and line.modified.lineno:
707 ${render_add_comment_button()}
710 ${render_add_comment_button()}
708 %endif
711 %endif
709 <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span>
712 <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span>
710 %if use_comments and line.modified.lineno and line_new_comments:
713 %if use_comments and line.modified.lineno and line_new_comments:
711 ${inline_comments_container(line_new_comments, inline_comments)}
714 ${inline_comments_container(line_new_comments, inline_comments)}
712 %endif
715 %endif
713 </td>
716 </td>
714 </tr>
717 </tr>
715 %endfor
718 %endfor
716 </%def>
719 </%def>
717
720
718
721
719 <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None)">
722 <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None)">
720 %for old_line_no, new_line_no, action, content, comments_args in hunk.unified:
723 %for old_line_no, new_line_no, action, content, comments_args in hunk.unified:
721
724
722 <%
725 <%
723 old_line_anchor, new_line_anchor = None, None
726 old_line_anchor, new_line_anchor = None, None
724 if old_line_no:
727 if old_line_no:
725 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, old_line_no, 'o')
728 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, old_line_no, 'o')
726 if new_line_no:
729 if new_line_no:
727 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, new_line_no, 'n')
730 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, new_line_no, 'n')
728 %>
731 %>
729 <tr class="cb-line">
732 <tr class="cb-line">
730 <td class="cb-data ${action_class(action)}">
733 <td class="cb-data ${action_class(action)}">
731 <div>
734 <div>
732
735
733 %if comments_args:
736 %if comments_args:
734 <% comments = get_comments_for('unified', inline_comments, *comments_args) %>
737 <% comments = get_comments_for('unified', inline_comments, *comments_args) %>
735 %else:
738 %else:
736 <% comments = None %>
739 <% comments = None %>
737 %endif
740 %endif
738
741
739 % if comments:
742 % if comments:
740 <% has_outdated = any([x.outdated for x in comments]) %>
743 <% has_outdated = any([x.outdated for x in comments]) %>
741 % if has_outdated:
744 % if has_outdated:
742 <i title="${_('comments including outdated')}:${len(comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
745 <i title="${_('comments including outdated')}:${len(comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
743 % else:
746 % else:
744 <i title="${_('comments')}: ${len(comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
747 <i title="${_('comments')}: ${len(comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
745 % endif
748 % endif
746 % endif
749 % endif
747 </div>
750 </div>
748 </td>
751 </td>
749 <td class="cb-lineno ${action_class(action)}"
752 <td class="cb-lineno ${action_class(action)}"
750 data-line-no="${old_line_no}"
753 data-line-no="${old_line_no}"
751 %if old_line_anchor:
754 %if old_line_anchor:
752 id="${old_line_anchor}"
755 id="${old_line_anchor}"
753 %endif
756 %endif
754 >
757 >
755 %if old_line_anchor:
758 %if old_line_anchor:
756 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
759 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
757 %endif
760 %endif
758 </td>
761 </td>
759 <td class="cb-lineno ${action_class(action)}"
762 <td class="cb-lineno ${action_class(action)}"
760 data-line-no="${new_line_no}"
763 data-line-no="${new_line_no}"
761 %if new_line_anchor:
764 %if new_line_anchor:
762 id="${new_line_anchor}"
765 id="${new_line_anchor}"
763 %endif
766 %endif
764 >
767 >
765 %if new_line_anchor:
768 %if new_line_anchor:
766 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
769 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
767 %endif
770 %endif
768 </td>
771 </td>
769 <td class="cb-content ${action_class(action)}"
772 <td class="cb-content ${action_class(action)}"
770 data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}"
773 data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}"
771 >
774 >
772 %if use_comments:
775 %if use_comments:
773 ${render_add_comment_button()}
776 ${render_add_comment_button()}
774 %endif
777 %endif
775 <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span>
778 <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span>
776 %if use_comments and comments:
779 %if use_comments and comments:
777 ${inline_comments_container(comments, inline_comments)}
780 ${inline_comments_container(comments, inline_comments)}
778 %endif
781 %endif
779 </td>
782 </td>
780 </tr>
783 </tr>
781 %endfor
784 %endfor
782 </%def>
785 </%def>
783
786
784
787
785 <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments)">
788 <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments)">
786 % if diff_mode == 'unified':
789 % if diff_mode == 'unified':
787 ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)}
790 ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)}
788 % elif diff_mode == 'sideside':
791 % elif diff_mode == 'sideside':
789 ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)}
792 ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)}
790 % else:
793 % else:
791 <tr class="cb-line">
794 <tr class="cb-line">
792 <td>unknown diff mode</td>
795 <td>unknown diff mode</td>
793 </tr>
796 </tr>
794 % endif
797 % endif
795 </%def>file changes
798 </%def>file changes
796
799
797
800
798 <%def name="render_add_comment_button()">
801 <%def name="render_add_comment_button()">
799 <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)">
802 <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)">
800 <span><i class="icon-comment"></i></span>
803 <span><i class="icon-comment"></i></span>
801 </button>
804 </button>
802 </%def>
805 </%def>
803
806
804 <%def name="render_diffset_menu(diffset, range_diff_on=None)">
807 <%def name="render_diffset_menu(diffset, range_diff_on=None)">
805 <% diffset_container_id = h.md5(diffset.target_ref) %>
808 <% diffset_container_id = h.md5(diffset.target_ref) %>
806
809
807 <div id="diff-file-sticky" class="diffset-menu clearinner">
810 <div id="diff-file-sticky" class="diffset-menu clearinner">
808 ## auto adjustable
811 ## auto adjustable
809 <div class="sidebar__inner">
812 <div class="sidebar__inner">
810 <div class="sidebar__bar">
813 <div class="sidebar__bar">
811 <div class="pull-right">
814 <div class="pull-right">
812 <div class="btn-group">
815 <div class="btn-group">
813 <a class="btn tooltip toggle-wide-diff" href="#toggle-wide-diff" onclick="toggleWideDiff(this); return false" title="${h.tooltip(_('Toggle wide diff'))}">
816 <a class="btn tooltip toggle-wide-diff" href="#toggle-wide-diff" onclick="toggleWideDiff(this); return false" title="${h.tooltip(_('Toggle wide diff'))}">
814 <i class="icon-wide-mode"></i>
817 <i class="icon-wide-mode"></i>
815 </a>
818 </a>
816 </div>
819 </div>
817 <div class="btn-group">
820 <div class="btn-group">
818
821
819 <a
822 <a
820 class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-active')} tooltip"
823 class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-active')} tooltip"
821 title="${h.tooltip(_('View diff as side by side'))}"
824 title="${h.tooltip(_('View diff as side by side'))}"
822 href="${h.current_route_path(request, diffmode='sideside')}">
825 href="${h.current_route_path(request, diffmode='sideside')}">
823 <span>${_('Side by Side')}</span>
826 <span>${_('Side by Side')}</span>
824 </a>
827 </a>
825
828
826 <a
829 <a
827 class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-active')} tooltip"
830 class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-active')} tooltip"
828 title="${h.tooltip(_('View diff as unified'))}" href="${h.current_route_path(request, diffmode='unified')}">
831 title="${h.tooltip(_('View diff as unified'))}" href="${h.current_route_path(request, diffmode='unified')}">
829 <span>${_('Unified')}</span>
832 <span>${_('Unified')}</span>
830 </a>
833 </a>
831
834
832 % if range_diff_on is True:
835 % if range_diff_on is True:
833 <a
836 <a
834 title="${_('Turn off: Show the diff as commit range')}"
837 title="${_('Turn off: Show the diff as commit range')}"
835 class="btn btn-primary"
838 class="btn btn-primary"
836 href="${h.current_route_path(request, **{"range-diff":"0"})}">
839 href="${h.current_route_path(request, **{"range-diff":"0"})}">
837 <span>${_('Range Diff')}</span>
840 <span>${_('Range Diff')}</span>
838 </a>
841 </a>
839 % elif range_diff_on is False:
842 % elif range_diff_on is False:
840 <a
843 <a
841 title="${_('Show the diff as commit range')}"
844 title="${_('Show the diff as commit range')}"
842 class="btn"
845 class="btn"
843 href="${h.current_route_path(request, **{"range-diff":"1"})}">
846 href="${h.current_route_path(request, **{"range-diff":"1"})}">
844 <span>${_('Range Diff')}</span>
847 <span>${_('Range Diff')}</span>
845 </a>
848 </a>
846 % endif
849 % endif
847 </div>
850 </div>
848 <div class="btn-group">
851 <div class="btn-group">
849
852
850 <div class="pull-left">
853 <div class="pull-left">
851 ${h.hidden('diff_menu_{}'.format(diffset_container_id))}
854 ${h.hidden('diff_menu_{}'.format(diffset_container_id))}
852 </div>
855 </div>
853
856
854 </div>
857 </div>
855 </div>
858 </div>
856 <div class="pull-left">
859 <div class="pull-left">
857 <div class="btn-group">
860 <div class="btn-group">
858 <div class="pull-left">
861 <div class="pull-left">
859 ${h.hidden('file_filter_{}'.format(diffset_container_id))}
862 ${h.hidden('file_filter_{}'.format(diffset_container_id))}
860 </div>
863 </div>
861
864
862 </div>
865 </div>
863 </div>
866 </div>
864 </div>
867 </div>
865 <div class="fpath-placeholder">
868 <div class="fpath-placeholder">
866 <i class="icon-file-text"></i>
869 <i class="icon-file-text"></i>
867 <strong class="fpath-placeholder-text">
870 <strong class="fpath-placeholder-text">
868 Context file:
871 Context file:
869 </strong>
872 </strong>
870 </div>
873 </div>
871 <div class="sidebar_inner_shadow"></div>
874 <div class="sidebar_inner_shadow"></div>
872 </div>
875 </div>
873 </div>
876 </div>
874
877
875 % if diffset:
878 % if diffset:
876 %if diffset.limited_diff:
879 %if diffset.limited_diff:
877 <% file_placeholder = _ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files} %>
880 <% file_placeholder = _ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files} %>
878 %else:
881 %else:
879 <% file_placeholder = h.literal(_ungettext('%(num)s file changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', '%(num)s files changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>',
882 <% file_placeholder = h.literal(_ungettext('%(num)s file changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', '%(num)s files changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>',
880 diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}) %>
883 diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}) %>
881
884
882 %endif
885 %endif
883 ## case on range-diff placeholder needs to be updated
886 ## case on range-diff placeholder needs to be updated
884 % if range_diff_on is True:
887 % if range_diff_on is True:
885 <% file_placeholder = _('Disabled on range diff') %>
888 <% file_placeholder = _('Disabled on range diff') %>
886 % endif
889 % endif
887
890
888 <script type="text/javascript">
891 <script type="text/javascript">
889 var feedFilesOptions = function (query, initialData) {
892 var feedFilesOptions = function (query, initialData) {
890 var data = {results: []};
893 var data = {results: []};
891 var isQuery = typeof query.term !== 'undefined';
894 var isQuery = typeof query.term !== 'undefined';
892
895
893 var section = _gettext('Changed files');
896 var section = _gettext('Changed files');
894 var filteredData = [];
897 var filteredData = [];
895
898
896 //filter results
899 //filter results
897 $.each(initialData.results, function (idx, value) {
900 $.each(initialData.results, function (idx, value) {
898
901
899 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
902 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
900 filteredData.push({
903 filteredData.push({
901 'id': this.id,
904 'id': this.id,
902 'text': this.text,
905 'text': this.text,
903 "ops": this.ops,
906 "ops": this.ops,
904 })
907 })
905 }
908 }
906
909
907 });
910 });
908
911
909 data.results = filteredData;
912 data.results = filteredData;
910
913
911 query.callback(data);
914 query.callback(data);
912 };
915 };
913
916
914 var selectionFormatter = function(data, escapeMarkup) {
917 var selectionFormatter = function(data, escapeMarkup) {
915 var container = '<div class="filelist" style="padding-right:100px">{0}</div>';
918 var container = '<div class="filelist" style="padding-right:100px">{0}</div>';
916 var tmpl = '<div><strong>{0}</strong></div>'.format(escapeMarkup(data['text']));
919 var tmpl = '<div><strong>{0}</strong></div>'.format(escapeMarkup(data['text']));
917 var pill = '<div class="pill-group" style="position: absolute; top:7px; right: 0">' +
920 var pill = '<div class="pill-group" style="position: absolute; top:7px; right: 0">' +
918 '<span class="pill" op="added">{0}</span>' +
921 '<span class="pill" op="added">{0}</span>' +
919 '<span class="pill" op="deleted">{1}</span>' +
922 '<span class="pill" op="deleted">{1}</span>' +
920 '</div>'
923 '</div>'
921 ;
924 ;
922 var added = data['ops']['added'];
925 var added = data['ops']['added'];
923 if (added === 0) {
926 if (added === 0) {
924 // don't show +0
927 // don't show +0
925 added = 0;
928 added = 0;
926 } else {
929 } else {
927 added = '+' + added;
930 added = '+' + added;
928 }
931 }
929
932
930 var deleted = -1*data['ops']['deleted'];
933 var deleted = -1*data['ops']['deleted'];
931
934
932 tmpl += pill.format(added, deleted);
935 tmpl += pill.format(added, deleted);
933 return container.format(tmpl);
936 return container.format(tmpl);
934 };
937 };
935 var formatFileResult = function(result, container, query, escapeMarkup) {
938 var formatFileResult = function(result, container, query, escapeMarkup) {
936 return selectionFormatter(result, escapeMarkup);
939 return selectionFormatter(result, escapeMarkup);
937 };
940 };
938
941
939 var formatSelection = function (data, container) {
942 var formatSelection = function (data, container) {
940 return '${file_placeholder}'
943 return '${file_placeholder}'
941 };
944 };
942
945
943 if (window.preloadFileFilterData === undefined) {
946 if (window.preloadFileFilterData === undefined) {
944 window.preloadFileFilterData = {}
947 window.preloadFileFilterData = {}
945 }
948 }
946
949
947 preloadFileFilterData["${diffset_container_id}"] = {
950 preloadFileFilterData["${diffset_container_id}"] = {
948 results: [
951 results: [
949 % for filediff in diffset.files:
952 % for filediff in diffset.files:
950 {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}",
953 {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}",
951 text:"${filediff.patch['filename']}",
954 text:"${filediff.patch['filename']}",
952 ops:${h.json.dumps(filediff.patch['stats'])|n}}${('' if loop.last else ',')}
955 ops:${h.json.dumps(filediff.patch['stats'])|n}}${('' if loop.last else ',')}
953 % endfor
956 % endfor
954 ]
957 ]
955 };
958 };
956
959
957 var diffFileFilterId = "#file_filter_" + "${diffset_container_id}";
960 var diffFileFilterId = "#file_filter_" + "${diffset_container_id}";
958 var diffFileFilter = $(diffFileFilterId).select2({
961 var diffFileFilter = $(diffFileFilterId).select2({
959 'dropdownAutoWidth': true,
962 'dropdownAutoWidth': true,
960 'width': 'auto',
963 'width': 'auto',
961
964
962 containerCssClass: "drop-menu",
965 containerCssClass: "drop-menu",
963 dropdownCssClass: "drop-menu-dropdown",
966 dropdownCssClass: "drop-menu-dropdown",
964 data: preloadFileFilterData["${diffset_container_id}"],
967 data: preloadFileFilterData["${diffset_container_id}"],
965 query: function(query) {
968 query: function(query) {
966 feedFilesOptions(query, preloadFileFilterData["${diffset_container_id}"]);
969 feedFilesOptions(query, preloadFileFilterData["${diffset_container_id}"]);
967 },
970 },
968 initSelection: function(element, callback) {
971 initSelection: function(element, callback) {
969 callback({'init': true});
972 callback({'init': true});
970 },
973 },
971 formatResult: formatFileResult,
974 formatResult: formatFileResult,
972 formatSelection: formatSelection
975 formatSelection: formatSelection
973 });
976 });
974
977
975 % if range_diff_on is True:
978 % if range_diff_on is True:
976 diffFileFilter.select2("enable", false);
979 diffFileFilter.select2("enable", false);
977 % endif
980 % endif
978
981
979 $(diffFileFilterId).on('select2-selecting', function (e) {
982 $(diffFileFilterId).on('select2-selecting', function (e) {
980 var idSelector = e.choice.id;
983 var idSelector = e.choice.id;
981
984
982 // expand the container if we quick-select the field
985 // expand the container if we quick-select the field
983 $('#'+idSelector).next().prop('checked', false);
986 $('#'+idSelector).next().prop('checked', false);
984 // hide the mast as we later do preventDefault()
987 // hide the mast as we later do preventDefault()
985 $("#select2-drop-mask").click();
988 $("#select2-drop-mask").click();
986
989
987 window.location.hash = '#'+idSelector;
990 window.location.hash = '#'+idSelector;
988 updateSticky();
991 updateSticky();
989
992
990 e.preventDefault();
993 e.preventDefault();
991 });
994 });
992
995
993 </script>
996 </script>
994 % endif
997 % endif
995
998
996 <script type="text/javascript">
999 <script type="text/javascript">
997 $(document).ready(function () {
1000 $(document).ready(function () {
998
1001
999 var contextPrefix = _gettext('Context file: ');
1002 var contextPrefix = _gettext('Context file: ');
1000 ## sticky sidebar
1003 ## sticky sidebar
1001 var sidebarElement = document.getElementById('diff-file-sticky');
1004 var sidebarElement = document.getElementById('diff-file-sticky');
1002 sidebar = new StickySidebar(sidebarElement, {
1005 sidebar = new StickySidebar(sidebarElement, {
1003 topSpacing: 0,
1006 topSpacing: 0,
1004 bottomSpacing: 0,
1007 bottomSpacing: 0,
1005 innerWrapperSelector: '.sidebar__inner'
1008 innerWrapperSelector: '.sidebar__inner'
1006 });
1009 });
1007 sidebarElement.addEventListener('affixed.static.stickySidebar', function () {
1010 sidebarElement.addEventListener('affixed.static.stickySidebar', function () {
1008 // reset our file so it's not holding new value
1011 // reset our file so it's not holding new value
1009 $('.fpath-placeholder-text').html(contextPrefix + ' - ')
1012 $('.fpath-placeholder-text').html(contextPrefix + ' - ')
1010 });
1013 });
1011
1014
1012 updateSticky = function () {
1015 updateSticky = function () {
1013 sidebar.updateSticky();
1016 sidebar.updateSticky();
1014 Waypoint.refreshAll();
1017 Waypoint.refreshAll();
1015 };
1018 };
1016
1019
1017 var animateText = function (fPath, anchorId) {
1020 var animateText = function (fPath, anchorId) {
1018 fPath = Select2.util.escapeMarkup(fPath);
1021 fPath = Select2.util.escapeMarkup(fPath);
1019 $('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>')
1022 $('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>')
1020 };
1023 };
1021
1024
1022 ## dynamic file waypoints
1025 ## dynamic file waypoints
1023 var setFPathInfo = function(fPath, anchorId){
1026 var setFPathInfo = function(fPath, anchorId){
1024 animateText(fPath, anchorId)
1027 animateText(fPath, anchorId)
1025 };
1028 };
1026
1029
1027 var codeBlock = $('.filediff');
1030 var codeBlock = $('.filediff');
1028
1031
1029 // forward waypoint
1032 // forward waypoint
1030 codeBlock.waypoint(
1033 codeBlock.waypoint(
1031 function(direction) {
1034 function(direction) {
1032 if (direction === "down"){
1035 if (direction === "down"){
1033 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1036 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1034 }
1037 }
1035 }, {
1038 }, {
1036 offset: function () {
1039 offset: function () {
1037 return 70;
1040 return 70;
1038 },
1041 },
1039 context: '.fpath-placeholder'
1042 context: '.fpath-placeholder'
1040 }
1043 }
1041 );
1044 );
1042
1045
1043 // backward waypoint
1046 // backward waypoint
1044 codeBlock.waypoint(
1047 codeBlock.waypoint(
1045 function(direction) {
1048 function(direction) {
1046 if (direction === "up"){
1049 if (direction === "up"){
1047 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1050 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1048 }
1051 }
1049 }, {
1052 }, {
1050 offset: function () {
1053 offset: function () {
1051 return -this.element.clientHeight + 90;
1054 return -this.element.clientHeight + 90;
1052 },
1055 },
1053 context: '.fpath-placeholder'
1056 context: '.fpath-placeholder'
1054 }
1057 }
1055 );
1058 );
1056
1059
1057 toggleWideDiff = function (el) {
1060 toggleWideDiff = function (el) {
1058 updateSticky();
1061 updateSticky();
1059 var wide = Rhodecode.comments.toggleWideMode(this);
1062 var wide = Rhodecode.comments.toggleWideMode(this);
1060 storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide);
1063 storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide);
1061 if (wide === true) {
1064 if (wide === true) {
1062 $(el).addClass('btn-active');
1065 $(el).addClass('btn-active');
1063 } else {
1066 } else {
1064 $(el).removeClass('btn-active');
1067 $(el).removeClass('btn-active');
1065 }
1068 }
1066 return null;
1069 return null;
1067 };
1070 };
1068
1071
1069 var preloadDiffMenuData = {
1072 var preloadDiffMenuData = {
1070 results: [
1073 results: [
1071
1074
1072 ## Whitespace change
1075 ## Whitespace change
1073 % if request.GET.get('ignorews', '') == '1':
1076 % if request.GET.get('ignorews', '') == '1':
1074 {
1077 {
1075 id: 2,
1078 id: 2,
1076 text: _gettext('Show whitespace changes'),
1079 text: _gettext('Show whitespace changes'),
1077 action: function () {},
1080 action: function () {},
1078 url: "${h.current_route_path(request, ignorews=0)|n}"
1081 url: "${h.current_route_path(request, ignorews=0)|n}"
1079 },
1082 },
1080 % else:
1083 % else:
1081 {
1084 {
1082 id: 2,
1085 id: 2,
1083 text: _gettext('Hide whitespace changes'),
1086 text: _gettext('Hide whitespace changes'),
1084 action: function () {},
1087 action: function () {},
1085 url: "${h.current_route_path(request, ignorews=1)|n}"
1088 url: "${h.current_route_path(request, ignorews=1)|n}"
1086 },
1089 },
1087 % endif
1090 % endif
1088
1091
1089 ## FULL CONTEXT
1092 ## FULL CONTEXT
1090 % if request.GET.get('fullcontext', '') == '1':
1093 % if request.GET.get('fullcontext', '') == '1':
1091 {
1094 {
1092 id: 3,
1095 id: 3,
1093 text: _gettext('Hide full context diff'),
1096 text: _gettext('Hide full context diff'),
1094 action: function () {},
1097 action: function () {},
1095 url: "${h.current_route_path(request, fullcontext=0)|n}"
1098 url: "${h.current_route_path(request, fullcontext=0)|n}"
1096 },
1099 },
1097 % else:
1100 % else:
1098 {
1101 {
1099 id: 3,
1102 id: 3,
1100 text: _gettext('Show full context diff'),
1103 text: _gettext('Show full context diff'),
1101 action: function () {},
1104 action: function () {},
1102 url: "${h.current_route_path(request, fullcontext=1)|n}"
1105 url: "${h.current_route_path(request, fullcontext=1)|n}"
1103 },
1106 },
1104 % endif
1107 % endif
1105
1108
1106 ]
1109 ]
1107 };
1110 };
1108
1111
1109 var diffMenuId = "#diff_menu_" + "${diffset_container_id}";
1112 var diffMenuId = "#diff_menu_" + "${diffset_container_id}";
1110 $(diffMenuId).select2({
1113 $(diffMenuId).select2({
1111 minimumResultsForSearch: -1,
1114 minimumResultsForSearch: -1,
1112 containerCssClass: "drop-menu-no-width",
1115 containerCssClass: "drop-menu-no-width",
1113 dropdownCssClass: "drop-menu-dropdown",
1116 dropdownCssClass: "drop-menu-dropdown",
1114 dropdownAutoWidth: true,
1117 dropdownAutoWidth: true,
1115 data: preloadDiffMenuData,
1118 data: preloadDiffMenuData,
1116 placeholder: "${_('...')}",
1119 placeholder: "${_('...')}",
1117 });
1120 });
1118 $(diffMenuId).on('select2-selecting', function (e) {
1121 $(diffMenuId).on('select2-selecting', function (e) {
1119 e.choice.action();
1122 e.choice.action();
1120 if (e.choice.url !== null) {
1123 if (e.choice.url !== null) {
1121 window.location = e.choice.url
1124 window.location = e.choice.url
1122 }
1125 }
1123 });
1126 });
1124 toggleExpand = function (el, diffsetEl) {
1127 toggleExpand = function (el, diffsetEl) {
1125 var el = $(el);
1128 var el = $(el);
1126 if (el.hasClass('collapsed')) {
1129 if (el.hasClass('collapsed')) {
1127 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', false);
1130 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', false);
1128 el.removeClass('collapsed');
1131 el.removeClass('collapsed');
1129 el.html(
1132 el.html(
1130 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1133 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1131 _gettext('Collapse all files'));
1134 _gettext('Collapse all files'));
1132 }
1135 }
1133 else {
1136 else {
1134 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', true);
1137 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', true);
1135 el.addClass('collapsed');
1138 el.addClass('collapsed');
1136 el.html(
1139 el.html(
1137 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1140 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1138 _gettext('Expand all files'));
1141 _gettext('Expand all files'));
1139 }
1142 }
1140 updateSticky()
1143 updateSticky()
1141 };
1144 };
1142
1145
1143 toggleCommitExpand = function (el) {
1146 toggleCommitExpand = function (el) {
1144 var $el = $(el);
1147 var $el = $(el);
1145 var commits = $el.data('toggleCommitsCnt');
1148 var commits = $el.data('toggleCommitsCnt');
1146 var collapseMsg = _ngettext('Collapse {0} commit', 'Collapse {0} commits', commits).format(commits);
1149 var collapseMsg = _ngettext('Collapse {0} commit', 'Collapse {0} commits', commits).format(commits);
1147 var expandMsg = _ngettext('Expand {0} commit', 'Expand {0} commits', commits).format(commits);
1150 var expandMsg = _ngettext('Expand {0} commit', 'Expand {0} commits', commits).format(commits);
1148
1151
1149 if ($el.hasClass('collapsed')) {
1152 if ($el.hasClass('collapsed')) {
1150 $('.compare_select').show();
1153 $('.compare_select').show();
1151 $('.compare_select_hidden').hide();
1154 $('.compare_select_hidden').hide();
1152
1155
1153 $el.removeClass('collapsed');
1156 $el.removeClass('collapsed');
1154 $el.html(
1157 $el.html(
1155 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1158 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1156 collapseMsg);
1159 collapseMsg);
1157 }
1160 }
1158 else {
1161 else {
1159 $('.compare_select').hide();
1162 $('.compare_select').hide();
1160 $('.compare_select_hidden').show();
1163 $('.compare_select_hidden').show();
1161 $el.addClass('collapsed');
1164 $el.addClass('collapsed');
1162 $el.html(
1165 $el.html(
1163 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1166 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1164 expandMsg);
1167 expandMsg);
1165 }
1168 }
1166 updateSticky();
1169 updateSticky();
1167 };
1170 };
1168
1171
1169 // get stored diff mode and pre-enable it
1172 // get stored diff mode and pre-enable it
1170 if (templateContext.session_attrs.wide_diff_mode === "true") {
1173 if (templateContext.session_attrs.wide_diff_mode === "true") {
1171 Rhodecode.comments.toggleWideMode(null);
1174 Rhodecode.comments.toggleWideMode(null);
1172 $('.toggle-wide-diff').addClass('btn-active');
1175 $('.toggle-wide-diff').addClass('btn-active');
1173 updateSticky();
1176 updateSticky();
1174 }
1177 }
1175 });
1178 });
1176 </script>
1179 </script>
1177
1180
1178 </%def>
1181 </%def>
@@ -1,842 +1,907 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
3 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
3 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${_('{} Pull Request !{}').format(c.repo_name, c.pull_request.pull_request_id)}
6 ${_('{} Pull Request !{}').format(c.repo_name, c.pull_request.pull_request_id)}
7 %if c.rhodecode_name:
7 %if c.rhodecode_name:
8 &middot; ${h.branding(c.rhodecode_name)}
8 &middot; ${h.branding(c.rhodecode_name)}
9 %endif
9 %endif
10 </%def>
10 </%def>
11
11
12 <%def name="breadcrumbs_links()">
12 <%def name="breadcrumbs_links()">
13
13
14 <div id="pr-title">
14 <div id="pr-title">
15 % if c.pull_request.is_closed():
15 % if c.pull_request.is_closed():
16 <span class="pr-title-closed-tag tag">${_('Closed')}</span>
16 <span class="pr-title-closed-tag tag">${_('Closed')}</span>
17 % endif
17 % endif
18 <input class="pr-title-input large disabled" disabled="disabled" name="pullrequest_title" type="text" value="${c.pull_request.title}">
18 <input class="pr-title-input large disabled" disabled="disabled" name="pullrequest_title" type="text" value="${c.pull_request.title}">
19 </div>
19 </div>
20 <div id="pr-title-edit" class="input" style="display: none;">
20 <div id="pr-title-edit" class="input" style="display: none;">
21 <input class="pr-title-input large" id="pr-title-input" name="pullrequest_title" type="text" value="${c.pull_request.title}">
21 <input class="pr-title-input large" id="pr-title-input" name="pullrequest_title" type="text" value="${c.pull_request.title}">
22 </div>
22 </div>
23 </%def>
23 </%def>
24
24
25 <%def name="menu_bar_nav()">
25 <%def name="menu_bar_nav()">
26 ${self.menu_items(active='repositories')}
26 ${self.menu_items(active='repositories')}
27 </%def>
27 </%def>
28
28
29 <%def name="menu_bar_subnav()">
29 <%def name="menu_bar_subnav()">
30 ${self.repo_menu(active='showpullrequest')}
30 ${self.repo_menu(active='showpullrequest')}
31 </%def>
31 </%def>
32
32
33 <%def name="main()">
33 <%def name="main()">
34
34
35 <script type="text/javascript">
35 <script type="text/javascript">
36 // TODO: marcink switch this to pyroutes
36 // TODO: marcink switch this to pyroutes
37 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
37 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
38 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
38 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
39 </script>
39 </script>
40
40
41 <div class="box">
41 <div class="box">
42
42
43 ${self.breadcrumbs()}
43 ${self.breadcrumbs()}
44
44
45 <div class="box pr-summary">
45 <div class="box pr-summary">
46
46
47 <div class="summary-details block-left">
47 <div class="summary-details block-left">
48 <% summary = lambda n:{False:'summary-short'}.get(n) %>
48 <% summary = lambda n:{False:'summary-short'}.get(n) %>
49 <div class="pr-details-title">
49 <div class="pr-details-title">
50 <div class="pull-left">
50 <div class="pull-left">
51 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request !{}').format(c.pull_request.pull_request_id)}</a>
51 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request !{}').format(c.pull_request.pull_request_id)}</a>
52 ${_('Created on')}
52 ${_('Created on')}
53 <span class="tooltip" title="${_('Last updated on')} ${h.format_date(c.pull_request.updated_on)}">${h.format_date(c.pull_request.created_on)},</span>
53 <span class="tooltip" title="${_('Last updated on')} ${h.format_date(c.pull_request.updated_on)}">${h.format_date(c.pull_request.created_on)},</span>
54 <span class="pr-details-title-author-pref">${_('by')}</span>
54 <span class="pr-details-title-author-pref">${_('by')}</span>
55 </div>
55 </div>
56
56
57 <div class="pull-left">
57 <div class="pull-left">
58 ${self.gravatar_with_user(c.pull_request.author.email, 16, tooltip=True)}
58 ${self.gravatar_with_user(c.pull_request.author.email, 16, tooltip=True)}
59 </div>
59 </div>
60
60
61 %if c.allowed_to_update:
61 %if c.allowed_to_update:
62 <div id="delete_pullrequest" class="pull-right action_button ${('' if c.allowed_to_delete else 'disabled' )}" >
62 <div class="pull-right">
63 % if c.allowed_to_delete:
63 <div id="edit_pull_request" class="action_button pr-save" style="display: none;">${_('Update title & description')}</div>
64 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
64 <div id="delete_pullrequest" class="action_button pr-save ${('' if c.allowed_to_delete else 'disabled' )}" style="display: none;">
65 ${h.submit('remove_%s' % c.pull_request.pull_request_id, _('Delete'),
65 % if c.allowed_to_delete:
66 class_="btn btn-link btn-danger no-margin",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
66 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
67 ${h.end_form()}
67 ${h.submit('remove_%s' % c.pull_request.pull_request_id, _('Delete pull request'),
68 % else:
68 class_="btn btn-link btn-danger no-margin",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
69 ${_('Delete')}
69 ${h.end_form()}
70 % endif
70 % else:
71 <span class="tooltip" title="${_('Not allowed to delete this pull request')}">${_('Delete pull request')}</span>
72 % endif
73 </div>
74 <div id="open_edit_pullrequest" class="action_button">${_('Edit')}</div>
75 <div id="close_edit_pullrequest" class="action_button" style="display: none;">${_('Cancel')}</div>
71 </div>
76 </div>
72 <div id="open_edit_pullrequest" class="pull-right action_button">${_('Edit')}</div>
77
73 <div id="close_edit_pullrequest" class="pull-right action_button" style="display: none;">${_('Cancel')}</div>
74 <div id="edit_pull_request" class="pull-right action_button pr-save" style="display: none;">${_('Save Changes')}</div>
75 %endif
78 %endif
76 </div>
79 </div>
77
80
78 <div id="pr-desc" class="input" title="${_('Rendered using {} renderer').format(c.renderer)}">
81 <div id="pr-desc" class="input" title="${_('Rendered using {} renderer').format(c.renderer)}">
79 ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name)}
82 ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name)}
80 </div>
83 </div>
81
84
82 <div id="pr-desc-edit" class="input textarea" style="display: none;">
85 <div id="pr-desc-edit" class="input textarea" style="display: none;">
83 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
86 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
84 ${dt.markup_form('pr-description-input', form_text=c.pull_request.description)}
87 ${dt.markup_form('pr-description-input', form_text=c.pull_request.description)}
85 </div>
88 </div>
86
89
87 <div id="summary" class="fields pr-details-content">
90 <div id="summary" class="fields pr-details-content">
88
91
89 ## review
92 ## review
90 <div class="field">
93 <div class="field">
91 <div class="label-pr-detail">
94 <div class="label-pr-detail">
92 <label>${_('Review status')}:</label>
95 <label>${_('Review status')}:</label>
93 </div>
96 </div>
94 <div class="input">
97 <div class="input">
95 %if c.pull_request_review_status:
98 %if c.pull_request_review_status:
96 <div class="tag status-tag-${c.pull_request_review_status}">
99 <div class="tag status-tag-${c.pull_request_review_status}">
97 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
100 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
98 <span class="changeset-status-lbl">
101 <span class="changeset-status-lbl">
99 %if c.pull_request.is_closed():
102 %if c.pull_request.is_closed():
100 ${_('Closed')},
103 ${_('Closed')},
101 %endif
104 %endif
102
105
103 ${h.commit_status_lbl(c.pull_request_review_status)}
106 ${h.commit_status_lbl(c.pull_request_review_status)}
104
107
105 </span>
108 </span>
106 </div>
109 </div>
107 - ${_ungettext('calculated based on {} reviewer vote', 'calculated based on {} reviewers votes', len(c.pull_request_reviewers)).format(len(c.pull_request_reviewers))}
110 - ${_ungettext('calculated based on {} reviewer vote', 'calculated based on {} reviewers votes', len(c.pull_request_reviewers)).format(len(c.pull_request_reviewers))}
108 %endif
111 %endif
109 </div>
112 </div>
110 </div>
113 </div>
111
114
112 ## source
115 ## source
113 <div class="field">
116 <div class="field">
114 <div class="label-pr-detail">
117 <div class="label-pr-detail">
115 <label>${_('Commit flow')}:</label>
118 <label>${_('Commit flow')}:</label>
116 </div>
119 </div>
117 <div class="input">
120 <div class="input">
118 <div class="pr-commit-flow">
121 <div class="pr-commit-flow">
119 ## Source
122 ## Source
120 %if c.pull_request.source_ref_parts.type == 'branch':
123 %if c.pull_request.source_ref_parts.type == 'branch':
121 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}"><code class="pr-source-info">${c.pull_request.source_ref_parts.type}:${c.pull_request.source_ref_parts.name}</code></a>
124 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}"><code class="pr-source-info">${c.pull_request.source_ref_parts.type}:${c.pull_request.source_ref_parts.name}</code></a>
122 %else:
125 %else:
123 <code class="pr-source-info">${'{}:{}'.format(c.pull_request.source_ref_parts.type, c.pull_request.source_ref_parts.name)}</code>
126 <code class="pr-source-info">${'{}:{}'.format(c.pull_request.source_ref_parts.type, c.pull_request.source_ref_parts.name)}</code>
124 %endif
127 %endif
125 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.repo_name}</a>
128 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.repo_name}</a>
126 &rarr;
129 &rarr;
127 ## Target
130 ## Target
128 %if c.pull_request.target_ref_parts.type == 'branch':
131 %if c.pull_request.target_ref_parts.type == 'branch':
129 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}"><code class="pr-target-info">${c.pull_request.target_ref_parts.type}:${c.pull_request.target_ref_parts.name}</code></a>
132 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}"><code class="pr-target-info">${c.pull_request.target_ref_parts.type}:${c.pull_request.target_ref_parts.name}</code></a>
130 %else:
133 %else:
131 <code class="pr-target-info">${'{}:{}'.format(c.pull_request.target_ref_parts.type, c.pull_request.target_ref_parts.name)}</code>
134 <code class="pr-target-info">${'{}:{}'.format(c.pull_request.target_ref_parts.type, c.pull_request.target_ref_parts.name)}</code>
132 %endif
135 %endif
133
136
134 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.repo_name}</a>
137 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.repo_name}</a>
135
138
136 <a class="source-details-action" href="#expand-source-details" onclick="return versionController.toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
139 <a class="source-details-action" href="#expand-source-details" onclick="return versionController.toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
137 <i class="icon-angle-down">more details</i>
140 <i class="icon-angle-down">more details</i>
138 </a>
141 </a>
139
142
140 </div>
143 </div>
141
144
142 <div class="source-details" style="display: none">
145 <div class="source-details" style="display: none">
143
146
144 <ul>
147 <ul>
145
148
146 ## common ancestor
149 ## common ancestor
147 <li>
150 <li>
148 ${_('Common ancestor')}:
151 ${_('Common ancestor')}:
149 % if c.ancestor_commit:
152 % if c.ancestor_commit:
150 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a>
153 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a>
151 % else:
154 % else:
152 ${_('not available')}
155 ${_('not available')}
153 % endif
156 % endif
154 </li>
157 </li>
155
158
156 ## pull url
159 ## pull url
157 <li>
160 <li>
158 %if h.is_hg(c.pull_request.source_repo):
161 %if h.is_hg(c.pull_request.source_repo):
159 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
162 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
160 %elif h.is_git(c.pull_request.source_repo):
163 %elif h.is_git(c.pull_request.source_repo):
161 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
164 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
162 %endif
165 %endif
163
166
164 <span>${_('Pull changes from source')}</span>: <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
167 <span>${_('Pull changes from source')}</span>: <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
165 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
168 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
166 </li>
169 </li>
167
170
168 ## Shadow repo
171 ## Shadow repo
169 <li>
172 <li>
170 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
173 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
171 %if h.is_hg(c.pull_request.target_repo):
174 %if h.is_hg(c.pull_request.target_repo):
172 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
175 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
173 %elif h.is_git(c.pull_request.target_repo):
176 %elif h.is_git(c.pull_request.target_repo):
174 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
177 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
175 %endif
178 %endif
176
179
177 <span class="tooltip" title="${_('Clone repository in its merged state using shadow repository')}">${_('Clone from shadow repository')}</span>: <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
180 <span class="tooltip" title="${_('Clone repository in its merged state using shadow repository')}">${_('Clone from shadow repository')}</span>: <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
178 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
181 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
179
182
180 % else:
183 % else:
181 <div class="">
184 <div class="">
182 ${_('Shadow repository data not available')}.
185 ${_('Shadow repository data not available')}.
183 </div>
186 </div>
184 % endif
187 % endif
185 </li>
188 </li>
186
189
187 </ul>
190 </ul>
188
191
189 </div>
192 </div>
190
193
191 </div>
194 </div>
192
195
193 </div>
196 </div>
194
197
195 ## versions
198 ## versions
196 <div class="field">
199 <div class="field">
197 <div class="label-pr-detail">
200 <div class="label-pr-detail">
198 <label>${_('Versions')}:</label>
201 <label>${_('Versions')}:</label>
199 </div>
202 </div>
200
203
201 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
204 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
202 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
205 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
203
206
204 <div class="pr-versions">
207 <div class="pr-versions">
205 % if c.show_version_changes:
208 % if c.show_version_changes:
206 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
209 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
207 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
210 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
208 ${_ungettext('{} version available for this pull request, ', '{} versions available for this pull request, ', len(c.versions)).format(len(c.versions))}
211 ${_ungettext('{} version available for this pull request, ', '{} versions available for this pull request, ', len(c.versions)).format(len(c.versions))}
209 <a id="show-pr-versions" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
212 <a id="show-pr-versions" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
210 data-toggle-on="${_('show versions')}."
213 data-toggle-on="${_('show versions')}."
211 data-toggle-off="${_('hide versions')}.">
214 data-toggle-off="${_('hide versions')}.">
212 ${_('show versions')}.
215 ${_('show versions')}.
213 </a>
216 </a>
214 <table>
217 <table>
215 ## SHOW ALL VERSIONS OF PR
218 ## SHOW ALL VERSIONS OF PR
216 <% ver_pr = None %>
219 <% ver_pr = None %>
217
220
218 % for data in reversed(list(enumerate(c.versions, 1))):
221 % for data in reversed(list(enumerate(c.versions, 1))):
219 <% ver_pos = data[0] %>
222 <% ver_pos = data[0] %>
220 <% ver = data[1] %>
223 <% ver = data[1] %>
221 <% ver_pr = ver.pull_request_version_id %>
224 <% ver_pr = ver.pull_request_version_id %>
222 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
225 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
223
226
224 <tr class="version-pr" style="display: ${display_row}">
227 <tr class="version-pr" style="display: ${display_row}">
225 <td>
228 <td>
226 <code>
229 <code>
227 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
230 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
228 </code>
231 </code>
229 </td>
232 </td>
230 <td>
233 <td>
231 <input ${('checked="checked"' if c.from_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
234 <input ${('checked="checked"' if c.from_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
232 <input ${('checked="checked"' if c.at_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
235 <input ${('checked="checked"' if c.at_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
233 </td>
236 </td>
234 <td>
237 <td>
235 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
238 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
236 <i class="tooltip icon-circle review-status-${review_status}" title="${_('Your review status at this version')}"></i>
239 <i class="tooltip icon-circle review-status-${review_status}" title="${_('Your review status at this version')}"></i>
237
240
238 </td>
241 </td>
239 <td>
242 <td>
240 % if c.at_version_num != ver_pr:
243 % if c.at_version_num != ver_pr:
241 <i class="tooltip icon-comment" title="${_('Comments from pull request version v{0}').format(ver_pos)}"></i>
244 <i class="tooltip icon-comment" title="${_('Comments from pull request version v{0}').format(ver_pos)}"></i>
242 <code>
245 <code>
243 General:${len(c.comment_versions[ver_pr]['at'])} / Inline:${len(c.inline_versions[ver_pr]['at'])}
246 General:${len(c.comment_versions[ver_pr]['at'])} / Inline:${len(c.inline_versions[ver_pr]['at'])}
244 </code>
247 </code>
245 % endif
248 % endif
246 </td>
249 </td>
247 <td>
250 <td>
248 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
251 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
249 </td>
252 </td>
250 <td>
253 <td>
251 <code>${h.age_component(ver.updated_on, time_is_local=True, tooltip=False)}</code>
254 <code>${h.age_component(ver.updated_on, time_is_local=True, tooltip=False)}</code>
252 </td>
255 </td>
253 </tr>
256 </tr>
254 % endfor
257 % endfor
255
258
256 <tr>
259 <tr>
257 <td colspan="6">
260 <td colspan="6">
258 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
261 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
259 data-label-text-locked="${_('select versions to show changes')}"
262 data-label-text-locked="${_('select versions to show changes')}"
260 data-label-text-diff="${_('show changes between versions')}"
263 data-label-text-diff="${_('show changes between versions')}"
261 data-label-text-show="${_('show pull request for this version')}"
264 data-label-text-show="${_('show pull request for this version')}"
262 >
265 >
263 ${_('select versions to show changes')}
266 ${_('select versions to show changes')}
264 </button>
267 </button>
265 </td>
268 </td>
266 </tr>
269 </tr>
267 </table>
270 </table>
268 % else:
271 % else:
269 <div class="input">
272 <div>
270 ${_('Pull request versions not available')}.
273 ${_('Pull request versions not available')}.
271 </div>
274 </div>
272 % endif
275 % endif
273 </div>
276 </div>
274 </div>
277 </div>
275
278
276 </div>
279 </div>
277
280
278 </div>
281 </div>
279
282
280 ## REVIEW RULES
283 ## REVIEW RULES
281 <div id="review_rules" style="display: none" class="reviewers-title block-right">
284 <div id="review_rules" style="display: none" class="reviewers-title block-right">
282 <div class="pr-details-title">
285 <div class="pr-details-title">
283 ${_('Reviewer rules')}
286 ${_('Reviewer rules')}
284 %if c.allowed_to_update:
287 %if c.allowed_to_update:
285 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
288 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
286 %endif
289 %endif
287 </div>
290 </div>
288 <div class="pr-reviewer-rules">
291 <div class="pr-reviewer-rules">
289 ## review rules will be appended here, by default reviewers logic
292 ## review rules will be appended here, by default reviewers logic
290 </div>
293 </div>
291 <input id="review_data" type="hidden" name="review_data" value="">
294 <input id="review_data" type="hidden" name="review_data" value="">
292 </div>
295 </div>
293
296
294 ## REVIEWERS
297 ## REVIEWERS
295 <div class="reviewers-title block-right">
298 <div class="reviewers-title block-right">
296 <div class="pr-details-title">
299 <div class="pr-details-title">
297 ${_('Pull request reviewers')}
300 ${_('Pull request reviewers')}
298 %if c.allowed_to_update:
301 %if c.allowed_to_update:
299 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
302 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
300 %endif
303 %endif
301 </div>
304 </div>
302 </div>
305 </div>
303 <div id="reviewers" class="block-right pr-details-content reviewers">
306 <div id="reviewers" class="block-right pr-details-content reviewers">
304
307
305 ## members redering block
308 ## members redering block
306 <input type="hidden" name="__start__" value="review_members:sequence">
309 <input type="hidden" name="__start__" value="review_members:sequence">
307 <ul id="review_members" class="group_members">
310 <ul id="review_members" class="group_members">
308
311
309 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
312 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
310 <script>
313 <script>
311 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
314 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
312 var status = "${(status[0][1].status if status else 'not_reviewed')}";
315 var status = "${(status[0][1].status if status else 'not_reviewed')}";
313 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
316 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
314 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
317 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
315
318
316 var entry = renderTemplate('reviewMemberEntry', {
319 var entry = renderTemplate('reviewMemberEntry', {
317 'member': member,
320 'member': member,
318 'mandatory': member.mandatory,
321 'mandatory': member.mandatory,
319 'reasons': member.reasons,
322 'reasons': member.reasons,
320 'allowed_to_update': allowed_to_update,
323 'allowed_to_update': allowed_to_update,
321 'review_status': status,
324 'review_status': status,
322 'review_status_label': status_lbl,
325 'review_status_label': status_lbl,
323 'user_group': member.user_group,
326 'user_group': member.user_group,
324 'create': false
327 'create': false
325 });
328 });
326 $('#review_members').append(entry)
329 $('#review_members').append(entry)
327 </script>
330 </script>
328
331
329 % endfor
332 % endfor
330
333
331 </ul>
334 </ul>
332
335
333 <input type="hidden" name="__end__" value="review_members:sequence">
336 <input type="hidden" name="__end__" value="review_members:sequence">
334 ## end members redering block
337 ## end members redering block
335
338
336 %if not c.pull_request.is_closed():
339 %if not c.pull_request.is_closed():
337 <div id="add_reviewer" class="ac" style="display: none;">
340 <div id="add_reviewer" class="ac" style="display: none;">
338 %if c.allowed_to_update:
341 %if c.allowed_to_update:
339 % if not c.forbid_adding_reviewers:
342 % if not c.forbid_adding_reviewers:
340 <div id="add_reviewer_input" class="reviewer_ac">
343 <div id="add_reviewer_input" class="reviewer_ac">
341 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
344 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
342 <div id="reviewers_container"></div>
345 <div id="reviewers_container"></div>
343 </div>
346 </div>
344 % endif
347 % endif
345 <div class="pull-right">
348 <div class="pull-right">
346 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
349 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
347 </div>
350 </div>
348 %endif
351 %endif
349 </div>
352 </div>
350 %endif
353 %endif
351 </div>
354 </div>
352
355
353 ## ## TODOs will be listed here
356 ## TODOs will be listed here
354 ## <div class="reviewers-title block-right">
357 <div class="reviewers-title block-right">
355 ## <div class="pr-details-title">
358 <div class="pr-details-title">
356 ## ${_('TODOs')}
359 ## Only show unresolved, that is only what matters
357 ## </div>
360 TODO Comments - ${len(c.unresolved_comments)} / ${(len(c.unresolved_comments) + len(c.resolved_comments))}
358 ## </div>
361
359 ## <div class="block-right pr-details-content reviewers">
362 % if not c.at_version:
360 ## <ul class="group_members">
363 % if c.resolved_comments:
361 ## <li>
364 <span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.unresolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
362 ## XXXX
365 % else:
363 ## </li>
366 <span class="block-right last-item noselect">Show resolved</span>
364 ## </ul>
367 % endif
365 ## </div>
368 % endif
366 ## </div>
369 </div>
370 </div>
371 <div class="block-right pr-details-content reviewers">
372
373 <table class="todo-table">
374 <%
375 def sorter(entry):
376 user_id = entry.author.user_id
377 resolved = '1' if entry.resolved else '0'
378 if user_id == c.rhodecode_user.user_id:
379 # own comments first
380 user_id = 0
381 return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100))
382 %>
383
384 % if c.at_version:
385 <tr>
386 <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td>
387 </tr>
388 % else:
389 % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter):
390 <% resolved = todo_comment.resolved %>
391 % if inline:
392 <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
393 % else:
394 <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %>
395 % endif
396
397 <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}>
398
399 <td class="td-todo-number">
400 % if resolved:
401 <a class="permalink todo-resolved tooltip" title="${_('Resolved by comment #{}').format(todo_comment.resolved.comment_id)}" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
402 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
403 % else:
404 <a class="permalink" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
405 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
406 % endif
407 </td>
408 <td class="td-todo-gravatar">
409 ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])}
410 </td>
411 <td class="todo-comment-text-wrapper">
412 <div class="todo-comment-text">
413 <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code>
414 </div>
415 </td>
416
417 </tr>
418 % endfor
419
420 % if len(c.unresolved_comments) == 0:
421 <tr>
422 <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td>
423 </tr>
424 % endif
425
426 % endif
427
428 </table>
429
430 </div>
431 </div>
367
432
368 </div>
433 </div>
369
434
370 <div class="box">
435 <div class="box">
371
436
372 % if c.state_progressing:
437 % if c.state_progressing:
373
438
374 <h2 style="text-align: center">
439 <h2 style="text-align: center">
375 ${_('Cannot show diff when pull request state is changing. Current progress state')}: <span class="tag tag-merge-state-${c.pull_request.state}">${c.pull_request.state}</span>
440 ${_('Cannot show diff when pull request state is changing. Current progress state')}: <span class="tag tag-merge-state-${c.pull_request.state}">${c.pull_request.state}</span>
376 </h2>
441 </h2>
377
442
378 % else:
443 % else:
379
444
380 ## Diffs rendered here
445 ## Diffs rendered here
381 <div class="table" >
446 <div class="table" >
382 <div id="changeset_compare_view_content">
447 <div id="changeset_compare_view_content">
383 ##CS
448 ##CS
384 % if c.missing_requirements:
449 % if c.missing_requirements:
385 <div class="box">
450 <div class="box">
386 <div class="alert alert-warning">
451 <div class="alert alert-warning">
387 <div>
452 <div>
388 <strong>${_('Missing requirements:')}</strong>
453 <strong>${_('Missing requirements:')}</strong>
389 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
454 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
390 </div>
455 </div>
391 </div>
456 </div>
392 </div>
457 </div>
393 % elif c.missing_commits:
458 % elif c.missing_commits:
394 <div class="box">
459 <div class="box">
395 <div class="alert alert-warning">
460 <div class="alert alert-warning">
396 <div>
461 <div>
397 <strong>${_('Missing commits')}:</strong>
462 <strong>${_('Missing commits')}:</strong>
398 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
463 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
399 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
464 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
400 ${_('Consider doing a {force_refresh_url} in case you think this is an error.').format(force_refresh_url=h.link_to('force refresh', h.current_route_path(request, force_refresh='1')))|n}
465 ${_('Consider doing a {force_refresh_url} in case you think this is an error.').format(force_refresh_url=h.link_to('force refresh', h.current_route_path(request, force_refresh='1')))|n}
401 </div>
466 </div>
402 </div>
467 </div>
403 </div>
468 </div>
404 % endif
469 % endif
405
470
406 <div class="compare_view_commits_title">
471 <div class="compare_view_commits_title">
407 % if not c.compare_mode:
472 % if not c.compare_mode:
408
473
409 % if c.at_version_pos:
474 % if c.at_version_pos:
410 <h4>
475 <h4>
411 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
476 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
412 </h4>
477 </h4>
413 % endif
478 % endif
414
479
415 <div class="pull-left">
480 <div class="pull-left">
416 <div class="btn-group">
481 <div class="btn-group">
417 <a class="${('collapsed' if c.collapse_all_commits else '')}" href="#expand-commits" onclick="toggleCommitExpand(this); return false" data-toggle-commits-cnt=${len(c.commit_ranges)} >
482 <a class="${('collapsed' if c.collapse_all_commits else '')}" href="#expand-commits" onclick="toggleCommitExpand(this); return false" data-toggle-commits-cnt=${len(c.commit_ranges)} >
418 % if c.collapse_all_commits:
483 % if c.collapse_all_commits:
419 <i class="icon-plus-squared-alt icon-no-margin"></i>
484 <i class="icon-plus-squared-alt icon-no-margin"></i>
420 ${_ungettext('Expand {} commit', 'Expand {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
485 ${_ungettext('Expand {} commit', 'Expand {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
421 % else:
486 % else:
422 <i class="icon-minus-squared-alt icon-no-margin"></i>
487 <i class="icon-minus-squared-alt icon-no-margin"></i>
423 ${_ungettext('Collapse {} commit', 'Collapse {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
488 ${_ungettext('Collapse {} commit', 'Collapse {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
424 % endif
489 % endif
425 </a>
490 </a>
426 </div>
491 </div>
427 </div>
492 </div>
428
493
429 <div class="pull-right">
494 <div class="pull-right">
430 % if c.allowed_to_update and not c.pull_request.is_closed():
495 % if c.allowed_to_update and not c.pull_request.is_closed():
431
496
432 <div class="btn-group btn-group-actions">
497 <div class="btn-group btn-group-actions">
433 <a id="update_commits" class="btn btn-primary no-margin" onclick="updateController.updateCommits(this); return false">
498 <a id="update_commits" class="btn btn-primary no-margin" onclick="updateController.updateCommits(this); return false">
434 ${_('Update commits')}
499 ${_('Update commits')}
435 </a>
500 </a>
436
501
437 <a id="update_commits_switcher" class="tooltip btn btn-primary" style="margin-left: -1px" data-toggle="dropdown" aria-pressed="false" role="button" title="${_('more update options')}">
502 <a id="update_commits_switcher" class="tooltip btn btn-primary" style="margin-left: -1px" data-toggle="dropdown" aria-pressed="false" role="button" title="${_('more update options')}">
438 <i class="icon-down"></i>
503 <i class="icon-down"></i>
439 </a>
504 </a>
440
505
441 <div class="btn-action-switcher-container" id="update-commits-switcher">
506 <div class="btn-action-switcher-container" id="update-commits-switcher">
442 <ul class="btn-action-switcher" role="menu">
507 <ul class="btn-action-switcher" role="menu">
443 <li>
508 <li>
444 <a href="#forceUpdate" onclick="updateController.forceUpdateCommits(this); return false">
509 <a href="#forceUpdate" onclick="updateController.forceUpdateCommits(this); return false">
445 ${_('Force update commits')}
510 ${_('Force update commits')}
446 </a>
511 </a>
447 <div class="action-help-block">
512 <div class="action-help-block">
448 ${_('Update commits and force refresh this pull request.')}
513 ${_('Update commits and force refresh this pull request.')}
449 </div>
514 </div>
450 </li>
515 </li>
451 </ul>
516 </ul>
452 </div>
517 </div>
453 </div>
518 </div>
454
519
455 % else:
520 % else:
456 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
521 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
457 % endif
522 % endif
458
523
459 </div>
524 </div>
460 % endif
525 % endif
461 </div>
526 </div>
462
527
463 % if not c.missing_commits:
528 % if not c.missing_commits:
464 % if c.compare_mode:
529 % if c.compare_mode:
465 % if c.at_version:
530 % if c.at_version:
466 <h4>
531 <h4>
467 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
532 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
468 </h4>
533 </h4>
469
534
470 <div class="subtitle-compare">
535 <div class="subtitle-compare">
471 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
536 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
472 </div>
537 </div>
473
538
474 <div class="container">
539 <div class="container">
475 <table class="rctable compare_view_commits">
540 <table class="rctable compare_view_commits">
476 <tr>
541 <tr>
477 <th></th>
542 <th></th>
478 <th>${_('Time')}</th>
543 <th>${_('Time')}</th>
479 <th>${_('Author')}</th>
544 <th>${_('Author')}</th>
480 <th>${_('Commit')}</th>
545 <th>${_('Commit')}</th>
481 <th></th>
546 <th></th>
482 <th>${_('Description')}</th>
547 <th>${_('Description')}</th>
483 </tr>
548 </tr>
484
549
485 % for c_type, commit in c.commit_changes:
550 % for c_type, commit in c.commit_changes:
486 % if c_type in ['a', 'r']:
551 % if c_type in ['a', 'r']:
487 <%
552 <%
488 if c_type == 'a':
553 if c_type == 'a':
489 cc_title = _('Commit added in displayed changes')
554 cc_title = _('Commit added in displayed changes')
490 elif c_type == 'r':
555 elif c_type == 'r':
491 cc_title = _('Commit removed in displayed changes')
556 cc_title = _('Commit removed in displayed changes')
492 else:
557 else:
493 cc_title = ''
558 cc_title = ''
494 %>
559 %>
495 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
560 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
496 <td>
561 <td>
497 <div class="commit-change-indicator color-${c_type}-border">
562 <div class="commit-change-indicator color-${c_type}-border">
498 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
563 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
499 ${c_type.upper()}
564 ${c_type.upper()}
500 </div>
565 </div>
501 </div>
566 </div>
502 </td>
567 </td>
503 <td class="td-time">
568 <td class="td-time">
504 ${h.age_component(commit.date)}
569 ${h.age_component(commit.date)}
505 </td>
570 </td>
506 <td class="td-user">
571 <td class="td-user">
507 ${base.gravatar_with_user(commit.author, 16, tooltip=True)}
572 ${base.gravatar_with_user(commit.author, 16, tooltip=True)}
508 </td>
573 </td>
509 <td class="td-hash">
574 <td class="td-hash">
510 <code>
575 <code>
511 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
576 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
512 r${commit.idx}:${h.short_id(commit.raw_id)}
577 r${commit.idx}:${h.short_id(commit.raw_id)}
513 </a>
578 </a>
514 ${h.hidden('revisions', commit.raw_id)}
579 ${h.hidden('revisions', commit.raw_id)}
515 </code>
580 </code>
516 </td>
581 </td>
517 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
582 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
518 <i class="icon-expand-linked"></i>
583 <i class="icon-expand-linked"></i>
519 </td>
584 </td>
520 <td class="mid td-description">
585 <td class="mid td-description">
521 <div class="log-container truncate-wrap">
586 <div class="log-container truncate-wrap">
522 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
587 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
523 </div>
588 </div>
524 </td>
589 </td>
525 </tr>
590 </tr>
526 % endif
591 % endif
527 % endfor
592 % endfor
528 </table>
593 </table>
529 </div>
594 </div>
530
595
531 % endif
596 % endif
532
597
533 % else:
598 % else:
534 <%include file="/compare/compare_commits.mako" />
599 <%include file="/compare/compare_commits.mako" />
535 % endif
600 % endif
536
601
537 <div class="cs_files">
602 <div class="cs_files">
538 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
603 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
539 % if c.at_version:
604 % if c.at_version:
540 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %>
605 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %>
541 <% c.comments = c.comment_versions[c.at_version_num]['display'] %>
606 <% c.comments = c.comment_versions[c.at_version_num]['display'] %>
542 % else:
607 % else:
543 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %>
608 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %>
544 <% c.comments = c.comment_versions[c.at_version_num]['until'] %>
609 <% c.comments = c.comment_versions[c.at_version_num]['until'] %>
545 % endif
610 % endif
546
611
547 <%
612 <%
548 pr_menu_data = {
613 pr_menu_data = {
549 'outdated_comm_count_ver': outdated_comm_count_ver
614 'outdated_comm_count_ver': outdated_comm_count_ver
550 }
615 }
551 %>
616 %>
552
617
553 ${cbdiffs.render_diffset_menu(c.diffset, range_diff_on=c.range_diff_on)}
618 ${cbdiffs.render_diffset_menu(c.diffset, range_diff_on=c.range_diff_on)}
554
619
555 % if c.range_diff_on:
620 % if c.range_diff_on:
556 % for commit in c.commit_ranges:
621 % for commit in c.commit_ranges:
557 ${cbdiffs.render_diffset(
622 ${cbdiffs.render_diffset(
558 c.changes[commit.raw_id],
623 c.changes[commit.raw_id],
559 commit=commit, use_comments=True,
624 commit=commit, use_comments=True,
560 collapse_when_files_over=5,
625 collapse_when_files_over=5,
561 disable_new_comments=True,
626 disable_new_comments=True,
562 deleted_files_comments=c.deleted_files_comments,
627 deleted_files_comments=c.deleted_files_comments,
563 inline_comments=c.inline_comments,
628 inline_comments=c.inline_comments,
564 pull_request_menu=pr_menu_data)}
629 pull_request_menu=pr_menu_data, show_todos=False)}
565 % endfor
630 % endfor
566 % else:
631 % else:
567 ${cbdiffs.render_diffset(
632 ${cbdiffs.render_diffset(
568 c.diffset, use_comments=True,
633 c.diffset, use_comments=True,
569 collapse_when_files_over=30,
634 collapse_when_files_over=30,
570 disable_new_comments=not c.allowed_to_comment,
635 disable_new_comments=not c.allowed_to_comment,
571 deleted_files_comments=c.deleted_files_comments,
636 deleted_files_comments=c.deleted_files_comments,
572 inline_comments=c.inline_comments,
637 inline_comments=c.inline_comments,
573 pull_request_menu=pr_menu_data)}
638 pull_request_menu=pr_menu_data, show_todos=False)}
574 % endif
639 % endif
575
640
576 </div>
641 </div>
577 % else:
642 % else:
578 ## skipping commits we need to clear the view for missing commits
643 ## skipping commits we need to clear the view for missing commits
579 <div style="clear:both;"></div>
644 <div style="clear:both;"></div>
580 % endif
645 % endif
581
646
582 </div>
647 </div>
583 </div>
648 </div>
584
649
585 ## template for inline comment form
650 ## template for inline comment form
586 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
651 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
587
652
588 ## comments heading with count
653 ## comments heading with count
589 <div class="comments-heading">
654 <div class="comments-heading">
590 <i class="icon-comment"></i>
655 <i class="icon-comment"></i>
591 ${_('Comments')} ${len(c.comments)}
656 ${_('Comments')} ${len(c.comments)}
592 </div>
657 </div>
593
658
594 ## render general comments
659 ## render general comments
595 <div id="comment-tr-show">
660 <div id="comment-tr-show">
596 % if general_outdated_comm_count_ver:
661 % if general_outdated_comm_count_ver:
597 <div class="info-box">
662 <div class="info-box">
598 % if general_outdated_comm_count_ver == 1:
663 % if general_outdated_comm_count_ver == 1:
599 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
664 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
600 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
665 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
601 % else:
666 % else:
602 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
667 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
603 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
668 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
604 % endif
669 % endif
605 </div>
670 </div>
606 % endif
671 % endif
607 </div>
672 </div>
608
673
609 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
674 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
610
675
611 % if not c.pull_request.is_closed():
676 % if not c.pull_request.is_closed():
612 ## main comment form and it status
677 ## main comment form and it status
613 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
678 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
614 pull_request_id=c.pull_request.pull_request_id),
679 pull_request_id=c.pull_request.pull_request_id),
615 c.pull_request_review_status,
680 c.pull_request_review_status,
616 is_pull_request=True, change_status=c.allowed_to_change_status)}
681 is_pull_request=True, change_status=c.allowed_to_change_status)}
617
682
618 ## merge status, and merge action
683 ## merge status, and merge action
619 <div class="pull-request-merge">
684 <div class="pull-request-merge">
620 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
685 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
621 </div>
686 </div>
622
687
623 %endif
688 %endif
624
689
625 % endif
690 % endif
626 </div>
691 </div>
627
692
628 <script type="text/javascript">
693 <script type="text/javascript">
629
694
630 versionController = new VersionController();
695 versionController = new VersionController();
631 versionController.init();
696 versionController.init();
632
697
633 reviewersController = new ReviewersController();
698 reviewersController = new ReviewersController();
634 commitsController = new CommitsController();
699 commitsController = new CommitsController();
635
700
636 updateController = new UpdatePrController();
701 updateController = new UpdatePrController();
637
702
638 $(function () {
703 $(function () {
639
704
640 // custom code mirror
705 // custom code mirror
641 var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
706 var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
642
707
643 var PRDetails = {
708 var PRDetails = {
644 editButton: $('#open_edit_pullrequest'),
709 editButton: $('#open_edit_pullrequest'),
645 closeButton: $('#close_edit_pullrequest'),
710 closeButton: $('#close_edit_pullrequest'),
646 deleteButton: $('#delete_pullrequest'),
711 deleteButton: $('#delete_pullrequest'),
647 viewFields: $('#pr-desc, #pr-title'),
712 viewFields: $('#pr-desc, #pr-title'),
648 editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
713 editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
649
714
650 init: function () {
715 init: function () {
651 var that = this;
716 var that = this;
652 this.editButton.on('click', function (e) {
717 this.editButton.on('click', function (e) {
653 that.edit();
718 that.edit();
654 });
719 });
655 this.closeButton.on('click', function (e) {
720 this.closeButton.on('click', function (e) {
656 that.view();
721 that.view();
657 });
722 });
658 },
723 },
659
724
660 edit: function (event) {
725 edit: function (event) {
661 this.viewFields.hide();
726 this.viewFields.hide();
662 this.editButton.hide();
727 this.editButton.hide();
663 this.deleteButton.hide();
728 this.deleteButton.hide();
664 this.closeButton.show();
729 this.closeButton.show();
665 this.editFields.show();
730 this.editFields.show();
666 codeMirrorInstance.refresh();
731 codeMirrorInstance.refresh();
667 },
732 },
668
733
669 view: function (event) {
734 view: function (event) {
670 this.editButton.show();
735 this.editButton.show();
671 this.deleteButton.show();
736 this.deleteButton.show();
672 this.editFields.hide();
737 this.editFields.hide();
673 this.closeButton.hide();
738 this.closeButton.hide();
674 this.viewFields.show();
739 this.viewFields.show();
675 }
740 }
676 };
741 };
677
742
678 var ReviewersPanel = {
743 var ReviewersPanel = {
679 editButton: $('#open_edit_reviewers'),
744 editButton: $('#open_edit_reviewers'),
680 closeButton: $('#close_edit_reviewers'),
745 closeButton: $('#close_edit_reviewers'),
681 addButton: $('#add_reviewer'),
746 addButton: $('#add_reviewer'),
682 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
747 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
683
748
684 init: function () {
749 init: function () {
685 var self = this;
750 var self = this;
686 this.editButton.on('click', function (e) {
751 this.editButton.on('click', function (e) {
687 self.edit();
752 self.edit();
688 });
753 });
689 this.closeButton.on('click', function (e) {
754 this.closeButton.on('click', function (e) {
690 self.close();
755 self.close();
691 });
756 });
692 },
757 },
693
758
694 edit: function (event) {
759 edit: function (event) {
695 this.editButton.hide();
760 this.editButton.hide();
696 this.closeButton.show();
761 this.closeButton.show();
697 this.addButton.show();
762 this.addButton.show();
698 this.removeButtons.css('visibility', 'visible');
763 this.removeButtons.css('visibility', 'visible');
699 // review rules
764 // review rules
700 reviewersController.loadReviewRules(
765 reviewersController.loadReviewRules(
701 ${c.pull_request.reviewer_data_json | n});
766 ${c.pull_request.reviewer_data_json | n});
702 },
767 },
703
768
704 close: function (event) {
769 close: function (event) {
705 this.editButton.show();
770 this.editButton.show();
706 this.closeButton.hide();
771 this.closeButton.hide();
707 this.addButton.hide();
772 this.addButton.hide();
708 this.removeButtons.css('visibility', 'hidden');
773 this.removeButtons.css('visibility', 'hidden');
709 // hide review rules
774 // hide review rules
710 reviewersController.hideReviewRules()
775 reviewersController.hideReviewRules()
711 }
776 }
712 };
777 };
713
778
714 PRDetails.init();
779 PRDetails.init();
715 ReviewersPanel.init();
780 ReviewersPanel.init();
716
781
717 showOutdated = function (self) {
782 showOutdated = function (self) {
718 $('.comment-inline.comment-outdated').show();
783 $('.comment-inline.comment-outdated').show();
719 $('.filediff-outdated').show();
784 $('.filediff-outdated').show();
720 $('.showOutdatedComments').hide();
785 $('.showOutdatedComments').hide();
721 $('.hideOutdatedComments').show();
786 $('.hideOutdatedComments').show();
722 };
787 };
723
788
724 hideOutdated = function (self) {
789 hideOutdated = function (self) {
725 $('.comment-inline.comment-outdated').hide();
790 $('.comment-inline.comment-outdated').hide();
726 $('.filediff-outdated').hide();
791 $('.filediff-outdated').hide();
727 $('.hideOutdatedComments').hide();
792 $('.hideOutdatedComments').hide();
728 $('.showOutdatedComments').show();
793 $('.showOutdatedComments').show();
729 };
794 };
730
795
731 refreshMergeChecks = function () {
796 refreshMergeChecks = function () {
732 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
797 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
733 $('.pull-request-merge').css('opacity', 0.3);
798 $('.pull-request-merge').css('opacity', 0.3);
734 $('.action-buttons-extra').css('opacity', 0.3);
799 $('.action-buttons-extra').css('opacity', 0.3);
735
800
736 $('.pull-request-merge').load(
801 $('.pull-request-merge').load(
737 loadUrl, function () {
802 loadUrl, function () {
738 $('.pull-request-merge').css('opacity', 1);
803 $('.pull-request-merge').css('opacity', 1);
739
804
740 $('.action-buttons-extra').css('opacity', 1);
805 $('.action-buttons-extra').css('opacity', 1);
741 }
806 }
742 );
807 );
743 };
808 };
744
809
745 closePullRequest = function (status) {
810 closePullRequest = function (status) {
746 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
811 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
747 return false;
812 return false;
748 }
813 }
749 // inject closing flag
814 // inject closing flag
750 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
815 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
751 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
816 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
752 $(generalCommentForm.submitForm).submit();
817 $(generalCommentForm.submitForm).submit();
753 };
818 };
754
819
755 $('#show-outdated-comments').on('click', function (e) {
820 $('#show-outdated-comments').on('click', function (e) {
756 var button = $(this);
821 var button = $(this);
757 var outdated = $('.comment-outdated');
822 var outdated = $('.comment-outdated');
758
823
759 if (button.html() === "(Show)") {
824 if (button.html() === "(Show)") {
760 button.html("(Hide)");
825 button.html("(Hide)");
761 outdated.show();
826 outdated.show();
762 } else {
827 } else {
763 button.html("(Show)");
828 button.html("(Show)");
764 outdated.hide();
829 outdated.hide();
765 }
830 }
766 });
831 });
767
832
768 $('.show-inline-comments').on('change', function (e) {
833 $('.show-inline-comments').on('change', function (e) {
769 var show = 'none';
834 var show = 'none';
770 var target = e.currentTarget;
835 var target = e.currentTarget;
771 if (target.checked) {
836 if (target.checked) {
772 show = ''
837 show = ''
773 }
838 }
774 var boxid = $(target).attr('id_for');
839 var boxid = $(target).attr('id_for');
775 var comments = $('#{0} .inline-comments'.format(boxid));
840 var comments = $('#{0} .inline-comments'.format(boxid));
776 var fn_display = function (idx) {
841 var fn_display = function (idx) {
777 $(this).css('display', show);
842 $(this).css('display', show);
778 };
843 };
779 $(comments).each(fn_display);
844 $(comments).each(fn_display);
780 var btns = $('#{0} .inline-comments-button'.format(boxid));
845 var btns = $('#{0} .inline-comments-button'.format(boxid));
781 $(btns).each(fn_display);
846 $(btns).each(fn_display);
782 });
847 });
783
848
784 $('#merge_pull_request_form').submit(function () {
849 $('#merge_pull_request_form').submit(function () {
785 if (!$('#merge_pull_request').attr('disabled')) {
850 if (!$('#merge_pull_request').attr('disabled')) {
786 $('#merge_pull_request').attr('disabled', 'disabled');
851 $('#merge_pull_request').attr('disabled', 'disabled');
787 }
852 }
788 return true;
853 return true;
789 });
854 });
790
855
791 $('#edit_pull_request').on('click', function (e) {
856 $('#edit_pull_request').on('click', function (e) {
792 var title = $('#pr-title-input').val();
857 var title = $('#pr-title-input').val();
793 var description = codeMirrorInstance.getValue();
858 var description = codeMirrorInstance.getValue();
794 var renderer = $('#pr-renderer-input').val();
859 var renderer = $('#pr-renderer-input').val();
795 editPullRequest(
860 editPullRequest(
796 "${c.repo_name}", "${c.pull_request.pull_request_id}",
861 "${c.repo_name}", "${c.pull_request.pull_request_id}",
797 title, description, renderer);
862 title, description, renderer);
798 });
863 });
799
864
800 $('#update_pull_request').on('click', function (e) {
865 $('#update_pull_request').on('click', function (e) {
801 $(this).attr('disabled', 'disabled');
866 $(this).attr('disabled', 'disabled');
802 $(this).addClass('disabled');
867 $(this).addClass('disabled');
803 $(this).html(_gettext('Saving...'));
868 $(this).html(_gettext('Saving...'));
804 reviewersController.updateReviewers(
869 reviewersController.updateReviewers(
805 "${c.repo_name}", "${c.pull_request.pull_request_id}");
870 "${c.repo_name}", "${c.pull_request.pull_request_id}");
806 });
871 });
807
872
808
873
809 // fixing issue with caches on firefox
874 // fixing issue with caches on firefox
810 $('#update_commits').removeAttr("disabled");
875 $('#update_commits').removeAttr("disabled");
811
876
812 $('.show-inline-comments').on('click', function (e) {
877 $('.show-inline-comments').on('click', function (e) {
813 var boxid = $(this).attr('data-comment-id');
878 var boxid = $(this).attr('data-comment-id');
814 var button = $(this);
879 var button = $(this);
815
880
816 if (button.hasClass("comments-visible")) {
881 if (button.hasClass("comments-visible")) {
817 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
882 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
818 $(this).hide();
883 $(this).hide();
819 });
884 });
820 button.removeClass("comments-visible");
885 button.removeClass("comments-visible");
821 } else {
886 } else {
822 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
887 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
823 $(this).show();
888 $(this).show();
824 });
889 });
825 button.addClass("comments-visible");
890 button.addClass("comments-visible");
826 }
891 }
827 });
892 });
828
893
829 // register submit callback on commentForm form to track TODOs
894 // register submit callback on commentForm form to track TODOs
830 window.commentFormGlobalSubmitSuccessCallback = function () {
895 window.commentFormGlobalSubmitSuccessCallback = function () {
831 refreshMergeChecks();
896 refreshMergeChecks();
832 };
897 };
833
898
834 ReviewerAutoComplete('#user');
899 ReviewerAutoComplete('#user');
835
900
836 })
901 })
837
902
838 </script>
903 </script>
839
904
840 </div>
905 </div>
841
906
842 </%def>
907 </%def>
General Comments 0
You need to be logged in to leave comments. Login now