author | Johan Herland <johan@herland.net> | 2010-06-09 23:09:29 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2010-06-19 08:40:22 (UTC) |
commit | 24fd7e54c82294efa68ecae5dd9cb8a8986c04bf (patch) (unidiff) | |
tree | 5a4824456d046f40717fc50686c1e03b5c6efdf4 /ui-shared.c | |
parent | c93ef96aaf77437abeb552bd9e30973f90365f3a (diff) | |
download | cgit-24fd7e54c82294efa68ecae5dd9cb8a8986c04bf.zip cgit-24fd7e54c82294efa68ecae5dd9cb8a8986c04bf.tar.gz cgit-24fd7e54c82294efa68ecae5dd9cb8a8986c04bf.tar.bz2 |
ui-shared: Teach "breadcrumb" navigation to path limit display beneath tab bar
When a path limit is in effect, and displayed directly beneath the tab bar,
it should offer breadcrumb navigation (like what the 'tree' page does), to
allow changing the path limit easily.
Implementing this requires a robust way to link back to the current page with
a changed ctx->qry.path, but without losing track of the other query
arguments. This is solved by adding the new cgit_self_link() function, which
is then invoked repeatedly by the new cgit_print_path_crumbs() function while
manipulating ctx->qry.path.
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | ui-shared.c | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/ui-shared.c b/ui-shared.c index bc14e70..4fa506f 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -378,48 +378,106 @@ void cgit_diff_link(const char *name, const char *title, const char *class, | |||
378 | html_url_arg(old_rev); | 378 | html_url_arg(old_rev); |
379 | delim = "&"; | 379 | delim = "&"; |
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 | ||
390 | void cgit_patch_link(const char *name, const char *title, const char *class, | 390 | void 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 | ||
396 | void cgit_stats_link(const char *name, const char *title, const char *class, | 396 | void 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 | ||
402 | void cgit_self_link(char *name, const char *title, const char *class, | ||
403 | struct cgit_context *ctx) | ||
404 | { | ||
405 | if (!strcmp(ctx->qry.page, "repolist")) | ||
406 | return cgit_index_link(name, title, class, ctx->qry.search, | ||
407 | ctx->qry.ofs); | ||
408 | else if (!strcmp(ctx->qry.page, "summary")) | ||
409 | return cgit_summary_link(name, title, class, ctx->qry.head); | ||
410 | else if (!strcmp(ctx->qry.page, "tag")) | ||
411 | return cgit_tag_link(name, title, class, ctx->qry.head, | ||
412 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL); | ||
413 | else if (!strcmp(ctx->qry.page, "tree")) | ||
414 | return cgit_tree_link(name, title, class, ctx->qry.head, | ||
415 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
416 | ctx->qry.path); | ||
417 | else if (!strcmp(ctx->qry.page, "plain")) | ||
418 | return cgit_plain_link(name, title, class, ctx->qry.head, | ||
419 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
420 | ctx->qry.path); | ||
421 | else if (!strcmp(ctx->qry.page, "log")) | ||
422 | return cgit_log_link(name, title, class, ctx->qry.head, | ||
423 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
424 | ctx->qry.path, ctx->qry.ofs, | ||
425 | ctx->qry.grep, ctx->qry.search, | ||
426 | ctx->qry.showmsg); | ||
427 | else if (!strcmp(ctx->qry.page, "commit")) | ||
428 | return cgit_commit_link(name, title, class, ctx->qry.head, | ||
429 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
430 | ctx->qry.path, 0); | ||
431 | else if (!strcmp(ctx->qry.page, "patch")) | ||
432 | return cgit_patch_link(name, title, class, ctx->qry.head, | ||
433 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
434 | ctx->qry.path); | ||
435 | else if (!strcmp(ctx->qry.page, "refs")) | ||
436 | return cgit_refs_link(name, title, class, ctx->qry.head, | ||
437 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
438 | ctx->qry.path); | ||
439 | else if (!strcmp(ctx->qry.page, "snapshot")) | ||
440 | return cgit_snapshot_link(name, title, class, ctx->qry.head, | ||
441 | ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, | ||
442 | ctx->qry.path); | ||
443 | else if (!strcmp(ctx->qry.page, "diff")) | ||
444 | return cgit_diff_link(name, title, class, ctx->qry.head, | ||
445 | ctx->qry.sha1, ctx->qry.sha2, | ||
446 | ctx->qry.path, 0); | ||
447 | else if (!strcmp(ctx->qry.page, "stats")) | ||
448 | return cgit_stats_link(name, title, class, ctx->qry.head, | ||
449 | ctx->qry.path); | ||
450 | |||
451 | /* Don't known how to make link for this page */ | ||
452 | repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path); | ||
453 | html("><!-- cgit_self_link() doesn't know how to make link for page '"); | ||
454 | html_txt(ctx->qry.page); | ||
455 | html("' -->"); | ||
456 | html_txt(name); | ||
457 | html("</a>"); | ||
458 | } | ||
459 | |||
402 | void cgit_object_link(struct object *obj) | 460 | void cgit_object_link(struct object *obj) |
403 | { | 461 | { |
404 | char *page, *shortrev, *fullrev, *name; | 462 | char *page, *shortrev, *fullrev, *name; |
405 | 463 | ||
406 | fullrev = sha1_to_hex(obj->sha1); | 464 | fullrev = sha1_to_hex(obj->sha1); |
407 | shortrev = xstrdup(fullrev); | 465 | shortrev = xstrdup(fullrev); |
408 | shortrev[10] = '\0'; | 466 | shortrev[10] = '\0'; |
409 | if (obj->type == OBJ_COMMIT) { | 467 | if (obj->type == OBJ_COMMIT) { |
410 | cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, | 468 | cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, |
411 | ctx.qry.head, fullrev, 0); | 469 | ctx.qry.head, fullrev, 0); |
412 | return; | 470 | return; |
413 | } else if (obj->type == OBJ_TREE) | 471 | } else if (obj->type == OBJ_TREE) |
414 | page = "tree"; | 472 | page = "tree"; |
415 | else if (obj->type == OBJ_TAG) | 473 | else if (obj->type == OBJ_TAG) |
416 | page = "tag"; | 474 | page = "tag"; |
417 | else | 475 | else |
418 | page = "blob"; | 476 | page = "blob"; |
419 | name = fmt("%s %s...", typename(obj->type), shortrev); | 477 | name = fmt("%s %s...", typename(obj->type), shortrev); |
420 | reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); | 478 | reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); |
421 | } | 479 | } |
422 | 480 | ||
423 | void cgit_print_date(time_t secs, const char *format, int local_time) | 481 | void cgit_print_date(time_t secs, const char *format, int local_time) |
424 | { | 482 | { |
425 | char buf[64]; | 483 | char buf[64]; |
@@ -629,48 +687,69 @@ void cgit_add_hidden_formfields(int incl_head, int incl_search, | |||
629 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && | 687 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && |
630 | strcmp(ctx.qry.head, ctx.repo->defbranch)) | 688 | strcmp(ctx.qry.head, ctx.repo->defbranch)) |
631 | html_hidden("h", ctx.qry.head); | 689 | html_hidden("h", ctx.qry.head); |
632 | 690 | ||
633 | if (ctx.qry.sha1) | 691 | if (ctx.qry.sha1) |
634 | html_hidden("id", ctx.qry.sha1); | 692 | html_hidden("id", ctx.qry.sha1); |
635 | if (ctx.qry.sha2) | 693 | if (ctx.qry.sha2) |
636 | html_hidden("id2", ctx.qry.sha2); | 694 | html_hidden("id2", ctx.qry.sha2); |
637 | if (ctx.qry.showmsg) | 695 | if (ctx.qry.showmsg) |
638 | html_hidden("showmsg", "1"); | 696 | html_hidden("showmsg", "1"); |
639 | 697 | ||
640 | if (incl_search) { | 698 | if (incl_search) { |
641 | if (ctx.qry.grep) | 699 | if (ctx.qry.grep) |
642 | html_hidden("qt", ctx.qry.grep); | 700 | html_hidden("qt", ctx.qry.grep); |
643 | if (ctx.qry.search) | 701 | if (ctx.qry.search) |
644 | html_hidden("q", ctx.qry.search); | 702 | html_hidden("q", ctx.qry.search); |
645 | } | 703 | } |
646 | } | 704 | } |
647 | 705 | ||
648 | static const char *hc(struct cgit_context *ctx, const char *page) | 706 | static const char *hc(struct cgit_context *ctx, const char *page) |
649 | { | 707 | { |
650 | return strcmp(ctx->qry.page, page) ? NULL : "active"; | 708 | return strcmp(ctx->qry.page, page) ? NULL : "active"; |
651 | } | 709 | } |
652 | 710 | ||
711 | static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path) | ||
712 | { | ||
713 | char *old_path = ctx->qry.path; | ||
714 | char *p = path, *q, *end = path + strlen(path); | ||
715 | |||
716 | ctx->qry.path = NULL; | ||
717 | cgit_self_link("root", NULL, NULL, ctx); | ||
718 | ctx->qry.path = p = path; | ||
719 | while (p < end) { | ||
720 | if (!(q = strchr(p, '/'))) | ||
721 | q = end; | ||
722 | *q = '\0'; | ||
723 | html_txt("/"); | ||
724 | cgit_self_link(p, NULL, NULL, ctx); | ||
725 | if (q < end) | ||
726 | *q = '/'; | ||
727 | p = q + 1; | ||
728 | } | ||
729 | ctx->qry.path = old_path; | ||
730 | } | ||
731 | |||
653 | static void print_header(struct cgit_context *ctx) | 732 | static void print_header(struct cgit_context *ctx) |
654 | { | 733 | { |
655 | html("<table id='header'>\n"); | 734 | html("<table id='header'>\n"); |
656 | html("<tr>\n"); | 735 | html("<tr>\n"); |
657 | 736 | ||
658 | if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { | 737 | if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { |
659 | html("<td class='logo' rowspan='2'><a href='"); | 738 | html("<td class='logo' rowspan='2'><a href='"); |
660 | if (ctx->cfg.logo_link) | 739 | if (ctx->cfg.logo_link) |
661 | html_attr(ctx->cfg.logo_link); | 740 | html_attr(ctx->cfg.logo_link); |
662 | else | 741 | else |
663 | html_attr(cgit_rooturl()); | 742 | html_attr(cgit_rooturl()); |
664 | html("'><img src='"); | 743 | html("'><img src='"); |
665 | html_attr(ctx->cfg.logo); | 744 | html_attr(ctx->cfg.logo); |
666 | html("' alt='cgit logo'/></a></td>\n"); | 745 | html("' alt='cgit logo'/></a></td>\n"); |
667 | } | 746 | } |
668 | 747 | ||
669 | html("<td class='main'>"); | 748 | html("<td class='main'>"); |
670 | if (ctx->repo) { | 749 | if (ctx->repo) { |
671 | cgit_index_link("index", NULL, NULL, NULL, 0); | 750 | cgit_index_link("index", NULL, NULL, NULL, 0); |
672 | html(" : "); | 751 | html(" : "); |
673 | cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); | 752 | cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); |
674 | html("</td><td class='form'>"); | 753 | html("</td><td class='form'>"); |
675 | html("<form method='get' action=''>\n"); | 754 | html("<form method='get' action=''>\n"); |
676 | cgit_add_hidden_formfields(0, 1, ctx->qry.page); | 755 | cgit_add_hidden_formfields(0, 1, ctx->qry.page); |
@@ -739,49 +818,49 @@ void cgit_print_pageheader(struct cgit_context *ctx) | |||
739 | html("<input class='txt' type='text' size='10' name='q' value='"); | 818 | html("<input class='txt' type='text' size='10' name='q' value='"); |
740 | html_attr(ctx->qry.search); | 819 | html_attr(ctx->qry.search); |
741 | html("'/>\n"); | 820 | html("'/>\n"); |
742 | html("<input type='submit' value='search'/>\n"); | 821 | html("<input type='submit' value='search'/>\n"); |
743 | html("</form>\n"); | 822 | html("</form>\n"); |
744 | } else { | 823 | } else { |
745 | site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); | 824 | site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); |
746 | if (ctx->cfg.root_readme) | 825 | if (ctx->cfg.root_readme) |
747 | site_link("about", "about", NULL, hc(ctx, "about"), | 826 | site_link("about", "about", NULL, hc(ctx, "about"), |
748 | NULL, 0); | 827 | NULL, 0); |
749 | html("</td><td class='form'>"); | 828 | html("</td><td class='form'>"); |
750 | html("<form method='get' action='"); | 829 | html("<form method='get' action='"); |
751 | html_attr(cgit_rooturl()); | 830 | html_attr(cgit_rooturl()); |
752 | html("'>\n"); | 831 | html("'>\n"); |
753 | html("<input type='text' name='q' size='10' value='"); | 832 | html("<input type='text' name='q' size='10' value='"); |
754 | html_attr(ctx->qry.search); | 833 | html_attr(ctx->qry.search); |
755 | html("'/>\n"); | 834 | html("'/>\n"); |
756 | html("<input type='submit' value='search'/>\n"); | 835 | html("<input type='submit' value='search'/>\n"); |
757 | html("</form>"); | 836 | html("</form>"); |
758 | } | 837 | } |
759 | html("</td></tr></table>\n"); | 838 | html("</td></tr></table>\n"); |
760 | if (ctx->qry.vpath) { | 839 | if (ctx->qry.vpath) { |
761 | html("<div class='path'>"); | 840 | html("<div class='path'>"); |
762 | html("path: "); | 841 | html("path: "); |
763 | html_txt(ctx->qry.vpath); | 842 | cgit_print_path_crumbs(ctx, ctx->qry.vpath); |
764 | html("</div>"); | 843 | html("</div>"); |
765 | } | 844 | } |
766 | html("<div class='content'>"); | 845 | html("<div class='content'>"); |
767 | } | 846 | } |
768 | 847 | ||
769 | void cgit_print_filemode(unsigned short mode) | 848 | void cgit_print_filemode(unsigned short mode) |
770 | { | 849 | { |
771 | if (S_ISDIR(mode)) | 850 | if (S_ISDIR(mode)) |
772 | html("d"); | 851 | html("d"); |
773 | else if (S_ISLNK(mode)) | 852 | else if (S_ISLNK(mode)) |
774 | html("l"); | 853 | html("l"); |
775 | else if (S_ISGITLINK(mode)) | 854 | else if (S_ISGITLINK(mode)) |
776 | html("m"); | 855 | html("m"); |
777 | else | 856 | else |
778 | html("-"); | 857 | html("-"); |
779 | html_fileperm(mode >> 6); | 858 | html_fileperm(mode >> 6); |
780 | html_fileperm(mode >> 3); | 859 | html_fileperm(mode >> 3); |
781 | html_fileperm(mode); | 860 | html_fileperm(mode); |
782 | } | 861 | } |
783 | 862 | ||
784 | void cgit_print_snapshot_links(const char *repo, const char *head, | 863 | void cgit_print_snapshot_links(const char *repo, const char *head, |
785 | const char *hex, int snapshots) | 864 | const char *hex, int snapshots) |
786 | { | 865 | { |
787 | const struct cgit_snapshot_format* f; | 866 | const struct cgit_snapshot_format* f; |