summaryrefslogtreecommitdiffabout
authorJohan Herland <johan@herland.net>2010-06-09 23:09:28 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2010-06-19 08:40:22 (UTC)
commitc93ef96aaf77437abeb552bd9e30973f90365f3a (patch) (unidiff)
treedec445607efb7a9996d008330517730fc0482de3
parentc8e3295469bd3b8e38a9ea4478d517d3861e6c93 (diff)
downloadcgit-c93ef96aaf77437abeb552bd9e30973f90365f3a.zip
cgit-c93ef96aaf77437abeb552bd9e30973f90365f3a.tar.gz
cgit-c93ef96aaf77437abeb552bd9e30973f90365f3a.tar.bz2
ui-shared: Display path limit directly beneath tab bar in relevant pages
Design-wise, the path is shown by "expanding" the grey border between the tab bar and the content area of the page to house the current path limit. This is only displayed on pages where the path limit is relevant, and only when a path limit is in effect. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css8
-rw-r--r--ui-shared.c6
2 files changed, 14 insertions, 0 deletions
diff --git a/cgit.css b/cgit.css
index 0cb894a..563f8e1 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,707 +1,715 @@
1body, table, form { 1body, table, form {
2 padding: 0em; 2 padding: 0em;
3 margin: 0em; 3 margin: 0em;
4} 4}
5 5
6body { 6body {
7 font-family: sans-serif; 7 font-family: sans-serif;
8 font-size: 10pt; 8 font-size: 10pt;
9 color: #333; 9 color: #333;
10 background: white; 10 background: white;
11 padding: 4px; 11 padding: 4px;
12} 12}
13 13
14a { 14a {
15 color: blue; 15 color: blue;
16 text-decoration: none; 16 text-decoration: none;
17} 17}
18 18
19a:hover { 19a:hover {
20 text-decoration: underline; 20 text-decoration: underline;
21} 21}
22 22
23table { 23table {
24 border-collapse: collapse; 24 border-collapse: collapse;
25} 25}
26 26
27table#header { 27table#header {
28 width: 100%; 28 width: 100%;
29 margin-bottom: 1em; 29 margin-bottom: 1em;
30} 30}
31 31
32table#header td.logo { 32table#header td.logo {
33 width: 96px; 33 width: 96px;
34} 34}
35 35
36table#header td.main { 36table#header td.main {
37 font-size: 250%; 37 font-size: 250%;
38 padding-left: 10px; 38 padding-left: 10px;
39 white-space: nowrap; 39 white-space: nowrap;
40} 40}
41 41
42table#header td.main a { 42table#header td.main a {
43 color: #000; 43 color: #000;
44} 44}
45 45
46table#header td.form { 46table#header td.form {
47 text-align: right; 47 text-align: right;
48 vertical-align: bottom; 48 vertical-align: bottom;
49 padding-right: 1em; 49 padding-right: 1em;
50 padding-bottom: 2px; 50 padding-bottom: 2px;
51 white-space: nowrap; 51 white-space: nowrap;
52} 52}
53 53
54table#header td.form form, 54table#header td.form form,
55table#header td.form input, 55table#header td.form input,
56table#header td.form select { 56table#header td.form select {
57 font-size: 90%; 57 font-size: 90%;
58} 58}
59 59
60table#header td.sub { 60table#header td.sub {
61 color: #777; 61 color: #777;
62 border-top: solid 1px #ccc; 62 border-top: solid 1px #ccc;
63 padding-left: 10px; 63 padding-left: 10px;
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 /* border-bottom: solid 2px #ccc; */
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
71 width: 100%; 71 width: 100%;
72} 72}
73 73
74table.tabs td { 74table.tabs td {
75 padding: 0px 1em; 75 padding: 0px 1em;
76 vertical-align: bottom; 76 vertical-align: bottom;
77} 77}
78 78
79table.tabs td a { 79table.tabs td a {
80 padding: 2px 0.75em; 80 padding: 2px 0.75em;
81 color: #777; 81 color: #777;
82 font-size: 110%; 82 font-size: 110%;
83} 83}
84 84
85table.tabs td a.active { 85table.tabs td a.active {
86 color: #000; 86 color: #000;
87 background-color: #ccc; 87 background-color: #ccc;
88} 88}
89 89
90table.tabs td.form { 90table.tabs td.form {
91 text-align: right; 91 text-align: right;
92} 92}
93 93
94table.tabs td.form form { 94table.tabs td.form form {
95 padding-bottom: 2px; 95 padding-bottom: 2px;
96 font-size: 90%; 96 font-size: 90%;
97 white-space: nowrap; 97 white-space: nowrap;
98} 98}
99 99
100table.tabs td.form input, 100table.tabs td.form input,
101table.tabs td.form select { 101table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.path {
106 margin: 0px;
107 padding: 5px 2em 2px 2em;
108 color: #000;
109 background-color: #ccc;
110 font-weight: bold;
111}
112
105div.content { 113div.content {
106 margin: 0px; 114 margin: 0px;
107 padding: 2em; 115 padding: 2em;
108 border-top: solid 3px #ccc; 116 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 117 border-bottom: solid 3px #ccc;
110} 118}
111 119
112 120
113table.list { 121table.list {
114 width: 100%; 122 width: 100%;
115 border: none; 123 border: none;
116 border-collapse: collapse; 124 border-collapse: collapse;
117} 125}
118 126
119table.list tr { 127table.list tr {
120 background: white; 128 background: white;
121} 129}
122 130
123table.list tr.logheader { 131table.list tr.logheader {
124 background: #eee; 132 background: #eee;
125} 133}
126 134
127table.list tr:hover { 135table.list tr:hover {
128 background: #eee; 136 background: #eee;
129} 137}
130 138
131table.list tr.nohover:hover { 139table.list tr.nohover:hover {
132 background: white; 140 background: white;
133} 141}
134 142
135table.list th { 143table.list th {
136 font-weight: bold; 144 font-weight: bold;
137 /* color: #888; 145 /* color: #888;
138 border-top: dashed 1px #888; 146 border-top: dashed 1px #888;
139 border-bottom: dashed 1px #888; 147 border-bottom: dashed 1px #888;
140 */ 148 */
141 padding: 0.1em 0.5em 0.05em 0.5em; 149 padding: 0.1em 0.5em 0.05em 0.5em;
142 vertical-align: baseline; 150 vertical-align: baseline;
143} 151}
144 152
145table.list td { 153table.list td {
146 border: none; 154 border: none;
147 padding: 0.1em 0.5em 0.1em 0.5em; 155 padding: 0.1em 0.5em 0.1em 0.5em;
148} 156}
149 157
150table.list td.logsubject { 158table.list td.logsubject {
151 font-family: monospace; 159 font-family: monospace;
152 font-weight: bold; 160 font-weight: bold;
153} 161}
154 162
155table.list td.logmsg { 163table.list td.logmsg {
156 font-family: monospace; 164 font-family: monospace;
157 white-space: pre; 165 white-space: pre;
158 padding: 1em 0.5em 2em 0.5em; 166 padding: 1em 0.5em 2em 0.5em;
159} 167}
160 168
161table.list td a { 169table.list td a {
162 color: black; 170 color: black;
163} 171}
164 172
165table.list td a.ls-dir { 173table.list td a.ls-dir {
166 font-weight: bold; 174 font-weight: bold;
167 color: #00f; 175 color: #00f;
168} 176}
169 177
170table.list td a:hover { 178table.list td a:hover {
171 color: #00f; 179 color: #00f;
172} 180}
173 181
174img { 182img {
175 border: none; 183 border: none;
176} 184}
177 185
178input#switch-btn { 186input#switch-btn {
179 margin: 2px 0px 0px 0px; 187 margin: 2px 0px 0px 0px;
180} 188}
181 189
182td#sidebar input.txt { 190td#sidebar input.txt {
183 width: 100%; 191 width: 100%;
184 margin: 2px 0px 0px 0px; 192 margin: 2px 0px 0px 0px;
185} 193}
186 194
187table#grid { 195table#grid {
188 margin: 0px; 196 margin: 0px;
189} 197}
190 198
191td#content { 199td#content {
192 vertical-align: top; 200 vertical-align: top;
193 padding: 1em 2em 1em 1em; 201 padding: 1em 2em 1em 1em;
194 border: none; 202 border: none;
195} 203}
196 204
197div#summary { 205div#summary {
198 vertical-align: top; 206 vertical-align: top;
199 margin-bottom: 1em; 207 margin-bottom: 1em;
200} 208}
201 209
202table#downloads { 210table#downloads {
203 float: right; 211 float: right;
204 border-collapse: collapse; 212 border-collapse: collapse;
205 border: solid 1px #777; 213 border: solid 1px #777;
206 margin-left: 0.5em; 214 margin-left: 0.5em;
207 margin-bottom: 0.5em; 215 margin-bottom: 0.5em;
208} 216}
209 217
210table#downloads th { 218table#downloads th {
211 background-color: #ccc; 219 background-color: #ccc;
212} 220}
213 221
214div#blob { 222div#blob {
215 border: solid 1px black; 223 border: solid 1px black;
216} 224}
217 225
218div.error { 226div.error {
219 color: red; 227 color: red;
220 font-weight: bold; 228 font-weight: bold;
221 margin: 1em 2em; 229 margin: 1em 2em;
222} 230}
223 231
224a.ls-blob, a.ls-dir, a.ls-mod { 232a.ls-blob, a.ls-dir, a.ls-mod {
225 font-family: monospace; 233 font-family: monospace;
226} 234}
227 235
228td.ls-size { 236td.ls-size {
229 text-align: right; 237 text-align: right;
230 font-family: monospace; 238 font-family: monospace;
231 width: 10em; 239 width: 10em;
232} 240}
233 241
234td.ls-mode { 242td.ls-mode {
235 font-family: monospace; 243 font-family: monospace;
236 width: 10em; 244 width: 10em;
237} 245}
238 246
239table.blob { 247table.blob {
240 margin-top: 0.5em; 248 margin-top: 0.5em;
241 border-top: solid 1px black; 249 border-top: solid 1px black;
242} 250}
243 251
244table.blob td.lines { 252table.blob td.lines {
245 margin: 0; padding: 0 0 0 0.5em; 253 margin: 0; padding: 0 0 0 0.5em;
246 vertical-align: top; 254 vertical-align: top;
247 color: black; 255 color: black;
248} 256}
249 257
250table.blob td.linenumbers { 258table.blob td.linenumbers {
251 margin: 0; padding: 0 0.5em 0 0.5em; 259 margin: 0; padding: 0 0.5em 0 0.5em;
252 vertical-align: top; 260 vertical-align: top;
253 text-align: right; 261 text-align: right;
254 border-right: 1px solid gray; 262 border-right: 1px solid gray;
255} 263}
256 264
257table.blob pre { 265table.blob pre {
258 padding: 0; margin: 0; 266 padding: 0; margin: 0;
259} 267}
260 268
261table.blob a.no { 269table.blob a.no {
262 color: gray; 270 color: gray;
263 text-align: right; 271 text-align: right;
264 text-decoration: none; 272 text-decoration: none;
265} 273}
266 274
267table.blob a.no a:hover { 275table.blob a.no a:hover {
268 color: black; 276 color: black;
269} 277}
270 278
271table.bin-blob { 279table.bin-blob {
272 margin-top: 0.5em; 280 margin-top: 0.5em;
273 border: solid 1px black; 281 border: solid 1px black;
274} 282}
275 283
276table.bin-blob th { 284table.bin-blob th {
277 font-family: monospace; 285 font-family: monospace;
278 white-space: pre; 286 white-space: pre;
279 border: solid 1px #777; 287 border: solid 1px #777;
280 padding: 0.5em 1em; 288 padding: 0.5em 1em;
281} 289}
282 290
283table.bin-blob td { 291table.bin-blob td {
284 font-family: monospace; 292 font-family: monospace;
285 white-space: pre; 293 white-space: pre;
286 border-left: solid 1px #777; 294 border-left: solid 1px #777;
287 padding: 0em 1em; 295 padding: 0em 1em;
288} 296}
289 297
290table.nowrap td { 298table.nowrap td {
291 white-space: nowrap; 299 white-space: nowrap;
292} 300}
293 301
294table.commit-info { 302table.commit-info {
295 border-collapse: collapse; 303 border-collapse: collapse;
296 margin-top: 1.5em; 304 margin-top: 1.5em;
297} 305}
298 306
299table.commit-info th { 307table.commit-info th {
300 text-align: left; 308 text-align: left;
301 font-weight: normal; 309 font-weight: normal;
302 padding: 0.1em 1em 0.1em 0.1em; 310 padding: 0.1em 1em 0.1em 0.1em;
303 vertical-align: top; 311 vertical-align: top;
304} 312}
305 313
306table.commit-info td { 314table.commit-info td {
307 font-weight: normal; 315 font-weight: normal;
308 padding: 0.1em 1em 0.1em 0.1em; 316 padding: 0.1em 1em 0.1em 0.1em;
309} 317}
310 318
311div.commit-subject { 319div.commit-subject {
312 font-weight: bold; 320 font-weight: bold;
313 font-size: 125%; 321 font-size: 125%;
314 margin: 1.5em 0em 0.5em 0em; 322 margin: 1.5em 0em 0.5em 0em;
315 padding: 0em; 323 padding: 0em;
316} 324}
317 325
318div.commit-msg { 326div.commit-msg {
319 white-space: pre; 327 white-space: pre;
320 font-family: monospace; 328 font-family: monospace;
321} 329}
322 330
323div.diffstat-header { 331div.diffstat-header {
324 font-weight: bold; 332 font-weight: bold;
325 padding-top: 1.5em; 333 padding-top: 1.5em;
326} 334}
327 335
328table.diffstat { 336table.diffstat {
329 border-collapse: collapse; 337 border-collapse: collapse;
330 border: solid 1px #aaa; 338 border: solid 1px #aaa;
331 background-color: #eee; 339 background-color: #eee;
332} 340}
333 341
334table.diffstat th { 342table.diffstat th {
335 font-weight: normal; 343 font-weight: normal;
336 text-align: left; 344 text-align: left;
337 text-decoration: underline; 345 text-decoration: underline;
338 padding: 0.1em 1em 0.1em 0.1em; 346 padding: 0.1em 1em 0.1em 0.1em;
339 font-size: 100%; 347 font-size: 100%;
340} 348}
341 349
342table.diffstat td { 350table.diffstat td {
343 padding: 0.2em 0.2em 0.1em 0.1em; 351 padding: 0.2em 0.2em 0.1em 0.1em;
344 font-size: 100%; 352 font-size: 100%;
345 border: none; 353 border: none;
346} 354}
347 355
348table.diffstat td.mode { 356table.diffstat td.mode {
349 white-space: nowrap; 357 white-space: nowrap;
350} 358}
351 359
352table.diffstat td span.modechange { 360table.diffstat td span.modechange {
353 padding-left: 1em; 361 padding-left: 1em;
354 color: red; 362 color: red;
355} 363}
356 364
357table.diffstat td.add a { 365table.diffstat td.add a {
358 color: green; 366 color: green;
359} 367}
360 368
361table.diffstat td.del a { 369table.diffstat td.del a {
362 color: red; 370 color: red;
363} 371}
364 372
365table.diffstat td.upd a { 373table.diffstat td.upd a {
366 color: blue; 374 color: blue;
367} 375}
368 376
369table.diffstat td.graph { 377table.diffstat td.graph {
370 width: 500px; 378 width: 500px;
371 vertical-align: middle; 379 vertical-align: middle;
372} 380}
373 381
374table.diffstat td.graph table { 382table.diffstat td.graph table {
375 border: none; 383 border: none;
376} 384}
377 385
378table.diffstat td.graph td { 386table.diffstat td.graph td {
379 padding: 0px; 387 padding: 0px;
380 border: 0px; 388 border: 0px;
381 height: 7pt; 389 height: 7pt;
382} 390}
383 391
384table.diffstat td.graph td.add { 392table.diffstat td.graph td.add {
385 background-color: #5c5; 393 background-color: #5c5;
386} 394}
387 395
388table.diffstat td.graph td.rem { 396table.diffstat td.graph td.rem {
389 background-color: #c55; 397 background-color: #c55;
390} 398}
391 399
392div.diffstat-summary { 400div.diffstat-summary {
393 color: #888; 401 color: #888;
394 padding-top: 0.5em; 402 padding-top: 0.5em;
395} 403}
396 404
397table.diff { 405table.diff {
398 width: 100%; 406 width: 100%;
399} 407}
400 408
401table.diff td { 409table.diff td {
402 font-family: monospace; 410 font-family: monospace;
403 white-space: pre; 411 white-space: pre;
404} 412}
405 413
406table.diff td div.head { 414table.diff td div.head {
407 font-weight: bold; 415 font-weight: bold;
408 margin-top: 1em; 416 margin-top: 1em;
409 color: black; 417 color: black;
410} 418}
411 419
412table.diff td div.hunk { 420table.diff td div.hunk {
413 color: #009; 421 color: #009;
414} 422}
415 423
416table.diff td div.add { 424table.diff td div.add {
417 color: green; 425 color: green;
418} 426}
419 427
420table.diff td div.del { 428table.diff td div.del {
421 color: red; 429 color: red;
422} 430}
423 431
424.sha1 { 432.sha1 {
425 font-family: monospace; 433 font-family: monospace;
426 font-size: 90%; 434 font-size: 90%;
427} 435}
428 436
429.left { 437.left {
430 text-align: left; 438 text-align: left;
431} 439}
432 440
433.right { 441.right {
434 text-align: right; 442 text-align: right;
435} 443}
436 444
437table.list td.reposection { 445table.list td.reposection {
438 font-style: italic; 446 font-style: italic;
439 color: #888; 447 color: #888;
440} 448}
441 449
442a.button { 450a.button {
443 font-size: 80%; 451 font-size: 80%;
444 padding: 0em 0.5em; 452 padding: 0em 0.5em;
445} 453}
446 454
447a.primary { 455a.primary {
448 font-size: 100%; 456 font-size: 100%;
449} 457}
450 458
451a.secondary { 459a.secondary {
452 font-size: 90%; 460 font-size: 90%;
453} 461}
454 462
455td.toplevel-repo { 463td.toplevel-repo {
456 464
457} 465}
458 466
459table.list td.sublevel-repo { 467table.list td.sublevel-repo {
460 padding-left: 1.5em; 468 padding-left: 1.5em;
461} 469}
462 470
463div.pager { 471div.pager {
464 text-align: center; 472 text-align: center;
465 margin: 1em 0em 0em 0em; 473 margin: 1em 0em 0em 0em;
466} 474}
467 475
468div.pager a { 476div.pager a {
469 color: #777; 477 color: #777;
470 margin: 0em 0.5em; 478 margin: 0em 0.5em;
471} 479}
472 480
473span.age-mins { 481span.age-mins {
474 font-weight: bold; 482 font-weight: bold;
475 color: #080; 483 color: #080;
476} 484}
477 485
478span.age-hours { 486span.age-hours {
479 color: #080; 487 color: #080;
480} 488}
481 489
482span.age-days { 490span.age-days {
483 color: #040; 491 color: #040;
484} 492}
485 493
486span.age-weeks { 494span.age-weeks {
487 color: #444; 495 color: #444;
488} 496}
489 497
490span.age-months { 498span.age-months {
491 color: #888; 499 color: #888;
492} 500}
493 501
494span.age-years { 502span.age-years {
495 color: #bbb; 503 color: #bbb;
496} 504}
497div.footer { 505div.footer {
498 margin-top: 0.5em; 506 margin-top: 0.5em;
499 text-align: center; 507 text-align: center;
500 font-size: 80%; 508 font-size: 80%;
501 color: #ccc; 509 color: #ccc;
502} 510}
503a.branch-deco { 511a.branch-deco {
504 margin: 0px 0.5em; 512 margin: 0px 0.5em;
505 padding: 0px 0.25em; 513 padding: 0px 0.25em;
506 background-color: #88ff88; 514 background-color: #88ff88;
507 border: solid 1px #007700; 515 border: solid 1px #007700;
508} 516}
509a.tag-deco { 517a.tag-deco {
510 margin: 0px 0.5em; 518 margin: 0px 0.5em;
511 padding: 0px 0.25em; 519 padding: 0px 0.25em;
512 background-color: #ffff88; 520 background-color: #ffff88;
513 border: solid 1px #777700; 521 border: solid 1px #777700;
514} 522}
515a.remote-deco { 523a.remote-deco {
516 margin: 0px 0.5em; 524 margin: 0px 0.5em;
517 padding: 0px 0.25em; 525 padding: 0px 0.25em;
518 background-color: #ccccff; 526 background-color: #ccccff;
519 border: solid 1px #000077; 527 border: solid 1px #000077;
520} 528}
521a.deco { 529a.deco {
522 margin: 0px 0.5em; 530 margin: 0px 0.5em;
523 padding: 0px 0.25em; 531 padding: 0px 0.25em;
524 background-color: #ff8888; 532 background-color: #ff8888;
525 border: solid 1px #770000; 533 border: solid 1px #770000;
526} 534}
527 535
528div.commit-subject a { 536div.commit-subject a {
529 margin-left: 1em; 537 margin-left: 1em;
530 font-size: 75%; 538 font-size: 75%;
531} 539}
532 540
533table.stats { 541table.stats {
534 border: solid 1px black; 542 border: solid 1px black;
535 border-collapse: collapse; 543 border-collapse: collapse;
536} 544}
537 545
538table.stats th { 546table.stats th {
539 text-align: left; 547 text-align: left;
540 padding: 1px 0.5em; 548 padding: 1px 0.5em;
541 background-color: #eee; 549 background-color: #eee;
542 border: solid 1px black; 550 border: solid 1px black;
543} 551}
544 552
545table.stats td { 553table.stats td {
546 text-align: right; 554 text-align: right;
547 padding: 1px 0.5em; 555 padding: 1px 0.5em;
548 border: solid 1px black; 556 border: solid 1px black;
549} 557}
550 558
551table.stats td.total { 559table.stats td.total {
552 font-weight: bold; 560 font-weight: bold;
553 text-align: left; 561 text-align: left;
554} 562}
555 563
556table.stats td.sum { 564table.stats td.sum {
557 color: #c00; 565 color: #c00;
558 font-weight: bold; 566 font-weight: bold;
559 /*background-color: #eee; */ 567 /*background-color: #eee; */
560} 568}
561 569
562table.stats td.left { 570table.stats td.left {
563 text-align: left; 571 text-align: left;
564} 572}
565 573
566table.vgraph { 574table.vgraph {
567 border-collapse: separate; 575 border-collapse: separate;
568 border: solid 1px black; 576 border: solid 1px black;
569 height: 200px; 577 height: 200px;
570} 578}
571 579
572table.vgraph th { 580table.vgraph th {
573 background-color: #eee; 581 background-color: #eee;
574 font-weight: bold; 582 font-weight: bold;
575 border: solid 1px white; 583 border: solid 1px white;
576 padding: 1px 0.5em; 584 padding: 1px 0.5em;
577} 585}
578 586
579table.vgraph td { 587table.vgraph td {
580 vertical-align: bottom; 588 vertical-align: bottom;
581 padding: 0px 10px; 589 padding: 0px 10px;
582} 590}
583 591
584table.vgraph div.bar { 592table.vgraph div.bar {
585 background-color: #eee; 593 background-color: #eee;
586} 594}
587 595
588table.hgraph { 596table.hgraph {
589 border: solid 1px black; 597 border: solid 1px black;
590 width: 800px; 598 width: 800px;
591} 599}
592 600
593table.hgraph th { 601table.hgraph th {
594 background-color: #eee; 602 background-color: #eee;
595 font-weight: bold; 603 font-weight: bold;
596 border: solid 1px black; 604 border: solid 1px black;
597 padding: 1px 0.5em; 605 padding: 1px 0.5em;
598} 606}
599 607
600table.hgraph td { 608table.hgraph td {
601 vertical-align: center; 609 vertical-align: center;
602 padding: 2px 2px; 610 padding: 2px 2px;
603} 611}
604 612
605table.hgraph div.bar { 613table.hgraph div.bar {
606 background-color: #eee; 614 background-color: #eee;
607 height: 1em; 615 height: 1em;
608} 616}
609 617
610table.ssdiff { 618table.ssdiff {
611 width: 100%; 619 width: 100%;
612} 620}
613 621
614table.ssdiff td { 622table.ssdiff td {
615 font-size: 75%; 623 font-size: 75%;
616 font-family: monospace; 624 font-family: monospace;
617 white-space: pre; 625 white-space: pre;
618 padding: 1px 4px 1px 4px; 626 padding: 1px 4px 1px 4px;
619 border-left: solid 1px #aaa; 627 border-left: solid 1px #aaa;
620 border-right: solid 1px #aaa; 628 border-right: solid 1px #aaa;
621} 629}
622 630
623table.ssdiff td.add { 631table.ssdiff td.add {
624 color: black; 632 color: black;
625 background: #cfc; 633 background: #cfc;
626 min-width: 50%; 634 min-width: 50%;
627} 635}
628 636
629table.ssdiff td.add_dark { 637table.ssdiff td.add_dark {
630 color: black; 638 color: black;
631 background: #aca; 639 background: #aca;
632 min-width: 50%; 640 min-width: 50%;
633} 641}
634 642
635table.ssdiff span.add { 643table.ssdiff span.add {
636 background: #cfc; 644 background: #cfc;
637 font-weight: bold; 645 font-weight: bold;
638} 646}
639 647
640table.ssdiff td.del { 648table.ssdiff td.del {
641 color: black; 649 color: black;
642 background: #fcc; 650 background: #fcc;
643 min-width: 50%; 651 min-width: 50%;
644} 652}
645 653
646table.ssdiff td.del_dark { 654table.ssdiff td.del_dark {
647 color: black; 655 color: black;
648 background: #caa; 656 background: #caa;
649 min-width: 50%; 657 min-width: 50%;
650} 658}
651 659
652table.ssdiff span.del { 660table.ssdiff span.del {
653 background: #fcc; 661 background: #fcc;
654 font-weight: bold; 662 font-weight: bold;
655} 663}
656 664
657table.ssdiff td.changed { 665table.ssdiff td.changed {
658 color: black; 666 color: black;
659 background: #ffc; 667 background: #ffc;
660 min-width: 50%; 668 min-width: 50%;
661} 669}
662 670
663table.ssdiff td.changed_dark { 671table.ssdiff td.changed_dark {
664 color: black; 672 color: black;
665 background: #cca; 673 background: #cca;
666 min-width: 50%; 674 min-width: 50%;
667} 675}
668 676
669table.ssdiff td.lineno { 677table.ssdiff td.lineno {
670 color: black; 678 color: black;
671 background: #eee; 679 background: #eee;
672 text-align: right; 680 text-align: right;
673 width: 3em; 681 width: 3em;
674 min-width: 3em; 682 min-width: 3em;
675} 683}
676 684
677table.ssdiff td.hunk { 685table.ssdiff td.hunk {
678 color: #black; 686 color: #black;
679 background: #ccf; 687 background: #ccf;
680 border-top: solid 1px #aaa; 688 border-top: solid 1px #aaa;
681 border-bottom: solid 1px #aaa; 689 border-bottom: solid 1px #aaa;
682} 690}
683 691
684table.ssdiff td.head { 692table.ssdiff td.head {
685 border-top: solid 1px #aaa; 693 border-top: solid 1px #aaa;
686 border-bottom: solid 1px #aaa; 694 border-bottom: solid 1px #aaa;
687} 695}
688 696
689table.ssdiff td.head div.head { 697table.ssdiff td.head div.head {
690 font-weight: bold; 698 font-weight: bold;
691 color: black; 699 color: black;
692} 700}
693 701
694table.ssdiff td.foot { 702table.ssdiff td.foot {
695 border-top: solid 1px #aaa; 703 border-top: solid 1px #aaa;
696 border-left: none; 704 border-left: none;
697 border-right: none; 705 border-right: none;
698 border-bottom: none; 706 border-bottom: none;
699} 707}
700 708
701table.ssdiff td.space { 709table.ssdiff td.space {
702 border: none; 710 border: none;
703} 711}
704 712
705table.ssdiff td.space div { 713table.ssdiff td.space div {
706 min-height: 3em; 714 min-height: 3em;
707} \ No newline at end of file 715} \ No newline at end of file
diff --git a/ui-shared.c b/ui-shared.c
index 3d5030b..bc14e70 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -1,797 +1,803 @@
1/* ui-shared.c: common web output functions 1/* ui-shared.c: common web output functions
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "cmd.h" 10#include "cmd.h"
11#include "html.h" 11#include "html.h"
12 12
13const char cgit_doctype[] = 13const char cgit_doctype[] =
14"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 14"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
15" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; 15" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
16 16
17static char *http_date(time_t t) 17static char *http_date(time_t t)
18{ 18{
19 static char day[][4] = 19 static char day[][4] =
20 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 20 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
21 static char month[][4] = 21 static char month[][4] =
22 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 22 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
23 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 23 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
24 struct tm *tm = gmtime(&t); 24 struct tm *tm = gmtime(&t);
25 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], 25 return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
26 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year, 26 tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year,
27 tm->tm_hour, tm->tm_min, tm->tm_sec); 27 tm->tm_hour, tm->tm_min, tm->tm_sec);
28} 28}
29 29
30void cgit_print_error(const char *msg) 30void cgit_print_error(const char *msg)
31{ 31{
32 html("<div class='error'>"); 32 html("<div class='error'>");
33 html_txt(msg); 33 html_txt(msg);
34 html("</div>\n"); 34 html("</div>\n");
35} 35}
36 36
37char *cgit_httpscheme() 37char *cgit_httpscheme()
38{ 38{
39 if (ctx.env.https && !strcmp(ctx.env.https, "on")) 39 if (ctx.env.https && !strcmp(ctx.env.https, "on"))
40 return "https://"; 40 return "https://";
41 else 41 else
42 return "http://"; 42 return "http://";
43} 43}
44 44
45char *cgit_hosturl() 45char *cgit_hosturl()
46{ 46{
47 if (ctx.env.http_host) 47 if (ctx.env.http_host)
48 return ctx.env.http_host; 48 return ctx.env.http_host;
49 if (!ctx.env.server_name) 49 if (!ctx.env.server_name)
50 return NULL; 50 return NULL;
51 if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) 51 if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80)
52 return ctx.env.server_name; 52 return ctx.env.server_name;
53 return xstrdup(fmt("%s:%s", ctx.env.server_name, ctx.env.server_port)); 53 return xstrdup(fmt("%s:%s", ctx.env.server_name, ctx.env.server_port));
54} 54}
55 55
56char *cgit_rooturl() 56char *cgit_rooturl()
57{ 57{
58 if (ctx.cfg.virtual_root) 58 if (ctx.cfg.virtual_root)
59 return fmt("%s/", ctx.cfg.virtual_root); 59 return fmt("%s/", ctx.cfg.virtual_root);
60 else 60 else
61 return ctx.cfg.script_name; 61 return ctx.cfg.script_name;
62} 62}
63 63
64char *cgit_repourl(const char *reponame) 64char *cgit_repourl(const char *reponame)
65{ 65{
66 if (ctx.cfg.virtual_root) { 66 if (ctx.cfg.virtual_root) {
67 return fmt("%s/%s/", ctx.cfg.virtual_root, reponame); 67 return fmt("%s/%s/", ctx.cfg.virtual_root, reponame);
68 } else { 68 } else {
69 return fmt("?r=%s", reponame); 69 return fmt("?r=%s", reponame);
70 } 70 }
71} 71}
72 72
73char *cgit_fileurl(const char *reponame, const char *pagename, 73char *cgit_fileurl(const char *reponame, const char *pagename,
74 const char *filename, const char *query) 74 const char *filename, const char *query)
75{ 75{
76 char *tmp; 76 char *tmp;
77 char *delim; 77 char *delim;
78 78
79 if (ctx.cfg.virtual_root) { 79 if (ctx.cfg.virtual_root) {
80 tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame, 80 tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame,
81 pagename, (filename ? filename:"")); 81 pagename, (filename ? filename:""));
82 delim = "?"; 82 delim = "?";
83 } else { 83 } else {
84 tmp = fmt("?url=%s/%s/%s", reponame, pagename, 84 tmp = fmt("?url=%s/%s/%s", reponame, pagename,
85 (filename ? filename : "")); 85 (filename ? filename : ""));
86 delim = "&"; 86 delim = "&";
87 } 87 }
88 if (query) 88 if (query)
89 tmp = fmt("%s%s%s", tmp, delim, query); 89 tmp = fmt("%s%s%s", tmp, delim, query);
90 return tmp; 90 return tmp;
91} 91}
92 92
93char *cgit_pageurl(const char *reponame, const char *pagename, 93char *cgit_pageurl(const char *reponame, const char *pagename,
94 const char *query) 94 const char *query)
95{ 95{
96 return cgit_fileurl(reponame,pagename,0,query); 96 return cgit_fileurl(reponame,pagename,0,query);
97} 97}
98 98
99const char *cgit_repobasename(const char *reponame) 99const char *cgit_repobasename(const char *reponame)
100{ 100{
101 /* I assume we don't need to store more than one repo basename */ 101 /* I assume we don't need to store more than one repo basename */
102 static char rvbuf[1024]; 102 static char rvbuf[1024];
103 int p; 103 int p;
104 const char *rv; 104 const char *rv;
105 strncpy(rvbuf,reponame,sizeof(rvbuf)); 105 strncpy(rvbuf,reponame,sizeof(rvbuf));
106 if(rvbuf[sizeof(rvbuf)-1]) 106 if(rvbuf[sizeof(rvbuf)-1])
107 die("cgit_repobasename: truncated repository name '%s'", reponame); 107 die("cgit_repobasename: truncated repository name '%s'", reponame);
108 p = strlen(rvbuf)-1; 108 p = strlen(rvbuf)-1;
109 /* strip trailing slashes */ 109 /* strip trailing slashes */
110 while(p && rvbuf[p]=='/') rvbuf[p--]=0; 110 while(p && rvbuf[p]=='/') rvbuf[p--]=0;
111 /* strip trailing .git */ 111 /* strip trailing .git */
112 if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { 112 if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) {
113 p -= 3; rvbuf[p--] = 0; 113 p -= 3; rvbuf[p--] = 0;
114 } 114 }
115 /* strip more trailing slashes if any */ 115 /* strip more trailing slashes if any */
116 while( p && rvbuf[p]=='/') rvbuf[p--]=0; 116 while( p && rvbuf[p]=='/') rvbuf[p--]=0;
117 /* find last slash in the remaining string */ 117 /* find last slash in the remaining string */
118 rv = strrchr(rvbuf,'/'); 118 rv = strrchr(rvbuf,'/');
119 if(rv) 119 if(rv)
120 return ++rv; 120 return ++rv;
121 return rvbuf; 121 return rvbuf;
122} 122}
123 123
124char *cgit_currurl() 124char *cgit_currurl()
125{ 125{
126 if (!ctx.cfg.virtual_root) 126 if (!ctx.cfg.virtual_root)
127 return ctx.cfg.script_name; 127 return ctx.cfg.script_name;
128 else if (ctx.qry.page) 128 else if (ctx.qry.page)
129 return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page); 129 return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page);
130 else if (ctx.qry.repo) 130 else if (ctx.qry.repo)
131 return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo); 131 return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo);
132 else 132 else
133 return fmt("%s/", ctx.cfg.virtual_root); 133 return fmt("%s/", ctx.cfg.virtual_root);
134} 134}
135 135
136static void site_url(const char *page, const char *search, int ofs) 136static void site_url(const char *page, const char *search, int ofs)
137{ 137{
138 char *delim = "?"; 138 char *delim = "?";
139 139
140 if (ctx.cfg.virtual_root) { 140 if (ctx.cfg.virtual_root) {
141 html_attr(ctx.cfg.virtual_root); 141 html_attr(ctx.cfg.virtual_root);
142 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') 142 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
143 html("/"); 143 html("/");
144 } else 144 } else
145 html(ctx.cfg.script_name); 145 html(ctx.cfg.script_name);
146 146
147 if (page) { 147 if (page) {
148 htmlf("?p=%s", page); 148 htmlf("?p=%s", page);
149 delim = "&"; 149 delim = "&";
150 } 150 }
151 if (search) { 151 if (search) {
152 html(delim); 152 html(delim);
153 html("q="); 153 html("q=");
154 html_attr(search); 154 html_attr(search);
155 delim = "&"; 155 delim = "&";
156 } 156 }
157 if (ofs) { 157 if (ofs) {
158 html(delim); 158 html(delim);
159 htmlf("ofs=%d", ofs); 159 htmlf("ofs=%d", ofs);
160 } 160 }
161} 161}
162 162
163static void site_link(const char *page, const char *name, const char *title, 163static void site_link(const char *page, const char *name, const char *title,
164 const char *class, const char *search, int ofs) 164 const char *class, const char *search, int ofs)
165{ 165{
166 html("<a"); 166 html("<a");
167 if (title) { 167 if (title) {
168 html(" title='"); 168 html(" title='");
169 html_attr(title); 169 html_attr(title);
170 html("'"); 170 html("'");
171 } 171 }
172 if (class) { 172 if (class) {
173 html(" class='"); 173 html(" class='");
174 html_attr(class); 174 html_attr(class);
175 html("'"); 175 html("'");
176 } 176 }
177 html(" href='"); 177 html(" href='");
178 site_url(page, search, ofs); 178 site_url(page, search, ofs);
179 html("'>"); 179 html("'>");
180 html_txt(name); 180 html_txt(name);
181 html("</a>"); 181 html("</a>");
182} 182}
183 183
184void cgit_index_link(const char *name, const char *title, const char *class, 184void cgit_index_link(const char *name, const char *title, const char *class,
185 const char *pattern, int ofs) 185 const char *pattern, int ofs)
186{ 186{
187 site_link(NULL, name, title, class, pattern, ofs); 187 site_link(NULL, name, title, class, pattern, ofs);
188} 188}
189 189
190static char *repolink(const char *title, const char *class, const char *page, 190static char *repolink(const char *title, const char *class, const char *page,
191 const char *head, const char *path) 191 const char *head, const char *path)
192{ 192{
193 char *delim = "?"; 193 char *delim = "?";
194 194
195 html("<a"); 195 html("<a");
196 if (title) { 196 if (title) {
197 html(" title='"); 197 html(" title='");
198 html_attr(title); 198 html_attr(title);
199 html("'"); 199 html("'");
200 } 200 }
201 if (class) { 201 if (class) {
202 html(" class='"); 202 html(" class='");
203 html_attr(class); 203 html_attr(class);
204 html("'"); 204 html("'");
205 } 205 }
206 html(" href='"); 206 html(" href='");
207 if (ctx.cfg.virtual_root) { 207 if (ctx.cfg.virtual_root) {
208 html_url_path(ctx.cfg.virtual_root); 208 html_url_path(ctx.cfg.virtual_root);
209 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/') 209 if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')
210 html("/"); 210 html("/");
211 html_url_path(ctx.repo->url); 211 html_url_path(ctx.repo->url);
212 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') 212 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
213 html("/"); 213 html("/");
214 if (page) { 214 if (page) {
215 html_url_path(page); 215 html_url_path(page);
216 html("/"); 216 html("/");
217 if (path) 217 if (path)
218 html_url_path(path); 218 html_url_path(path);
219 } 219 }
220 } else { 220 } else {
221 html(ctx.cfg.script_name); 221 html(ctx.cfg.script_name);
222 html("?url="); 222 html("?url=");
223 html_url_arg(ctx.repo->url); 223 html_url_arg(ctx.repo->url);
224 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/') 224 if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')
225 html("/"); 225 html("/");
226 if (page) { 226 if (page) {
227 html_url_arg(page); 227 html_url_arg(page);
228 html("/"); 228 html("/");
229 if (path) 229 if (path)
230 html_url_arg(path); 230 html_url_arg(path);
231 } 231 }
232 delim = "&amp;"; 232 delim = "&amp;";
233 } 233 }
234 if (head && strcmp(head, ctx.repo->defbranch)) { 234 if (head && strcmp(head, ctx.repo->defbranch)) {
235 html(delim); 235 html(delim);
236 html("h="); 236 html("h=");
237 html_url_arg(head); 237 html_url_arg(head);
238 delim = "&amp;"; 238 delim = "&amp;";
239 } 239 }
240 return fmt("%s", delim); 240 return fmt("%s", delim);
241} 241}
242 242
243static void reporevlink(const char *page, const char *name, const char *title, 243static void reporevlink(const char *page, const char *name, const char *title,
244 const char *class, const char *head, const char *rev, 244 const char *class, const char *head, const char *rev,
245 const char *path) 245 const char *path)
246{ 246{
247 char *delim; 247 char *delim;
248 248
249 delim = repolink(title, class, page, head, path); 249 delim = repolink(title, class, page, head, path);
250 if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { 250 if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) {
251 html(delim); 251 html(delim);
252 html("id="); 252 html("id=");
253 html_url_arg(rev); 253 html_url_arg(rev);
254 } 254 }
255 html("'>"); 255 html("'>");
256 html_txt(name); 256 html_txt(name);
257 html("</a>"); 257 html("</a>");
258} 258}
259 259
260void cgit_summary_link(const char *name, const char *title, const char *class, 260void cgit_summary_link(const char *name, const char *title, const char *class,
261 const char *head) 261 const char *head)
262{ 262{
263 reporevlink(NULL, name, title, class, head, NULL, NULL); 263 reporevlink(NULL, name, title, class, head, NULL, NULL);
264} 264}
265 265
266void cgit_tag_link(const char *name, const char *title, const char *class, 266void cgit_tag_link(const char *name, const char *title, const char *class,
267 const char *head, const char *rev) 267 const char *head, const char *rev)
268{ 268{
269 reporevlink("tag", name, title, class, head, rev, NULL); 269 reporevlink("tag", name, title, class, head, rev, NULL);
270} 270}
271 271
272void cgit_tree_link(const char *name, const char *title, const char *class, 272void cgit_tree_link(const char *name, const char *title, const char *class,
273 const char *head, const char *rev, const char *path) 273 const char *head, const char *rev, const char *path)
274{ 274{
275 reporevlink("tree", name, title, class, head, rev, path); 275 reporevlink("tree", name, title, class, head, rev, path);
276} 276}
277 277
278void cgit_plain_link(const char *name, const char *title, const char *class, 278void cgit_plain_link(const char *name, const char *title, const char *class,
279 const char *head, const char *rev, const char *path) 279 const char *head, const char *rev, const char *path)
280{ 280{
281 reporevlink("plain", name, title, class, head, rev, path); 281 reporevlink("plain", name, title, class, head, rev, path);
282} 282}
283 283
284void cgit_log_link(const char *name, const char *title, const char *class, 284void cgit_log_link(const char *name, const char *title, const char *class,
285 const char *head, const char *rev, const char *path, 285 const char *head, const char *rev, const char *path,
286 int ofs, const char *grep, const char *pattern, int showmsg) 286 int ofs, const char *grep, const char *pattern, int showmsg)
287{ 287{
288 char *delim; 288 char *delim;
289 289
290 delim = repolink(title, class, "log", head, path); 290 delim = repolink(title, class, "log", head, path);
291 if (rev && strcmp(rev, ctx.qry.head)) { 291 if (rev && strcmp(rev, ctx.qry.head)) {
292 html(delim); 292 html(delim);
293 html("id="); 293 html("id=");
294 html_url_arg(rev); 294 html_url_arg(rev);
295 delim = "&"; 295 delim = "&";
296 } 296 }
297 if (grep && pattern) { 297 if (grep && pattern) {
298 html(delim); 298 html(delim);
299 html("qt="); 299 html("qt=");
300 html_url_arg(grep); 300 html_url_arg(grep);
301 delim = "&"; 301 delim = "&";
302 html(delim); 302 html(delim);
303 html("q="); 303 html("q=");
304 html_url_arg(pattern); 304 html_url_arg(pattern);
305 } 305 }
306 if (ofs > 0) { 306 if (ofs > 0) {
307 html(delim); 307 html(delim);
308 html("ofs="); 308 html("ofs=");
309 htmlf("%d", ofs); 309 htmlf("%d", ofs);
310 delim = "&"; 310 delim = "&";
311 } 311 }
312 if (showmsg) { 312 if (showmsg) {
313 html(delim); 313 html(delim);
314 html("showmsg=1"); 314 html("showmsg=1");
315 } 315 }
316 html("'>"); 316 html("'>");
317 html_txt(name); 317 html_txt(name);
318 html("</a>"); 318 html("</a>");
319} 319}
320 320
321void cgit_commit_link(char *name, const char *title, const char *class, 321void cgit_commit_link(char *name, const char *title, const char *class,
322 const char *head, const char *rev, int toggle_ssdiff) 322 const char *head, const char *rev, int toggle_ssdiff)
323{ 323{
324 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { 324 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
325 name[ctx.cfg.max_msg_len] = '\0'; 325 name[ctx.cfg.max_msg_len] = '\0';
326 name[ctx.cfg.max_msg_len - 1] = '.'; 326 name[ctx.cfg.max_msg_len - 1] = '.';
327 name[ctx.cfg.max_msg_len - 2] = '.'; 327 name[ctx.cfg.max_msg_len - 2] = '.';
328 name[ctx.cfg.max_msg_len - 3] = '.'; 328 name[ctx.cfg.max_msg_len - 3] = '.';
329 } 329 }
330 330
331 char *delim; 331 char *delim;
332 332
333 delim = repolink(title, class, "commit", head, NULL); 333 delim = repolink(title, class, "commit", head, NULL);
334 if (rev && strcmp(rev, ctx.qry.head)) { 334 if (rev && strcmp(rev, ctx.qry.head)) {
335 html(delim); 335 html(delim);
336 html("id="); 336 html("id=");
337 html_url_arg(rev); 337 html_url_arg(rev);
338 delim = "&amp;"; 338 delim = "&amp;";
339 } 339 }
340 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { 340 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
341 html(delim); 341 html(delim);
342 html("ss=1"); 342 html("ss=1");
343 } 343 }
344 html("'>"); 344 html("'>");
345 html_txt(name); 345 html_txt(name);
346 html("</a>"); 346 html("</a>");
347} 347}
348 348
349void cgit_refs_link(const char *name, const char *title, const char *class, 349void cgit_refs_link(const char *name, const char *title, const char *class,
350 const char *head, const char *rev, const char *path) 350 const char *head, const char *rev, const char *path)
351{ 351{
352 reporevlink("refs", name, title, class, head, rev, path); 352 reporevlink("refs", name, title, class, head, rev, path);
353} 353}
354 354
355void cgit_snapshot_link(const char *name, const char *title, const char *class, 355void cgit_snapshot_link(const char *name, const char *title, const char *class,
356 const char *head, const char *rev, 356 const char *head, const char *rev,
357 const char *archivename) 357 const char *archivename)
358{ 358{
359 reporevlink("snapshot", name, title, class, head, rev, archivename); 359 reporevlink("snapshot", name, title, class, head, rev, archivename);
360} 360}
361 361
362void cgit_diff_link(const char *name, const char *title, const char *class, 362void cgit_diff_link(const char *name, const char *title, const char *class,
363 const char *head, const char *new_rev, const char *old_rev, 363 const char *head, const char *new_rev, const char *old_rev,
364 const char *path, int toggle_ssdiff) 364 const char *path, int toggle_ssdiff)
365{ 365{
366 char *delim; 366 char *delim;
367 367
368 delim = repolink(title, class, "diff", head, path); 368 delim = repolink(title, class, "diff", head, path);
369 if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) { 369 if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) {
370 html(delim); 370 html(delim);
371 html("id="); 371 html("id=");
372 html_url_arg(new_rev); 372 html_url_arg(new_rev);
373 delim = "&amp;"; 373 delim = "&amp;";
374 } 374 }
375 if (old_rev) { 375 if (old_rev) {
376 html(delim); 376 html(delim);
377 html("id2="); 377 html("id2=");
378 html_url_arg(old_rev); 378 html_url_arg(old_rev);
379 delim = "&amp;"; 379 delim = "&amp;";
380 } 380 }
381 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { 381 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
382 html(delim); 382 html(delim);
383 html("ss=1"); 383 html("ss=1");
384 } 384 }
385 html("'>"); 385 html("'>");
386 html_txt(name); 386 html_txt(name);
387 html("</a>"); 387 html("</a>");
388} 388}
389 389
390void cgit_patch_link(const char *name, const char *title, const char *class, 390void cgit_patch_link(const char *name, const char *title, const char *class,
391 const char *head, const char *rev) 391 const char *head, const char *rev)
392{ 392{
393 reporevlink("patch", name, title, class, head, rev, NULL); 393 reporevlink("patch", name, title, class, head, rev, NULL);
394} 394}
395 395
396void cgit_stats_link(const char *name, const char *title, const char *class, 396void cgit_stats_link(const char *name, const char *title, const char *class,
397 const char *head, const char *path) 397 const char *head, const char *path)
398{ 398{
399 reporevlink("stats", name, title, class, head, NULL, path); 399 reporevlink("stats", name, title, class, head, NULL, path);
400} 400}
401 401
402void cgit_object_link(struct object *obj) 402void cgit_object_link(struct object *obj)
403{ 403{
404 char *page, *shortrev, *fullrev, *name; 404 char *page, *shortrev, *fullrev, *name;
405 405
406 fullrev = sha1_to_hex(obj->sha1); 406 fullrev = sha1_to_hex(obj->sha1);
407 shortrev = xstrdup(fullrev); 407 shortrev = xstrdup(fullrev);
408 shortrev[10] = '\0'; 408 shortrev[10] = '\0';
409 if (obj->type == OBJ_COMMIT) { 409 if (obj->type == OBJ_COMMIT) {
410 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, 410 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
411 ctx.qry.head, fullrev, 0); 411 ctx.qry.head, fullrev, 0);
412 return; 412 return;
413 } else if (obj->type == OBJ_TREE) 413 } else if (obj->type == OBJ_TREE)
414 page = "tree"; 414 page = "tree";
415 else if (obj->type == OBJ_TAG) 415 else if (obj->type == OBJ_TAG)
416 page = "tag"; 416 page = "tag";
417 else 417 else
418 page = "blob"; 418 page = "blob";
419 name = fmt("%s %s...", typename(obj->type), shortrev); 419 name = fmt("%s %s...", typename(obj->type), shortrev);
420 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); 420 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
421} 421}
422 422
423void cgit_print_date(time_t secs, const char *format, int local_time) 423void cgit_print_date(time_t secs, const char *format, int local_time)
424{ 424{
425 char buf[64]; 425 char buf[64];
426 struct tm *time; 426 struct tm *time;
427 427
428 if (!secs) 428 if (!secs)
429 return; 429 return;
430 if(local_time) 430 if(local_time)
431 time = localtime(&secs); 431 time = localtime(&secs);
432 else 432 else
433 time = gmtime(&secs); 433 time = gmtime(&secs);
434 strftime(buf, sizeof(buf)-1, format, time); 434 strftime(buf, sizeof(buf)-1, format, time);
435 html_txt(buf); 435 html_txt(buf);
436} 436}
437 437
438void cgit_print_age(time_t t, time_t max_relative, const char *format) 438void cgit_print_age(time_t t, time_t max_relative, const char *format)
439{ 439{
440 time_t now, secs; 440 time_t now, secs;
441 441
442 if (!t) 442 if (!t)
443 return; 443 return;
444 time(&now); 444 time(&now);
445 secs = now - t; 445 secs = now - t;
446 446
447 if (secs > max_relative && max_relative >= 0) { 447 if (secs > max_relative && max_relative >= 0) {
448 cgit_print_date(t, format, ctx.cfg.local_time); 448 cgit_print_date(t, format, ctx.cfg.local_time);
449 return; 449 return;
450 } 450 }
451 451
452 if (secs < TM_HOUR * 2) { 452 if (secs < TM_HOUR * 2) {
453 htmlf("<span class='age-mins'>%.0f min.</span>", 453 htmlf("<span class='age-mins'>%.0f min.</span>",
454 secs * 1.0 / TM_MIN); 454 secs * 1.0 / TM_MIN);
455 return; 455 return;
456 } 456 }
457 if (secs < TM_DAY * 2) { 457 if (secs < TM_DAY * 2) {
458 htmlf("<span class='age-hours'>%.0f hours</span>", 458 htmlf("<span class='age-hours'>%.0f hours</span>",
459 secs * 1.0 / TM_HOUR); 459 secs * 1.0 / TM_HOUR);
460 return; 460 return;
461 } 461 }
462 if (secs < TM_WEEK * 2) { 462 if (secs < TM_WEEK * 2) {
463 htmlf("<span class='age-days'>%.0f days</span>", 463 htmlf("<span class='age-days'>%.0f days</span>",
464 secs * 1.0 / TM_DAY); 464 secs * 1.0 / TM_DAY);
465 return; 465 return;
466 } 466 }
467 if (secs < TM_MONTH * 2) { 467 if (secs < TM_MONTH * 2) {
468 htmlf("<span class='age-weeks'>%.0f weeks</span>", 468 htmlf("<span class='age-weeks'>%.0f weeks</span>",
469 secs * 1.0 / TM_WEEK); 469 secs * 1.0 / TM_WEEK);
470 return; 470 return;
471 } 471 }
472 if (secs < TM_YEAR * 2) { 472 if (secs < TM_YEAR * 2) {
473 htmlf("<span class='age-months'>%.0f months</span>", 473 htmlf("<span class='age-months'>%.0f months</span>",
474 secs * 1.0 / TM_MONTH); 474 secs * 1.0 / TM_MONTH);
475 return; 475 return;
476 } 476 }
477 htmlf("<span class='age-years'>%.0f years</span>", 477 htmlf("<span class='age-years'>%.0f years</span>",
478 secs * 1.0 / TM_YEAR); 478 secs * 1.0 / TM_YEAR);
479} 479}
480 480
481void cgit_print_http_headers(struct cgit_context *ctx) 481void cgit_print_http_headers(struct cgit_context *ctx)
482{ 482{
483 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1")) 483 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
484 return; 484 return;
485 485
486 if (ctx->page.status) 486 if (ctx->page.status)
487 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); 487 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
488 if (ctx->page.mimetype && ctx->page.charset) 488 if (ctx->page.mimetype && ctx->page.charset)
489 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 489 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
490 ctx->page.charset); 490 ctx->page.charset);
491 else if (ctx->page.mimetype) 491 else if (ctx->page.mimetype)
492 htmlf("Content-Type: %s\n", ctx->page.mimetype); 492 htmlf("Content-Type: %s\n", ctx->page.mimetype);
493 if (ctx->page.size) 493 if (ctx->page.size)
494 htmlf("Content-Length: %ld\n", ctx->page.size); 494 htmlf("Content-Length: %ld\n", ctx->page.size);
495 if (ctx->page.filename) 495 if (ctx->page.filename)
496 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 496 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
497 ctx->page.filename); 497 ctx->page.filename);
498 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 498 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
499 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 499 htmlf("Expires: %s\n", http_date(ctx->page.expires));
500 if (ctx->page.etag) 500 if (ctx->page.etag)
501 htmlf("ETag: \"%s\"\n", ctx->page.etag); 501 htmlf("ETag: \"%s\"\n", ctx->page.etag);
502 html("\n"); 502 html("\n");
503 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) 503 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
504 exit(0); 504 exit(0);
505} 505}
506 506
507void cgit_print_docstart(struct cgit_context *ctx) 507void cgit_print_docstart(struct cgit_context *ctx)
508{ 508{
509 if (ctx->cfg.embedded) { 509 if (ctx->cfg.embedded) {
510 if (ctx->cfg.header) 510 if (ctx->cfg.header)
511 html_include(ctx->cfg.header); 511 html_include(ctx->cfg.header);
512 return; 512 return;
513 } 513 }
514 514
515 char *host = cgit_hosturl(); 515 char *host = cgit_hosturl();
516 html(cgit_doctype); 516 html(cgit_doctype);
517 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 517 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
518 html("<head>\n"); 518 html("<head>\n");
519 html("<title>"); 519 html("<title>");
520 html_txt(ctx->page.title); 520 html_txt(ctx->page.title);
521 html("</title>\n"); 521 html("</title>\n");
522 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 522 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
523 if (ctx->cfg.robots && *ctx->cfg.robots) 523 if (ctx->cfg.robots && *ctx->cfg.robots)
524 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 524 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
525 html("<link rel='stylesheet' type='text/css' href='"); 525 html("<link rel='stylesheet' type='text/css' href='");
526 html_attr(ctx->cfg.css); 526 html_attr(ctx->cfg.css);
527 html("'/>\n"); 527 html("'/>\n");
528 if (ctx->cfg.favicon) { 528 if (ctx->cfg.favicon) {
529 html("<link rel='shortcut icon' href='"); 529 html("<link rel='shortcut icon' href='");
530 html_attr(ctx->cfg.favicon); 530 html_attr(ctx->cfg.favicon);
531 html("'/>\n"); 531 html("'/>\n");
532 } 532 }
533 if (host && ctx->repo) { 533 if (host && ctx->repo) {
534 html("<link rel='alternate' title='Atom feed' href='"); 534 html("<link rel='alternate' title='Atom feed' href='");
535 html(cgit_httpscheme()); 535 html(cgit_httpscheme());
536 html_attr(cgit_hosturl()); 536 html_attr(cgit_hosturl());
537 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, 537 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,
538 fmt("h=%s", ctx->qry.head))); 538 fmt("h=%s", ctx->qry.head)));
539 html("' type='application/atom+xml'/>\n"); 539 html("' type='application/atom+xml'/>\n");
540 } 540 }
541 if (ctx->cfg.head_include) 541 if (ctx->cfg.head_include)
542 html_include(ctx->cfg.head_include); 542 html_include(ctx->cfg.head_include);
543 html("</head>\n"); 543 html("</head>\n");
544 html("<body>\n"); 544 html("<body>\n");
545 if (ctx->cfg.header) 545 if (ctx->cfg.header)
546 html_include(ctx->cfg.header); 546 html_include(ctx->cfg.header);
547} 547}
548 548
549void cgit_print_docend() 549void cgit_print_docend()
550{ 550{
551 html("</div> <!-- class=content -->\n"); 551 html("</div> <!-- class=content -->\n");
552 if (ctx.cfg.embedded) { 552 if (ctx.cfg.embedded) {
553 html("</div> <!-- id=cgit -->\n"); 553 html("</div> <!-- id=cgit -->\n");
554 if (ctx.cfg.footer) 554 if (ctx.cfg.footer)
555 html_include(ctx.cfg.footer); 555 html_include(ctx.cfg.footer);
556 return; 556 return;
557 } 557 }
558 if (ctx.cfg.footer) 558 if (ctx.cfg.footer)
559 html_include(ctx.cfg.footer); 559 html_include(ctx.cfg.footer);
560 else { 560 else {
561 htmlf("<div class='footer'>generated by cgit %s at ", 561 htmlf("<div class='footer'>generated by cgit %s at ",
562 cgit_version); 562 cgit_version);
563 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 563 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
564 html("</div>\n"); 564 html("</div>\n");
565 } 565 }
566 html("</div> <!-- id=cgit -->\n"); 566 html("</div> <!-- id=cgit -->\n");
567 html("</body>\n</html>\n"); 567 html("</body>\n</html>\n");
568} 568}
569 569
570int print_branch_option(const char *refname, const unsigned char *sha1, 570int print_branch_option(const char *refname, const unsigned char *sha1,
571 int flags, void *cb_data) 571 int flags, void *cb_data)
572{ 572{
573 char *name = (char *)refname; 573 char *name = (char *)refname;
574 html_option(name, name, ctx.qry.head); 574 html_option(name, name, ctx.qry.head);
575 return 0; 575 return 0;
576} 576}
577 577
578int print_archive_ref(const char *refname, const unsigned char *sha1, 578int print_archive_ref(const char *refname, const unsigned char *sha1,
579 int flags, void *cb_data) 579 int flags, void *cb_data)
580{ 580{
581 struct tag *tag; 581 struct tag *tag;
582 struct taginfo *info; 582 struct taginfo *info;
583 struct object *obj; 583 struct object *obj;
584 char buf[256], *url; 584 char buf[256], *url;
585 unsigned char fileid[20]; 585 unsigned char fileid[20];
586 int *header = (int *)cb_data; 586 int *header = (int *)cb_data;
587 587
588 if (prefixcmp(refname, "refs/archives")) 588 if (prefixcmp(refname, "refs/archives"))
589 return 0; 589 return 0;
590 strncpy(buf, refname+14, sizeof(buf)); 590 strncpy(buf, refname+14, sizeof(buf));
591 obj = parse_object(sha1); 591 obj = parse_object(sha1);
592 if (!obj) 592 if (!obj)
593 return 1; 593 return 1;
594 if (obj->type == OBJ_TAG) { 594 if (obj->type == OBJ_TAG) {
595 tag = lookup_tag(sha1); 595 tag = lookup_tag(sha1);
596 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 596 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
597 return 0; 597 return 0;
598 hashcpy(fileid, tag->tagged->sha1); 598 hashcpy(fileid, tag->tagged->sha1);
599 } else if (obj->type != OBJ_BLOB) { 599 } else if (obj->type != OBJ_BLOB) {
600 return 0; 600 return 0;
601 } else { 601 } else {
602 hashcpy(fileid, sha1); 602 hashcpy(fileid, sha1);
603 } 603 }
604 if (!*header) { 604 if (!*header) {
605 html("<h1>download</h1>\n"); 605 html("<h1>download</h1>\n");
606 *header = 1; 606 *header = 1;
607 } 607 }
608 url = cgit_pageurl(ctx.qry.repo, "blob", 608 url = cgit_pageurl(ctx.qry.repo, "blob",
609 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 609 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
610 buf)); 610 buf));
611 html_link_open(url, NULL, "menu"); 611 html_link_open(url, NULL, "menu");
612 html_txt(strlpart(buf, 20)); 612 html_txt(strlpart(buf, 20));
613 html_link_close(); 613 html_link_close();
614 return 0; 614 return 0;
615} 615}
616 616
617void cgit_add_hidden_formfields(int incl_head, int incl_search, 617void cgit_add_hidden_formfields(int incl_head, int incl_search,
618 const char *page) 618 const char *page)
619{ 619{
620 char *url; 620 char *url;
621 621
622 if (!ctx.cfg.virtual_root) { 622 if (!ctx.cfg.virtual_root) {
623 url = fmt("%s/%s", ctx.qry.repo, page); 623 url = fmt("%s/%s", ctx.qry.repo, page);
624 if (ctx.qry.vpath) 624 if (ctx.qry.vpath)
625 url = fmt("%s/%s", url, ctx.qry.vpath); 625 url = fmt("%s/%s", url, ctx.qry.vpath);
626 html_hidden("url", url); 626 html_hidden("url", url);
627 } 627 }
628 628
629 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 629 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
630 strcmp(ctx.qry.head, ctx.repo->defbranch)) 630 strcmp(ctx.qry.head, ctx.repo->defbranch))
631 html_hidden("h", ctx.qry.head); 631 html_hidden("h", ctx.qry.head);
632 632
633 if (ctx.qry.sha1) 633 if (ctx.qry.sha1)
634 html_hidden("id", ctx.qry.sha1); 634 html_hidden("id", ctx.qry.sha1);
635 if (ctx.qry.sha2) 635 if (ctx.qry.sha2)
636 html_hidden("id2", ctx.qry.sha2); 636 html_hidden("id2", ctx.qry.sha2);
637 if (ctx.qry.showmsg) 637 if (ctx.qry.showmsg)
638 html_hidden("showmsg", "1"); 638 html_hidden("showmsg", "1");
639 639
640 if (incl_search) { 640 if (incl_search) {
641 if (ctx.qry.grep) 641 if (ctx.qry.grep)
642 html_hidden("qt", ctx.qry.grep); 642 html_hidden("qt", ctx.qry.grep);
643 if (ctx.qry.search) 643 if (ctx.qry.search)
644 html_hidden("q", ctx.qry.search); 644 html_hidden("q", ctx.qry.search);
645 } 645 }
646} 646}
647 647
648static const char *hc(struct cgit_context *ctx, const char *page) 648static const char *hc(struct cgit_context *ctx, const char *page)
649{ 649{
650 return strcmp(ctx->qry.page, page) ? NULL : "active"; 650 return strcmp(ctx->qry.page, page) ? NULL : "active";
651} 651}
652 652
653static void print_header(struct cgit_context *ctx) 653static void print_header(struct cgit_context *ctx)
654{ 654{
655 html("<table id='header'>\n"); 655 html("<table id='header'>\n");
656 html("<tr>\n"); 656 html("<tr>\n");
657 657
658 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { 658 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) {
659 html("<td class='logo' rowspan='2'><a href='"); 659 html("<td class='logo' rowspan='2'><a href='");
660 if (ctx->cfg.logo_link) 660 if (ctx->cfg.logo_link)
661 html_attr(ctx->cfg.logo_link); 661 html_attr(ctx->cfg.logo_link);
662 else 662 else
663 html_attr(cgit_rooturl()); 663 html_attr(cgit_rooturl());
664 html("'><img src='"); 664 html("'><img src='");
665 html_attr(ctx->cfg.logo); 665 html_attr(ctx->cfg.logo);
666 html("' alt='cgit logo'/></a></td>\n"); 666 html("' alt='cgit logo'/></a></td>\n");
667 } 667 }
668 668
669 html("<td class='main'>"); 669 html("<td class='main'>");
670 if (ctx->repo) { 670 if (ctx->repo) {
671 cgit_index_link("index", NULL, NULL, NULL, 0); 671 cgit_index_link("index", NULL, NULL, NULL, 0);
672 html(" : "); 672 html(" : ");
673 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 673 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
674 html("</td><td class='form'>"); 674 html("</td><td class='form'>");
675 html("<form method='get' action=''>\n"); 675 html("<form method='get' action=''>\n");
676 cgit_add_hidden_formfields(0, 1, ctx->qry.page); 676 cgit_add_hidden_formfields(0, 1, ctx->qry.page);
677 html("<select name='h' onchange='this.form.submit();'>\n"); 677 html("<select name='h' onchange='this.form.submit();'>\n");
678 for_each_branch_ref(print_branch_option, ctx->qry.head); 678 for_each_branch_ref(print_branch_option, ctx->qry.head);
679 html("</select> "); 679 html("</select> ");
680 html("<input type='submit' name='' value='switch'/>"); 680 html("<input type='submit' name='' value='switch'/>");
681 html("</form>"); 681 html("</form>");
682 } else 682 } else
683 html_txt(ctx->cfg.root_title); 683 html_txt(ctx->cfg.root_title);
684 html("</td></tr>\n"); 684 html("</td></tr>\n");
685 685
686 html("<tr><td class='sub'>"); 686 html("<tr><td class='sub'>");
687 if (ctx->repo) { 687 if (ctx->repo) {
688 html_txt(ctx->repo->desc); 688 html_txt(ctx->repo->desc);
689 html("</td><td class='sub right'>"); 689 html("</td><td class='sub right'>");
690 html_txt(ctx->repo->owner); 690 html_txt(ctx->repo->owner);
691 } else { 691 } else {
692 if (ctx->cfg.root_desc) 692 if (ctx->cfg.root_desc)
693 html_txt(ctx->cfg.root_desc); 693 html_txt(ctx->cfg.root_desc);
694 else if (ctx->cfg.index_info) 694 else if (ctx->cfg.index_info)
695 html_include(ctx->cfg.index_info); 695 html_include(ctx->cfg.index_info);
696 } 696 }
697 html("</td></tr></table>\n"); 697 html("</td></tr></table>\n");
698} 698}
699 699
700void cgit_print_pageheader(struct cgit_context *ctx) 700void cgit_print_pageheader(struct cgit_context *ctx)
701{ 701{
702 html("<div id='cgit'>"); 702 html("<div id='cgit'>");
703 if (!ctx->cfg.noheader) 703 if (!ctx->cfg.noheader)
704 print_header(ctx); 704 print_header(ctx);
705 705
706 html("<table class='tabs'><tr><td>\n"); 706 html("<table class='tabs'><tr><td>\n");
707 if (ctx->repo) { 707 if (ctx->repo) {
708 cgit_summary_link("summary", NULL, hc(ctx, "summary"), 708 cgit_summary_link("summary", NULL, hc(ctx, "summary"),
709 ctx->qry.head); 709 ctx->qry.head);
710 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head, 710 cgit_refs_link("refs", NULL, hc(ctx, "refs"), ctx->qry.head,
711 ctx->qry.sha1, NULL); 711 ctx->qry.sha1, NULL);
712 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head, 712 cgit_log_link("log", NULL, hc(ctx, "log"), ctx->qry.head,
713 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); 713 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg);
714 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head, 714 cgit_tree_link("tree", NULL, hc(ctx, "tree"), ctx->qry.head,
715 ctx->qry.sha1, NULL); 715 ctx->qry.sha1, NULL);
716 cgit_commit_link("commit", NULL, hc(ctx, "commit"), 716 cgit_commit_link("commit", NULL, hc(ctx, "commit"),
717 ctx->qry.head, ctx->qry.sha1, 0); 717 ctx->qry.head, ctx->qry.sha1, 0);
718 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head, 718 cgit_diff_link("diff", NULL, hc(ctx, "diff"), ctx->qry.head,
719 ctx->qry.sha1, ctx->qry.sha2, NULL, 0); 719 ctx->qry.sha1, ctx->qry.sha2, NULL, 0);
720 if (ctx->repo->max_stats) 720 if (ctx->repo->max_stats)
721 cgit_stats_link("stats", NULL, hc(ctx, "stats"), 721 cgit_stats_link("stats", NULL, hc(ctx, "stats"),
722 ctx->qry.head, NULL); 722 ctx->qry.head, NULL);
723 if (ctx->repo->readme) 723 if (ctx->repo->readme)
724 reporevlink("about", "about", NULL, 724 reporevlink("about", "about", NULL,
725 hc(ctx, "about"), ctx->qry.head, NULL, 725 hc(ctx, "about"), ctx->qry.head, NULL,
726 NULL); 726 NULL);
727 html("</td><td class='form'>"); 727 html("</td><td class='form'>");
728 html("<form class='right' method='get' action='"); 728 html("<form class='right' method='get' action='");
729 if (ctx->cfg.virtual_root) 729 if (ctx->cfg.virtual_root)
730 html_url_path(cgit_fileurl(ctx->qry.repo, "log", 730 html_url_path(cgit_fileurl(ctx->qry.repo, "log",
731 ctx->qry.vpath, NULL)); 731 ctx->qry.vpath, NULL));
732 html("'>\n"); 732 html("'>\n");
733 cgit_add_hidden_formfields(1, 0, "log"); 733 cgit_add_hidden_formfields(1, 0, "log");
734 html("<select name='qt'>\n"); 734 html("<select name='qt'>\n");
735 html_option("grep", "log msg", ctx->qry.grep); 735 html_option("grep", "log msg", ctx->qry.grep);
736 html_option("author", "author", ctx->qry.grep); 736 html_option("author", "author", ctx->qry.grep);
737 html_option("committer", "committer", ctx->qry.grep); 737 html_option("committer", "committer", ctx->qry.grep);
738 html("</select>\n"); 738 html("</select>\n");
739 html("<input class='txt' type='text' size='10' name='q' value='"); 739 html("<input class='txt' type='text' size='10' name='q' value='");
740 html_attr(ctx->qry.search); 740 html_attr(ctx->qry.search);
741 html("'/>\n"); 741 html("'/>\n");
742 html("<input type='submit' value='search'/>\n"); 742 html("<input type='submit' value='search'/>\n");
743 html("</form>\n"); 743 html("</form>\n");
744 } else { 744 } else {
745 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); 745 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0);
746 if (ctx->cfg.root_readme) 746 if (ctx->cfg.root_readme)
747 site_link("about", "about", NULL, hc(ctx, "about"), 747 site_link("about", "about", NULL, hc(ctx, "about"),
748 NULL, 0); 748 NULL, 0);
749 html("</td><td class='form'>"); 749 html("</td><td class='form'>");
750 html("<form method='get' action='"); 750 html("<form method='get' action='");
751 html_attr(cgit_rooturl()); 751 html_attr(cgit_rooturl());
752 html("'>\n"); 752 html("'>\n");
753 html("<input type='text' name='q' size='10' value='"); 753 html("<input type='text' name='q' size='10' value='");
754 html_attr(ctx->qry.search); 754 html_attr(ctx->qry.search);
755 html("'/>\n"); 755 html("'/>\n");
756 html("<input type='submit' value='search'/>\n"); 756 html("<input type='submit' value='search'/>\n");
757 html("</form>"); 757 html("</form>");
758 } 758 }
759 html("</td></tr></table>\n"); 759 html("</td></tr></table>\n");
760 if (ctx->qry.vpath) {
761 html("<div class='path'>");
762 html("path: ");
763 html_txt(ctx->qry.vpath);
764 html("</div>");
765 }
760 html("<div class='content'>"); 766 html("<div class='content'>");
761} 767}
762 768
763void cgit_print_filemode(unsigned short mode) 769void cgit_print_filemode(unsigned short mode)
764{ 770{
765 if (S_ISDIR(mode)) 771 if (S_ISDIR(mode))
766 html("d"); 772 html("d");
767 else if (S_ISLNK(mode)) 773 else if (S_ISLNK(mode))
768 html("l"); 774 html("l");
769 else if (S_ISGITLINK(mode)) 775 else if (S_ISGITLINK(mode))
770 html("m"); 776 html("m");
771 else 777 else
772 html("-"); 778 html("-");
773 html_fileperm(mode >> 6); 779 html_fileperm(mode >> 6);
774 html_fileperm(mode >> 3); 780 html_fileperm(mode >> 3);
775 html_fileperm(mode); 781 html_fileperm(mode);
776} 782}
777 783
778void cgit_print_snapshot_links(const char *repo, const char *head, 784void cgit_print_snapshot_links(const char *repo, const char *head,
779 const char *hex, int snapshots) 785 const char *hex, int snapshots)
780{ 786{
781 const struct cgit_snapshot_format* f; 787 const struct cgit_snapshot_format* f;
782 char *prefix; 788 char *prefix;
783 char *filename; 789 char *filename;
784 unsigned char sha1[20]; 790 unsigned char sha1[20];
785 791
786 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && 792 if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 &&
787 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) 793 (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1]))
788 hex++; 794 hex++;
789 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex)); 795 prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex));
790 for (f = cgit_snapshot_formats; f->suffix; f++) { 796 for (f = cgit_snapshot_formats; f->suffix; f++) {
791 if (!(snapshots & f->bit)) 797 if (!(snapshots & f->bit))
792 continue; 798 continue;
793 filename = fmt("%s%s", prefix, f->suffix); 799 filename = fmt("%s%s", prefix, f->suffix);
794 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); 800 cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename);
795 html("<br/>"); 801 html("<br/>");
796 } 802 }
797} 803}