Fossil SCM

Allow wiki pages with names like "branch/BRANCH", "checkin/HASH", and "tag/TAGNAME" to automatically link to displays of the corresponding branch, checkin, or tag.

drh 2018-12-31 20:10 trunk merge
Commit 5602385493252ed8eb3358e19a8a6580c2ffdc9a4c0cfe318e7b798df63ba62f
+1 -1
--- src/doc.c
+++ src/doc.c
@@ -510,11 +510,11 @@
510510
** action="$ROOT/
511511
**
512512
** Convert $ROOT to the root URI of the repository. Allow ' in place of "
513513
** and any case for href or action.
514514
*/
515
-static void convert_href_and_output(Blob *pIn){
515
+void convert_href_and_output(Blob *pIn){
516516
int i, base;
517517
int n = blob_size(pIn);
518518
char *z = blob_buffer(pIn);
519519
for(base=0, i=7; i<n; i++){
520520
if( z[i]=='$'
521521
--- src/doc.c
+++ src/doc.c
@@ -510,11 +510,11 @@
510 ** action="$ROOT/
511 **
512 ** Convert $ROOT to the root URI of the repository. Allow ' in place of "
513 ** and any case for href or action.
514 */
515 static void convert_href_and_output(Blob *pIn){
516 int i, base;
517 int n = blob_size(pIn);
518 char *z = blob_buffer(pIn);
519 for(base=0, i=7; i<n; i++){
520 if( z[i]=='$'
521
--- src/doc.c
+++ src/doc.c
@@ -510,11 +510,11 @@
510 ** action="$ROOT/
511 **
512 ** Convert $ROOT to the root URI of the repository. Allow ' in place of "
513 ** and any case for href or action.
514 */
515 void convert_href_and_output(Blob *pIn){
516 int i, base;
517 int n = blob_size(pIn);
518 char *z = blob_buffer(pIn);
519 for(base=0, i=7; i<n; i++){
520 if( z[i]=='$'
521
+41 -1
--- src/info.c
+++ src/info.c
@@ -690,10 +690,13 @@
690690
const char *zUser;
691691
const char *zOrigUser;
692692
const char *zComment;
693693
const char *zDate;
694694
const char *zOrigDate;
695
+ const char *zBrName;
696
+ int okWiki = 0;
697
+ Blob wiki_links = BLOB_INITIALIZER;
695698
696699
style_header("Check-in [%S]", zUuid);
697700
login_anonymous_available();
698701
zEUser = db_text(0,
699702
"SELECT value FROM tagxref"
@@ -700,10 +703,13 @@
700703
" WHERE tagid=%d AND rid=%d AND tagtype>0",
701704
TAG_USER, rid);
702705
zEComment = db_text(0,
703706
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
704707
TAG_COMMENT, rid);
708
+ zBrName = db_text(0,
709
+ "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
710
+ TAG_BRANCH, rid);
705711
zOrigUser = db_column_text(&q1, 2);
706712
zUser = zEUser ? zEUser : zOrigUser;
707713
zComment = db_column_text(&q1, 3);
708714
zDate = db_column_text(&q1,1);
709715
zOrigDate = db_column_text(&q1, 4);
@@ -754,11 +760,23 @@
754760
" WHERE rid=%d AND tagtype>0 "
755761
" AND tag.tagid=tagxref.tagid "
756762
" AND +tag.tagname GLOB 'sym-*'", rid);
757763
while( db_step(&q2)==SQLITE_ROW ){
758764
const char *zTagName = db_column_text(&q2, 0);
759
- @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
765
+ if( fossil_strcmp(zTagName,zBrName)==0 ){
766
+ @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
767
+ if( g.perm.Write || wiki_tagid2("branch",zTagName)!=0 ){
768
+ blob_appendf(&wiki_links, " | %z%h</a>",
769
+ href("%R/wiki?name=branch/%h",zTagName), zTagName);
770
+ }
771
+ }else{
772
+ @ | %z(href("%R/timeline?t=%T&unhide",zTagName))%h(zTagName)</a>
773
+ if( g.perm.Write || wiki_tagid2("tag",zTagName)!=0 ){
774
+ blob_appendf(&wiki_links, " | %z%h</a>",
775
+ href("%R/wiki?name=tag/%h",zTagName), zTagName);
776
+ }
777
+ }
760778
}
761779
db_finalize(&q2);
762780
@ </td></tr>
763781
764782
@ <tr><th>Files:</th>
@@ -803,10 +821,28 @@
803821
@ <tr><th>Received&nbsp;From:</th>
804822
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
805823
}
806824
db_finalize(&q2);
807825
}
826
+
827
+ /* Only show links to wiki pages if the users can read wiki,
828
+ ** and only if the wiki pages already exist or the user has the
829
+ ** ability to create new ones. */
830
+ if( g.perm.RdWiki
831
+ && (g.perm.Write || blob_size(&wiki_links)>0
832
+ || (okWiki = wiki_tagid2("checkin",zUuid))!=0)
833
+ && db_get_boolean("wiki-about",1)
834
+ ){
835
+ const char *zLinks = blob_str(&wiki_links);
836
+ if( zLinks[0] ) zLinks += 3;
837
+ @ <tr><th>Wiki:</th><td>\
838
+ if( g.perm.Write || okWiki ){
839
+ @ %z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> | \
840
+ }
841
+ @ %s(zLinks)</td></tr>
842
+ }
843
+
808844
if( g.perm.Hyperlink ){
809845
@ <tr><th>Other&nbsp;Links:</th>
810846
@ <td>
811847
@ %z(href("%R/artifact/%!S",zUuid))manifest</a>
812848
@ | %z(href("%R/ci_tags/%!S",zUuid))tags</a>
@@ -818,15 +854,19 @@
818854
}
819855
@ </td>
820856
@ </tr>
821857
}
822858
@ </table>
859
+ blob_reset(&wiki_links);
823860
}else{
824861
style_header("Check-in Information");
825862
login_anonymous_available();
826863
}
827864
db_finalize(&q1);
865
+ if( !PB("nowiki") ){
866
+ wiki_render_associated("checkin", zUuid, 0);
867
+ }
828868
render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
829869
@ <div class="section">Context</div>
830870
render_checkin_context(rid, 0);
831871
@ <div class="section">Changes</div>
832872
@ <div class="sectionmenu">
833873
--- src/info.c
+++ src/info.c
@@ -690,10 +690,13 @@
690 const char *zUser;
691 const char *zOrigUser;
692 const char *zComment;
693 const char *zDate;
694 const char *zOrigDate;
 
 
 
695
696 style_header("Check-in [%S]", zUuid);
697 login_anonymous_available();
698 zEUser = db_text(0,
699 "SELECT value FROM tagxref"
@@ -700,10 +703,13 @@
700 " WHERE tagid=%d AND rid=%d AND tagtype>0",
701 TAG_USER, rid);
702 zEComment = db_text(0,
703 "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
704 TAG_COMMENT, rid);
 
 
 
705 zOrigUser = db_column_text(&q1, 2);
706 zUser = zEUser ? zEUser : zOrigUser;
707 zComment = db_column_text(&q1, 3);
708 zDate = db_column_text(&q1,1);
709 zOrigDate = db_column_text(&q1, 4);
@@ -754,11 +760,23 @@
754 " WHERE rid=%d AND tagtype>0 "
755 " AND tag.tagid=tagxref.tagid "
756 " AND +tag.tagname GLOB 'sym-*'", rid);
757 while( db_step(&q2)==SQLITE_ROW ){
758 const char *zTagName = db_column_text(&q2, 0);
759 @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
 
 
 
 
 
 
 
 
 
 
 
 
760 }
761 db_finalize(&q2);
762 @ </td></tr>
763
764 @ <tr><th>Files:</th>
@@ -803,10 +821,28 @@
803 @ <tr><th>Received&nbsp;From:</th>
804 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
805 }
806 db_finalize(&q2);
807 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
808 if( g.perm.Hyperlink ){
809 @ <tr><th>Other&nbsp;Links:</th>
810 @ <td>
811 @ %z(href("%R/artifact/%!S",zUuid))manifest</a>
812 @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a>
@@ -818,15 +854,19 @@
818 }
819 @ </td>
820 @ </tr>
821 }
822 @ </table>
 
823 }else{
824 style_header("Check-in Information");
825 login_anonymous_available();
826 }
827 db_finalize(&q1);
 
 
 
828 render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
829 @ <div class="section">Context</div>
830 render_checkin_context(rid, 0);
831 @ <div class="section">Changes</div>
832 @ <div class="sectionmenu">
833
--- src/info.c
+++ src/info.c
@@ -690,10 +690,13 @@
690 const char *zUser;
691 const char *zOrigUser;
692 const char *zComment;
693 const char *zDate;
694 const char *zOrigDate;
695 const char *zBrName;
696 int okWiki = 0;
697 Blob wiki_links = BLOB_INITIALIZER;
698
699 style_header("Check-in [%S]", zUuid);
700 login_anonymous_available();
701 zEUser = db_text(0,
702 "SELECT value FROM tagxref"
@@ -700,10 +703,13 @@
703 " WHERE tagid=%d AND rid=%d AND tagtype>0",
704 TAG_USER, rid);
705 zEComment = db_text(0,
706 "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
707 TAG_COMMENT, rid);
708 zBrName = db_text(0,
709 "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
710 TAG_BRANCH, rid);
711 zOrigUser = db_column_text(&q1, 2);
712 zUser = zEUser ? zEUser : zOrigUser;
713 zComment = db_column_text(&q1, 3);
714 zDate = db_column_text(&q1,1);
715 zOrigDate = db_column_text(&q1, 4);
@@ -754,11 +760,23 @@
760 " WHERE rid=%d AND tagtype>0 "
761 " AND tag.tagid=tagxref.tagid "
762 " AND +tag.tagname GLOB 'sym-*'", rid);
763 while( db_step(&q2)==SQLITE_ROW ){
764 const char *zTagName = db_column_text(&q2, 0);
765 if( fossil_strcmp(zTagName,zBrName)==0 ){
766 @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
767 if( g.perm.Write || wiki_tagid2("branch",zTagName)!=0 ){
768 blob_appendf(&wiki_links, " | %z%h</a>",
769 href("%R/wiki?name=branch/%h",zTagName), zTagName);
770 }
771 }else{
772 @ | %z(href("%R/timeline?t=%T&unhide",zTagName))%h(zTagName)</a>
773 if( g.perm.Write || wiki_tagid2("tag",zTagName)!=0 ){
774 blob_appendf(&wiki_links, " | %z%h</a>",
775 href("%R/wiki?name=tag/%h",zTagName), zTagName);
776 }
777 }
778 }
779 db_finalize(&q2);
780 @ </td></tr>
781
782 @ <tr><th>Files:</th>
@@ -803,10 +821,28 @@
821 @ <tr><th>Received&nbsp;From:</th>
822 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
823 }
824 db_finalize(&q2);
825 }
826
827 /* Only show links to wiki pages if the users can read wiki,
828 ** and only if the wiki pages already exist or the user has the
829 ** ability to create new ones. */
830 if( g.perm.RdWiki
831 && (g.perm.Write || blob_size(&wiki_links)>0
832 || (okWiki = wiki_tagid2("checkin",zUuid))!=0)
833 && db_get_boolean("wiki-about",1)
834 ){
835 const char *zLinks = blob_str(&wiki_links);
836 if( zLinks[0] ) zLinks += 3;
837 @ <tr><th>Wiki:</th><td>\
838 if( g.perm.Write || okWiki ){
839 @ %z(href("%R/wiki?name=checkin/%s",zUuid))this checkin</a> | \
840 }
841 @ %s(zLinks)</td></tr>
842 }
843
844 if( g.perm.Hyperlink ){
845 @ <tr><th>Other&nbsp;Links:</th>
846 @ <td>
847 @ %z(href("%R/artifact/%!S",zUuid))manifest</a>
848 @ | %z(href("%R/ci_tags/%!S",zUuid))tags</a>
@@ -818,15 +854,19 @@
854 }
855 @ </td>
856 @ </tr>
857 }
858 @ </table>
859 blob_reset(&wiki_links);
860 }else{
861 style_header("Check-in Information");
862 login_anonymous_available();
863 }
864 db_finalize(&q1);
865 if( !PB("nowiki") ){
866 wiki_render_associated("checkin", zUuid, 0);
867 }
868 render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
869 @ <div class="section">Context</div>
870 render_checkin_context(rid, 0);
871 @ <div class="section">Changes</div>
872 @ <div class="sectionmenu">
873
+14
--- src/setup.c
+++ src/setup.c
@@ -941,10 +941,24 @@
941941
style_header("Wiki Configuration");
942942
db_begin_transaction();
943943
@ <form action="%s(g.zTop)/setup_wiki" method="post"><div>
944944
login_insert_csrf_secret();
945945
@ <input type="submit" name="submit" value="Apply Changes" /></p>
946
+ @ <hr />
947
+ onoff_attribute("Associate Wiki Pages With Branches, Tags, or Checkins",
948
+ "wiki-about", "wiki-about", 1, 0);
949
+ @ <p>
950
+ @ Associate wiki pages with branches, tags, or checkins, based on
951
+ @ the wiki page name. Wiki pages that begin with "branch/", "checkin/"
952
+ @ or "tag/" and which continue with the name of an existing branch, checkin
953
+ @ or tag are treated specially when this feature is enabled.
954
+ @ <ul>
955
+ @ <li> <b>branch/</b><i>branch-name</i>
956
+ @ <li> <b>checkin/</b><i>full-checkin-hash</i>
957
+ @ <li> <b>tag/</b><i>tag-name</i>
958
+ @ </ul>
959
+ @ (Property: "wiki-about")</p>
946960
@ <hr />
947961
onoff_attribute("Enable WYSIWYG Wiki Editing",
948962
"wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
949963
@ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
950964
@ The WYSIWYG editor generates HTML instead of markup, which makes
951965
--- src/setup.c
+++ src/setup.c
@@ -941,10 +941,24 @@
941 style_header("Wiki Configuration");
942 db_begin_transaction();
943 @ <form action="%s(g.zTop)/setup_wiki" method="post"><div>
944 login_insert_csrf_secret();
945 @ <input type="submit" name="submit" value="Apply Changes" /></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946 @ <hr />
947 onoff_attribute("Enable WYSIWYG Wiki Editing",
948 "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
949 @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
950 @ The WYSIWYG editor generates HTML instead of markup, which makes
951
--- src/setup.c
+++ src/setup.c
@@ -941,10 +941,24 @@
941 style_header("Wiki Configuration");
942 db_begin_transaction();
943 @ <form action="%s(g.zTop)/setup_wiki" method="post"><div>
944 login_insert_csrf_secret();
945 @ <input type="submit" name="submit" value="Apply Changes" /></p>
946 @ <hr />
947 onoff_attribute("Associate Wiki Pages With Branches, Tags, or Checkins",
948 "wiki-about", "wiki-about", 1, 0);
949 @ <p>
950 @ Associate wiki pages with branches, tags, or checkins, based on
951 @ the wiki page name. Wiki pages that begin with "branch/", "checkin/"
952 @ or "tag/" and which continue with the name of an existing branch, checkin
953 @ or tag are treated specially when this feature is enabled.
954 @ <ul>
955 @ <li> <b>branch/</b><i>branch-name</i>
956 @ <li> <b>checkin/</b><i>full-checkin-hash</i>
957 @ <li> <b>tag/</b><i>tag-name</i>
958 @ </ul>
959 @ (Property: "wiki-about")</p>
960 @ <hr />
961 onoff_attribute("Enable WYSIWYG Wiki Editing",
962 "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
963 @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
964 @ The WYSIWYG editor generates HTML instead of markup, which makes
965
+19 -2
--- src/timeline.c
+++ src/timeline.c
@@ -1423,10 +1423,11 @@
14231423
** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN
14241424
** t=TAG Show only check-ins with the given TAG
14251425
** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel
14261426
** rel Show related check-ins as well as those matching t=TAG
14271427
** mionly Limit rel to show ancestors but not descendants
1428
+** nowiki Do not show wiki associated with branch or tag
14281429
** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP
14291430
** u=USER Only show items associated with USER
14301431
** y=TYPE 'ci', 'w', 't', 'e', 'f', or 'all'.
14311432
** ss=VIEWSTYLE c: "Compact" v: "Verbose" m: "Modern" j: "Columnar"
14321433
** advm Use the "Advanced" or "Busy" menu design.
@@ -1444,20 +1445,20 @@
14441445
** name matches one of the comma-separate GLOBLIST
14451446
** brbg Background color from branch name
14461447
** ubg Background color from user
14471448
** namechng Show only check-ins that have filename changes
14481449
** forks Show only forks and their children
1450
+** cherrypicks Show all cherrypicks
14491451
** ym=YYYY-MM Show only events for the given year/month
14501452
** yw=YYYY-WW Show only events for the given week of the given year
14511453
** yw=YYYY-MM-DD Show events for the week that includes the given day
14521454
** ymd=YYYY-MM-DD Show only events on the given day
14531455
** days=N Show events over the previous N days
14541456
** datefmt=N Override the date format
14551457
** bisect Show the check-ins that are in the current bisect
14561458
** showid Show RIDs
14571459
** showsql Show the SQL text
1458
-** cherrypicks Show all cherrypicks
14591460
**
14601461
** p= and d= can appear individually or together. If either p= or d=
14611462
** appear, then u=, y=, a=, and b= are ignored.
14621463
**
14631464
** If both a= and b= appear then both upper and lower bounds are honored.
@@ -2269,11 +2270,27 @@
22692270
blob_zero(&sql);
22702271
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
22712272
if( fossil_islower(desc.aData[0]) ){
22722273
desc.aData[0] = fossil_toupper(desc.aData[0]);
22732274
}
2274
- @ <h2>%b(&desc)</h2>
2275
+ if( zBrName
2276
+ && !PB("nowiki")
2277
+ && wiki_render_associated("branch", zBrName,
2278
+ WIKIASSOC_FULL_TITLE|WIKIASSOC_MENU)
2279
+ ){
2280
+ @ <div class="section">%b(&desc)</div>
2281
+ }else
2282
+ if( zTagName
2283
+ && matchStyle==MS_EXACT
2284
+ && !PB("nowiki")
2285
+ && wiki_render_associated("tag", zTagName,
2286
+ WIKIASSOC_FULL_TITLE|WIKIASSOC_MENU)
2287
+ ){
2288
+ @ <div class="section">%b(&desc)</div>
2289
+ } else{
2290
+ @ <h2>%b(&desc)</h2>
2291
+ }
22752292
blob_reset(&desc);
22762293
22772294
/* Report any errors. */
22782295
if( zError ){
22792296
@ <p class="generalError">%h(zError)</p>
22802297
--- src/timeline.c
+++ src/timeline.c
@@ -1423,10 +1423,11 @@
1423 ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN
1424 ** t=TAG Show only check-ins with the given TAG
1425 ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel
1426 ** rel Show related check-ins as well as those matching t=TAG
1427 ** mionly Limit rel to show ancestors but not descendants
 
1428 ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP
1429 ** u=USER Only show items associated with USER
1430 ** y=TYPE 'ci', 'w', 't', 'e', 'f', or 'all'.
1431 ** ss=VIEWSTYLE c: "Compact" v: "Verbose" m: "Modern" j: "Columnar"
1432 ** advm Use the "Advanced" or "Busy" menu design.
@@ -1444,20 +1445,20 @@
1444 ** name matches one of the comma-separate GLOBLIST
1445 ** brbg Background color from branch name
1446 ** ubg Background color from user
1447 ** namechng Show only check-ins that have filename changes
1448 ** forks Show only forks and their children
 
1449 ** ym=YYYY-MM Show only events for the given year/month
1450 ** yw=YYYY-WW Show only events for the given week of the given year
1451 ** yw=YYYY-MM-DD Show events for the week that includes the given day
1452 ** ymd=YYYY-MM-DD Show only events on the given day
1453 ** days=N Show events over the previous N days
1454 ** datefmt=N Override the date format
1455 ** bisect Show the check-ins that are in the current bisect
1456 ** showid Show RIDs
1457 ** showsql Show the SQL text
1458 ** cherrypicks Show all cherrypicks
1459 **
1460 ** p= and d= can appear individually or together. If either p= or d=
1461 ** appear, then u=, y=, a=, and b= are ignored.
1462 **
1463 ** If both a= and b= appear then both upper and lower bounds are honored.
@@ -2269,11 +2270,27 @@
2269 blob_zero(&sql);
2270 db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
2271 if( fossil_islower(desc.aData[0]) ){
2272 desc.aData[0] = fossil_toupper(desc.aData[0]);
2273 }
2274 @ <h2>%b(&desc)</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2275 blob_reset(&desc);
2276
2277 /* Report any errors. */
2278 if( zError ){
2279 @ <p class="generalError">%h(zError)</p>
2280
--- src/timeline.c
+++ src/timeline.c
@@ -1423,10 +1423,11 @@
1423 ** dp=CHECKIN The same as d=CHECKIN&p=CHECKIN
1424 ** t=TAG Show only check-ins with the given TAG
1425 ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel
1426 ** rel Show related check-ins as well as those matching t=TAG
1427 ** mionly Limit rel to show ancestors but not descendants
1428 ** nowiki Do not show wiki associated with branch or tag
1429 ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP
1430 ** u=USER Only show items associated with USER
1431 ** y=TYPE 'ci', 'w', 't', 'e', 'f', or 'all'.
1432 ** ss=VIEWSTYLE c: "Compact" v: "Verbose" m: "Modern" j: "Columnar"
1433 ** advm Use the "Advanced" or "Busy" menu design.
@@ -1444,20 +1445,20 @@
1445 ** name matches one of the comma-separate GLOBLIST
1446 ** brbg Background color from branch name
1447 ** ubg Background color from user
1448 ** namechng Show only check-ins that have filename changes
1449 ** forks Show only forks and their children
1450 ** cherrypicks Show all cherrypicks
1451 ** ym=YYYY-MM Show only events for the given year/month
1452 ** yw=YYYY-WW Show only events for the given week of the given year
1453 ** yw=YYYY-MM-DD Show events for the week that includes the given day
1454 ** ymd=YYYY-MM-DD Show only events on the given day
1455 ** days=N Show events over the previous N days
1456 ** datefmt=N Override the date format
1457 ** bisect Show the check-ins that are in the current bisect
1458 ** showid Show RIDs
1459 ** showsql Show the SQL text
 
1460 **
1461 ** p= and d= can appear individually or together. If either p= or d=
1462 ** appear, then u=, y=, a=, and b= are ignored.
1463 **
1464 ** If both a= and b= appear then both upper and lower bounds are honored.
@@ -2269,11 +2270,27 @@
2270 blob_zero(&sql);
2271 db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
2272 if( fossil_islower(desc.aData[0]) ){
2273 desc.aData[0] = fossil_toupper(desc.aData[0]);
2274 }
2275 if( zBrName
2276 && !PB("nowiki")
2277 && wiki_render_associated("branch", zBrName,
2278 WIKIASSOC_FULL_TITLE|WIKIASSOC_MENU)
2279 ){
2280 @ <div class="section">%b(&desc)</div>
2281 }else
2282 if( zTagName
2283 && matchStyle==MS_EXACT
2284 && !PB("nowiki")
2285 && wiki_render_associated("tag", zTagName,
2286 WIKIASSOC_FULL_TITLE|WIKIASSOC_MENU)
2287 ){
2288 @ <div class="section">%b(&desc)</div>
2289 } else{
2290 @ <h2>%b(&desc)</h2>
2291 }
2292 blob_reset(&desc);
2293
2294 /* Report any errors. */
2295 if( zError ){
2296 @ <p class="generalError">%h(zError)</p>
2297
+180 -5
--- src/wiki.c
+++ src/wiki.c
@@ -78,10 +78,14 @@
7878
** Return the tagid associated with a particular wiki page.
7979
*/
8080
int wiki_tagid(const char *zPageName){
8181
return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName);
8282
}
83
+int wiki_tagid2(const char *zPrefix, const char *zPageName){
84
+ return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q/%q'",
85
+ zPrefix, zPageName);
86
+}
8387
8488
/*
8589
** Return the RID of the next or previous version of a wiki page.
8690
** Return 0 if rid is the last/first version.
8791
*/
@@ -343,10 +347,58 @@
343347
style_header("Wiki Search");
344348
wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
345349
search_screen(SRCH_WIKI, 0);
346350
style_footer();
347351
}
352
+
353
+/*
354
+** Add an appropriate style_header() for either the /wiki or /wikiedit page
355
+** for zPageName.
356
+*/
357
+static void wiki_page_header(const char *zPageName, const char *zExtra){
358
+ if( db_get_boolean("wiki-about",1)==0 ){
359
+ style_header("%s%s", zExtra, zPageName);
360
+ }else
361
+ if( sqlite3_strglob("checkin/*", zPageName)==0
362
+ && db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8)
363
+ ){
364
+ style_header("Notes About Checkin %S", zPageName + 8);
365
+ style_submenu_element("Checkin Timeline","%R/timeline?f=%s",zPageName + 8);
366
+ style_submenu_element("Checkin Info","%R/info/%s",zPageName + 8);
367
+ }else
368
+ if( sqlite3_strglob("branch/*", zPageName)==0 ){
369
+ style_header("Notes About Branch %h", zPageName + 7);
370
+ style_submenu_element("Branch Timeline","%R/timeline?r=%t",zPageName + 7);
371
+ }else
372
+ if( sqlite3_strglob("tag/*", zPageName)==0 ){
373
+ style_header("Notes About Tag %h", zPageName + 4);
374
+ style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName + 4);
375
+ }
376
+ else{
377
+ style_header("%s%s", zExtra, zPageName);
378
+ }
379
+}
380
+
381
+/*
382
+** Wiki pages with special names "branch/...", "checkin/...", and "tag/..."
383
+** requires perm.Write privilege in addition to perm.WrWiki in order
384
+** to write. This function determines whether the extra perm.Write
385
+** is required and available. Return true if writing to the wiki page
386
+** may proceed, and return false if permission is lacking.
387
+*/
388
+static int wiki_special_permission(const char *zPageName){
389
+ if( strncmp(zPageName,"branch/",7)!=0
390
+ && strncmp(zPageName,"checkin/",8)!=0
391
+ && strncmp(zPageName,"tag/",4)!=0
392
+ ){
393
+ return 1;
394
+ }
395
+ if( db_get_boolean("wiki-about",1)==0 ){
396
+ return 1;
397
+ }
398
+ return g.perm.Write;
399
+}
348400
349401
/*
350402
** WEBPAGE: wiki
351403
** URL: /wiki?name=PAGENAME
352404
*/
@@ -396,11 +448,13 @@
396448
zMimetype = pWiki->zMimetype;
397449
}
398450
}
399451
zMimetype = wiki_filter_mimetypes(zMimetype);
400452
if( !g.isHome ){
401
- if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
453
+ if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
454
+ && wiki_special_permission(zPageName)
455
+ ){
402456
if( db_get_boolean("wysiwyg-wiki", 0) ){
403457
style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1",
404458
g.zTop, zPageName);
405459
}else{
406460
style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName);
@@ -410,11 +464,11 @@
410464
style_submenu_element("History", "%s/whistory?name=%T",
411465
g.zTop, zPageName);
412466
}
413467
}
414468
style_set_current_page("%T?name=%T", g.zPath, zPageName);
415
- style_header("%s", zPageName);
469
+ wiki_page_header(zPageName, "");
416470
wiki_standard_submenu(submenuFlags);
417471
if( zBody[0]==0 ){
418472
@ <i>This page has been deleted</i>
419473
}else{
420474
blob_init(&wiki, zBody, -1);
@@ -526,10 +580,14 @@
526580
"SELECT rid FROM tagxref"
527581
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
528582
" ORDER BY mtime DESC", zTag
529583
);
530584
free(zTag);
585
+ if( !wiki_special_permission(zPageName) ){
586
+ login_needed(0);
587
+ return;
588
+ }
531589
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
532590
login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
533591
return;
534592
}
535593
if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
@@ -579,11 +637,11 @@
579637
}
580638
if( zBody==0 ){
581639
zBody = mprintf("<i>Empty Page</i>");
582640
}
583641
style_set_current_page("%T?name=%T", g.zPath, zPageName);
584
- style_header("Edit: %s", zPageName);
642
+ wiki_page_header(zPageName, "Edit: ");
585643
if( rid && !isSandbox && g.perm.ApndWiki ){
586644
if( g.perm.Attach ){
587645
style_submenu_element("Attach",
588646
"%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
589647
g.zTop, zPageName, g.zTop, zPageName);
@@ -1067,26 +1125,34 @@
10671125
int wrid = db_column_int(&q, 2);
10681126
double rWmtime = db_column_double(&q, 3);
10691127
sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0);
10701128
char *zAge;
10711129
int wcnt = db_column_int(&q, 4);
1130
+ char *zWDisplayName;
1131
+
1132
+ if( sqlite3_strglob("checkin/*", zWName)==0 ){
1133
+ zWDisplayName = mprintf("%.25s...", zWName);
1134
+ }else{
1135
+ zWDisplayName = mprintf("%s", zWName);
1136
+ }
10721137
if( wrid==0 ){
10731138
if( !showAll ) continue;
10741139
@ <tr><td data-sortkey="%h(zSort)">\
1075
- @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWName)</s></a></td>
1140
+ @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td>
10761141
}else{
10771142
@ <tr><td data=sortkey='%h(zSort)">\
1078
- @ %z(href("%R/wiki?name=%T",zWName))%h(zWName)</a></td>
1143
+ @ %z(href("%R/wiki?name=%T",zWName))%h(zWDisplayName)</a></td>
10791144
}
10801145
zAge = human_readable_age(rNow - rWmtime);
10811146
@ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td>
10821147
fossil_free(zAge);
10831148
@ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td>
10841149
if( showRid ){
10851150
@ <td>%d(wrid)</td>
10861151
}
10871152
@ </tr>
1153
+ fossil_free(zWDisplayName);
10881154
}
10891155
@ </tbody></table></div>
10901156
db_finalize(&q);
10911157
style_table_sorter();
10921158
style_footer();
@@ -1483,5 +1549,114 @@
14831549
blob_zero(&out);
14841550
blob_read_from_file(&in, g.argv[2], ExtFILE);
14851551
markdown_to_html(&in, 0, &out);
14861552
blob_write_to_file(&out, "-");
14871553
}
1554
+
1555
+/*
1556
+** Allowed flags for wiki_render_associated
1557
+*/
1558
+#if INTERFACE
1559
+#define WIKIASSOC_FULL_TITLE 0x00001 /* Full title */
1560
+#define WIKIASSOC_MENU 0x00002 /* Add a submenu to the About section */
1561
+#endif
1562
+
1563
+/*
1564
+** Show the default Section label for an associated wiki page.
1565
+*/
1566
+static void wiki_section_label(
1567
+ const char *zPrefix, /* "branch", "tag", or "checkin" */
1568
+ const char *zName, /* Name of the object */
1569
+ unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1570
+){
1571
+ if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
1572
+ @ <div class="section">About</div>
1573
+ }else if( zPrefix[0]=='c' ){ /* checkin/... */
1574
+ @ <div class="section">About checkin %.20h(zName)</div>
1575
+ }else{
1576
+ @ <div class="section">About %s(zPrefix) %h(zName)</div>
1577
+ }
1578
+}
1579
+
1580
+/*
1581
+** Add an "Wiki" button in a submenu for a Wiki page.
1582
+*/
1583
+static void wiki_section_menu(
1584
+ const char *zPrefix, /* "branch", "tag", or "checkin" */
1585
+ const char *zName, /* Name of the object */
1586
+ unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1587
+){
1588
+ if( g.perm.WrWiki && (mFlags & WIKIASSOC_MENU)!=0 ){
1589
+ style_submenu_element("Wiki", "%R/wiki?name=%s/%t", zPrefix, zName);
1590
+ }
1591
+}
1592
+
1593
+/*
1594
+** Check to see if there exists a wiki page with a name zPrefix/zName.
1595
+** If there is, then render a <div class='section'>..</div> and
1596
+** return true.
1597
+**
1598
+** If there is no such wiki page, return false.
1599
+*/
1600
+int wiki_render_associated(
1601
+ const char *zPrefix, /* "branch", "tag", or "checkin" */
1602
+ const char *zName, /* Name of the object */
1603
+ unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1604
+){
1605
+ int rid;
1606
+ Manifest *pWiki;
1607
+ if( !db_get_boolean("wiki-about",1) ) return 0;
1608
+ rid = db_int(0,
1609
+ "SELECT rid FROM tagxref"
1610
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='wiki-%q/%q')"
1611
+ " ORDER BY mtime DESC LIMIT 1",
1612
+ zPrefix, zName
1613
+ );
1614
+ if( rid==0 ) return 0;
1615
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
1616
+ if( pWiki==0 ) return 0;
1617
+ if( fossil_strcmp(pWiki->zMimetype, "text/x-markdown")==0 ){
1618
+ Blob tail = BLOB_INITIALIZER;
1619
+ Blob title = BLOB_INITIALIZER;
1620
+ Blob markdown;
1621
+ blob_init(&markdown, pWiki->zWiki, -1);
1622
+ markdown_to_html(&markdown, &title, &tail);
1623
+ if( blob_size(&title) ){
1624
+ @ <div class="section">%h(blob_str(&title))</div>
1625
+ }else{
1626
+ wiki_section_label(zPrefix, zName, mFlags);
1627
+ }
1628
+ wiki_section_menu(zPrefix, zName, mFlags);
1629
+ convert_href_and_output(&tail);
1630
+ blob_reset(&tail);
1631
+ blob_reset(&title);
1632
+ blob_reset(&markdown);
1633
+ }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){
1634
+ wiki_section_label(zPrefix, zName, mFlags);
1635
+ wiki_section_menu(zPrefix, zName, mFlags);
1636
+ @ <pre>
1637
+ @ %h(pWiki->zWiki)
1638
+ @ </pre>
1639
+ }else{
1640
+ Blob tail = BLOB_INITIALIZER;
1641
+ Blob title = BLOB_INITIALIZER;
1642
+ Blob wiki;
1643
+ Blob *pBody;
1644
+ blob_init(&wiki, pWiki->zWiki, -1);
1645
+ if( wiki_find_title(&wiki, &title, &tail) ){
1646
+ @ <div class="section">%h(blob_str(&title))</div>
1647
+ pBody = &tail;
1648
+ }else{
1649
+ wiki_section_label(zPrefix, zName, mFlags);
1650
+ pBody = &wiki;
1651
+ }
1652
+ wiki_section_menu(zPrefix, zName, mFlags);
1653
+ @ <div class="wiki">
1654
+ wiki_convert(pBody, 0, WIKI_BUTTONS);
1655
+ @ </div>
1656
+ blob_reset(&tail);
1657
+ blob_reset(&title);
1658
+ blob_reset(&wiki);
1659
+ }
1660
+ manifest_destroy(pWiki);
1661
+ return 1;
1662
+}
14881663
--- src/wiki.c
+++ src/wiki.c
@@ -78,10 +78,14 @@
78 ** Return the tagid associated with a particular wiki page.
79 */
80 int wiki_tagid(const char *zPageName){
81 return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName);
82 }
 
 
 
 
83
84 /*
85 ** Return the RID of the next or previous version of a wiki page.
86 ** Return 0 if rid is the last/first version.
87 */
@@ -343,10 +347,58 @@
343 style_header("Wiki Search");
344 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
345 search_screen(SRCH_WIKI, 0);
346 style_footer();
347 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
349 /*
350 ** WEBPAGE: wiki
351 ** URL: /wiki?name=PAGENAME
352 */
@@ -396,11 +448,13 @@
396 zMimetype = pWiki->zMimetype;
397 }
398 }
399 zMimetype = wiki_filter_mimetypes(zMimetype);
400 if( !g.isHome ){
401 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
 
 
402 if( db_get_boolean("wysiwyg-wiki", 0) ){
403 style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1",
404 g.zTop, zPageName);
405 }else{
406 style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName);
@@ -410,11 +464,11 @@
410 style_submenu_element("History", "%s/whistory?name=%T",
411 g.zTop, zPageName);
412 }
413 }
414 style_set_current_page("%T?name=%T", g.zPath, zPageName);
415 style_header("%s", zPageName);
416 wiki_standard_submenu(submenuFlags);
417 if( zBody[0]==0 ){
418 @ <i>This page has been deleted</i>
419 }else{
420 blob_init(&wiki, zBody, -1);
@@ -526,10 +580,14 @@
526 "SELECT rid FROM tagxref"
527 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
528 " ORDER BY mtime DESC", zTag
529 );
530 free(zTag);
 
 
 
 
531 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
532 login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
533 return;
534 }
535 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
@@ -579,11 +637,11 @@
579 }
580 if( zBody==0 ){
581 zBody = mprintf("<i>Empty Page</i>");
582 }
583 style_set_current_page("%T?name=%T", g.zPath, zPageName);
584 style_header("Edit: %s", zPageName);
585 if( rid && !isSandbox && g.perm.ApndWiki ){
586 if( g.perm.Attach ){
587 style_submenu_element("Attach",
588 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
589 g.zTop, zPageName, g.zTop, zPageName);
@@ -1067,26 +1125,34 @@
1067 int wrid = db_column_int(&q, 2);
1068 double rWmtime = db_column_double(&q, 3);
1069 sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0);
1070 char *zAge;
1071 int wcnt = db_column_int(&q, 4);
 
 
 
 
 
 
 
1072 if( wrid==0 ){
1073 if( !showAll ) continue;
1074 @ <tr><td data-sortkey="%h(zSort)">\
1075 @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWName)</s></a></td>
1076 }else{
1077 @ <tr><td data=sortkey='%h(zSort)">\
1078 @ %z(href("%R/wiki?name=%T",zWName))%h(zWName)</a></td>
1079 }
1080 zAge = human_readable_age(rNow - rWmtime);
1081 @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td>
1082 fossil_free(zAge);
1083 @ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td>
1084 if( showRid ){
1085 @ <td>%d(wrid)</td>
1086 }
1087 @ </tr>
 
