Fossil SCM
Very rough proof-of-concept for a pure-CSS expand/collapse option for forum posts. Demonstrates the capability but is far from polished enough to bring online.
Commit
be157e46f03257e7128634ca2257fb7c1189c4a14f86998b3ac0e14a21c51071
Parent
29f7da931863784…
2 files changed
+28
+19
+28
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -764,10 +764,14 @@ | ||
| 764 | 764 | border: 1px solid black; |
| 765 | 765 | padding-left: 1ex; |
| 766 | 766 | padding-right: 1ex; |
| 767 | 767 | margin-top: 1ex; |
| 768 | 768 | } |
| 769 | +div.forumHier, div.forumTime, div.forumHierRoot { | |
| 770 | + display: flex; | |
| 771 | + flex-direction: column; | |
| 772 | +} | |
| 769 | 773 | div.forumPostBody { |
| 770 | 774 | max-height: 100em; |
| 771 | 775 | overflow: auto; |
| 772 | 776 | } |
| 773 | 777 | div.forumSel { |
| @@ -774,10 +778,34 @@ | ||
| 774 | 778 | background-color: #cef; |
| 775 | 779 | } |
| 776 | 780 | div.forumObs { |
| 777 | 781 | color: #bbb; |
| 778 | 782 | } |
| 783 | + | |
| 784 | +input[type=checkbox].forum-post-collapser { | |
| 785 | + opacity: 0; | |
| 786 | + position: absolute; | |
| 787 | + z-index: -1; | |
| 788 | +} | |
| 789 | +input[type=checkbox].forum-post-collapser:checked ~ label.forum-post-collapser::before { | |
| 790 | + content: "Collapse"; | |
| 791 | +} | |
| 792 | +input[type=checkbox].forum-post-collapser:not(:checked) ~ label.forum-post-collapser::before { | |
| 793 | + content: "Expand"; | |
| 794 | +} | |
| 795 | +label.forum-post-collapser { | |
| 796 | + display: block; | |
| 797 | + border: 1px outset; | |
| 798 | + border-radius: 0.25em; | |
| 799 | +} | |
| 800 | +input[type=checkbox].forum-post-collapser:not(:checked) ~ div.forumPostBody { | |
| 801 | + max-height: 10em; | |
| 802 | +} | |
| 803 | +input[type=checkbox].forum-post-collapser:checked ~ div.forumPostBody { | |
| 804 | + max-height: 200em; | |
| 805 | +} | |
| 806 | + | |
| 779 | 807 | #capabilitySummary { |
| 780 | 808 | text-align: center; |
| 781 | 809 | } |
| 782 | 810 | #capabilitySummary td { |
| 783 | 811 | padding-left: 3ex; |
| 784 | 812 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -764,10 +764,14 @@ | |
| 764 | border: 1px solid black; |
| 765 | padding-left: 1ex; |
| 766 | padding-right: 1ex; |
| 767 | margin-top: 1ex; |
| 768 | } |
| 769 | div.forumPostBody { |
| 770 | max-height: 100em; |
| 771 | overflow: auto; |
| 772 | } |
| 773 | div.forumSel { |
| @@ -774,10 +778,34 @@ | |
| 774 | background-color: #cef; |
| 775 | } |
| 776 | div.forumObs { |
| 777 | color: #bbb; |
| 778 | } |
| 779 | #capabilitySummary { |
| 780 | text-align: center; |
| 781 | } |
| 782 | #capabilitySummary td { |
| 783 | padding-left: 3ex; |
| 784 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -764,10 +764,14 @@ | |
| 764 | border: 1px solid black; |
| 765 | padding-left: 1ex; |
| 766 | padding-right: 1ex; |
| 767 | margin-top: 1ex; |
| 768 | } |
| 769 | div.forumHier, div.forumTime, div.forumHierRoot { |
| 770 | display: flex; |
| 771 | flex-direction: column; |
| 772 | } |
| 773 | div.forumPostBody { |
| 774 | max-height: 100em; |
| 775 | overflow: auto; |
| 776 | } |
| 777 | div.forumSel { |
| @@ -774,10 +778,34 @@ | |
| 778 | background-color: #cef; |
| 779 | } |
| 780 | div.forumObs { |
| 781 | color: #bbb; |
| 782 | } |
| 783 | |
| 784 | input[type=checkbox].forum-post-collapser { |
| 785 | opacity: 0; |
| 786 | position: absolute; |
| 787 | z-index: -1; |
| 788 | } |
| 789 | input[type=checkbox].forum-post-collapser:checked ~ label.forum-post-collapser::before { |
| 790 | content: "Collapse"; |
| 791 | } |
| 792 | input[type=checkbox].forum-post-collapser:not(:checked) ~ label.forum-post-collapser::before { |
| 793 | content: "Expand"; |
| 794 | } |
| 795 | label.forum-post-collapser { |
| 796 | display: block; |
| 797 | border: 1px outset; |
| 798 | border-radius: 0.25em; |
| 799 | } |
| 800 | input[type=checkbox].forum-post-collapser:not(:checked) ~ div.forumPostBody { |
| 801 | max-height: 10em; |
| 802 | } |
| 803 | input[type=checkbox].forum-post-collapser:checked ~ div.forumPostBody { |
| 804 | max-height: 200em; |
| 805 | } |
| 806 | |
| 807 | #capabilitySummary { |
| 808 | text-align: center; |
| 809 | } |
| 810 | #capabilitySummary td { |
| 811 | padding-left: 3ex; |
| 812 |
+19
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -402,10 +402,26 @@ | ||
| 402 | 402 | } |
| 403 | 403 | db_reset(&q); |
| 404 | 404 | return zResult; |
| 405 | 405 | } |
| 406 | 406 | |
| 407 | +/* | |
| 408 | +** Emits a checkbox and label for implementing a CSS-only | |
| 409 | +** collapse/expand button on posts. It should be passed the UUID of | |
| 410 | +** the current post, but that value is only used for constructing a | |
| 411 | +** unique ID for the (invisible) checkbox so that the label can be | |
| 412 | +** bound to it via its 'for' attribute. Thus it doesn't really matter | |
| 413 | +** whether the UUID refers to the current (edited) instance of the | |
| 414 | +** post or an ancestor version, so long as the UUID is unique within | |
| 415 | +** the current page. | |
| 416 | +*/ | |
| 417 | +static void forum_emit_post_toggle(const char * zUuid){ | |
| 418 | + @ <input type='checkbox' id='cb-post-%S(zUuid)' \ | |
| 419 | + @ class='forum-post-collapser'> | |
| 420 | + @ <label for='cb-post-%S(zUuid)' \ | |
| 421 | + @ class='forum-post-collapser'></label> | |
| 422 | +} | |
| 407 | 423 | |
| 408 | 424 | /* |
| 409 | 425 | ** Display all posts in a forum thread in chronological order |
| 410 | 426 | */ |
| 411 | 427 | static void forum_display_chronological(int froot, int target, int bRawMode){ |
| @@ -469,10 +485,11 @@ | ||
| 469 | 485 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 470 | 486 | } |
| 471 | 487 | isPrivate = content_is_private(p->fpid); |
| 472 | 488 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 473 | 489 | @ </h3> |
| 490 | + forum_emit_post_toggle(p->zUuid); | |
| 474 | 491 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 475 | 492 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 476 | 493 | }else{ |
| 477 | 494 | const char *zMimetype; |
| 478 | 495 | if( bRawMode ){ |
| @@ -584,10 +601,11 @@ | ||
| 584 | 601 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 585 | 602 | } |
| 586 | 603 | isPrivate = content_is_private(p->fpid); |
| 587 | 604 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 588 | 605 | @ </h3> |
| 606 | + forum_emit_post_toggle(zUuid); | |
| 589 | 607 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 590 | 608 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 591 | 609 | }else{ |
| 592 | 610 | forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, |
| 593 | 611 | 0, 1); |
| @@ -711,10 +729,11 @@ | ||
| 711 | 729 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| 712 | 730 | @ %d(pIrt->sid)</a> |
| 713 | 731 | } |
| 714 | 732 | } |
| 715 | 733 | @ </h3> |
| 734 | + forum_emit_post_toggle(zUuid); | |
| 716 | 735 | isPrivate = content_is_private(fpid); |
| 717 | 736 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 718 | 737 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 719 | 738 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 720 | 739 | }else{ |
| 721 | 740 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -402,10 +402,26 @@ | |
| 402 | } |
| 403 | db_reset(&q); |
| 404 | return zResult; |
| 405 | } |
| 406 | |
| 407 | |
| 408 | /* |
| 409 | ** Display all posts in a forum thread in chronological order |
| 410 | */ |
| 411 | static void forum_display_chronological(int froot, int target, int bRawMode){ |
| @@ -469,10 +485,11 @@ | |
| 469 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 470 | } |
| 471 | isPrivate = content_is_private(p->fpid); |
| 472 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 473 | @ </h3> |
| 474 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 475 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 476 | }else{ |
| 477 | const char *zMimetype; |
| 478 | if( bRawMode ){ |
| @@ -584,10 +601,11 @@ | |
| 584 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 585 | } |
| 586 | isPrivate = content_is_private(p->fpid); |
| 587 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 588 | @ </h3> |
| 589 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 590 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 591 | }else{ |
| 592 | forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, |
| 593 | 0, 1); |
| @@ -711,10 +729,11 @@ | |
| 711 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| 712 | @ %d(pIrt->sid)</a> |
| 713 | } |
| 714 | } |
| 715 | @ </h3> |
| 716 | isPrivate = content_is_private(fpid); |
| 717 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 718 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 719 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 720 | }else{ |
| 721 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -402,10 +402,26 @@ | |
| 402 | } |
| 403 | db_reset(&q); |
| 404 | return zResult; |
| 405 | } |
| 406 | |
| 407 | /* |
| 408 | ** Emits a checkbox and label for implementing a CSS-only |
| 409 | ** collapse/expand button on posts. It should be passed the UUID of |
| 410 | ** the current post, but that value is only used for constructing a |
| 411 | ** unique ID for the (invisible) checkbox so that the label can be |
| 412 | ** bound to it via its 'for' attribute. Thus it doesn't really matter |
| 413 | ** whether the UUID refers to the current (edited) instance of the |
| 414 | ** post or an ancestor version, so long as the UUID is unique within |
| 415 | ** the current page. |
| 416 | */ |
| 417 | static void forum_emit_post_toggle(const char * zUuid){ |
| 418 | @ <input type='checkbox' id='cb-post-%S(zUuid)' \ |
| 419 | @ class='forum-post-collapser'> |
| 420 | @ <label for='cb-post-%S(zUuid)' \ |
| 421 | @ class='forum-post-collapser'></label> |
| 422 | } |
| 423 | |
| 424 | /* |
| 425 | ** Display all posts in a forum thread in chronological order |
| 426 | */ |
| 427 | static void forum_display_chronological(int froot, int target, int bRawMode){ |
| @@ -469,10 +485,11 @@ | |
| 485 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 486 | } |
| 487 | isPrivate = content_is_private(p->fpid); |
| 488 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 489 | @ </h3> |
| 490 | forum_emit_post_toggle(p->zUuid); |
| 491 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 492 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 493 | }else{ |
| 494 | const char *zMimetype; |
| 495 | if( bRawMode ){ |
| @@ -584,10 +601,11 @@ | |
| 601 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 602 | } |
| 603 | isPrivate = content_is_private(p->fpid); |
| 604 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 605 | @ </h3> |
| 606 | forum_emit_post_toggle(zUuid); |
| 607 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 608 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 609 | }else{ |
| 610 | forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, |
| 611 | 0, 1); |
| @@ -711,10 +729,11 @@ | |
| 729 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| 730 | @ %d(pIrt->sid)</a> |
| 731 | } |
| 732 | } |
| 733 | @ </h3> |
| 734 | forum_emit_post_toggle(zUuid); |
| 735 | isPrivate = content_is_private(fpid); |
| 736 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 737 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 738 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 739 | }else{ |
| 740 |