1088 }
1089 @ </tbody></table></div>
1090 db_finalize(&q);
1091 style_table_sorter();
1092 style_footer();
@@ -1483,5 +1549,114 @@
1483 blob_zero(&out);
1484 blob_read_from_file(&in, g.argv[2], ExtFILE);
1485 markdown_to_html(&in, 0, &out);
1486 blob_write_to_file(&out, "-");
1487 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1488
--- src/wiki.c
+++ src/wiki.c
@@ -78,10 +78,14 @@
78 ** Return the tagid associated with a particular wiki page.
79 */
80 int wiki_tagid(const char *zPageName){
81 return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q'",zPageName);
82 }
83 int wiki_tagid2(const char *zPrefix, const char *zPageName){
84 return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q/%q'",
85 zPrefix, zPageName);
86 }
87
88 /*
89 ** Return the RID of the next or previous version of a wiki page.
90 ** Return 0 if rid is the last/first version.
91 */
@@ -343,10 +347,58 @@
347 style_header("Wiki Search");
348 wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
349 search_screen(SRCH_WIKI, 0);
350 style_footer();
351 }
352
353 /*
354 ** Add an appropriate style_header() for either the /wiki or /wikiedit page
355 ** for zPageName.
356 */
357 static void wiki_page_header(const char *zPageName, const char *zExtra){
358 if( db_get_boolean("wiki-about",1)==0 ){
359 style_header("%s%s", zExtra, zPageName);
360 }else
361 if( sqlite3_strglob("checkin/*", zPageName)==0
362 && db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8)
363 ){
364 style_header("Notes About Checkin %S", zPageName + 8);
365 style_submenu_element("Checkin Timeline","%R/timeline?f=%s",zPageName + 8);
366 style_submenu_element("Checkin Info","%R/info/%s",zPageName + 8);
367 }else
368 if( sqlite3_strglob("branch/*", zPageName)==0 ){
369 style_header("Notes About Branch %h", zPageName + 7);
370 style_submenu_element("Branch Timeline","%R/timeline?r=%t",zPageName + 7);
371 }else
372 if( sqlite3_strglob("tag/*", zPageName)==0 ){
373 style_header("Notes About Tag %h", zPageName + 4);
374 style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName + 4);
375 }
376 else{
377 style_header("%s%s", zExtra, zPageName);
378 }
379 }
380
381 /*
382 ** Wiki pages with special names "branch/...", "checkin/...", and "tag/..."
383 ** requires perm.Write privilege in addition to perm.WrWiki in order
384 ** to write. This function determines whether the extra perm.Write
385 ** is required and available. Return true if writing to the wiki page
386 ** may proceed, and return false if permission is lacking.
387 */
388 static int wiki_special_permission(const char *zPageName){
389 if( strncmp(zPageName,"branch/",7)!=0
390 && strncmp(zPageName,"checkin/",8)!=0
391 && strncmp(zPageName,"tag/",4)!=0
392 ){
393 return 1;
394 }
395 if( db_get_boolean("wiki-about",1)==0 ){
396 return 1;
397 }
398 return g.perm.Write;
399 }
400
401 /*
402 ** WEBPAGE: wiki
403 ** URL: /wiki?name=PAGENAME
404 */
@@ -396,11 +448,13 @@
448 zMimetype = pWiki->zMimetype;
449 }
450 }
451 zMimetype = wiki_filter_mimetypes(zMimetype);
452 if( !g.isHome ){
453 if( ((rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki))
454 && wiki_special_permission(zPageName)
455 ){
456 if( db_get_boolean("wysiwyg-wiki", 0) ){
457 style_submenu_element("Edit", "%s/wikiedit?name=%T&wysiwyg=1",
458 g.zTop, zPageName);
459 }else{
460 style_submenu_element("Edit", "%s/wikiedit?name=%T", g.zTop, zPageName);
@@ -410,11 +464,11 @@
464 style_submenu_element("History", "%s/whistory?name=%T",
465 g.zTop, zPageName);
466 }
467 }
468 style_set_current_page("%T?name=%T", g.zPath, zPageName);
469 wiki_page_header(zPageName, "");
470 wiki_standard_submenu(submenuFlags);
471 if( zBody[0]==0 ){
472 @ <i>This page has been deleted</i>
473 }else{
474 blob_init(&wiki, zBody, -1);
@@ -526,10 +580,14 @@
580 "SELECT rid FROM tagxref"
581 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
582 " ORDER BY mtime DESC", zTag
583 );
584 free(zTag);
585 if( !wiki_special_permission(zPageName) ){
586 login_needed(0);
587 return;
588 }
589 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
590 login_needed(rid ? g.anon.WrWiki : g.anon.NewWiki);
591 return;
592 }
593 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
@@ -579,11 +637,11 @@
637 }
638 if( zBody==0 ){
639 zBody = mprintf("<i>Empty Page</i>");
640 }
641 style_set_current_page("%T?name=%T", g.zPath, zPageName);
642 wiki_page_header(zPageName, "Edit: ");
643 if( rid && !isSandbox && g.perm.ApndWiki ){
644 if( g.perm.Attach ){
645 style_submenu_element("Attach",
646 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
647 g.zTop, zPageName, g.zTop, zPageName);
@@ -1067,26 +1125,34 @@
1125 int wrid = db_column_int(&q, 2);
1126 double rWmtime = db_column_double(&q, 3);
1127 sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0);
1128 char *zAge;
1129 int wcnt = db_column_int(&q, 4);
1130 char *zWDisplayName;
1131
1132 if( sqlite3_strglob("checkin/*", zWName)==0 ){
1133 zWDisplayName = mprintf("%.25s...", zWName);
1134 }else{
1135 zWDisplayName = mprintf("%s", zWName);
1136 }
1137 if( wrid==0 ){
1138 if( !showAll ) continue;
1139 @ <tr><td data-sortkey="%h(zSort)">\
1140 @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td>
1141 }else{
1142 @ <tr><td data=sortkey='%h(zSort)">\
1143 @ %z(href("%R/wiki?name=%T",zWName))%h(zWDisplayName)</a></td>
1144 }
1145 zAge = human_readable_age(rNow - rWmtime);
1146 @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td>
1147 fossil_free(zAge);
1148 @ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td>
1149 if( showRid ){
1150 @ <td>%d(wrid)</td>
1151 }
1152 @ </tr>
1153 fossil_free(zWDisplayName);
1154 }
1155 @ </tbody></table></div>
1156 db_finalize(&q);
1157 style_table_sorter();
1158 style_footer();
@@ -1483,5 +1549,114 @@
1549 blob_zero(&out);
1550 blob_read_from_file(&in, g.argv[2], ExtFILE);
1551 markdown_to_html(&in, 0, &out);
1552 blob_write_to_file(&out, "-");
1553 }
1554
1555 /*
1556 ** Allowed flags for wiki_render_associated
1557 */
1558 #if INTERFACE
1559 #define WIKIASSOC_FULL_TITLE 0x00001 /* Full title */
1560 #define WIKIASSOC_MENU 0x00002 /* Add a submenu to the About section */
1561 #endif
1562
1563 /*
1564 ** Show the default Section label for an associated wiki page.
1565 */
1566 static void wiki_section_label(
1567 const char *zPrefix, /* "branch", "tag", or "checkin" */
1568 const char *zName, /* Name of the object */
1569 unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1570 ){
1571 if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){
1572 @ <div class="section">About</div>
1573 }else if( zPrefix[0]=='c' ){ /* checkin/... */
1574 @ <div class="section">About checkin %.20h(zName)</div>
1575 }else{
1576 @ <div class="section">About %s(zPrefix) %h(zName)</div>
1577 }
1578 }
1579
1580 /*
1581 ** Add an "Wiki" button in a submenu for a Wiki page.
1582 */
1583 static void wiki_section_menu(
1584 const char *zPrefix, /* "branch", "tag", or "checkin" */
1585 const char *zName, /* Name of the object */
1586 unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1587 ){
1588 if( g.perm.WrWiki && (mFlags & WIKIASSOC_MENU)!=0 ){
1589 style_submenu_element("Wiki", "%R/wiki?name=%s/%t", zPrefix, zName);
1590 }
1591 }
1592
1593 /*
1594 ** Check to see if there exists a wiki page with a name zPrefix/zName.
1595 ** If there is, then render a <div class='section'>..</div> and
1596 ** return true.
1597 **
1598 ** If there is no such wiki page, return false.
1599 */
1600 int wiki_render_associated(
1601 const char *zPrefix, /* "branch", "tag", or "checkin" */
1602 const char *zName, /* Name of the object */
1603 unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
1604 ){
1605 int rid;
1606 Manifest *pWiki;
1607 if( !db_get_boolean("wiki-about",1) ) return 0;
1608 rid = db_int(0,
1609 "SELECT rid FROM tagxref"
1610 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='wiki-%q/%q')"
1611 " ORDER BY mtime DESC LIMIT 1",
1612 zPrefix, zName
1613 );
1614 if( rid==0 ) return 0;
1615 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
1616 if( pWiki==0 ) return 0;
1617 if( fossil_strcmp(pWiki->zMimetype, "text/x-markdown")==0 ){
1618 Blob tail = BLOB_INITIALIZER;
1619 Blob title = BLOB_INITIALIZER;
1620 Blob markdown;
1621 blob_init(&markdown, pWiki->zWiki, -1);
1622 markdown_to_html(&markdown, &title, &tail);
1623 if( blob_size(&title) ){
1624 @ <div class="section">%h(blob_str(&title))</div>
1625 }else{
1626 wiki_section_label(zPrefix, zName, mFlags);
1627 }
1628 wiki_section_menu(zPrefix, zName, mFlags);
1629 convert_href_and_output(&tail);
1630 blob_reset(&tail);
1631 blob_reset(&title);
1632 blob_reset(&markdown);
1633 }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){
1634 wiki_section_label(zPrefix, zName, mFlags);
1635 wiki_section_menu(zPrefix, zName, mFlags);
1636 @ <pre>
1637 @ %h(pWiki->zWiki)
1638 @ </pre>
1639 }else{
1640 Blob tail = BLOB_INITIALIZER;
1641 Blob title = BLOB_INITIALIZER;
1642 Blob wiki;
1643 Blob *pBody;
1644 blob_init(&wiki, pWiki->zWiki, -1);
1645 if( wiki_find_title(&wiki, &title, &tail) ){
1646 @ <div class="section">%h(blob_str(&title))</div>
1647 pBody = &tail;
1648 }else{
1649 wiki_section_label(zPrefix, zName, mFlags);
1650 pBody = &wiki;
1651 }
1652 wiki_section_menu(zPrefix, zName, mFlags);
1653 @ <div class="wiki">
1654 wiki_convert(pBody, 0, WIKI_BUTTONS);
1655 @ </div>
1656 blob_reset(&tail);
1657 blob_reset(&title);
1658 blob_reset(&wiki);
1659 }
1660 manifest_destroy(pWiki);
1661 return 1;
1662 }
1663

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button