Fossil SCM
merge [trunk]
Commit
0b63227882a8342c415c5292f25fae748d52c6facb1fe9997a1dbe50bc542554
Parent
ba00ba5d7bf52af…
26 files changed
+27
+1
-1
+31
+2
-1
+22
-16
+4
-1
+2
-2
+1
+2
-2
+3
-1
+3
-2
+48
-8
+89
-20
+1
+11
+8
-6
+2
-1
+11
-8
+2
-1
+1
-1
+2
-1
+1
-1
+35
+2
-2
+1
+4
~
src/accordion.js
~
src/attach.c
~
src/default_css.txt
~
src/file.c
~
src/forum.c
~
src/fshell.c
~
src/info.c
~
src/main.mk
~
src/makemake.tcl
~
src/manifest.c
~
src/moderate.c
~
src/name.c
~
src/search.c
~
src/setup.c
~
src/style.c
~
src/timeline.c
~
src/update.c
~
src/wiki.c
~
win/Makefile.mingw
~
win/Makefile.mingw.mistachkin
~
win/Makefile.msc
~
www/build.wiki
~
www/css-tricks.md
~
www/defcsp.md
~
www/mkindex.tcl
~
www/permutedindex.html
+27
| --- a/src/accordion.js | ||
| +++ b/src/accordion.js | ||
| @@ -0,0 +1,27 @@ | ||
| 1 | +/* Attach appropriate javascript to each ".accordion" button so that | |
| 2 | +** it expands and contracts when clicked. | |
| 3 | +**ntracts when clicked. | |
| 4 | +** | |
| 5 | +** The uncompressed source code for the SV | |
| 6 | +** wiki page "branch/accordion-experiments" window to a smaller | |
| 7 | +** width, causing vertical growth.) | |
| 8 | +** | |
| 9 | +** Ano"+"/"+"ttach appropriate javascript to each ".accordion" button so that | |
| 10 | +** it expands and contracts when clicked. | |
| 11 | +**ntracts when clicked. | |
| 12 | +** | |
| 13 | +** The uncompressed source code for the SV | |
| 14 | +** wiki page "branch/accordion-experiments" window to a smaller | |
| 15 | +** width, causing vertical growth.) | |
| 16 | +** | |
| 17 | +** Another problem is that `scrollHeight' used to calculate the expanded height | |
| 18 | +** while still in the contracted state may return values with small errors on | |
| 19 | +** some browsers, especially for large elements, presumably due to omitting the | |
| 20 | +** space required by the vertical scrollbar that may become necessary, causing | |
| 21 | +** additional horizontal shrinking and consequently more vertical growth than | |
| 22 | +** calculated. That's why se/* Attach appropriate javascript to each ".accordion" button so that | |
| 23 | +** it expands and contracts when clicked. | |
| 24 | +**ntracts when clicked. | |
| 25 | +** | |
| 26 | +** The uncompressed source code for the SV | |
| 27 | +** wiki page "branch/accordion-experiments" window to a smvar p = a[i].nextElementSibli |
| --- a/src/accordion.js | |
| +++ b/src/accordion.js | |
| @@ -0,0 +1,27 @@ | |
| --- a/src/accordion.js | |
| +++ b/src/accordion.js | |
| @@ -0,0 +1,27 @@ | |
| 1 | /* Attach appropriate javascript to each ".accordion" button so that |
| 2 | ** it expands and contracts when clicked. |
| 3 | **ntracts when clicked. |
| 4 | ** |
| 5 | ** The uncompressed source code for the SV |
| 6 | ** wiki page "branch/accordion-experiments" window to a smaller |
| 7 | ** width, causing vertical growth.) |
| 8 | ** |
| 9 | ** Ano"+"/"+"ttach appropriate javascript to each ".accordion" button so that |
| 10 | ** it expands and contracts when clicked. |
| 11 | **ntracts when clicked. |
| 12 | ** |
| 13 | ** The uncompressed source code for the SV |
| 14 | ** wiki page "branch/accordion-experiments" window to a smaller |
| 15 | ** width, causing vertical growth.) |
| 16 | ** |
| 17 | ** Another problem is that `scrollHeight' used to calculate the expanded height |
| 18 | ** while still in the contracted state may return values with small errors on |
| 19 | ** some browsers, especially for large elements, presumably due to omitting the |
| 20 | ** space required by the vertical scrollbar that may become necessary, causing |
| 21 | ** additional horizontal shrinking and consequently more vertical growth than |
| 22 | ** calculated. That's why se/* Attach appropriate javascript to each ".accordion" button so that |
| 23 | ** it expands and contracts when clicked. |
| 24 | **ntracts when clicked. |
| 25 | ** |
| 26 | ** The uncompressed source code for the SV |
| 27 | ** wiki page "branch/accordion-experiments" window to a smvar p = a[i].nextElementSibli |
+1
-1
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -545,11 +545,11 @@ | ||
| 545 | 545 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 546 | 546 | } |
| 547 | 547 | return; |
| 548 | 548 | } |
| 549 | 549 | if( strcmp(zModAction,"approve")==0 ){ |
| 550 | - moderation_approve(rid); | |
| 550 | + moderation_approve('a', rid); | |
| 551 | 551 | } |
| 552 | 552 | } |
| 553 | 553 | style_header("Attachment Details"); |
| 554 | 554 | style_submenu_element("Raw", "%R/artifact/%s", zUuid); |
| 555 | 555 | if(fShowContent){ |
| 556 | 556 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -545,11 +545,11 @@ | |
| 545 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 546 | } |
| 547 | return; |
| 548 | } |
| 549 | if( strcmp(zModAction,"approve")==0 ){ |
| 550 | moderation_approve(rid); |
| 551 | } |
| 552 | } |
| 553 | style_header("Attachment Details"); |
| 554 | style_submenu_element("Raw", "%R/artifact/%s", zUuid); |
| 555 | if(fShowContent){ |
| 556 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -545,11 +545,11 @@ | |
| 545 | cgi_redirectf("%R/wiki?name=%t", zWikiName); |
| 546 | } |
| 547 | return; |
| 548 | } |
| 549 | if( strcmp(zModAction,"approve")==0 ){ |
| 550 | moderation_approve('a', rid); |
| 551 | } |
| 552 | } |
| 553 | style_header("Attachment Details"); |
| 554 | style_submenu_element("Raw", "%R/artifact/%s", zUuid); |
| 555 | if(fShowContent){ |
| 556 |
+31
| --- src/default_css.txt | ||
| +++ src/default_css.txt | ||
| @@ -745,10 +745,12 @@ | ||
| 745 | 745 | } |
| 746 | 746 | div.forumTimeline { |
| 747 | 747 | border: 1px solid black; |
| 748 | 748 | padding-left: 1ex; |
| 749 | 749 | padding-right: 1ex; |
| 750 | + max-width: 50em; | |
| 751 | + overflow: auto; | |
| 750 | 752 | } |
| 751 | 753 | div.forumTimeline code { |
| 752 | 754 | white-space: pre-wrap; |
| 753 | 755 | } |
| 754 | 756 | div.markdown code { |
| @@ -757,10 +759,14 @@ | ||
| 757 | 759 | div.forumHier, div.forumTime { |
| 758 | 760 | border: 1px solid black; |
| 759 | 761 | padding-left: 1ex; |
| 760 | 762 | padding-right: 1ex; |
| 761 | 763 | margin-top: 1ex; |
| 764 | +} | |
| 765 | +div.forumPostBody { | |
| 766 | + max-height: 40em; | |
| 767 | + overflow: auto; | |
| 762 | 768 | } |
| 763 | 769 | div.forumSel { |
| 764 | 770 | background-color: #cef; |
| 765 | 771 | } |
| 766 | 772 | div.forumObs { |
| @@ -810,5 +816,30 @@ | ||
| 810 | 816 | margin-right: 0; |
| 811 | 817 | } |
| 812 | 818 | .nobr { |
| 813 | 819 | white-space: nowrap; |
| 814 | 820 | } |
| 821 | +.accordion { | |
| 822 | + cursor: pointer; | |
| 823 | +} | |
| 824 | +.accordion_btn { | |
| 825 | + display: inline-block; | |
| 826 | + width: 16px; | |
| 827 | + height: 16px; | |
| 828 | + margin-right: .5em; | |
| 829 | + vertical-align: middle; | |
| 830 | +} | |
| 831 | +// Note: the order of the next 3 entries should be | |
| 832 | +// maintained for the hierarchical cascade to work. | |
| 833 | +.accordion > .accordion_btn_plus { | |
| 834 | + display: none; | |
| 835 | +} | |
| 836 | +.accordion_closed > .accordion_btn_minus { | |
| 837 | + display: none; | |
| 838 | +} | |
| 839 | +.accordion_closed > .accordion_btn_plus { | |
| 840 | + display: inline-block; | |
| 841 | +} | |
| 842 | +.accordion_panel { | |
| 843 | + overflow: hidden; | |
| 844 | + transition: max-height 0.25s ease-out; | |
| 845 | +} | |
| 815 | 846 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -745,10 +745,12 @@ | |
| 745 | } |
| 746 | div.forumTimeline { |
| 747 | border: 1px solid black; |
| 748 | padding-left: 1ex; |
| 749 | padding-right: 1ex; |
| 750 | } |
| 751 | div.forumTimeline code { |
| 752 | white-space: pre-wrap; |
| 753 | } |
| 754 | div.markdown code { |
| @@ -757,10 +759,14 @@ | |
| 757 | div.forumHier, div.forumTime { |
| 758 | border: 1px solid black; |
| 759 | padding-left: 1ex; |
| 760 | padding-right: 1ex; |
| 761 | margin-top: 1ex; |
| 762 | } |
| 763 | div.forumSel { |
| 764 | background-color: #cef; |
| 765 | } |
| 766 | div.forumObs { |
| @@ -810,5 +816,30 @@ | |
| 810 | margin-right: 0; |
| 811 | } |
| 812 | .nobr { |
| 813 | white-space: nowrap; |
| 814 | } |
| 815 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -745,10 +745,12 @@ | |
| 745 | } |
| 746 | div.forumTimeline { |
| 747 | border: 1px solid black; |
| 748 | padding-left: 1ex; |
| 749 | padding-right: 1ex; |
| 750 | max-width: 50em; |
| 751 | overflow: auto; |
| 752 | } |
| 753 | div.forumTimeline code { |
| 754 | white-space: pre-wrap; |
| 755 | } |
| 756 | div.markdown code { |
| @@ -757,10 +759,14 @@ | |
| 759 | div.forumHier, div.forumTime { |
| 760 | border: 1px solid black; |
| 761 | padding-left: 1ex; |
| 762 | padding-right: 1ex; |
| 763 | margin-top: 1ex; |
| 764 | } |
| 765 | div.forumPostBody { |
| 766 | max-height: 40em; |
| 767 | overflow: auto; |
| 768 | } |
| 769 | div.forumSel { |
| 770 | background-color: #cef; |
| 771 | } |
| 772 | div.forumObs { |
| @@ -810,5 +816,30 @@ | |
| 816 | margin-right: 0; |
| 817 | } |
| 818 | .nobr { |
| 819 | white-space: nowrap; |
| 820 | } |
| 821 | .accordion { |
| 822 | cursor: pointer; |
| 823 | } |
| 824 | .accordion_btn { |
| 825 | display: inline-block; |
| 826 | width: 16px; |
| 827 | height: 16px; |
| 828 | margin-right: .5em; |
| 829 | vertical-align: middle; |
| 830 | } |
| 831 | // Note: the order of the next 3 entries should be |
| 832 | // maintained for the hierarchical cascade to work. |
| 833 | .accordion > .accordion_btn_plus { |
| 834 | display: none; |
| 835 | } |
| 836 | .accordion_closed > .accordion_btn_minus { |
| 837 | display: none; |
| 838 | } |
| 839 | .accordion_closed > .accordion_btn_plus { |
| 840 | display: inline-block; |
| 841 | } |
| 842 | .accordion_panel { |
| 843 | overflow: hidden; |
| 844 | transition: max-height 0.25s ease-out; |
| 845 | } |
| 846 |
+2
-1
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -1126,10 +1126,11 @@ | ||
| 1126 | 1126 | memset(&testFileStat, 0, sizeof(struct fossilStat)); |
| 1127 | 1127 | rc = fossil_stat(zPath, &testFileStat, 0); |
| 1128 | 1128 | fossil_print(" stat_rc = %d\n", rc); |
| 1129 | 1129 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size); |
| 1130 | 1130 | fossil_print(" stat_size = %s\n", zBuf); |
| 1131 | + if( g.db==0 ) sqlite3_open(":memory:", &g.db); | |
| 1131 | 1132 | z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime); |
| 1132 | 1133 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z); |
| 1133 | 1134 | fossil_free(z); |
| 1134 | 1135 | fossil_print(" stat_mtime = %s\n", zBuf); |
| 1135 | 1136 | fossil_print(" stat_mode = 0%o\n", testFileStat.st_mode); |
| @@ -1192,11 +1193,11 @@ | ||
| 1192 | 1193 | int resetFlag = find_option("reset",0,0)!=0; |
| 1193 | 1194 | const char *zAllow = find_option("allow-symlinks",0,1); |
| 1194 | 1195 | if( find_option("open-config", 0, 0)!=0 ){ |
| 1195 | 1196 | Th_OpenConfig(1); |
| 1196 | 1197 | } |
| 1197 | - db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); | |
| 1198 | + db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); | |
| 1198 | 1199 | fossil_print("filenames_are_case_sensitive() = %d\n", |
| 1199 | 1200 | filenames_are_case_sensitive()); |
| 1200 | 1201 | fossil_print("db_allow_symlinks_by_default() = %d\n", |
| 1201 | 1202 | db_allow_symlinks_by_default()); |
| 1202 | 1203 | if( zAllow ){ |
| 1203 | 1204 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -1126,10 +1126,11 @@ | |
| 1126 | memset(&testFileStat, 0, sizeof(struct fossilStat)); |
| 1127 | rc = fossil_stat(zPath, &testFileStat, 0); |
| 1128 | fossil_print(" stat_rc = %d\n", rc); |
| 1129 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size); |
| 1130 | fossil_print(" stat_size = %s\n", zBuf); |
| 1131 | z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime); |
| 1132 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z); |
| 1133 | fossil_free(z); |
| 1134 | fossil_print(" stat_mtime = %s\n", zBuf); |
| 1135 | fossil_print(" stat_mode = 0%o\n", testFileStat.st_mode); |
| @@ -1192,11 +1193,11 @@ | |
| 1192 | int resetFlag = find_option("reset",0,0)!=0; |
| 1193 | const char *zAllow = find_option("allow-symlinks",0,1); |
| 1194 | if( find_option("open-config", 0, 0)!=0 ){ |
| 1195 | Th_OpenConfig(1); |
| 1196 | } |
| 1197 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 1198 | fossil_print("filenames_are_case_sensitive() = %d\n", |
| 1199 | filenames_are_case_sensitive()); |
| 1200 | fossil_print("db_allow_symlinks_by_default() = %d\n", |
| 1201 | db_allow_symlinks_by_default()); |
| 1202 | if( zAllow ){ |
| 1203 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -1126,10 +1126,11 @@ | |
| 1126 | memset(&testFileStat, 0, sizeof(struct fossilStat)); |
| 1127 | rc = fossil_stat(zPath, &testFileStat, 0); |
| 1128 | fossil_print(" stat_rc = %d\n", rc); |
| 1129 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", testFileStat.st_size); |
| 1130 | fossil_print(" stat_size = %s\n", zBuf); |
| 1131 | if( g.db==0 ) sqlite3_open(":memory:", &g.db); |
| 1132 | z = db_text(0, "SELECT datetime(%lld, 'unixepoch')", testFileStat.st_mtime); |
| 1133 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld (%s)", testFileStat.st_mtime, z); |
| 1134 | fossil_free(z); |
| 1135 | fossil_print(" stat_mtime = %s\n", zBuf); |
| 1136 | fossil_print(" stat_mode = 0%o\n", testFileStat.st_mode); |
| @@ -1192,11 +1193,11 @@ | |
| 1193 | int resetFlag = find_option("reset",0,0)!=0; |
| 1194 | const char *zAllow = find_option("allow-symlinks",0,1); |
| 1195 | if( find_option("open-config", 0, 0)!=0 ){ |
| 1196 | Th_OpenConfig(1); |
| 1197 | } |
| 1198 | db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); |
| 1199 | fossil_print("filenames_are_case_sensitive() = %d\n", |
| 1200 | filenames_are_case_sensitive()); |
| 1201 | fossil_print("db_allow_symlinks_by_default() = %d\n", |
| 1202 | db_allow_symlinks_by_default()); |
| 1203 | if( zAllow ){ |
| 1204 |
+22
-16
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -309,11 +309,12 @@ | ||
| 309 | 309 | */ |
| 310 | 310 | void forum_render( |
| 311 | 311 | const char *zTitle, /* The title. Might be NULL for no title */ |
| 312 | 312 | const char *zMimetype, /* Mimetype of the message */ |
| 313 | 313 | const char *zContent, /* Content of the message */ |
| 314 | - const char *zClass /* Put in a <div> if not NULL */ | |
| 314 | + const char *zClass, /* Put in a <div> if not NULL */ | |
| 315 | + int bScroll /* Large message content scrolls if true */ | |
| 315 | 316 | ){ |
| 316 | 317 | if( zClass ){ |
| 317 | 318 | @ <div class='%s(zClass)'> |
| 318 | 319 | } |
| 319 | 320 | if( zTitle ){ |
| @@ -323,14 +324,20 @@ | ||
| 323 | 324 | @ <h1><i>Deleted</i></h1> |
| 324 | 325 | } |
| 325 | 326 | } |
| 326 | 327 | if( zContent && zContent[0] ){ |
| 327 | 328 | Blob x; |
| 329 | + if( bScroll ){ | |
| 330 | + @ <div class='forumPostBody'> | |
| 331 | + }else{ | |
| 332 | + @ <div class='forumPostFullBody'> | |
| 333 | + } | |
| 328 | 334 | blob_init(&x, 0, 0); |
| 329 | 335 | blob_append(&x, zContent, -1); |
| 330 | 336 | wiki_render_by_mimetype(&x, zMimetype); |
| 331 | 337 | blob_reset(&x); |
| 338 | + @ </div> | |
| 332 | 339 | }else{ |
| 333 | 340 | @ <i>Deleted</i> |
| 334 | 341 | } |
| 335 | 342 | if( zClass ){ |
| 336 | 343 | @ </div> |
| @@ -444,20 +451,21 @@ | ||
| 444 | 451 | zUuid = p->pLeaf->zUuid; |
| 445 | 452 | } |
| 446 | 453 | if( p->fpid!=target ){ |
| 447 | 454 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 448 | 455 | } |
| 449 | - if( !bRawMode && fossil_strcmp(pPost->zMimetype,"text/plain")!=0 ){ | |
| 456 | + if( !bRawMode ){ | |
| 450 | 457 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 451 | 458 | } |
| 452 | 459 | isPrivate = content_is_private(p->fpid); |
| 453 | 460 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 454 | 461 | @ </h3> |
| 455 | 462 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 456 | 463 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 457 | 464 | }else{ |
| 458 | - forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, 0); | |
| 465 | + forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, | |
| 466 | + 0, 1); | |
| 459 | 467 | } |
| 460 | 468 | if( g.perm.WrForum && p->pLeaf==0 ){ |
| 461 | 469 | int sameUser = login_is_individual() |
| 462 | 470 | && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 463 | 471 | @ <p><form action="%R/forumedit" method="POST"> |
| @@ -565,13 +573,11 @@ | ||
| 565 | 573 | manifest_destroy(pOPost); |
| 566 | 574 | } |
| 567 | 575 | if( fpid!=target ){ |
| 568 | 576 | @ %z(href("%R/forumpost/%S",zUuid))[link]</a> |
| 569 | 577 | } |
| 570 | - if( fossil_strcmp(pPost->zMimetype,"text/plain")!=0 ){ | |
| 571 | - @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> | |
| 572 | - } | |
| 578 | + @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> | |
| 573 | 579 | if( p->firt ){ |
| 574 | 580 | ForumEntry *pIrt = p->pPrev; |
| 575 | 581 | while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev; |
| 576 | 582 | if( pIrt ){ |
| 577 | 583 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| @@ -582,11 +588,11 @@ | ||
| 582 | 588 | isPrivate = content_is_private(fpid); |
| 583 | 589 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 584 | 590 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 585 | 591 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 586 | 592 | }else{ |
| 587 | - forum_render(0, pPost->zMimetype, pPost->zWiki, 0); | |
| 593 | + forum_render(0, pPost->zMimetype, pPost->zWiki, 0, 1); | |
| 588 | 594 | } |
| 589 | 595 | if( g.perm.WrForum ){ |
| 590 | 596 | @ <p><form action="%R/forumedit" method="POST"> |
| 591 | 597 | @ <input type="hidden" name="fpid" value="%s(zUuid)"> |
| 592 | 598 | if( !isPrivate ){ |
| @@ -717,11 +723,11 @@ | ||
| 717 | 723 | int notAnon = login_is_individual(); |
| 718 | 724 | int sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 719 | 725 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 720 | 726 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 721 | 727 | }else{ |
| 722 | - forum_render(0, "text/plain", pPost->zWiki, 0); | |
| 728 | + forum_render(0, "text/plain", pPost->zWiki, 0, 0); | |
| 723 | 729 | } |
| 724 | 730 | manifest_destroy(pPost); |
| 725 | 731 | } |
| 726 | 732 | }else if( zMode[0]=='c' ){ |
| 727 | 733 | style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName); |
| @@ -949,11 +955,11 @@ | ||
| 949 | 955 | if( P("submit") ){ |
| 950 | 956 | if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return; |
| 951 | 957 | } |
| 952 | 958 | if( P("preview") ){ |
| 953 | 959 | @ <h1>Preview:</h1> |
| 954 | - forum_render(zTitle, zMimetype, zContent, "forumEdit"); | |
| 960 | + forum_render(zTitle, zMimetype, zContent, "forumEdit", 1); | |
| 955 | 961 | } |
| 956 | 962 | style_header("New Forum Thread"); |
| 957 | 963 | @ <form action="%R/forume1" method="POST"> |
| 958 | 964 | @ <h1>New Thread:</h1> |
| 959 | 965 | forum_from_line(); |
| @@ -1018,11 +1024,11 @@ | ||
| 1018 | 1024 | } |
| 1019 | 1025 | isCsrfSafe = cgi_csrf_safe(1); |
| 1020 | 1026 | if( g.perm.ModForum && isCsrfSafe ){ |
| 1021 | 1027 | if( P("approve") ){ |
| 1022 | 1028 | const char *zUserToTrust; |
| 1023 | - moderation_approve(fpid); | |
| 1029 | + moderation_approve('f', fpid); | |
| 1024 | 1030 | if( g.perm.AdminForum |
| 1025 | 1031 | && PB("trust") |
| 1026 | 1032 | && (zUserToTrust = P("trustuser"))!=0 |
| 1027 | 1033 | ){ |
| 1028 | 1034 | db_multi_exec("UPDATE user SET cap=cap||'4' " |
| @@ -1067,13 +1073,13 @@ | ||
| 1067 | 1073 | zContent = ""; |
| 1068 | 1074 | if( pPost->zThreadTitle ) zTitle = ""; |
| 1069 | 1075 | style_header("Delete %s", zTitle ? "Post" : "Reply"); |
| 1070 | 1076 | @ <h1>Original Post:</h1> |
| 1071 | 1077 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1072 | - "forumEdit"); | |
| 1078 | + "forumEdit", 1); | |
| 1073 | 1079 | @ <h1>Change Into:</h1> |
| 1074 | - forum_render(zTitle, zMimetype, zContent,"forumEdit"); | |
| 1080 | + forum_render(zTitle, zMimetype, zContent,"forumEdit", 1); | |
| 1075 | 1081 | @ <form action="%R/forume2" method="POST"> |
| 1076 | 1082 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1077 | 1083 | @ <input type="hidden" name="nullout" value="1"> |
| 1078 | 1084 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1079 | 1085 | @ <input type="hidden" name="content" value="%h(zContent)"> |
| @@ -1091,14 +1097,14 @@ | ||
| 1091 | 1097 | zTitle = fossil_strdup(pPost->zThreadTitle); |
| 1092 | 1098 | } |
| 1093 | 1099 | style_header("Edit %s", zTitle ? "Post" : "Reply"); |
| 1094 | 1100 | @ <h2>Original Post:</h2> |
| 1095 | 1101 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1096 | - "forumEdit"); | |
| 1102 | + "forumEdit", 1); | |
| 1097 | 1103 | if( P("preview") ){ |
| 1098 | 1104 | @ <h2>Preview of Edited Post:</h2> |
| 1099 | - forum_render(zTitle, zMimetype, zContent,"forumEdit"); | |
| 1105 | + forum_render(zTitle, zMimetype, zContent,"forumEdit", 1); | |
| 1100 | 1106 | } |
| 1101 | 1107 | @ <h2>Revised Message:</h2> |
| 1102 | 1108 | @ <form action="%R/forume2" method="POST"> |
| 1103 | 1109 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1104 | 1110 | @ <input type="hidden" name="edit" value="1"> |
| @@ -1117,14 +1123,14 @@ | ||
| 1117 | 1123 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 1118 | 1124 | zDisplayName = display_name_from_login(pPost->zUser); |
| 1119 | 1125 | @ <h3 class='forumPostHdr'>By %h(zDisplayName) on %h(zDate)</h3> |
| 1120 | 1126 | fossil_free(zDisplayName); |
| 1121 | 1127 | fossil_free(zDate); |
| 1122 | - forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit"); | |
| 1128 | + forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit", 1); | |
| 1123 | 1129 | if( P("preview") ){ |
| 1124 | 1130 | @ <h2>Preview:</h2> |
| 1125 | - forum_render(0, zMimetype,zContent, "forumEdit"); | |
| 1131 | + forum_render(0, zMimetype,zContent, "forumEdit", 1); | |
| 1126 | 1132 | } |
| 1127 | 1133 | @ <h2>Enter Reply:</h2> |
| 1128 | 1134 | @ <form action="%R/forume2" method="POST"> |
| 1129 | 1135 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1130 | 1136 | @ <input type="hidden" name="reply" value="1"> |
| 1131 | 1137 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -309,11 +309,12 @@ | |
| 309 | */ |
| 310 | void forum_render( |
| 311 | const char *zTitle, /* The title. Might be NULL for no title */ |
| 312 | const char *zMimetype, /* Mimetype of the message */ |
| 313 | const char *zContent, /* Content of the message */ |
| 314 | const char *zClass /* Put in a <div> if not NULL */ |
| 315 | ){ |
| 316 | if( zClass ){ |
| 317 | @ <div class='%s(zClass)'> |
| 318 | } |
| 319 | if( zTitle ){ |
| @@ -323,14 +324,20 @@ | |
| 323 | @ <h1><i>Deleted</i></h1> |
| 324 | } |
| 325 | } |
| 326 | if( zContent && zContent[0] ){ |
| 327 | Blob x; |
| 328 | blob_init(&x, 0, 0); |
| 329 | blob_append(&x, zContent, -1); |
| 330 | wiki_render_by_mimetype(&x, zMimetype); |
| 331 | blob_reset(&x); |
| 332 | }else{ |
| 333 | @ <i>Deleted</i> |
| 334 | } |
| 335 | if( zClass ){ |
| 336 | @ </div> |
| @@ -444,20 +451,21 @@ | |
| 444 | zUuid = p->pLeaf->zUuid; |
| 445 | } |
| 446 | if( p->fpid!=target ){ |
| 447 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 448 | } |
| 449 | if( !bRawMode && fossil_strcmp(pPost->zMimetype,"text/plain")!=0 ){ |
| 450 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 451 | } |
| 452 | isPrivate = content_is_private(p->fpid); |
| 453 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 454 | @ </h3> |
| 455 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 456 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 457 | }else{ |
| 458 | forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, 0); |
| 459 | } |
| 460 | if( g.perm.WrForum && p->pLeaf==0 ){ |
| 461 | int sameUser = login_is_individual() |
| 462 | && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 463 | @ <p><form action="%R/forumedit" method="POST"> |
| @@ -565,13 +573,11 @@ | |
| 565 | manifest_destroy(pOPost); |
| 566 | } |
| 567 | if( fpid!=target ){ |
| 568 | @ %z(href("%R/forumpost/%S",zUuid))[link]</a> |
| 569 | } |
| 570 | if( fossil_strcmp(pPost->zMimetype,"text/plain")!=0 ){ |
| 571 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 572 | } |
| 573 | if( p->firt ){ |
| 574 | ForumEntry *pIrt = p->pPrev; |
| 575 | while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev; |
| 576 | if( pIrt ){ |
| 577 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| @@ -582,11 +588,11 @@ | |
| 582 | isPrivate = content_is_private(fpid); |
| 583 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 584 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 585 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 586 | }else{ |
| 587 | forum_render(0, pPost->zMimetype, pPost->zWiki, 0); |
| 588 | } |
| 589 | if( g.perm.WrForum ){ |
| 590 | @ <p><form action="%R/forumedit" method="POST"> |
| 591 | @ <input type="hidden" name="fpid" value="%s(zUuid)"> |
| 592 | if( !isPrivate ){ |
| @@ -717,11 +723,11 @@ | |
| 717 | int notAnon = login_is_individual(); |
| 718 | int sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 719 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 720 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 721 | }else{ |
| 722 | forum_render(0, "text/plain", pPost->zWiki, 0); |
| 723 | } |
| 724 | manifest_destroy(pPost); |
| 725 | } |
| 726 | }else if( zMode[0]=='c' ){ |
| 727 | style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName); |
| @@ -949,11 +955,11 @@ | |
| 949 | if( P("submit") ){ |
| 950 | if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return; |
| 951 | } |
| 952 | if( P("preview") ){ |
| 953 | @ <h1>Preview:</h1> |
| 954 | forum_render(zTitle, zMimetype, zContent, "forumEdit"); |
| 955 | } |
| 956 | style_header("New Forum Thread"); |
| 957 | @ <form action="%R/forume1" method="POST"> |
| 958 | @ <h1>New Thread:</h1> |
| 959 | forum_from_line(); |
| @@ -1018,11 +1024,11 @@ | |
| 1018 | } |
| 1019 | isCsrfSafe = cgi_csrf_safe(1); |
| 1020 | if( g.perm.ModForum && isCsrfSafe ){ |
| 1021 | if( P("approve") ){ |
| 1022 | const char *zUserToTrust; |
| 1023 | moderation_approve(fpid); |
| 1024 | if( g.perm.AdminForum |
| 1025 | && PB("trust") |
| 1026 | && (zUserToTrust = P("trustuser"))!=0 |
| 1027 | ){ |
| 1028 | db_multi_exec("UPDATE user SET cap=cap||'4' " |
| @@ -1067,13 +1073,13 @@ | |
| 1067 | zContent = ""; |
| 1068 | if( pPost->zThreadTitle ) zTitle = ""; |
| 1069 | style_header("Delete %s", zTitle ? "Post" : "Reply"); |
| 1070 | @ <h1>Original Post:</h1> |
| 1071 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1072 | "forumEdit"); |
| 1073 | @ <h1>Change Into:</h1> |
| 1074 | forum_render(zTitle, zMimetype, zContent,"forumEdit"); |
| 1075 | @ <form action="%R/forume2" method="POST"> |
| 1076 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1077 | @ <input type="hidden" name="nullout" value="1"> |
| 1078 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1079 | @ <input type="hidden" name="content" value="%h(zContent)"> |
| @@ -1091,14 +1097,14 @@ | |
| 1091 | zTitle = fossil_strdup(pPost->zThreadTitle); |
| 1092 | } |
| 1093 | style_header("Edit %s", zTitle ? "Post" : "Reply"); |
| 1094 | @ <h2>Original Post:</h2> |
| 1095 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1096 | "forumEdit"); |
| 1097 | if( P("preview") ){ |
| 1098 | @ <h2>Preview of Edited Post:</h2> |
| 1099 | forum_render(zTitle, zMimetype, zContent,"forumEdit"); |
| 1100 | } |
| 1101 | @ <h2>Revised Message:</h2> |
| 1102 | @ <form action="%R/forume2" method="POST"> |
| 1103 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1104 | @ <input type="hidden" name="edit" value="1"> |
| @@ -1117,14 +1123,14 @@ | |
| 1117 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 1118 | zDisplayName = display_name_from_login(pPost->zUser); |
| 1119 | @ <h3 class='forumPostHdr'>By %h(zDisplayName) on %h(zDate)</h3> |
| 1120 | fossil_free(zDisplayName); |
| 1121 | fossil_free(zDate); |
| 1122 | forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit"); |
| 1123 | if( P("preview") ){ |
| 1124 | @ <h2>Preview:</h2> |
| 1125 | forum_render(0, zMimetype,zContent, "forumEdit"); |
| 1126 | } |
| 1127 | @ <h2>Enter Reply:</h2> |
| 1128 | @ <form action="%R/forume2" method="POST"> |
| 1129 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1130 | @ <input type="hidden" name="reply" value="1"> |
| 1131 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -309,11 +309,12 @@ | |
| 309 | */ |
| 310 | void forum_render( |
| 311 | const char *zTitle, /* The title. Might be NULL for no title */ |
| 312 | const char *zMimetype, /* Mimetype of the message */ |
| 313 | const char *zContent, /* Content of the message */ |
| 314 | const char *zClass, /* Put in a <div> if not NULL */ |
| 315 | int bScroll /* Large message content scrolls if true */ |
| 316 | ){ |
| 317 | if( zClass ){ |
| 318 | @ <div class='%s(zClass)'> |
| 319 | } |
| 320 | if( zTitle ){ |
| @@ -323,14 +324,20 @@ | |
| 324 | @ <h1><i>Deleted</i></h1> |
| 325 | } |
| 326 | } |
| 327 | if( zContent && zContent[0] ){ |
| 328 | Blob x; |
| 329 | if( bScroll ){ |
| 330 | @ <div class='forumPostBody'> |
| 331 | }else{ |
| 332 | @ <div class='forumPostFullBody'> |
| 333 | } |
| 334 | blob_init(&x, 0, 0); |
| 335 | blob_append(&x, zContent, -1); |
| 336 | wiki_render_by_mimetype(&x, zMimetype); |
| 337 | blob_reset(&x); |
| 338 | @ </div> |
| 339 | }else{ |
| 340 | @ <i>Deleted</i> |
| 341 | } |
| 342 | if( zClass ){ |
| 343 | @ </div> |
| @@ -444,20 +451,21 @@ | |
| 451 | zUuid = p->pLeaf->zUuid; |
| 452 | } |
| 453 | if( p->fpid!=target ){ |
| 454 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 455 | } |
| 456 | if( !bRawMode ){ |
| 457 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 458 | } |
| 459 | isPrivate = content_is_private(p->fpid); |
| 460 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 461 | @ </h3> |
| 462 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 463 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 464 | }else{ |
| 465 | forum_render(0, bRawMode?"text/plain":pPost->zMimetype, pPost->zWiki, |
| 466 | 0, 1); |
| 467 | } |
| 468 | if( g.perm.WrForum && p->pLeaf==0 ){ |
| 469 | int sameUser = login_is_individual() |
| 470 | && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 471 | @ <p><form action="%R/forumedit" method="POST"> |
| @@ -565,13 +573,11 @@ | |
| 573 | manifest_destroy(pOPost); |
| 574 | } |
| 575 | if( fpid!=target ){ |
| 576 | @ %z(href("%R/forumpost/%S",zUuid))[link]</a> |
| 577 | } |
| 578 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 579 | if( p->firt ){ |
| 580 | ForumEntry *pIrt = p->pPrev; |
| 581 | while( pIrt && pIrt->fpid!=p->firt ) pIrt = pIrt->pPrev; |
| 582 | if( pIrt ){ |
| 583 | @ in reply to %z(href("%R/forumpost/%S?t=h",pIrt->zUuid))\ |
| @@ -582,11 +588,11 @@ | |
| 588 | isPrivate = content_is_private(fpid); |
| 589 | sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 590 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 591 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 592 | }else{ |
| 593 | forum_render(0, pPost->zMimetype, pPost->zWiki, 0, 1); |
| 594 | } |
| 595 | if( g.perm.WrForum ){ |
| 596 | @ <p><form action="%R/forumedit" method="POST"> |
| 597 | @ <input type="hidden" name="fpid" value="%s(zUuid)"> |
| 598 | if( !isPrivate ){ |
| @@ -717,11 +723,11 @@ | |
| 723 | int notAnon = login_is_individual(); |
| 724 | int sameUser = notAnon && fossil_strcmp(pPost->zUser, g.zLogin)==0; |
| 725 | if( isPrivate && !g.perm.ModForum && !sameUser ){ |
| 726 | @ <p><span class="modpending">Awaiting Moderator Approval</span></p> |
| 727 | }else{ |
| 728 | forum_render(0, "text/plain", pPost->zWiki, 0, 0); |
| 729 | } |
| 730 | manifest_destroy(pPost); |
| 731 | } |
| 732 | }else if( zMode[0]=='c' ){ |
| 733 | style_submenu_element("Hierarchical", "%R/%s/%s?t=h", g.zPath, zName); |
| @@ -949,11 +955,11 @@ | |
| 955 | if( P("submit") ){ |
| 956 | if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return; |
| 957 | } |
| 958 | if( P("preview") ){ |
| 959 | @ <h1>Preview:</h1> |
| 960 | forum_render(zTitle, zMimetype, zContent, "forumEdit", 1); |
| 961 | } |
| 962 | style_header("New Forum Thread"); |
| 963 | @ <form action="%R/forume1" method="POST"> |
| 964 | @ <h1>New Thread:</h1> |
| 965 | forum_from_line(); |
| @@ -1018,11 +1024,11 @@ | |
| 1024 | } |
| 1025 | isCsrfSafe = cgi_csrf_safe(1); |
| 1026 | if( g.perm.ModForum && isCsrfSafe ){ |
| 1027 | if( P("approve") ){ |
| 1028 | const char *zUserToTrust; |
| 1029 | moderation_approve('f', fpid); |
| 1030 | if( g.perm.AdminForum |
| 1031 | && PB("trust") |
| 1032 | && (zUserToTrust = P("trustuser"))!=0 |
| 1033 | ){ |
| 1034 | db_multi_exec("UPDATE user SET cap=cap||'4' " |
| @@ -1067,13 +1073,13 @@ | |
| 1073 | zContent = ""; |
| 1074 | if( pPost->zThreadTitle ) zTitle = ""; |
| 1075 | style_header("Delete %s", zTitle ? "Post" : "Reply"); |
| 1076 | @ <h1>Original Post:</h1> |
| 1077 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1078 | "forumEdit", 1); |
| 1079 | @ <h1>Change Into:</h1> |
| 1080 | forum_render(zTitle, zMimetype, zContent,"forumEdit", 1); |
| 1081 | @ <form action="%R/forume2" method="POST"> |
| 1082 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1083 | @ <input type="hidden" name="nullout" value="1"> |
| 1084 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1085 | @ <input type="hidden" name="content" value="%h(zContent)"> |
| @@ -1091,14 +1097,14 @@ | |
| 1097 | zTitle = fossil_strdup(pPost->zThreadTitle); |
| 1098 | } |
| 1099 | style_header("Edit %s", zTitle ? "Post" : "Reply"); |
| 1100 | @ <h2>Original Post:</h2> |
| 1101 | forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki, |
| 1102 | "forumEdit", 1); |
| 1103 | if( P("preview") ){ |
| 1104 | @ <h2>Preview of Edited Post:</h2> |
| 1105 | forum_render(zTitle, zMimetype, zContent,"forumEdit", 1); |
| 1106 | } |
| 1107 | @ <h2>Revised Message:</h2> |
| 1108 | @ <form action="%R/forume2" method="POST"> |
| 1109 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1110 | @ <input type="hidden" name="edit" value="1"> |
| @@ -1117,14 +1123,14 @@ | |
| 1123 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 1124 | zDisplayName = display_name_from_login(pPost->zUser); |
| 1125 | @ <h3 class='forumPostHdr'>By %h(zDisplayName) on %h(zDate)</h3> |
| 1126 | fossil_free(zDisplayName); |
| 1127 | fossil_free(zDate); |
| 1128 | forum_render(0, pPost->zMimetype, pPost->zWiki, "forumEdit", 1); |
| 1129 | if( P("preview") ){ |
| 1130 | @ <h2>Preview:</h2> |
| 1131 | forum_render(0, zMimetype,zContent, "forumEdit", 1); |
| 1132 | } |
| 1133 | @ <h2>Enter Reply:</h2> |
| 1134 | @ <form action="%R/forume2" method="POST"> |
| 1135 | @ <input type="hidden" name="fpid" value="%h(P("fpid"))"> |
| 1136 | @ <input type="hidden" name="reply" value="1"> |
| 1137 |
+4
-1
| --- src/fshell.c | ||
| +++ src/fshell.c | ||
| @@ -57,16 +57,18 @@ | ||
| 57 | 57 | int n, i; |
| 58 | 58 | char **azArg = 0; |
| 59 | 59 | int fDebug; |
| 60 | 60 | pid_t childPid; |
| 61 | 61 | char *zLine = 0; |
| 62 | + char *zPrompt = 0; | |
| 62 | 63 | fDebug = find_option("debug", 0, 0)!=0; |
| 63 | 64 | db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); |
| 65 | + zPrompt = mprintf("fossil (%z)> ", db_get("project-name","no repo")); | |
| 64 | 66 | db_close(0); |
| 65 | 67 | sqlite3_shutdown(); |
| 66 | 68 | linenoiseSetMultiLine(1); |
| 67 | - while( (free(zLine), zLine = linenoise("fossil> ")) ){ | |
| 69 | + while( (free(zLine), zLine = linenoise(zPrompt)) ){ | |
| 68 | 70 | /* Remember shell history within the current session */ |
| 69 | 71 | linenoiseHistoryAdd(zLine); |
| 70 | 72 | |
| 71 | 73 | /* Parse the line of input */ |
| 72 | 74 | n = (int)strlen(zLine); |
| @@ -117,7 +119,8 @@ | ||
| 117 | 119 | /* The parent process */ |
| 118 | 120 | int status; |
| 119 | 121 | waitpid(childPid, &status, 0); |
| 120 | 122 | } |
| 121 | 123 | } |
| 124 | + free(zPrompt); | |
| 122 | 125 | #endif |
| 123 | 126 | } |
| 124 | 127 |
| --- src/fshell.c | |
| +++ src/fshell.c | |
| @@ -57,16 +57,18 @@ | |
| 57 | int n, i; |
| 58 | char **azArg = 0; |
| 59 | int fDebug; |
| 60 | pid_t childPid; |
| 61 | char *zLine = 0; |
| 62 | fDebug = find_option("debug", 0, 0)!=0; |
| 63 | db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); |
| 64 | db_close(0); |
| 65 | sqlite3_shutdown(); |
| 66 | linenoiseSetMultiLine(1); |
| 67 | while( (free(zLine), zLine = linenoise("fossil> ")) ){ |
| 68 | /* Remember shell history within the current session */ |
| 69 | linenoiseHistoryAdd(zLine); |
| 70 | |
| 71 | /* Parse the line of input */ |
| 72 | n = (int)strlen(zLine); |
| @@ -117,7 +119,8 @@ | |
| 117 | /* The parent process */ |
| 118 | int status; |
| 119 | waitpid(childPid, &status, 0); |
| 120 | } |
| 121 | } |
| 122 | #endif |
| 123 | } |
| 124 |
| --- src/fshell.c | |
| +++ src/fshell.c | |
| @@ -57,16 +57,18 @@ | |
| 57 | int n, i; |
| 58 | char **azArg = 0; |
| 59 | int fDebug; |
| 60 | pid_t childPid; |
| 61 | char *zLine = 0; |
| 62 | char *zPrompt = 0; |
| 63 | fDebug = find_option("debug", 0, 0)!=0; |
| 64 | db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); |
| 65 | zPrompt = mprintf("fossil (%z)> ", db_get("project-name","no repo")); |
| 66 | db_close(0); |
| 67 | sqlite3_shutdown(); |
| 68 | linenoiseSetMultiLine(1); |
| 69 | while( (free(zLine), zLine = linenoise(zPrompt)) ){ |
| 70 | /* Remember shell history within the current session */ |
| 71 | linenoiseHistoryAdd(zLine); |
| 72 | |
| 73 | /* Parse the line of input */ |
| 74 | n = (int)strlen(zLine); |
| @@ -117,7 +119,8 @@ | |
| 119 | /* The parent process */ |
| 120 | int status; |
| 121 | waitpid(childPid, &status, 0); |
| 122 | } |
| 123 | } |
| 124 | free(zPrompt); |
| 125 | #endif |
| 126 | } |
| 127 |
+2
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1022,11 +1022,11 @@ | ||
| 1022 | 1022 | cgi_redirectf("%R/modreq"); |
| 1023 | 1023 | /*NOTREACHED*/ |
| 1024 | 1024 | } |
| 1025 | 1025 | } |
| 1026 | 1026 | if( strcmp(zModAction,"approve")==0 ){ |
| 1027 | - moderation_approve(rid); | |
| 1027 | + moderation_approve('w', rid); | |
| 1028 | 1028 | } |
| 1029 | 1029 | } |
| 1030 | 1030 | style_header("Update of \"%h\"", pWiki->zWikiTitle); |
| 1031 | 1031 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1032 | 1032 | zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); |
| @@ -2423,11 +2423,11 @@ | ||
| 2423 | 2423 | cgi_redirectf("%R/modreq"); |
| 2424 | 2424 | /*NOTREACHED*/ |
| 2425 | 2425 | } |
| 2426 | 2426 | } |
| 2427 | 2427 | if( strcmp(zModAction,"approve")==0 ){ |
| 2428 | - moderation_approve(rid); | |
| 2428 | + moderation_approve('t', rid); | |
| 2429 | 2429 | } |
| 2430 | 2430 | } |
| 2431 | 2431 | zTktTitle = db_table_has_column("repository", "ticket", "title" ) |
| 2432 | 2432 | ? db_text("(No title)", |
| 2433 | 2433 | "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) |
| 2434 | 2434 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | cgi_redirectf("%R/modreq"); |
| 1023 | /*NOTREACHED*/ |
| 1024 | } |
| 1025 | } |
| 1026 | if( strcmp(zModAction,"approve")==0 ){ |
| 1027 | moderation_approve(rid); |
| 1028 | } |
| 1029 | } |
| 1030 | style_header("Update of \"%h\"", pWiki->zWikiTitle); |
| 1031 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1032 | zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); |
| @@ -2423,11 +2423,11 @@ | |
| 2423 | cgi_redirectf("%R/modreq"); |
| 2424 | /*NOTREACHED*/ |
| 2425 | } |
| 2426 | } |
| 2427 | if( strcmp(zModAction,"approve")==0 ){ |
| 2428 | moderation_approve(rid); |
| 2429 | } |
| 2430 | } |
| 2431 | zTktTitle = db_table_has_column("repository", "ticket", "title" ) |
| 2432 | ? db_text("(No title)", |
| 2433 | "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) |
| 2434 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1022,11 +1022,11 @@ | |
| 1022 | cgi_redirectf("%R/modreq"); |
| 1023 | /*NOTREACHED*/ |
| 1024 | } |
| 1025 | } |
| 1026 | if( strcmp(zModAction,"approve")==0 ){ |
| 1027 | moderation_approve('w', rid); |
| 1028 | } |
| 1029 | } |
| 1030 | style_header("Update of \"%h\"", pWiki->zWikiTitle); |
| 1031 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1032 | zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); |
| @@ -2423,11 +2423,11 @@ | |
| 2423 | cgi_redirectf("%R/modreq"); |
| 2424 | /*NOTREACHED*/ |
| 2425 | } |
| 2426 | } |
| 2427 | if( strcmp(zModAction,"approve")==0 ){ |
| 2428 | moderation_approve('t', rid); |
| 2429 | } |
| 2430 | } |
| 2431 | zTktTitle = db_table_has_column("repository", "ticket", "title" ) |
| 2432 | ? db_text("(No title)", |
| 2433 | "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName) |
| 2434 |
+1
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -211,10 +211,11 @@ | ||
| 211 | 211 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 212 | 212 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 213 | 213 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 214 | 214 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 215 | 215 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 216 | + $(SRCDIR)/accordion.js \ | |
| 216 | 217 | $(SRCDIR)/ci_edit.js \ |
| 217 | 218 | $(SRCDIR)/copybtn.js \ |
| 218 | 219 | $(SRCDIR)/diff.tcl \ |
| 219 | 220 | $(SRCDIR)/forum.js \ |
| 220 | 221 | $(SRCDIR)/graph.js \ |
| 221 | 222 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -211,10 +211,11 @@ | |
| 211 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 212 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 213 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 214 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 215 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 216 | $(SRCDIR)/ci_edit.js \ |
| 217 | $(SRCDIR)/copybtn.js \ |
| 218 | $(SRCDIR)/diff.tcl \ |
| 219 | $(SRCDIR)/forum.js \ |
| 220 | $(SRCDIR)/graph.js \ |
| 221 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -211,10 +211,11 @@ | |
| 211 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 212 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 213 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 214 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 215 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 216 | $(SRCDIR)/accordion.js \ |
| 217 | $(SRCDIR)/ci_edit.js \ |
| 218 | $(SRCDIR)/copybtn.js \ |
| 219 | $(SRCDIR)/diff.tcl \ |
| 220 | $(SRCDIR)/forum.js \ |
| 221 | $(SRCDIR)/graph.js \ |
| 222 |
+2
-2
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -713,11 +713,11 @@ | ||
| 713 | 713 | #### The directories where the OpenSSL include and library files are located. |
| 714 | 714 | # The recommended usage here is to use the Sysinternals junction tool |
| 715 | 715 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 716 | 716 | # Fossil source code directory and the target OpenSSL source directory. |
| 717 | 717 | # |
| 718 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e | |
| 718 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f | |
| 719 | 719 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 720 | 720 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 721 | 721 | |
| 722 | 722 | #### Either the directory where the Tcl library is installed or the Tcl |
| 723 | 723 | # source code directory resides (depending on the value of the macro |
| @@ -1570,11 +1570,11 @@ | ||
| 1570 | 1570 | !ifndef USE_SEE |
| 1571 | 1571 | USE_SEE = 0 |
| 1572 | 1572 | !endif |
| 1573 | 1573 | |
| 1574 | 1574 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 1575 | -SSLDIR = $(B)\compat\openssl-1.1.1e | |
| 1575 | +SSLDIR = $(B)\compat\openssl-1.1.1f | |
| 1576 | 1576 | SSLINCDIR = $(SSLDIR)\include |
| 1577 | 1577 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 1578 | 1578 | SSLLIBDIR = $(SSLDIR) |
| 1579 | 1579 | !else |
| 1580 | 1580 | SSLLIBDIR = $(SSLDIR) |
| 1581 | 1581 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -713,11 +713,11 @@ | |
| 713 | #### The directories where the OpenSSL include and library files are located. |
| 714 | # The recommended usage here is to use the Sysinternals junction tool |
| 715 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 716 | # Fossil source code directory and the target OpenSSL source directory. |
| 717 | # |
| 718 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e |
| 719 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 720 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 721 | |
| 722 | #### Either the directory where the Tcl library is installed or the Tcl |
| 723 | # source code directory resides (depending on the value of the macro |
| @@ -1570,11 +1570,11 @@ | |
| 1570 | !ifndef USE_SEE |
| 1571 | USE_SEE = 0 |
| 1572 | !endif |
| 1573 | |
| 1574 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 1575 | SSLDIR = $(B)\compat\openssl-1.1.1e |
| 1576 | SSLINCDIR = $(SSLDIR)\include |
| 1577 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 1578 | SSLLIBDIR = $(SSLDIR) |
| 1579 | !else |
| 1580 | SSLLIBDIR = $(SSLDIR) |
| 1581 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -713,11 +713,11 @@ | |
| 713 | #### The directories where the OpenSSL include and library files are located. |
| 714 | # The recommended usage here is to use the Sysinternals junction tool |
| 715 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 716 | # Fossil source code directory and the target OpenSSL source directory. |
| 717 | # |
| 718 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f |
| 719 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 720 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 721 | |
| 722 | #### Either the directory where the Tcl library is installed or the Tcl |
| 723 | # source code directory resides (depending on the value of the macro |
| @@ -1570,11 +1570,11 @@ | |
| 1570 | !ifndef USE_SEE |
| 1571 | USE_SEE = 0 |
| 1572 | !endif |
| 1573 | |
| 1574 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 1575 | SSLDIR = $(B)\compat\openssl-1.1.1f |
| 1576 | SSLINCDIR = $(SSLDIR)\include |
| 1577 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 1578 | SSLLIBDIR = $(SSLDIR) |
| 1579 | !else |
| 1580 | SSLLIBDIR = $(SSLDIR) |
| 1581 |
+3
-1
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -2059,19 +2059,20 @@ | ||
| 2059 | 2059 | return c; |
| 2060 | 2060 | } |
| 2061 | 2061 | |
| 2062 | 2062 | /* |
| 2063 | 2063 | ** Scan artifact rid/pContent to see if it is a control artifact of |
| 2064 | -** any key: | |
| 2064 | +** any type: | |
| 2065 | 2065 | ** |
| 2066 | 2066 | ** * Manifest |
| 2067 | 2067 | ** * Control |
| 2068 | 2068 | ** * Wiki Page |
| 2069 | 2069 | ** * Ticket Change |
| 2070 | 2070 | ** * Cluster |
| 2071 | 2071 | ** * Attachment |
| 2072 | 2072 | ** * Event |
| 2073 | +** * Forum post | |
| 2073 | 2074 | ** |
| 2074 | 2075 | ** If the input is a control artifact, then make appropriate entries |
| 2075 | 2076 | ** in the auxiliary tables of the database in order to crosslink the |
| 2076 | 2077 | ** artifact. |
| 2077 | 2078 | ** |
| @@ -2558,10 +2559,11 @@ | ||
| 2558 | 2559 | if( p->type==CFTYPE_FORUM ){ |
| 2559 | 2560 | int froot, fprev, firt; |
| 2560 | 2561 | char *zFType; |
| 2561 | 2562 | char *zTitle; |
| 2562 | 2563 | schema_forum(); |
| 2564 | + search_doc_touch('f', rid, 0); | |
| 2563 | 2565 | froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid; |
| 2564 | 2566 | fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0; |
| 2565 | 2567 | firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0; |
| 2566 | 2568 | db_multi_exec( |
| 2567 | 2569 | "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)" |
| 2568 | 2570 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -2059,19 +2059,20 @@ | |
| 2059 | return c; |
| 2060 | } |
| 2061 | |
| 2062 | /* |
| 2063 | ** Scan artifact rid/pContent to see if it is a control artifact of |
| 2064 | ** any key: |
| 2065 | ** |
| 2066 | ** * Manifest |
| 2067 | ** * Control |
| 2068 | ** * Wiki Page |
| 2069 | ** * Ticket Change |
| 2070 | ** * Cluster |
| 2071 | ** * Attachment |
| 2072 | ** * Event |
| 2073 | ** |
| 2074 | ** If the input is a control artifact, then make appropriate entries |
| 2075 | ** in the auxiliary tables of the database in order to crosslink the |
| 2076 | ** artifact. |
| 2077 | ** |
| @@ -2558,10 +2559,11 @@ | |
| 2558 | if( p->type==CFTYPE_FORUM ){ |
| 2559 | int froot, fprev, firt; |
| 2560 | char *zFType; |
| 2561 | char *zTitle; |
| 2562 | schema_forum(); |
| 2563 | froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid; |
| 2564 | fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0; |
| 2565 | firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0; |
| 2566 | db_multi_exec( |
| 2567 | "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)" |
| 2568 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -2059,19 +2059,20 @@ | |
| 2059 | return c; |
| 2060 | } |
| 2061 | |
| 2062 | /* |
| 2063 | ** Scan artifact rid/pContent to see if it is a control artifact of |
| 2064 | ** any type: |
| 2065 | ** |
| 2066 | ** * Manifest |
| 2067 | ** * Control |
| 2068 | ** * Wiki Page |
| 2069 | ** * Ticket Change |
| 2070 | ** * Cluster |
| 2071 | ** * Attachment |
| 2072 | ** * Event |
| 2073 | ** * Forum post |
| 2074 | ** |
| 2075 | ** If the input is a control artifact, then make appropriate entries |
| 2076 | ** in the auxiliary tables of the database in order to crosslink the |
| 2077 | ** artifact. |
| 2078 | ** |
| @@ -2558,10 +2559,11 @@ | |
| 2559 | if( p->type==CFTYPE_FORUM ){ |
| 2560 | int froot, fprev, firt; |
| 2561 | char *zFType; |
| 2562 | char *zTitle; |
| 2563 | schema_forum(); |
| 2564 | search_doc_touch('f', rid, 0); |
| 2565 | froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid; |
| 2566 | fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0; |
| 2567 | firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0; |
| 2568 | db_multi_exec( |
| 2569 | "REPLACE INTO forumpost(fpid,froot,fprev,firt,fmtime)" |
| 2570 |
+3
-2
| --- src/moderate.c | ||
| +++ src/moderate.c | ||
| @@ -147,21 +147,22 @@ | ||
| 147 | 147 | } |
| 148 | 148 | |
| 149 | 149 | /* |
| 150 | 150 | ** Approve an object held for moderation. |
| 151 | 151 | */ |
| 152 | -void moderation_approve(int rid){ | |
| 152 | +void moderation_approve(char class, int rid){ | |
| 153 | 153 | if( !moderation_pending(rid) ) return; |
| 154 | 154 | db_begin_transaction(); |
| 155 | 155 | db_multi_exec( |
| 156 | 156 | "DELETE FROM private WHERE rid=%d;" |
| 157 | 157 | "INSERT OR IGNORE INTO unclustered VALUES(%d);" |
| 158 | 158 | "INSERT OR IGNORE INTO unsent VALUES(%d);", |
| 159 | 159 | rid, rid, rid |
| 160 | 160 | ); |
| 161 | 161 | db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid); |
| 162 | - admin_log("Approved moderation of rid %d.", rid); | |
| 162 | + admin_log("Approved moderation of rid %c-%d.", class, rid); | |
| 163 | + if( class!='a' ) search_doc_touch(class, rid, 0); | |
| 163 | 164 | db_end_transaction(0); |
| 164 | 165 | } |
| 165 | 166 | |
| 166 | 167 | /* |
| 167 | 168 | ** WEBPAGE: modreq |
| 168 | 169 |
| --- src/moderate.c | |
| +++ src/moderate.c | |
| @@ -147,21 +147,22 @@ | |
| 147 | } |
| 148 | |
| 149 | /* |
| 150 | ** Approve an object held for moderation. |
| 151 | */ |
| 152 | void moderation_approve(int rid){ |
| 153 | if( !moderation_pending(rid) ) return; |
| 154 | db_begin_transaction(); |
| 155 | db_multi_exec( |
| 156 | "DELETE FROM private WHERE rid=%d;" |
| 157 | "INSERT OR IGNORE INTO unclustered VALUES(%d);" |
| 158 | "INSERT OR IGNORE INTO unsent VALUES(%d);", |
| 159 | rid, rid, rid |
| 160 | ); |
| 161 | db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid); |
| 162 | admin_log("Approved moderation of rid %d.", rid); |
| 163 | db_end_transaction(0); |
| 164 | } |
| 165 | |
| 166 | /* |
| 167 | ** WEBPAGE: modreq |
| 168 |
| --- src/moderate.c | |
| +++ src/moderate.c | |
| @@ -147,21 +147,22 @@ | |
| 147 | } |
| 148 | |
| 149 | /* |
| 150 | ** Approve an object held for moderation. |
| 151 | */ |
| 152 | void moderation_approve(char class, int rid){ |
| 153 | if( !moderation_pending(rid) ) return; |
| 154 | db_begin_transaction(); |
| 155 | db_multi_exec( |
| 156 | "DELETE FROM private WHERE rid=%d;" |
| 157 | "INSERT OR IGNORE INTO unclustered VALUES(%d);" |
| 158 | "INSERT OR IGNORE INTO unsent VALUES(%d);", |
| 159 | rid, rid, rid |
| 160 | ); |
| 161 | db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid); |
| 162 | admin_log("Approved moderation of rid %c-%d.", class, rid); |
| 163 | if( class!='a' ) search_doc_touch(class, rid, 0); |
| 164 | db_end_transaction(0); |
| 165 | } |
| 166 | |
| 167 | /* |
| 168 | ** WEBPAGE: modreq |
| 169 |
+48
-8
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -105,10 +105,43 @@ | ||
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | /* It looks like this may be a date. Return it with punctuation added. */ |
| 108 | 108 | return zEDate; |
| 109 | 109 | } |
| 110 | + | |
| 111 | +/* | |
| 112 | +** The data-time string in the argument is going to be used as an | |
| 113 | +** upper bound like this: mtime<=julianday(zDate,'localtime'). | |
| 114 | +** But if the zDate parameter omits the fractional seconds or the | |
| 115 | +** seconds, or the time, that might mess up the == part of the | |
| 116 | +** comparison. So add in missing factional seconds or seconds or time. | |
| 117 | +** | |
| 118 | +** The returned string is held in a static buffer that is overwritten | |
| 119 | +** with each call, or else is just a copy of its input if there are | |
| 120 | +** no changes. | |
| 121 | +*/ | |
| 122 | +const char *fossil_roundup_date(const char *zDate){ | |
| 123 | + static char zUp[24]; | |
| 124 | + int n = (int)strlen(zDate); | |
| 125 | + if( n==19 ){ /* YYYY-MM-DD HH:MM:SS */ | |
| 126 | + memcpy(zUp, zDate, 19); | |
| 127 | + memcpy(zUp+19, ".999", 5); | |
| 128 | + return zUp; | |
| 129 | + } | |
| 130 | + if( n==16 ){ /* YYYY-MM-DD HH:MM */ | |
| 131 | + memcpy(zUp, zDate, 16); | |
| 132 | + memcpy(zUp+16, ":59.999", 8); | |
| 133 | + return zUp; | |
| 134 | + } | |
| 135 | + if( n==10 ){ /* YYYY-MM-DD */ | |
| 136 | + memcpy(zUp, zDate, 10); | |
| 137 | + memcpy(zUp+10, " 23:59:59.999", 14); | |
| 138 | + return zUp; | |
| 139 | + } | |
| 140 | + return zDate; | |
| 141 | +} | |
| 142 | + | |
| 110 | 143 | |
| 111 | 144 | /* |
| 112 | 145 | ** Return the RID that is the "root" of the branch that contains |
| 113 | 146 | ** check-in "rid". Details depending on eType: |
| 114 | 147 | ** |
| @@ -235,19 +268,19 @@ | ||
| 235 | 268 | if( zDate==0 ) zDate = &zTag[5]; |
| 236 | 269 | rid = db_int(0, |
| 237 | 270 | "SELECT objid FROM event" |
| 238 | 271 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 239 | 272 | " ORDER BY mtime DESC LIMIT 1", |
| 240 | - zDate, zType); | |
| 273 | + fossil_roundup_date(zDate), zType); | |
| 241 | 274 | return rid; |
| 242 | 275 | } |
| 243 | 276 | if( fossil_isdate(zTag) ){ |
| 244 | 277 | rid = db_int(0, |
| 245 | 278 | "SELECT objid FROM event" |
| 246 | 279 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 247 | 280 | " ORDER BY mtime DESC LIMIT 1", |
| 248 | - zTag, zType); | |
| 281 | + fossil_roundup_date(zTag), zType); | |
| 249 | 282 | if( rid) return rid; |
| 250 | 283 | } |
| 251 | 284 | |
| 252 | 285 | /* Deprecated date & time formats: "local:" + date-time and |
| 253 | 286 | ** "utc:" + date-time */ |
| @@ -262,11 +295,11 @@ | ||
| 262 | 295 | if( memcmp(zTag, "utc:", 4)==0 ){ |
| 263 | 296 | rid = db_int(0, |
| 264 | 297 | "SELECT objid FROM event" |
| 265 | 298 | " WHERE mtime<=julianday('%qz') AND type GLOB '%q'" |
| 266 | 299 | " ORDER BY mtime DESC LIMIT 1", |
| 267 | - &zTag[4], zType); | |
| 300 | + fossil_roundup_date(&zTag[4]), zType); | |
| 268 | 301 | return rid; |
| 269 | 302 | } |
| 270 | 303 | |
| 271 | 304 | /* "tag:" + symbolic-name */ |
| 272 | 305 | if( memcmp(zTag, "tag:", 4)==0 ){ |
| @@ -294,29 +327,36 @@ | ||
| 294 | 327 | return start_of_branch(rid, 2); |
| 295 | 328 | } |
| 296 | 329 | |
| 297 | 330 | /* symbolic-name ":" date-time */ |
| 298 | 331 | nTag = strlen(zTag); |
| 299 | - for(i=0; i<nTag-10 && zTag[i]!=':'; i++){} | |
| 300 | - if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){ | |
| 332 | + for(i=0; i<nTag-8 && zTag[i]!=':'; i++){} | |
| 333 | + if( zTag[i]==':' | |
| 334 | + && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0) | |
| 335 | + ){ | |
| 301 | 336 | char *zDate = mprintf("%s", &zTag[i+1]); |
| 302 | 337 | char *zTagBase = mprintf("%.*s", i, zTag); |
| 338 | + char *zXDate; | |
| 303 | 339 | int nDate = strlen(zDate); |
| 304 | 340 | if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ |
| 305 | 341 | zDate[nDate-3] = 'z'; |
| 306 | 342 | zDate[nDate-2] = 0; |
| 307 | 343 | } |
| 344 | + zXDate = fossil_expand_datetime(zDate,0); | |
| 345 | + if( zXDate==0 ) zXDate = zDate; | |
| 308 | 346 | rid = db_int(0, |
| 309 | 347 | "SELECT event.objid, max(event.mtime)" |
| 310 | 348 | " FROM tag, tagxref, event" |
| 311 | 349 | " WHERE tag.tagname='sym-%q' " |
| 312 | 350 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 313 | 351 | " AND event.objid=tagxref.rid " |
| 314 | - " AND event.mtime<=julianday(%Q)" | |
| 352 | + " AND event.mtime<=julianday(%Q,fromLocal())" | |
| 315 | 353 | " AND event.type GLOB '%q'", |
| 316 | - zTagBase, zDate, zType | |
| 354 | + zTagBase, fossil_roundup_date(zXDate), zType | |
| 317 | 355 | ); |
| 356 | + fossil_free(zDate); | |
| 357 | + fossil_free(zTagBase); | |
| 318 | 358 | return rid; |
| 319 | 359 | } |
| 320 | 360 | |
| 321 | 361 | /* Remove optional [...] */ |
| 322 | 362 | zXTag = zTag; |
| @@ -381,11 +421,11 @@ | ||
| 381 | 421 | if( zDate ){ |
| 382 | 422 | rid = db_int(0, |
| 383 | 423 | "SELECT objid FROM event" |
| 384 | 424 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 385 | 425 | " ORDER BY mtime DESC LIMIT 1", |
| 386 | - zDate, zType); | |
| 426 | + fossil_roundup_date(zDate), zType); | |
| 387 | 427 | if( rid) return rid; |
| 388 | 428 | } |
| 389 | 429 | |
| 390 | 430 | |
| 391 | 431 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 392 | 432 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -105,10 +105,43 @@ | |
| 105 | } |
| 106 | |
| 107 | /* It looks like this may be a date. Return it with punctuation added. */ |
| 108 | return zEDate; |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** Return the RID that is the "root" of the branch that contains |
| 113 | ** check-in "rid". Details depending on eType: |
| 114 | ** |
| @@ -235,19 +268,19 @@ | |
| 235 | if( zDate==0 ) zDate = &zTag[5]; |
| 236 | rid = db_int(0, |
| 237 | "SELECT objid FROM event" |
| 238 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 239 | " ORDER BY mtime DESC LIMIT 1", |
| 240 | zDate, zType); |
| 241 | return rid; |
| 242 | } |
| 243 | if( fossil_isdate(zTag) ){ |
| 244 | rid = db_int(0, |
| 245 | "SELECT objid FROM event" |
| 246 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 247 | " ORDER BY mtime DESC LIMIT 1", |
| 248 | zTag, zType); |
| 249 | if( rid) return rid; |
| 250 | } |
| 251 | |
| 252 | /* Deprecated date & time formats: "local:" + date-time and |
| 253 | ** "utc:" + date-time */ |
| @@ -262,11 +295,11 @@ | |
| 262 | if( memcmp(zTag, "utc:", 4)==0 ){ |
| 263 | rid = db_int(0, |
| 264 | "SELECT objid FROM event" |
| 265 | " WHERE mtime<=julianday('%qz') AND type GLOB '%q'" |
| 266 | " ORDER BY mtime DESC LIMIT 1", |
| 267 | &zTag[4], zType); |
| 268 | return rid; |
| 269 | } |
| 270 | |
| 271 | /* "tag:" + symbolic-name */ |
| 272 | if( memcmp(zTag, "tag:", 4)==0 ){ |
| @@ -294,29 +327,36 @@ | |
| 294 | return start_of_branch(rid, 2); |
| 295 | } |
| 296 | |
| 297 | /* symbolic-name ":" date-time */ |
| 298 | nTag = strlen(zTag); |
| 299 | for(i=0; i<nTag-10 && zTag[i]!=':'; i++){} |
| 300 | if( zTag[i]==':' && fossil_isdate(&zTag[i+1]) ){ |
| 301 | char *zDate = mprintf("%s", &zTag[i+1]); |
| 302 | char *zTagBase = mprintf("%.*s", i, zTag); |
| 303 | int nDate = strlen(zDate); |
| 304 | if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ |
| 305 | zDate[nDate-3] = 'z'; |
| 306 | zDate[nDate-2] = 0; |
| 307 | } |
| 308 | rid = db_int(0, |
| 309 | "SELECT event.objid, max(event.mtime)" |
| 310 | " FROM tag, tagxref, event" |
| 311 | " WHERE tag.tagname='sym-%q' " |
| 312 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 313 | " AND event.objid=tagxref.rid " |
| 314 | " AND event.mtime<=julianday(%Q)" |
| 315 | " AND event.type GLOB '%q'", |
| 316 | zTagBase, zDate, zType |
| 317 | ); |
| 318 | return rid; |
| 319 | } |
| 320 | |
| 321 | /* Remove optional [...] */ |
| 322 | zXTag = zTag; |
| @@ -381,11 +421,11 @@ | |
| 381 | if( zDate ){ |
| 382 | rid = db_int(0, |
| 383 | "SELECT objid FROM event" |
| 384 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 385 | " ORDER BY mtime DESC LIMIT 1", |
| 386 | zDate, zType); |
| 387 | if( rid) return rid; |
| 388 | } |
| 389 | |
| 390 | |
| 391 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 392 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -105,10 +105,43 @@ | |
| 105 | } |
| 106 | |
| 107 | /* It looks like this may be a date. Return it with punctuation added. */ |
| 108 | return zEDate; |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | ** The data-time string in the argument is going to be used as an |
| 113 | ** upper bound like this: mtime<=julianday(zDate,'localtime'). |
| 114 | ** But if the zDate parameter omits the fractional seconds or the |
| 115 | ** seconds, or the time, that might mess up the == part of the |
| 116 | ** comparison. So add in missing factional seconds or seconds or time. |
| 117 | ** |
| 118 | ** The returned string is held in a static buffer that is overwritten |
| 119 | ** with each call, or else is just a copy of its input if there are |
| 120 | ** no changes. |
| 121 | */ |
| 122 | const char *fossil_roundup_date(const char *zDate){ |
| 123 | static char zUp[24]; |
| 124 | int n = (int)strlen(zDate); |
| 125 | if( n==19 ){ /* YYYY-MM-DD HH:MM:SS */ |
| 126 | memcpy(zUp, zDate, 19); |
| 127 | memcpy(zUp+19, ".999", 5); |
| 128 | return zUp; |
| 129 | } |
| 130 | if( n==16 ){ /* YYYY-MM-DD HH:MM */ |
| 131 | memcpy(zUp, zDate, 16); |
| 132 | memcpy(zUp+16, ":59.999", 8); |
| 133 | return zUp; |
| 134 | } |
| 135 | if( n==10 ){ /* YYYY-MM-DD */ |
| 136 | memcpy(zUp, zDate, 10); |
| 137 | memcpy(zUp+10, " 23:59:59.999", 14); |
| 138 | return zUp; |
| 139 | } |
| 140 | return zDate; |
| 141 | } |
| 142 | |
| 143 | |
| 144 | /* |
| 145 | ** Return the RID that is the "root" of the branch that contains |
| 146 | ** check-in "rid". Details depending on eType: |
| 147 | ** |
| @@ -235,19 +268,19 @@ | |
| 268 | if( zDate==0 ) zDate = &zTag[5]; |
| 269 | rid = db_int(0, |
| 270 | "SELECT objid FROM event" |
| 271 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 272 | " ORDER BY mtime DESC LIMIT 1", |
| 273 | fossil_roundup_date(zDate), zType); |
| 274 | return rid; |
| 275 | } |
| 276 | if( fossil_isdate(zTag) ){ |
| 277 | rid = db_int(0, |
| 278 | "SELECT objid FROM event" |
| 279 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 280 | " ORDER BY mtime DESC LIMIT 1", |
| 281 | fossil_roundup_date(zTag), zType); |
| 282 | if( rid) return rid; |
| 283 | } |
| 284 | |
| 285 | /* Deprecated date & time formats: "local:" + date-time and |
| 286 | ** "utc:" + date-time */ |
| @@ -262,11 +295,11 @@ | |
| 295 | if( memcmp(zTag, "utc:", 4)==0 ){ |
| 296 | rid = db_int(0, |
| 297 | "SELECT objid FROM event" |
| 298 | " WHERE mtime<=julianday('%qz') AND type GLOB '%q'" |
| 299 | " ORDER BY mtime DESC LIMIT 1", |
| 300 | fossil_roundup_date(&zTag[4]), zType); |
| 301 | return rid; |
| 302 | } |
| 303 | |
| 304 | /* "tag:" + symbolic-name */ |
| 305 | if( memcmp(zTag, "tag:", 4)==0 ){ |
| @@ -294,29 +327,36 @@ | |
| 327 | return start_of_branch(rid, 2); |
| 328 | } |
| 329 | |
| 330 | /* symbolic-name ":" date-time */ |
| 331 | nTag = strlen(zTag); |
| 332 | for(i=0; i<nTag-8 && zTag[i]!=':'; i++){} |
| 333 | if( zTag[i]==':' |
| 334 | && (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0)!=0) |
| 335 | ){ |
| 336 | char *zDate = mprintf("%s", &zTag[i+1]); |
| 337 | char *zTagBase = mprintf("%.*s", i, zTag); |
| 338 | char *zXDate; |
| 339 | int nDate = strlen(zDate); |
| 340 | if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ |
| 341 | zDate[nDate-3] = 'z'; |
| 342 | zDate[nDate-2] = 0; |
| 343 | } |
| 344 | zXDate = fossil_expand_datetime(zDate,0); |
| 345 | if( zXDate==0 ) zXDate = zDate; |
| 346 | rid = db_int(0, |
| 347 | "SELECT event.objid, max(event.mtime)" |
| 348 | " FROM tag, tagxref, event" |
| 349 | " WHERE tag.tagname='sym-%q' " |
| 350 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 351 | " AND event.objid=tagxref.rid " |
| 352 | " AND event.mtime<=julianday(%Q,fromLocal())" |
| 353 | " AND event.type GLOB '%q'", |
| 354 | zTagBase, fossil_roundup_date(zXDate), zType |
| 355 | ); |
| 356 | fossil_free(zDate); |
| 357 | fossil_free(zTagBase); |
| 358 | return rid; |
| 359 | } |
| 360 | |
| 361 | /* Remove optional [...] */ |
| 362 | zXTag = zTag; |
| @@ -381,11 +421,11 @@ | |
| 421 | if( zDate ){ |
| 422 | rid = db_int(0, |
| 423 | "SELECT objid FROM event" |
| 424 | " WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'" |
| 425 | " ORDER BY mtime DESC LIMIT 1", |
| 426 | fossil_roundup_date(zDate), zType); |
| 427 | if( rid) return rid; |
| 428 | } |
| 429 | |
| 430 | |
| 431 | /* Undocumented: numeric tags get translated directly into the RID */ |
| 432 |
+89
-20
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -14,11 +14,12 @@ | ||
| 14 | 14 | ** http://www.hwaci.com/drh/ |
| 15 | 15 | ** |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code to implement a search functions |
| 19 | -** against timeline comments, check-in content, wiki pages, and/or tickets. | |
| 19 | +** against timeline comments, check-in content, wiki pages, tickets, | |
| 20 | +** and/or forum posts. | |
| 20 | 21 | ** |
| 21 | 22 | ** The search can be either a per-query "grep"-like search that scans |
| 22 | 23 | ** the entire corpus. Or it can use the FTS4 or FTS5 search engine of |
| 23 | 24 | ** SQLite. The choice is a administrator configuration option. |
| 24 | 25 | ** |
| @@ -331,10 +332,18 @@ | ||
| 331 | 332 | ** |
| 332 | 333 | ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... |
| 333 | 334 | ** |
| 334 | 335 | ** Run the full-scan search algorithm using SEARCHSTRING against |
| 335 | 336 | ** the text of the files listed. Output matches and snippets. |
| 337 | +** | |
| 338 | +** Options: | |
| 339 | +** | |
| 340 | +** --begin TEXT Text to insert before each match | |
| 341 | +** --end TEXT Text to insert after each match | |
| 342 | +** --gap TEXT Text to indicate elided content | |
| 343 | +** --html Input is HTML | |
| 344 | +** --static Use the static Search object | |
| 336 | 345 | */ |
| 337 | 346 | void test_match_cmd(void){ |
| 338 | 347 | Search *p; |
| 339 | 348 | int i; |
| 340 | 349 | Blob x; |
| @@ -372,11 +381,12 @@ | ||
| 372 | 381 | ** |
| 373 | 382 | ** All arguments are optional. PATTERN is the search pattern. If it |
| 374 | 383 | ** is omitted, then the global search pattern is reset. BEGIN and END |
| 375 | 384 | ** and GAP are the strings used to construct snippets. FLAGS is an |
| 376 | 385 | ** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, |
| 377 | -** SRCH_TKT, or SRCH_ALL bits to determine what is to be searched. | |
| 386 | +** SRCH_TKT, SRCH_FORUM, or SRCH_ALL bits to determine what is to be | |
| 387 | +** searched. | |
| 378 | 388 | */ |
| 379 | 389 | static void search_init_sqlfunc( |
| 380 | 390 | sqlite3_context *context, |
| 381 | 391 | int argc, |
| 382 | 392 | sqlite3_value **argv |
| @@ -407,11 +417,11 @@ | ||
| 407 | 417 | |
| 408 | 418 | /* search_match(TEXT, TEXT, ....) |
| 409 | 419 | ** |
| 410 | 420 | ** Using the full-scan search engine created by the most recent call |
| 411 | 421 | ** to search_init(), match the input the TEXT arguments. |
| 412 | -** Remember the results global full-scan search object. | |
| 422 | +** Remember the results in the global full-scan search object. | |
| 413 | 423 | ** Return non-zero on a match and zero on a miss. |
| 414 | 424 | */ |
| 415 | 425 | static void search_match_sqlfunc( |
| 416 | 426 | sqlite3_context *context, |
| 417 | 427 | int argc, |
| @@ -560,10 +570,15 @@ | ||
| 560 | 570 | ** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... |
| 561 | 571 | ** |
| 562 | 572 | ** Search for timeline entries matching all words provided on the |
| 563 | 573 | ** command line. Whole-word matches scope more highly than partial |
| 564 | 574 | ** matches. |
| 575 | +** | |
| 576 | +** Note: The command only search the EVENT table. So it will only | |
| 577 | +** display check-in comments or other comments that appear on an | |
| 578 | +** unaugmented timeline. It does not search document text or forum | |
| 579 | +** messages. | |
| 565 | 580 | ** |
| 566 | 581 | ** Outputs, by default, some top-N fraction of the results. The -all |
| 567 | 582 | ** option can be used to output all matches, regardless of their search |
| 568 | 583 | ** score. The -limit option can be used to limit the number of entries |
| 569 | 584 | ** returned. The -width option can be used to set the output width used |
| @@ -645,11 +660,12 @@ | ||
| 645 | 660 | #define SRCH_ALL 0x003f /* Search over everything */ |
| 646 | 661 | #endif |
| 647 | 662 | |
| 648 | 663 | /* |
| 649 | 664 | ** Remove bits from srchFlags which are disallowed by either the |
| 650 | -** current server configuration or by user permissions. | |
| 665 | +** current server configuration or by user permissions. Return | |
| 666 | +** the revised search flags mask. | |
| 651 | 667 | */ |
| 652 | 668 | unsigned int search_restrict(unsigned int srchFlags){ |
| 653 | 669 | static unsigned int knownGood = 0; |
| 654 | 670 | static unsigned int knownBad = 0; |
| 655 | 671 | static const struct { unsigned m; const char *zKey; } aSetng[] = { |
| @@ -1569,11 +1585,11 @@ | ||
| 1569 | 1585 | ** updated. If the document has already been indexed, then unindex it |
| 1570 | 1586 | ** now while we still have access to the old content. Add the document |
| 1571 | 1587 | ** to the queue of documents that need to be indexed or reindexed. |
| 1572 | 1588 | */ |
| 1573 | 1589 | void search_doc_touch(char cType, int rid, const char *zName){ |
| 1574 | - if( search_index_exists() ){ | |
| 1590 | + if( search_index_exists() && !content_is_private(rid) ){ | |
| 1575 | 1591 | char zType[2]; |
| 1576 | 1592 | zType[0] = cType; |
| 1577 | 1593 | zType[1] = 0; |
| 1578 | 1594 | search_sql_setup(g.db); |
| 1579 | 1595 | db_multi_exec( |
| @@ -1836,18 +1852,25 @@ | ||
| 1836 | 1852 | ** |
| 1837 | 1853 | ** The current search settings are displayed after any changes are applied. |
| 1838 | 1854 | ** Run this command with no arguments to simply see the settings. |
| 1839 | 1855 | */ |
| 1840 | 1856 | void fts_config_cmd(void){ |
| 1841 | - static const struct { int iCmd; const char *z; } aCmd[] = { | |
| 1857 | + static const struct { | |
| 1858 | + int iCmd; | |
| 1859 | + const char *z; | |
| 1860 | + } aCmd[] = { | |
| 1842 | 1861 | { 1, "reindex" }, |
| 1843 | 1862 | { 2, "index" }, |
| 1844 | 1863 | { 3, "disable" }, |
| 1845 | 1864 | { 4, "enable" }, |
| 1846 | 1865 | { 5, "stemmer" }, |
| 1847 | 1866 | }; |
| 1848 | - static const struct { const char *zSetting; const char *zName; const char *zSw; } aSetng[] = { | |
| 1867 | + static const struct { | |
| 1868 | + const char *zSetting; | |
| 1869 | + const char *zName; | |
| 1870 | + const char *zSw; | |
| 1871 | + } aSetng[] = { | |
| 1849 | 1872 | { "search-ci", "check-in search:", "c" }, |
| 1850 | 1873 | { "search-doc", "document search:", "d" }, |
| 1851 | 1874 | { "search-tkt", "ticket search:", "t" }, |
| 1852 | 1875 | { "search-wiki", "wiki search:", "w" }, |
| 1853 | 1876 | { "search-technote", "tech note search:", "e" }, |
| @@ -1937,48 +1960,77 @@ | ||
| 1937 | 1960 | Stmt q; |
| 1938 | 1961 | const char *zId = P("id"); |
| 1939 | 1962 | const char *zType = P("y"); |
| 1940 | 1963 | const char *zIdxed = P("ixed"); |
| 1941 | 1964 | int id; |
| 1942 | - int cnt = 0; | |
| 1965 | + int cnt1 = 0, cnt2 = 0, cnt3 = 0; | |
| 1943 | 1966 | login_check_credentials(); |
| 1944 | 1967 | if( !g.perm.Admin ){ login_needed(0); return; } |
| 1945 | 1968 | if( !search_index_exists() ){ |
| 1946 | 1969 | @ <p>Indexed search is disabled |
| 1947 | 1970 | style_footer(); |
| 1948 | 1971 | return; |
| 1949 | 1972 | } |
| 1973 | + search_sql_setup(g.db); | |
| 1974 | + style_submenu_element("Setup","%R/srchsetup"); | |
| 1950 | 1975 | if( zId!=0 && (id = atoi(zId))>0 ){ |
| 1951 | 1976 | /* Show information about a single ftsdocs entry */ |
| 1952 | 1977 | style_header("Information about ftsdoc entry %d", id); |
| 1978 | + style_submenu_element("Summary","%R/test-ftsdocs"); | |
| 1953 | 1979 | db_prepare(&q, |
| 1954 | 1980 | "SELECT type||rid, name, idxed, label, url, datetime(mtime)" |
| 1955 | 1981 | " FROM ftsdocs WHERE rowid=%d", id |
| 1956 | 1982 | ); |
| 1957 | 1983 | if( db_step(&q)==SQLITE_ROW ){ |
| 1958 | 1984 | const char *zUrl = db_column_text(&q,4); |
| 1985 | + const char *zDocId = db_column_text(&q,0); | |
| 1986 | + char *zName; | |
| 1987 | + char *z; | |
| 1959 | 1988 | @ <table border=0> |
| 1960 | - @ <tr><td align='right'>rowid:<td> <td>%d(id) | |
| 1961 | - @ <tr><td align='right'>id:<td><td>%s(db_column_text(&q,0)) | |
| 1989 | + @ <tr><td align='right'>docid:<td> <td>%d(id) | |
| 1990 | + @ <tr><td align='right'>id:<td><td>%s(zDocId) | |
| 1962 | 1991 | @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1)) |
| 1963 | 1992 | @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2)) |
| 1964 | 1993 | @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3)) |
| 1965 | 1994 | @ <tr><td align='right'>url:<td><td> |
| 1966 | 1995 | @ <a href='%R%s(zUrl)'>%h(zUrl)</a> |
| 1967 | 1996 | @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5)) |
| 1997 | + z = db_text(0, "SELECT title FROM ftsidx WHERE docid=%d",id); | |
| 1998 | + if( z && z[0] ){ | |
| 1999 | + @ <tr><td align="right">title:<td><td>%h(z) | |
| 2000 | + fossil_free(z); | |
| 2001 | + } | |
| 2002 | + z = db_text(0, "SELECT body FROM ftsidx WHERE docid=%d",id); | |
| 2003 | + if( z && z[0] ){ | |
| 2004 | + @ <tr><td align="right" valign="top">body:<td><td>%h(z) | |
| 2005 | + fossil_free(z); | |
| 2006 | + } | |
| 1968 | 2007 | @ </table> |
| 2008 | + zName = mprintf("Indexed '%c' docs",zDocId[0]); | |
| 2009 | + style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]); | |
| 2010 | + zName = mprintf("Unindexed '%c' docs",zDocId[0]); | |
| 2011 | + style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]); | |
| 1969 | 2012 | } |
| 1970 | 2013 | db_finalize(&q); |
| 1971 | 2014 | style_footer(); |
| 1972 | 2015 | return; |
| 1973 | 2016 | } |
| 1974 | 2017 | if( zType!=0 && zType[0]!=0 && zType[1]==0 && |
| 1975 | 2018 | zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0 |
| 1976 | 2019 | ){ |
| 1977 | 2020 | int ixed = zIdxed[0]=='1'; |
| 2021 | + char *zName; | |
| 1978 | 2022 | style_header("List of '%c' documents that are%s indexed", |
| 1979 | 2023 | zType[0], ixed ? "" : " not"); |
| 2024 | + style_submenu_element("Summary","%R/test-ftsdocs"); | |
| 2025 | + if( ixed==0 ){ | |
| 2026 | + zName = mprintf("Indexed '%c' docs",zType[0]); | |
| 2027 | + style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zType[0]); | |
| 2028 | + }else{ | |
| 2029 | + zName = mprintf("Unindexed '%c' docs",zType[0]); | |
| 2030 | + style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zType[0]); | |
| 2031 | + } | |
| 1980 | 2032 | db_prepare(&q, |
| 1981 | 2033 | "SELECT rowid, type||rid ||' '|| coalesce(label,'')" |
| 1982 | 2034 | " FROM ftsdocs WHERE type='%c' AND %s idxed", |
| 1983 | 2035 | zType[0], ixed ? "" : "NOT" |
| 1984 | 2036 | ); |
| @@ -1992,29 +2044,46 @@ | ||
| 1992 | 2044 | style_footer(); |
| 1993 | 2045 | return; |
| 1994 | 2046 | } |
| 1995 | 2047 | style_header("Summary of ftsdocs"); |
| 1996 | 2048 | db_prepare(&q, |
| 1997 | - "SELECT type, idxed, count(*) FROM ftsdocs" | |
| 1998 | - " GROUP BY 1, 2 ORDER BY 3 DESC" | |
| 2049 | + "SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)" | |
| 2050 | + " FROM ftsdocs" | |
| 2051 | + " GROUP BY 1 ORDER BY 4 DESC" | |
| 1999 | 2052 | ); |
| 2000 | 2053 | @ <table border=1 cellpadding=3 cellspacing=0> |
| 2001 | 2054 | @ <thead> |
| 2002 | - @ <tr><th>Type<th>Indexed?<th>Count<th>Link | |
| 2055 | + @ <tr><th>Type<th>Indexed<th>Unindexed<th>Total | |
| 2003 | 2056 | @ </thead> |
| 2004 | 2057 | @ <tbody> |
| 2005 | 2058 | while( db_step(&q)==SQLITE_ROW ){ |
| 2006 | 2059 | const char *zType = db_column_text(&q,0); |
| 2007 | - int idxed = db_column_int(&q,1); | |
| 2008 | - int n = db_column_int(&q,2); | |
| 2009 | - @ <tr><td>%h(zType)<td>%d(idxed) | |
| 2010 | - @ <td>%d(n) | |
| 2011 | - @ <td><a href='test-ftsdocs?y=%s(zType)&ixed=%d(idxed)'>listing</a> | |
| 2060 | + int nIndexed = db_column_int(&q, 1); | |
| 2061 | + int nUnindexed = db_column_int(&q, 2); | |
| 2062 | + int nTotal = db_column_int(&q, 3); | |
| 2063 | + @ <tr><td>%h(zType) | |
| 2064 | + if( nIndexed>0 ){ | |
| 2065 | + @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=1'>\ | |
| 2066 | + @ %d(nIndexed)</a> | |
| 2067 | + }else{ | |
| 2068 | + @ <td align="right">0 | |
| 2069 | + } | |
| 2070 | + if( nUnindexed>0 ){ | |
| 2071 | + @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=0'>\ | |
| 2072 | + @ %d(nUnindexed)</a> | |
| 2073 | + }else{ | |
| 2074 | + @ <td align="right">0 | |
| 2075 | + } | |
| 2076 | + @ <td align="right">%d(nTotal) | |
| 2012 | 2077 | @ </tr> |
| 2013 | - cnt += n; | |
| 2078 | + cnt1 += nIndexed; | |
| 2079 | + cnt2 += nUnindexed; | |
| 2080 | + cnt3 += nTotal; | |
| 2014 | 2081 | } |
| 2082 | + db_finalize(&q); | |
| 2015 | 2083 | @ </tbody><tfooter> |
| 2016 | - @ <tr><th>Total<th><th>%d(cnt)<th> | |
| 2084 | + @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2) | |
| 2085 | + @ <th align="right">%d(cnt3) | |
| 2017 | 2086 | @ </tfooter> |
| 2018 | 2087 | @ </table> |
| 2019 | 2088 | style_footer(); |
| 2020 | 2089 | } |
| 2021 | 2090 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -14,11 +14,12 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code to implement a search functions |
| 19 | ** against timeline comments, check-in content, wiki pages, and/or tickets. |
| 20 | ** |
| 21 | ** The search can be either a per-query "grep"-like search that scans |
| 22 | ** the entire corpus. Or it can use the FTS4 or FTS5 search engine of |
| 23 | ** SQLite. The choice is a administrator configuration option. |
| 24 | ** |
| @@ -331,10 +332,18 @@ | |
| 331 | ** |
| 332 | ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... |
| 333 | ** |
| 334 | ** Run the full-scan search algorithm using SEARCHSTRING against |
| 335 | ** the text of the files listed. Output matches and snippets. |
| 336 | */ |
| 337 | void test_match_cmd(void){ |
| 338 | Search *p; |
| 339 | int i; |
| 340 | Blob x; |
| @@ -372,11 +381,12 @@ | |
| 372 | ** |
| 373 | ** All arguments are optional. PATTERN is the search pattern. If it |
| 374 | ** is omitted, then the global search pattern is reset. BEGIN and END |
| 375 | ** and GAP are the strings used to construct snippets. FLAGS is an |
| 376 | ** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, |
| 377 | ** SRCH_TKT, or SRCH_ALL bits to determine what is to be searched. |
| 378 | */ |
| 379 | static void search_init_sqlfunc( |
| 380 | sqlite3_context *context, |
| 381 | int argc, |
| 382 | sqlite3_value **argv |
| @@ -407,11 +417,11 @@ | |
| 407 | |
| 408 | /* search_match(TEXT, TEXT, ....) |
| 409 | ** |
| 410 | ** Using the full-scan search engine created by the most recent call |
| 411 | ** to search_init(), match the input the TEXT arguments. |
| 412 | ** Remember the results global full-scan search object. |
| 413 | ** Return non-zero on a match and zero on a miss. |
| 414 | */ |
| 415 | static void search_match_sqlfunc( |
| 416 | sqlite3_context *context, |
| 417 | int argc, |
| @@ -560,10 +570,15 @@ | |
| 560 | ** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... |
| 561 | ** |
| 562 | ** Search for timeline entries matching all words provided on the |
| 563 | ** command line. Whole-word matches scope more highly than partial |
| 564 | ** matches. |
| 565 | ** |
| 566 | ** Outputs, by default, some top-N fraction of the results. The -all |
| 567 | ** option can be used to output all matches, regardless of their search |
| 568 | ** score. The -limit option can be used to limit the number of entries |
| 569 | ** returned. The -width option can be used to set the output width used |
| @@ -645,11 +660,12 @@ | |
| 645 | #define SRCH_ALL 0x003f /* Search over everything */ |
| 646 | #endif |
| 647 | |
| 648 | /* |
| 649 | ** Remove bits from srchFlags which are disallowed by either the |
| 650 | ** current server configuration or by user permissions. |
| 651 | */ |
| 652 | unsigned int search_restrict(unsigned int srchFlags){ |
| 653 | static unsigned int knownGood = 0; |
| 654 | static unsigned int knownBad = 0; |
| 655 | static const struct { unsigned m; const char *zKey; } aSetng[] = { |
| @@ -1569,11 +1585,11 @@ | |
| 1569 | ** updated. If the document has already been indexed, then unindex it |
| 1570 | ** now while we still have access to the old content. Add the document |
| 1571 | ** to the queue of documents that need to be indexed or reindexed. |
| 1572 | */ |
| 1573 | void search_doc_touch(char cType, int rid, const char *zName){ |
| 1574 | if( search_index_exists() ){ |
| 1575 | char zType[2]; |
| 1576 | zType[0] = cType; |
| 1577 | zType[1] = 0; |
| 1578 | search_sql_setup(g.db); |
| 1579 | db_multi_exec( |
| @@ -1836,18 +1852,25 @@ | |
| 1836 | ** |
| 1837 | ** The current search settings are displayed after any changes are applied. |
| 1838 | ** Run this command with no arguments to simply see the settings. |
| 1839 | */ |
| 1840 | void fts_config_cmd(void){ |
| 1841 | static const struct { int iCmd; const char *z; } aCmd[] = { |
| 1842 | { 1, "reindex" }, |
| 1843 | { 2, "index" }, |
| 1844 | { 3, "disable" }, |
| 1845 | { 4, "enable" }, |
| 1846 | { 5, "stemmer" }, |
| 1847 | }; |
| 1848 | static const struct { const char *zSetting; const char *zName; const char *zSw; } aSetng[] = { |
| 1849 | { "search-ci", "check-in search:", "c" }, |
| 1850 | { "search-doc", "document search:", "d" }, |
| 1851 | { "search-tkt", "ticket search:", "t" }, |
| 1852 | { "search-wiki", "wiki search:", "w" }, |
| 1853 | { "search-technote", "tech note search:", "e" }, |
| @@ -1937,48 +1960,77 @@ | |
| 1937 | Stmt q; |
| 1938 | const char *zId = P("id"); |
| 1939 | const char *zType = P("y"); |
| 1940 | const char *zIdxed = P("ixed"); |
| 1941 | int id; |
| 1942 | int cnt = 0; |
| 1943 | login_check_credentials(); |
| 1944 | if( !g.perm.Admin ){ login_needed(0); return; } |
| 1945 | if( !search_index_exists() ){ |
| 1946 | @ <p>Indexed search is disabled |
| 1947 | style_footer(); |
| 1948 | return; |
| 1949 | } |
| 1950 | if( zId!=0 && (id = atoi(zId))>0 ){ |
| 1951 | /* Show information about a single ftsdocs entry */ |
| 1952 | style_header("Information about ftsdoc entry %d", id); |
| 1953 | db_prepare(&q, |
| 1954 | "SELECT type||rid, name, idxed, label, url, datetime(mtime)" |
| 1955 | " FROM ftsdocs WHERE rowid=%d", id |
| 1956 | ); |
| 1957 | if( db_step(&q)==SQLITE_ROW ){ |
| 1958 | const char *zUrl = db_column_text(&q,4); |
| 1959 | @ <table border=0> |
| 1960 | @ <tr><td align='right'>rowid:<td> <td>%d(id) |
| 1961 | @ <tr><td align='right'>id:<td><td>%s(db_column_text(&q,0)) |
| 1962 | @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1)) |
| 1963 | @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2)) |
| 1964 | @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3)) |
| 1965 | @ <tr><td align='right'>url:<td><td> |
| 1966 | @ <a href='%R%s(zUrl)'>%h(zUrl)</a> |
| 1967 | @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5)) |
| 1968 | @ </table> |
| 1969 | } |
| 1970 | db_finalize(&q); |
| 1971 | style_footer(); |
| 1972 | return; |
| 1973 | } |
| 1974 | if( zType!=0 && zType[0]!=0 && zType[1]==0 && |
| 1975 | zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0 |
| 1976 | ){ |
| 1977 | int ixed = zIdxed[0]=='1'; |
| 1978 | style_header("List of '%c' documents that are%s indexed", |
| 1979 | zType[0], ixed ? "" : " not"); |
| 1980 | db_prepare(&q, |
| 1981 | "SELECT rowid, type||rid ||' '|| coalesce(label,'')" |
| 1982 | " FROM ftsdocs WHERE type='%c' AND %s idxed", |
| 1983 | zType[0], ixed ? "" : "NOT" |
| 1984 | ); |
| @@ -1992,29 +2044,46 @@ | |
| 1992 | style_footer(); |
| 1993 | return; |
| 1994 | } |
| 1995 | style_header("Summary of ftsdocs"); |
| 1996 | db_prepare(&q, |
| 1997 | "SELECT type, idxed, count(*) FROM ftsdocs" |
| 1998 | " GROUP BY 1, 2 ORDER BY 3 DESC" |
| 1999 | ); |
| 2000 | @ <table border=1 cellpadding=3 cellspacing=0> |
| 2001 | @ <thead> |
| 2002 | @ <tr><th>Type<th>Indexed?<th>Count<th>Link |
| 2003 | @ </thead> |
| 2004 | @ <tbody> |
| 2005 | while( db_step(&q)==SQLITE_ROW ){ |
| 2006 | const char *zType = db_column_text(&q,0); |
| 2007 | int idxed = db_column_int(&q,1); |
| 2008 | int n = db_column_int(&q,2); |
| 2009 | @ <tr><td>%h(zType)<td>%d(idxed) |
| 2010 | @ <td>%d(n) |
| 2011 | @ <td><a href='test-ftsdocs?y=%s(zType)&ixed=%d(idxed)'>listing</a> |
| 2012 | @ </tr> |
| 2013 | cnt += n; |
| 2014 | } |
| 2015 | @ </tbody><tfooter> |
| 2016 | @ <tr><th>Total<th><th>%d(cnt)<th> |
| 2017 | @ </tfooter> |
| 2018 | @ </table> |
| 2019 | style_footer(); |
| 2020 | } |
| 2021 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -14,11 +14,12 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code to implement a search functions |
| 19 | ** against timeline comments, check-in content, wiki pages, tickets, |
| 20 | ** and/or forum posts. |
| 21 | ** |
| 22 | ** The search can be either a per-query "grep"-like search that scans |
| 23 | ** the entire corpus. Or it can use the FTS4 or FTS5 search engine of |
| 24 | ** SQLite. The choice is a administrator configuration option. |
| 25 | ** |
| @@ -331,10 +332,18 @@ | |
| 332 | ** |
| 333 | ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... |
| 334 | ** |
| 335 | ** Run the full-scan search algorithm using SEARCHSTRING against |
| 336 | ** the text of the files listed. Output matches and snippets. |
| 337 | ** |
| 338 | ** Options: |
| 339 | ** |
| 340 | ** --begin TEXT Text to insert before each match |
| 341 | ** --end TEXT Text to insert after each match |
| 342 | ** --gap TEXT Text to indicate elided content |
| 343 | ** --html Input is HTML |
| 344 | ** --static Use the static Search object |
| 345 | */ |
| 346 | void test_match_cmd(void){ |
| 347 | Search *p; |
| 348 | int i; |
| 349 | Blob x; |
| @@ -372,11 +381,12 @@ | |
| 381 | ** |
| 382 | ** All arguments are optional. PATTERN is the search pattern. If it |
| 383 | ** is omitted, then the global search pattern is reset. BEGIN and END |
| 384 | ** and GAP are the strings used to construct snippets. FLAGS is an |
| 385 | ** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, |
| 386 | ** SRCH_TKT, SRCH_FORUM, or SRCH_ALL bits to determine what is to be |
| 387 | ** searched. |
| 388 | */ |
| 389 | static void search_init_sqlfunc( |
| 390 | sqlite3_context *context, |
| 391 | int argc, |
| 392 | sqlite3_value **argv |
| @@ -407,11 +417,11 @@ | |
| 417 | |
| 418 | /* search_match(TEXT, TEXT, ....) |
| 419 | ** |
| 420 | ** Using the full-scan search engine created by the most recent call |
| 421 | ** to search_init(), match the input the TEXT arguments. |
| 422 | ** Remember the results in the global full-scan search object. |
| 423 | ** Return non-zero on a match and zero on a miss. |
| 424 | */ |
| 425 | static void search_match_sqlfunc( |
| 426 | sqlite3_context *context, |
| 427 | int argc, |
| @@ -560,10 +570,15 @@ | |
| 570 | ** Usage: %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... |
| 571 | ** |
| 572 | ** Search for timeline entries matching all words provided on the |
| 573 | ** command line. Whole-word matches scope more highly than partial |
| 574 | ** matches. |
| 575 | ** |
| 576 | ** Note: The command only search the EVENT table. So it will only |
| 577 | ** display check-in comments or other comments that appear on an |
| 578 | ** unaugmented timeline. It does not search document text or forum |
| 579 | ** messages. |
| 580 | ** |
| 581 | ** Outputs, by default, some top-N fraction of the results. The -all |
| 582 | ** option can be used to output all matches, regardless of their search |
| 583 | ** score. The -limit option can be used to limit the number of entries |
| 584 | ** returned. The -width option can be used to set the output width used |
| @@ -645,11 +660,12 @@ | |
| 660 | #define SRCH_ALL 0x003f /* Search over everything */ |
| 661 | #endif |
| 662 | |
| 663 | /* |
| 664 | ** Remove bits from srchFlags which are disallowed by either the |
| 665 | ** current server configuration or by user permissions. Return |
| 666 | ** the revised search flags mask. |
| 667 | */ |
| 668 | unsigned int search_restrict(unsigned int srchFlags){ |
| 669 | static unsigned int knownGood = 0; |
| 670 | static unsigned int knownBad = 0; |
| 671 | static const struct { unsigned m; const char *zKey; } aSetng[] = { |
| @@ -1569,11 +1585,11 @@ | |
| 1585 | ** updated. If the document has already been indexed, then unindex it |
| 1586 | ** now while we still have access to the old content. Add the document |
| 1587 | ** to the queue of documents that need to be indexed or reindexed. |
| 1588 | */ |
| 1589 | void search_doc_touch(char cType, int rid, const char *zName){ |
| 1590 | if( search_index_exists() && !content_is_private(rid) ){ |
| 1591 | char zType[2]; |
| 1592 | zType[0] = cType; |
| 1593 | zType[1] = 0; |
| 1594 | search_sql_setup(g.db); |
| 1595 | db_multi_exec( |
| @@ -1836,18 +1852,25 @@ | |
| 1852 | ** |
| 1853 | ** The current search settings are displayed after any changes are applied. |
| 1854 | ** Run this command with no arguments to simply see the settings. |
| 1855 | */ |
| 1856 | void fts_config_cmd(void){ |
| 1857 | static const struct { |
| 1858 | int iCmd; |
| 1859 | const char *z; |
| 1860 | } aCmd[] = { |
| 1861 | { 1, "reindex" }, |
| 1862 | { 2, "index" }, |
| 1863 | { 3, "disable" }, |
| 1864 | { 4, "enable" }, |
| 1865 | { 5, "stemmer" }, |
| 1866 | }; |
| 1867 | static const struct { |
| 1868 | const char *zSetting; |
| 1869 | const char *zName; |
| 1870 | const char *zSw; |
| 1871 | } aSetng[] = { |
| 1872 | { "search-ci", "check-in search:", "c" }, |
| 1873 | { "search-doc", "document search:", "d" }, |
| 1874 | { "search-tkt", "ticket search:", "t" }, |
| 1875 | { "search-wiki", "wiki search:", "w" }, |
| 1876 | { "search-technote", "tech note search:", "e" }, |
| @@ -1937,48 +1960,77 @@ | |
| 1960 | Stmt q; |
| 1961 | const char *zId = P("id"); |
| 1962 | const char *zType = P("y"); |
| 1963 | const char *zIdxed = P("ixed"); |
| 1964 | int id; |
| 1965 | int cnt1 = 0, cnt2 = 0, cnt3 = 0; |
| 1966 | login_check_credentials(); |
| 1967 | if( !g.perm.Admin ){ login_needed(0); return; } |
| 1968 | if( !search_index_exists() ){ |
| 1969 | @ <p>Indexed search is disabled |
| 1970 | style_footer(); |
| 1971 | return; |
| 1972 | } |
| 1973 | search_sql_setup(g.db); |
| 1974 | style_submenu_element("Setup","%R/srchsetup"); |
| 1975 | if( zId!=0 && (id = atoi(zId))>0 ){ |
| 1976 | /* Show information about a single ftsdocs entry */ |
| 1977 | style_header("Information about ftsdoc entry %d", id); |
| 1978 | style_submenu_element("Summary","%R/test-ftsdocs"); |
| 1979 | db_prepare(&q, |
| 1980 | "SELECT type||rid, name, idxed, label, url, datetime(mtime)" |
| 1981 | " FROM ftsdocs WHERE rowid=%d", id |
| 1982 | ); |
| 1983 | if( db_step(&q)==SQLITE_ROW ){ |
| 1984 | const char *zUrl = db_column_text(&q,4); |
| 1985 | const char *zDocId = db_column_text(&q,0); |
| 1986 | char *zName; |
| 1987 | char *z; |
| 1988 | @ <table border=0> |
| 1989 | @ <tr><td align='right'>docid:<td> <td>%d(id) |
| 1990 | @ <tr><td align='right'>id:<td><td>%s(zDocId) |
| 1991 | @ <tr><td align='right'>name:<td><td>%h(db_column_text(&q,1)) |
| 1992 | @ <tr><td align='right'>idxed:<td><td>%d(db_column_int(&q,2)) |
| 1993 | @ <tr><td align='right'>label:<td><td>%h(db_column_text(&q,3)) |
| 1994 | @ <tr><td align='right'>url:<td><td> |
| 1995 | @ <a href='%R%s(zUrl)'>%h(zUrl)</a> |
| 1996 | @ <tr><td align='right'>mtime:<td><td>%s(db_column_text(&q,5)) |
| 1997 | z = db_text(0, "SELECT title FROM ftsidx WHERE docid=%d",id); |
| 1998 | if( z && z[0] ){ |
| 1999 | @ <tr><td align="right">title:<td><td>%h(z) |
| 2000 | fossil_free(z); |
| 2001 | } |
| 2002 | z = db_text(0, "SELECT body FROM ftsidx WHERE docid=%d",id); |
| 2003 | if( z && z[0] ){ |
| 2004 | @ <tr><td align="right" valign="top">body:<td><td>%h(z) |
| 2005 | fossil_free(z); |
| 2006 | } |
| 2007 | @ </table> |
| 2008 | zName = mprintf("Indexed '%c' docs",zDocId[0]); |
| 2009 | style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zDocId[0]); |
| 2010 | zName = mprintf("Unindexed '%c' docs",zDocId[0]); |
| 2011 | style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zDocId[0]); |
| 2012 | } |
| 2013 | db_finalize(&q); |
| 2014 | style_footer(); |
| 2015 | return; |
| 2016 | } |
| 2017 | if( zType!=0 && zType[0]!=0 && zType[1]==0 && |
| 2018 | zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0 |
| 2019 | ){ |
| 2020 | int ixed = zIdxed[0]=='1'; |
| 2021 | char *zName; |
| 2022 | style_header("List of '%c' documents that are%s indexed", |
| 2023 | zType[0], ixed ? "" : " not"); |
| 2024 | style_submenu_element("Summary","%R/test-ftsdocs"); |
| 2025 | if( ixed==0 ){ |
| 2026 | zName = mprintf("Indexed '%c' docs",zType[0]); |
| 2027 | style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=1",zType[0]); |
| 2028 | }else{ |
| 2029 | zName = mprintf("Unindexed '%c' docs",zType[0]); |
| 2030 | style_submenu_element(zName,"%R/test-ftsdocs?y=%c&ixed=0",zType[0]); |
| 2031 | } |
| 2032 | db_prepare(&q, |
| 2033 | "SELECT rowid, type||rid ||' '|| coalesce(label,'')" |
| 2034 | " FROM ftsdocs WHERE type='%c' AND %s idxed", |
| 2035 | zType[0], ixed ? "" : "NOT" |
| 2036 | ); |
| @@ -1992,29 +2044,46 @@ | |
| 2044 | style_footer(); |
| 2045 | return; |
| 2046 | } |
| 2047 | style_header("Summary of ftsdocs"); |
| 2048 | db_prepare(&q, |
| 2049 | "SELECT type, sum(idxed IS TRUE), sum(idxed IS FALSE), count(*)" |
| 2050 | " FROM ftsdocs" |
| 2051 | " GROUP BY 1 ORDER BY 4 DESC" |
| 2052 | ); |
| 2053 | @ <table border=1 cellpadding=3 cellspacing=0> |
| 2054 | @ <thead> |
| 2055 | @ <tr><th>Type<th>Indexed<th>Unindexed<th>Total |
| 2056 | @ </thead> |
| 2057 | @ <tbody> |
| 2058 | while( db_step(&q)==SQLITE_ROW ){ |
| 2059 | const char *zType = db_column_text(&q,0); |
| 2060 | int nIndexed = db_column_int(&q, 1); |
| 2061 | int nUnindexed = db_column_int(&q, 2); |
| 2062 | int nTotal = db_column_int(&q, 3); |
| 2063 | @ <tr><td>%h(zType) |
| 2064 | if( nIndexed>0 ){ |
| 2065 | @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=1'>\ |
| 2066 | @ %d(nIndexed)</a> |
| 2067 | }else{ |
| 2068 | @ <td align="right">0 |
| 2069 | } |
| 2070 | if( nUnindexed>0 ){ |
| 2071 | @ <td align="right"><a href='%R/test-ftsdocs?y=%s(zType)&ixed=0'>\ |
| 2072 | @ %d(nUnindexed)</a> |
| 2073 | }else{ |
| 2074 | @ <td align="right">0 |
| 2075 | } |
| 2076 | @ <td align="right">%d(nTotal) |
| 2077 | @ </tr> |
| 2078 | cnt1 += nIndexed; |
| 2079 | cnt2 += nUnindexed; |
| 2080 | cnt3 += nTotal; |
| 2081 | } |
| 2082 | db_finalize(&q); |
| 2083 | @ </tbody><tfooter> |
| 2084 | @ <tr><th>Total<th align="right">%d(cnt1)<th align="right">%d(cnt2) |
| 2085 | @ <th align="right">%d(cnt3) |
| 2086 | @ </tfooter> |
| 2087 | @ </table> |
| 2088 | style_footer(); |
| 2089 | } |
| 2090 |
+1
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -1640,10 +1640,11 @@ | ||
| 1640 | 1640 | @ <p>Currently using an SQLite FTS4 search index. This makes search |
| 1641 | 1641 | @ run faster, especially on large repositories, but takes up space.</p> |
| 1642 | 1642 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1643 | 1643 | @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index"> |
| 1644 | 1644 | @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index"> |
| 1645 | + style_submenu_element("FTS Index Debugging","%R/test-ftsdocs"); | |
| 1645 | 1646 | }else{ |
| 1646 | 1647 | @ <p>The SQLite FTS4 search index is disabled. All searching will be |
| 1647 | 1648 | @ a full-text scan. This usually works fine, but can be slow for |
| 1648 | 1649 | @ larger repositories.</p> |
| 1649 | 1650 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1650 | 1651 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1640,10 +1640,11 @@ | |
| 1640 | @ <p>Currently using an SQLite FTS4 search index. This makes search |
| 1641 | @ run faster, especially on large repositories, but takes up space.</p> |
| 1642 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1643 | @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index"> |
| 1644 | @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index"> |
| 1645 | }else{ |
| 1646 | @ <p>The SQLite FTS4 search index is disabled. All searching will be |
| 1647 | @ a full-text scan. This usually works fine, but can be slow for |
| 1648 | @ larger repositories.</p> |
| 1649 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1650 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1640,10 +1640,11 @@ | |
| 1640 | @ <p>Currently using an SQLite FTS4 search index. This makes search |
| 1641 | @ run faster, especially on large repositories, but takes up space.</p> |
| 1642 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1643 | @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index"> |
| 1644 | @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index"> |
| 1645 | style_submenu_element("FTS Index Debugging","%R/test-ftsdocs"); |
| 1646 | }else{ |
| 1647 | @ <p>The SQLite FTS4 search index is disabled. All searching will be |
| 1648 | @ a full-text scan. This usually works fine, but can be slow for |
| 1649 | @ larger repositories.</p> |
| 1650 | onoff_attribute("Use Porter Stemmer","search-stemmer","ss",0,0); |
| 1651 |
+11
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -91,10 +91,11 @@ | ||
| 91 | 91 | */ |
| 92 | 92 | static int needHrefJs = 0; /* href.js */ |
| 93 | 93 | static int needSortJs = 0; /* sorttable.js */ |
| 94 | 94 | static int needGraphJs = 0; /* graph.js */ |
| 95 | 95 | static int needCopyBtnJs = 0; /* copybtn.js */ |
| 96 | +static int needAccordionJs = 0; /* accordion.js */ | |
| 96 | 97 | |
| 97 | 98 | /* |
| 98 | 99 | ** Extra JS added to the end of the file. |
| 99 | 100 | */ |
| 100 | 101 | static Blob blobOnLoad = BLOB_INITIALIZER; |
| @@ -680,10 +681,17 @@ | ||
| 680 | 681 | ** Indicate that the table-sorting javascript is needed. |
| 681 | 682 | */ |
| 682 | 683 | void style_table_sorter(void){ |
| 683 | 684 | needSortJs = 1; |
| 684 | 685 | } |
| 686 | + | |
| 687 | +/* | |
| 688 | +** Indicate that the accordion javascript is needed. | |
| 689 | +*/ | |
| 690 | +void style_accordion(void){ | |
| 691 | + needAccordionJs = 1; | |
| 692 | +} | |
| 685 | 693 | |
| 686 | 694 | /* |
| 687 | 695 | ** Indicate that the timeline graph javascript is needed. |
| 688 | 696 | */ |
| 689 | 697 | void style_graph_generator(void){ |
| @@ -750,10 +758,13 @@ | ||
| 750 | 758 | cgi_append_content(builtin_text("graph.js"),-1); |
| 751 | 759 | } |
| 752 | 760 | if( needCopyBtnJs ){ |
| 753 | 761 | cgi_append_content(builtin_text("copybtn.js"),-1); |
| 754 | 762 | } |
| 763 | + if( needAccordionJs ){ | |
| 764 | + cgi_append_content(builtin_text("accordion.js"),-1); | |
| 765 | + } | |
| 755 | 766 | for(i=0; i<nJsToLoad; i++){ |
| 756 | 767 | cgi_append_content(builtin_text(azJsToLoad[i]),-1); |
| 757 | 768 | } |
| 758 | 769 | if( blob_size(&blobOnLoad)>0 ){ |
| 759 | 770 | @ window.onload = function(){ |
| 760 | 771 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -91,10 +91,11 @@ | |
| 91 | */ |
| 92 | static int needHrefJs = 0; /* href.js */ |
| 93 | static int needSortJs = 0; /* sorttable.js */ |
| 94 | static int needGraphJs = 0; /* graph.js */ |
| 95 | static int needCopyBtnJs = 0; /* copybtn.js */ |
| 96 | |
| 97 | /* |
| 98 | ** Extra JS added to the end of the file. |
| 99 | */ |
| 100 | static Blob blobOnLoad = BLOB_INITIALIZER; |
| @@ -680,10 +681,17 @@ | |
| 680 | ** Indicate that the table-sorting javascript is needed. |
| 681 | */ |
| 682 | void style_table_sorter(void){ |
| 683 | needSortJs = 1; |
| 684 | } |
| 685 | |
| 686 | /* |
| 687 | ** Indicate that the timeline graph javascript is needed. |
| 688 | */ |
| 689 | void style_graph_generator(void){ |
| @@ -750,10 +758,13 @@ | |
| 750 | cgi_append_content(builtin_text("graph.js"),-1); |
| 751 | } |
| 752 | if( needCopyBtnJs ){ |
| 753 | cgi_append_content(builtin_text("copybtn.js"),-1); |
| 754 | } |
| 755 | for(i=0; i<nJsToLoad; i++){ |
| 756 | cgi_append_content(builtin_text(azJsToLoad[i]),-1); |
| 757 | } |
| 758 | if( blob_size(&blobOnLoad)>0 ){ |
| 759 | @ window.onload = function(){ |
| 760 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -91,10 +91,11 @@ | |
| 91 | */ |
| 92 | static int needHrefJs = 0; /* href.js */ |
| 93 | static int needSortJs = 0; /* sorttable.js */ |
| 94 | static int needGraphJs = 0; /* graph.js */ |
| 95 | static int needCopyBtnJs = 0; /* copybtn.js */ |
| 96 | static int needAccordionJs = 0; /* accordion.js */ |
| 97 | |
| 98 | /* |
| 99 | ** Extra JS added to the end of the file. |
| 100 | */ |
| 101 | static Blob blobOnLoad = BLOB_INITIALIZER; |
| @@ -680,10 +681,17 @@ | |
| 681 | ** Indicate that the table-sorting javascript is needed. |
| 682 | */ |
| 683 | void style_table_sorter(void){ |
| 684 | needSortJs = 1; |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | ** Indicate that the accordion javascript is needed. |
| 689 | */ |
| 690 | void style_accordion(void){ |
| 691 | needAccordionJs = 1; |
| 692 | } |
| 693 | |
| 694 | /* |
| 695 | ** Indicate that the timeline graph javascript is needed. |
| 696 | */ |
| 697 | void style_graph_generator(void){ |
| @@ -750,10 +758,13 @@ | |
| 758 | cgi_append_content(builtin_text("graph.js"),-1); |
| 759 | } |
| 760 | if( needCopyBtnJs ){ |
| 761 | cgi_append_content(builtin_text("copybtn.js"),-1); |
| 762 | } |
| 763 | if( needAccordionJs ){ |
| 764 | cgi_append_content(builtin_text("accordion.js"),-1); |
| 765 | } |
| 766 | for(i=0; i<nJsToLoad; i++){ |
| 767 | cgi_append_content(builtin_text(azJsToLoad[i]),-1); |
| 768 | } |
| 769 | if( blob_size(&blobOnLoad)>0 ){ |
| 770 | @ window.onload = function(){ |
| 771 |
+8
-6
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -798,11 +798,11 @@ | ||
| 798 | 798 | if( pPost ){ |
| 799 | 799 | const char *zClass = "forumTimeline"; |
| 800 | 800 | if( forum_rid_has_been_edited(rid) ){ |
| 801 | 801 | zClass = "forumTimeline forumObs"; |
| 802 | 802 | } |
| 803 | - forum_render(0, pPost->zMimetype, pPost->zWiki, zClass); | |
| 803 | + forum_render(0, pPost->zMimetype, pPost->zWiki, zClass, 1); | |
| 804 | 804 | manifest_destroy(pPost); |
| 805 | 805 | } |
| 806 | 806 | } |
| 807 | 807 | } |
| 808 | 808 | if( suppressCnt ){ |
| @@ -1113,15 +1113,17 @@ | ||
| 1113 | 1113 | if( fossil_isdate(z) ){ |
| 1114 | 1114 | mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z); |
| 1115 | 1115 | if( mtime>0.0 ) return mtime; |
| 1116 | 1116 | } |
| 1117 | 1117 | zDate = fossil_expand_datetime(z, 1); |
| 1118 | - if( zDate!=0 | |
| 1119 | - && (mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", zDate))>0.0 | |
| 1120 | - ){ | |
| 1121 | - if( pzDisplay ) *pzDisplay = fossil_strdup(zDate); | |
| 1122 | - return mtime; | |
| 1118 | + if( zDate!=0 ){ | |
| 1119 | + mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", | |
| 1120 | + fossil_roundup_date(zDate)); | |
| 1121 | + if( mtime>0.0 ){ | |
| 1122 | + if( pzDisplay ) *pzDisplay = fossil_strdup(zDate); | |
| 1123 | + return mtime; | |
| 1124 | + } | |
| 1123 | 1125 | } |
| 1124 | 1126 | rid = symbolic_name_to_rid(z, "*"); |
| 1125 | 1127 | if( rid ){ |
| 1126 | 1128 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 1127 | 1129 | }else{ |
| 1128 | 1130 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -798,11 +798,11 @@ | |
| 798 | if( pPost ){ |
| 799 | const char *zClass = "forumTimeline"; |
| 800 | if( forum_rid_has_been_edited(rid) ){ |
| 801 | zClass = "forumTimeline forumObs"; |
| 802 | } |
| 803 | forum_render(0, pPost->zMimetype, pPost->zWiki, zClass); |
| 804 | manifest_destroy(pPost); |
| 805 | } |
| 806 | } |
| 807 | } |
| 808 | if( suppressCnt ){ |
| @@ -1113,15 +1113,17 @@ | |
| 1113 | if( fossil_isdate(z) ){ |
| 1114 | mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z); |
| 1115 | if( mtime>0.0 ) return mtime; |
| 1116 | } |
| 1117 | zDate = fossil_expand_datetime(z, 1); |
| 1118 | if( zDate!=0 |
| 1119 | && (mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", zDate))>0.0 |
| 1120 | ){ |
| 1121 | if( pzDisplay ) *pzDisplay = fossil_strdup(zDate); |
| 1122 | return mtime; |
| 1123 | } |
| 1124 | rid = symbolic_name_to_rid(z, "*"); |
| 1125 | if( rid ){ |
| 1126 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 1127 | }else{ |
| 1128 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -798,11 +798,11 @@ | |
| 798 | if( pPost ){ |
| 799 | const char *zClass = "forumTimeline"; |
| 800 | if( forum_rid_has_been_edited(rid) ){ |
| 801 | zClass = "forumTimeline forumObs"; |
| 802 | } |
| 803 | forum_render(0, pPost->zMimetype, pPost->zWiki, zClass, 1); |
| 804 | manifest_destroy(pPost); |
| 805 | } |
| 806 | } |
| 807 | } |
| 808 | if( suppressCnt ){ |
| @@ -1113,15 +1113,17 @@ | |
| 1113 | if( fossil_isdate(z) ){ |
| 1114 | mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z); |
| 1115 | if( mtime>0.0 ) return mtime; |
| 1116 | } |
| 1117 | zDate = fossil_expand_datetime(z, 1); |
| 1118 | if( zDate!=0 ){ |
| 1119 | mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", |
| 1120 | fossil_roundup_date(zDate)); |
| 1121 | if( mtime>0.0 ){ |
| 1122 | if( pzDisplay ) *pzDisplay = fossil_strdup(zDate); |
| 1123 | return mtime; |
| 1124 | } |
| 1125 | } |
| 1126 | rid = symbolic_name_to_rid(z, "*"); |
| 1127 | if( rid ){ |
| 1128 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 1129 | }else{ |
| 1130 |
+2
-1
| --- src/update.c | ||
| +++ src/update.c | ||
| @@ -688,10 +688,11 @@ | ||
| 688 | 688 | }else if( !g.localOpen ){ |
| 689 | 689 | vid = name_to_typed_rid(db_get("main-branch", 0), "ci"); |
| 690 | 690 | }else{ |
| 691 | 691 | vid = db_lget_int("checkout", 0); |
| 692 | 692 | if( !is_a_version(vid) ){ |
| 693 | + if( vid==0 ) return 0; | |
| 693 | 694 | zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); |
| 694 | 695 | if( zRevision ){ |
| 695 | 696 | fossil_fatal("checkout artifact is not a check-in: %s", zRevision); |
| 696 | 697 | }else{ |
| 697 | 698 | fossil_fatal("invalid checkout artifact ID: %d", vid); |
| @@ -858,11 +859,11 @@ | ||
| 858 | 859 | } |
| 859 | 860 | while( db_step(&q)==SQLITE_ROW ){ |
| 860 | 861 | char *zFull; |
| 861 | 862 | zFile = db_column_text(&q, 0); |
| 862 | 863 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 863 | - pRvFile = manifest_file_find(pRvManifest, zFile); | |
| 864 | + pRvFile = pRvManifest? manifest_file_find(pRvManifest, zFile) : 0; | |
| 864 | 865 | if( !pRvFile ){ |
| 865 | 866 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", |
| 866 | 867 | zFile, zFile)==0 ){ |
| 867 | 868 | fossil_print("UNMANAGE %s\n", zFile); |
| 868 | 869 | }else{ |
| 869 | 870 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -688,10 +688,11 @@ | |
| 688 | }else if( !g.localOpen ){ |
| 689 | vid = name_to_typed_rid(db_get("main-branch", 0), "ci"); |
| 690 | }else{ |
| 691 | vid = db_lget_int("checkout", 0); |
| 692 | if( !is_a_version(vid) ){ |
| 693 | zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); |
| 694 | if( zRevision ){ |
| 695 | fossil_fatal("checkout artifact is not a check-in: %s", zRevision); |
| 696 | }else{ |
| 697 | fossil_fatal("invalid checkout artifact ID: %d", vid); |
| @@ -858,11 +859,11 @@ | |
| 858 | } |
| 859 | while( db_step(&q)==SQLITE_ROW ){ |
| 860 | char *zFull; |
| 861 | zFile = db_column_text(&q, 0); |
| 862 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 863 | pRvFile = manifest_file_find(pRvManifest, zFile); |
| 864 | if( !pRvFile ){ |
| 865 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", |
| 866 | zFile, zFile)==0 ){ |
| 867 | fossil_print("UNMANAGE %s\n", zFile); |
| 868 | }else{ |
| 869 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -688,10 +688,11 @@ | |
| 688 | }else if( !g.localOpen ){ |
| 689 | vid = name_to_typed_rid(db_get("main-branch", 0), "ci"); |
| 690 | }else{ |
| 691 | vid = db_lget_int("checkout", 0); |
| 692 | if( !is_a_version(vid) ){ |
| 693 | if( vid==0 ) return 0; |
| 694 | zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); |
| 695 | if( zRevision ){ |
| 696 | fossil_fatal("checkout artifact is not a check-in: %s", zRevision); |
| 697 | }else{ |
| 698 | fossil_fatal("invalid checkout artifact ID: %d", vid); |
| @@ -858,11 +859,11 @@ | |
| 859 | } |
| 860 | while( db_step(&q)==SQLITE_ROW ){ |
| 861 | char *zFull; |
| 862 | zFile = db_column_text(&q, 0); |
| 863 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 864 | pRvFile = pRvManifest? manifest_file_find(pRvManifest, zFile) : 0; |
| 865 | if( !pRvFile ){ |
| 866 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", |
| 867 | zFile, zFile)==0 ){ |
| 868 | fossil_print("UNMANAGE %s\n", zFile); |
| 869 | }else{ |
| 870 |
+11
-8
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1713,15 +1713,15 @@ | ||
| 1713 | 1713 | const char *zPrefix, /* "branch", "tag", or "checkin" */ |
| 1714 | 1714 | const char *zName, /* Name of the object */ |
| 1715 | 1715 | unsigned int mFlags /* Zero or more WIKIASSOC_* flags */ |
| 1716 | 1716 | ){ |
| 1717 | 1717 | if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){ |
| 1718 | - @ <div class="section">About</div> | |
| 1718 | + @ <div class="section accordion">About</div> | |
| 1719 | 1719 | }else if( zPrefix[0]=='c' ){ /* checkin/... */ |
| 1720 | - @ <div class="section">About checkin %.20h(zName)</div> | |
| 1720 | + @ <div class="section accordion">About checkin %.20h(zName)</div> | |
| 1721 | 1721 | }else{ |
| 1722 | - @ <div class="section">About %s(zPrefix) %h(zName)</div> | |
| 1722 | + @ <div class="section accordion">About %s(zPrefix) %h(zName)</div> | |
| 1723 | 1723 | } |
| 1724 | 1724 | } |
| 1725 | 1725 | |
| 1726 | 1726 | /* |
| 1727 | 1727 | ** Add an "Wiki" button in a submenu that links to the read-wiki page. |
| @@ -1775,39 +1775,42 @@ | ||
| 1775 | 1775 | @ <div class="section">%h(blob_str(&title))</div> |
| 1776 | 1776 | }else{ |
| 1777 | 1777 | wiki_section_label(zPrefix, zName, mFlags); |
| 1778 | 1778 | } |
| 1779 | 1779 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1780 | + @ <div class="accordion_panel"> | |
| 1780 | 1781 | convert_href_and_output(&tail); |
| 1782 | + @ </div> | |
| 1781 | 1783 | blob_reset(&tail); |
| 1782 | 1784 | blob_reset(&title); |
| 1783 | 1785 | blob_reset(&markdown); |
| 1784 | 1786 | }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){ |
| 1785 | 1787 | wiki_section_label(zPrefix, zName, mFlags); |
| 1786 | 1788 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1787 | - @ <pre> | |
| 1789 | + @ <div class="accordion_panel"><pre> | |
| 1788 | 1790 | @ %h(pWiki->zWiki) |
| 1789 | - @ </pre> | |
| 1791 | + @ </pre></div> | |
| 1790 | 1792 | }else{ |
| 1791 | 1793 | Blob tail = BLOB_INITIALIZER; |
| 1792 | 1794 | Blob title = BLOB_INITIALIZER; |
| 1793 | 1795 | Blob wiki; |
| 1794 | 1796 | Blob *pBody; |
| 1795 | 1797 | blob_init(&wiki, pWiki->zWiki, -1); |
| 1796 | 1798 | if( wiki_find_title(&wiki, &title, &tail) ){ |
| 1797 | - @ <div class="section">%h(blob_str(&title))</div> | |
| 1799 | + @ <div class="section accordion">%h(blob_str(&title))</div> | |
| 1798 | 1800 | pBody = &tail; |
| 1799 | 1801 | }else{ |
| 1800 | 1802 | wiki_section_label(zPrefix, zName, mFlags); |
| 1801 | 1803 | pBody = &wiki; |
| 1802 | 1804 | } |
| 1803 | 1805 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1804 | - @ <div class="wiki"> | |
| 1806 | + @ <div class="accordion_panel"><div class="wiki"> | |
| 1805 | 1807 | wiki_convert(pBody, 0, WIKI_BUTTONS); |
| 1806 | - @ </div> | |
| 1808 | + @ </div></div> | |
| 1807 | 1809 | blob_reset(&tail); |
| 1808 | 1810 | blob_reset(&title); |
| 1809 | 1811 | blob_reset(&wiki); |
| 1810 | 1812 | } |
| 1811 | 1813 | manifest_destroy(pWiki); |
| 1814 | + style_accordion(); | |
| 1812 | 1815 | return 1; |
| 1813 | 1816 | } |
| 1814 | 1817 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1713,15 +1713,15 @@ | |
| 1713 | const char *zPrefix, /* "branch", "tag", or "checkin" */ |
| 1714 | const char *zName, /* Name of the object */ |
| 1715 | unsigned int mFlags /* Zero or more WIKIASSOC_* flags */ |
| 1716 | ){ |
| 1717 | if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){ |
| 1718 | @ <div class="section">About</div> |
| 1719 | }else if( zPrefix[0]=='c' ){ /* checkin/... */ |
| 1720 | @ <div class="section">About checkin %.20h(zName)</div> |
| 1721 | }else{ |
| 1722 | @ <div class="section">About %s(zPrefix) %h(zName)</div> |
| 1723 | } |
| 1724 | } |
| 1725 | |
| 1726 | /* |
| 1727 | ** Add an "Wiki" button in a submenu that links to the read-wiki page. |
| @@ -1775,39 +1775,42 @@ | |
| 1775 | @ <div class="section">%h(blob_str(&title))</div> |
| 1776 | }else{ |
| 1777 | wiki_section_label(zPrefix, zName, mFlags); |
| 1778 | } |
| 1779 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1780 | convert_href_and_output(&tail); |
| 1781 | blob_reset(&tail); |
| 1782 | blob_reset(&title); |
| 1783 | blob_reset(&markdown); |
| 1784 | }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){ |
| 1785 | wiki_section_label(zPrefix, zName, mFlags); |
| 1786 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1787 | @ <pre> |
| 1788 | @ %h(pWiki->zWiki) |
| 1789 | @ </pre> |
| 1790 | }else{ |
| 1791 | Blob tail = BLOB_INITIALIZER; |
| 1792 | Blob title = BLOB_INITIALIZER; |
| 1793 | Blob wiki; |
| 1794 | Blob *pBody; |
| 1795 | blob_init(&wiki, pWiki->zWiki, -1); |
| 1796 | if( wiki_find_title(&wiki, &title, &tail) ){ |
| 1797 | @ <div class="section">%h(blob_str(&title))</div> |
| 1798 | pBody = &tail; |
| 1799 | }else{ |
| 1800 | wiki_section_label(zPrefix, zName, mFlags); |
| 1801 | pBody = &wiki; |
| 1802 | } |
| 1803 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1804 | @ <div class="wiki"> |
| 1805 | wiki_convert(pBody, 0, WIKI_BUTTONS); |
| 1806 | @ </div> |
| 1807 | blob_reset(&tail); |
| 1808 | blob_reset(&title); |
| 1809 | blob_reset(&wiki); |
| 1810 | } |
| 1811 | manifest_destroy(pWiki); |
| 1812 | return 1; |
| 1813 | } |
| 1814 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1713,15 +1713,15 @@ | |
| 1713 | const char *zPrefix, /* "branch", "tag", or "checkin" */ |
| 1714 | const char *zName, /* Name of the object */ |
| 1715 | unsigned int mFlags /* Zero or more WIKIASSOC_* flags */ |
| 1716 | ){ |
| 1717 | if( (mFlags & WIKIASSOC_FULL_TITLE)==0 ){ |
| 1718 | @ <div class="section accordion">About</div> |
| 1719 | }else if( zPrefix[0]=='c' ){ /* checkin/... */ |
| 1720 | @ <div class="section accordion">About checkin %.20h(zName)</div> |
| 1721 | }else{ |
| 1722 | @ <div class="section accordion">About %s(zPrefix) %h(zName)</div> |
| 1723 | } |
| 1724 | } |
| 1725 | |
| 1726 | /* |
| 1727 | ** Add an "Wiki" button in a submenu that links to the read-wiki page. |
| @@ -1775,39 +1775,42 @@ | |
| 1775 | @ <div class="section">%h(blob_str(&title))</div> |
| 1776 | }else{ |
| 1777 | wiki_section_label(zPrefix, zName, mFlags); |
| 1778 | } |
| 1779 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1780 | @ <div class="accordion_panel"> |
| 1781 | convert_href_and_output(&tail); |
| 1782 | @ </div> |
| 1783 | blob_reset(&tail); |
| 1784 | blob_reset(&title); |
| 1785 | blob_reset(&markdown); |
| 1786 | }else if( fossil_strcmp(pWiki->zMimetype, "text/plain")==0 ){ |
| 1787 | wiki_section_label(zPrefix, zName, mFlags); |
| 1788 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1789 | @ <div class="accordion_panel"><pre> |
| 1790 | @ %h(pWiki->zWiki) |
| 1791 | @ </pre></div> |
| 1792 | }else{ |
| 1793 | Blob tail = BLOB_INITIALIZER; |
| 1794 | Blob title = BLOB_INITIALIZER; |
| 1795 | Blob wiki; |
| 1796 | Blob *pBody; |
| 1797 | blob_init(&wiki, pWiki->zWiki, -1); |
| 1798 | if( wiki_find_title(&wiki, &title, &tail) ){ |
| 1799 | @ <div class="section accordion">%h(blob_str(&title))</div> |
| 1800 | pBody = &tail; |
| 1801 | }else{ |
| 1802 | wiki_section_label(zPrefix, zName, mFlags); |
| 1803 | pBody = &wiki; |
| 1804 | } |
| 1805 | wiki_submenu_to_read_wiki(zPrefix, zName, mFlags); |
| 1806 | @ <div class="accordion_panel"><div class="wiki"> |
| 1807 | wiki_convert(pBody, 0, WIKI_BUTTONS); |
| 1808 | @ </div></div> |
| 1809 | blob_reset(&tail); |
| 1810 | blob_reset(&title); |
| 1811 | blob_reset(&wiki); |
| 1812 | } |
| 1813 | manifest_destroy(pWiki); |
| 1814 | style_accordion(); |
| 1815 | return 1; |
| 1816 | } |
| 1817 |
+2
-1
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -174,11 +174,11 @@ | ||
| 174 | 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | 178 | # |
| 179 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e | |
| 179 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f | |
| 180 | 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | 182 | |
| 183 | 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | 184 | # source code directory resides (depending on the value of the macro |
| @@ -633,10 +633,11 @@ | ||
| 633 | 633 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 634 | 634 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 635 | 635 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 636 | 636 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 637 | 637 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 638 | + $(SRCDIR)/accordion.js \ | |
| 638 | 639 | $(SRCDIR)/ci_edit.js \ |
| 639 | 640 | $(SRCDIR)/copybtn.js \ |
| 640 | 641 | $(SRCDIR)/diff.tcl \ |
| 641 | 642 | $(SRCDIR)/forum.js \ |
| 642 | 643 | $(SRCDIR)/graph.js \ |
| 643 | 644 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -174,11 +174,11 @@ | |
| 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | # |
| 179 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e |
| 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | |
| 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | # source code directory resides (depending on the value of the macro |
| @@ -633,10 +633,11 @@ | |
| 633 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 634 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 635 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 636 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 637 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 638 | $(SRCDIR)/ci_edit.js \ |
| 639 | $(SRCDIR)/copybtn.js \ |
| 640 | $(SRCDIR)/diff.tcl \ |
| 641 | $(SRCDIR)/forum.js \ |
| 642 | $(SRCDIR)/graph.js \ |
| 643 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -174,11 +174,11 @@ | |
| 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | # |
| 179 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f |
| 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | |
| 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | # source code directory resides (depending on the value of the macro |
| @@ -633,10 +633,11 @@ | |
| 633 | $(SRCDIR)/../skins/rounded1/header.txt \ |
| 634 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 635 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 636 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 637 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 638 | $(SRCDIR)/accordion.js \ |
| 639 | $(SRCDIR)/ci_edit.js \ |
| 640 | $(SRCDIR)/copybtn.js \ |
| 641 | $(SRCDIR)/diff.tcl \ |
| 642 | $(SRCDIR)/forum.js \ |
| 643 | $(SRCDIR)/graph.js \ |
| 644 |
+1
-1
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -174,11 +174,11 @@ | ||
| 174 | 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | 178 | # |
| 179 | -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e | |
| 179 | +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f | |
| 180 | 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | 182 | |
| 183 | 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | 184 | # source code directory resides (depending on the value of the macro |
| 185 | 185 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -174,11 +174,11 @@ | |
| 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | # |
| 179 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1e |
| 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | |
| 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | # source code directory resides (depending on the value of the macro |
| 185 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -174,11 +174,11 @@ | |
| 174 | #### The directories where the OpenSSL include and library files are located. |
| 175 | # The recommended usage here is to use the Sysinternals junction tool |
| 176 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 177 | # Fossil source code directory and the target OpenSSL source directory. |
| 178 | # |
| 179 | OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.1f |
| 180 | OPENSSLINCDIR = $(OPENSSLDIR)/include |
| 181 | OPENSSLLIBDIR = $(OPENSSLDIR) |
| 182 | |
| 183 | #### Either the directory where the Tcl library is installed or the Tcl |
| 184 | # source code directory resides (depending on the value of the macro |
| 185 |
+2
-1
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -98,11 +98,11 @@ | ||
| 98 | 98 | !ifndef USE_SEE |
| 99 | 99 | USE_SEE = 0 |
| 100 | 100 | !endif |
| 101 | 101 | |
| 102 | 102 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 103 | -SSLDIR = $(B)\compat\openssl-1.1.1e | |
| 103 | +SSLDIR = $(B)\compat\openssl-1.1.1f | |
| 104 | 104 | SSLINCDIR = $(SSLDIR)\include |
| 105 | 105 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 106 | 106 | SSLLIBDIR = $(SSLDIR) |
| 107 | 107 | !else |
| 108 | 108 | SSLLIBDIR = $(SSLDIR) |
| @@ -540,10 +540,11 @@ | ||
| 540 | 540 | $(SRCDIR)\..\skins\rounded1\header.txt \ |
| 541 | 541 | $(SRCDIR)\..\skins\xekri\css.txt \ |
| 542 | 542 | $(SRCDIR)\..\skins\xekri\details.txt \ |
| 543 | 543 | $(SRCDIR)\..\skins\xekri\footer.txt \ |
| 544 | 544 | $(SRCDIR)\..\skins\xekri\header.txt \ |
| 545 | + $(SRCDIR)\accordion.js \ | |
| 545 | 546 | $(SRCDIR)\ci_edit.js \ |
| 546 | 547 | $(SRCDIR)\copybtn.js \ |
| 547 | 548 | $(SRCDIR)\diff.tcl \ |
| 548 | 549 | $(SRCDIR)\forum.js \ |
| 549 | 550 | $(SRCDIR)\graph.js \ |
| 550 | 551 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -98,11 +98,11 @@ | |
| 98 | !ifndef USE_SEE |
| 99 | USE_SEE = 0 |
| 100 | !endif |
| 101 | |
| 102 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 103 | SSLDIR = $(B)\compat\openssl-1.1.1e |
| 104 | SSLINCDIR = $(SSLDIR)\include |
| 105 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 106 | SSLLIBDIR = $(SSLDIR) |
| 107 | !else |
| 108 | SSLLIBDIR = $(SSLDIR) |
| @@ -540,10 +540,11 @@ | |
| 540 | $(SRCDIR)\..\skins\rounded1\header.txt \ |
| 541 | $(SRCDIR)\..\skins\xekri\css.txt \ |
| 542 | $(SRCDIR)\..\skins\xekri\details.txt \ |
| 543 | $(SRCDIR)\..\skins\xekri\footer.txt \ |
| 544 | $(SRCDIR)\..\skins\xekri\header.txt \ |
| 545 | $(SRCDIR)\ci_edit.js \ |
| 546 | $(SRCDIR)\copybtn.js \ |
| 547 | $(SRCDIR)\diff.tcl \ |
| 548 | $(SRCDIR)\forum.js \ |
| 549 | $(SRCDIR)\graph.js \ |
| 550 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -98,11 +98,11 @@ | |
| 98 | !ifndef USE_SEE |
| 99 | USE_SEE = 0 |
| 100 | !endif |
| 101 | |
| 102 | !if $(FOSSIL_ENABLE_SSL)!=0 |
| 103 | SSLDIR = $(B)\compat\openssl-1.1.1f |
| 104 | SSLINCDIR = $(SSLDIR)\include |
| 105 | !if $(FOSSIL_DYNAMIC_BUILD)!=0 |
| 106 | SSLLIBDIR = $(SSLDIR) |
| 107 | !else |
| 108 | SSLLIBDIR = $(SSLDIR) |
| @@ -540,10 +540,11 @@ | |
| 540 | $(SRCDIR)\..\skins\rounded1\header.txt \ |
| 541 | $(SRCDIR)\..\skins\xekri\css.txt \ |
| 542 | $(SRCDIR)\..\skins\xekri\details.txt \ |
| 543 | $(SRCDIR)\..\skins\xekri\footer.txt \ |
| 544 | $(SRCDIR)\..\skins\xekri\header.txt \ |
| 545 | $(SRCDIR)\accordion.js \ |
| 546 | $(SRCDIR)\ci_edit.js \ |
| 547 | $(SRCDIR)\copybtn.js \ |
| 548 | $(SRCDIR)\diff.tcl \ |
| 549 | $(SRCDIR)\forum.js \ |
| 550 | $(SRCDIR)\graph.js \ |
| 551 |
+1
-1
| --- www/build.wiki | ||
| +++ www/build.wiki | ||
| @@ -161,11 +161,11 @@ | ||
| 161 | 161 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 162 | 162 | first <a href="https://www.openssl.org/source/">download the official |
| 163 | 163 | source code for OpenSSL</a> and extract it to an appropriately named |
| 164 | 164 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 165 | 165 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 166 | -"<b>compat/openssl-1.1.1e</b>"), then make sure that some recent | |
| 166 | +"<b>compat/openssl-1.1.1f</b>"), then make sure that some recent | |
| 167 | 167 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 168 | 168 | and finally run one of the following commands: |
| 169 | 169 | <blockquote><pre> |
| 170 | 170 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 171 | 171 | </pre></blockquote> |
| 172 | 172 | |
| 173 | 173 | ADDED www/css-tricks.md |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -161,11 +161,11 @@ | |
| 161 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 162 | first <a href="https://www.openssl.org/source/">download the official |
| 163 | source code for OpenSSL</a> and extract it to an appropriately named |
| 164 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 165 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 166 | "<b>compat/openssl-1.1.1e</b>"), then make sure that some recent |
| 167 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 168 | and finally run one of the following commands: |
| 169 | <blockquote><pre> |
| 170 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 171 | </pre></blockquote> |
| 172 | |
| 173 | DDED www/css-tricks.md |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -161,11 +161,11 @@ | |
| 161 | the optional <a href="https://www.openssl.org/">OpenSSL</a> support, |
| 162 | first <a href="https://www.openssl.org/source/">download the official |
| 163 | source code for OpenSSL</a> and extract it to an appropriately named |
| 164 | "<b>openssl-X.Y.ZA</b>" subdirectory within the local |
| 165 | [/tree?ci=trunk&name=compat | compat] directory (e.g. |
| 166 | "<b>compat/openssl-1.1.1f</b>"), then make sure that some recent |
| 167 | <a href="http://www.perl.org/">Perl</a> binaries are installed locally, |
| 168 | and finally run one of the following commands: |
| 169 | <blockquote><pre> |
| 170 | nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin |
| 171 | </pre></blockquote> |
| 172 | |
| 173 | DDED www/css-tricks.md |
+35
| --- a/www/css-tricks.md | ||
| +++ b/www/css-tricks.md | ||
| @@ -0,0 +1,35 @@ | ||
| 1 | +# Fossil CSS Tips and Tricks | |
| 2 | + | |
| 3 | +Many Overriding Default Rules | |
| 4 | + | |
| 5 | +One behavior of the skinning system works considerably differently | |
| 6 | +from the cascading nature of CSS: if a skin appliand Tricks | |
| 7 | + | |
| 8 | +Many has a built-in default value, Fossil elides the entire | |
| 9 | +default definition for that rule. i.e., the skin's definition is the | |
| 10 | +only one which is applied, rather than cascading the definition from | |
| 11 | +the default value. | |
| 12 | + | |
| 13 | +For example, if Fossil has a default CSS rule which looks like: | |
| 14 | + | |
| 15 | +```css | |
| 16 | +div.foo { | |
| 17 | + font-size: 120%; | |
| 18 | + margin-left: 1em; | |
| 19 | +} | |
| 20 | +``` | |
| 21 | + | |
| 22 | +And a skin has: | |
| 23 | + | |
| 24 | +```css | |
| 25 | +div.foo {} | |
| 26 | +``` | |
| 27 | + | |
| 28 | +Then Fossil will *not* emit its default rule and the user's copy will | |
| 29 | +become the only definition of that CSS rule. This is different from | |
| 30 | +normal CSS cascading rules, in which the above sequence would result | |
| 31 | +in, effectively, the top set of rules being applied because the second | |
| 32 | +(empty) one does not override anything from the first. | |
| 33 | + | |
| 34 | +If a skin applies a given selector more than once, or imports external | |
| 35 | +style sheets which do, those cascade following CSS's normal rulesr |
| --- a/www/css-tricks.md | |
| +++ b/www/css-tricks.md | |
| @@ -0,0 +1,35 @@ | |
| --- a/www/css-tricks.md | |
| +++ b/www/css-tricks.md | |
| @@ -0,0 +1,35 @@ | |
| 1 | # Fossil CSS Tips and Tricks |
| 2 | |
| 3 | Many Overriding Default Rules |
| 4 | |
| 5 | One behavior of the skinning system works considerably differently |
| 6 | from the cascading nature of CSS: if a skin appliand Tricks |
| 7 | |
| 8 | Many has a built-in default value, Fossil elides the entire |
| 9 | default definition for that rule. i.e., the skin's definition is the |
| 10 | only one which is applied, rather than cascading the definition from |
| 11 | the default value. |
| 12 | |
| 13 | For example, if Fossil has a default CSS rule which looks like: |
| 14 | |
| 15 | ```css |
| 16 | div.foo { |
| 17 | font-size: 120%; |
| 18 | margin-left: 1em; |
| 19 | } |
| 20 | ``` |
| 21 | |
| 22 | And a skin has: |
| 23 | |
| 24 | ```css |
| 25 | div.foo {} |
| 26 | ``` |
| 27 | |
| 28 | Then Fossil will *not* emit its default rule and the user's copy will |
| 29 | become the only definition of that CSS rule. This is different from |
| 30 | normal CSS cascading rules, in which the above sequence would result |
| 31 | in, effectively, the top set of rules being applied because the second |
| 32 | (empty) one does not override anything from the first. |
| 33 | |
| 34 | If a skin applies a given selector more than once, or imports external |
| 35 | style sheets which do, those cascade following CSS's normal rulesr |
+2
-2
| --- www/defcsp.md | ||
| +++ www/defcsp.md | ||
| @@ -319,20 +319,20 @@ | ||
| 319 | 319 | |
| 320 | 320 | The best place to do that is from the [`th1-setup` |
| 321 | 321 | script](./th1-hooks.md), which runs before TH1 processing happens during |
| 322 | 322 | skin processing: |
| 323 | 323 | |
| 324 | - $ fossil set th1-setup "set default_csp {default-src: 'self'}" | |
| 324 | + $ fossil set th1-setup "set default_csp {default-src 'self'}" | |
| 325 | 325 | |
| 326 | 326 | This is the cleanest method, allowing you to set a custom CSP without |
| 327 | 327 | recompiling Fossil or providing a hand-written `<head>` section in the |
| 328 | 328 | Header section of a custom skin. |
| 329 | 329 | |
| 330 | 330 | You can’t remove the CSP entirely with this method, but you can get the |
| 331 | 331 | same effect by telling the browser there are no content restrictions: |
| 332 | 332 | |
| 333 | - $ fossil set th1-setup 'set default_csp {default-src: *}' | |
| 333 | + $ fossil set th1-setup 'set default_csp {default-src *}' | |
| 334 | 334 | |
| 335 | 335 | |
| 336 | 336 | ### <a name="header"></a>Custom Skin Header |
| 337 | 337 | |
| 338 | 338 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 339 | 339 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -319,20 +319,20 @@ | |
| 319 | |
| 320 | The best place to do that is from the [`th1-setup` |
| 321 | script](./th1-hooks.md), which runs before TH1 processing happens during |
| 322 | skin processing: |
| 323 | |
| 324 | $ fossil set th1-setup "set default_csp {default-src: 'self'}" |
| 325 | |
| 326 | This is the cleanest method, allowing you to set a custom CSP without |
| 327 | recompiling Fossil or providing a hand-written `<head>` section in the |
| 328 | Header section of a custom skin. |
| 329 | |
| 330 | You can’t remove the CSP entirely with this method, but you can get the |
| 331 | same effect by telling the browser there are no content restrictions: |
| 332 | |
| 333 | $ fossil set th1-setup 'set default_csp {default-src: *}' |
| 334 | |
| 335 | |
| 336 | ### <a name="header"></a>Custom Skin Header |
| 337 | |
| 338 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 339 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -319,20 +319,20 @@ | |
| 319 | |
| 320 | The best place to do that is from the [`th1-setup` |
| 321 | script](./th1-hooks.md), which runs before TH1 processing happens during |
| 322 | skin processing: |
| 323 | |
| 324 | $ fossil set th1-setup "set default_csp {default-src 'self'}" |
| 325 | |
| 326 | This is the cleanest method, allowing you to set a custom CSP without |
| 327 | recompiling Fossil or providing a hand-written `<head>` section in the |
| 328 | Header section of a custom skin. |
| 329 | |
| 330 | You can’t remove the CSP entirely with this method, but you can get the |
| 331 | same effect by telling the browser there are no content restrictions: |
| 332 | |
| 333 | $ fossil set th1-setup 'set default_csp {default-src *}' |
| 334 | |
| 335 | |
| 336 | ### <a name="header"></a>Custom Skin Header |
| 337 | |
| 338 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 339 |
+1
| --- www/mkindex.tcl | ||
| +++ www/mkindex.tcl | ||
| @@ -28,10 +28,11 @@ | ||
| 28 | 28 | checkin.wiki {Check-in Checklist} |
| 29 | 29 | childprojects.wiki {Child Projects} |
| 30 | 30 | copyright-release.html {Contributor License Agreement} |
| 31 | 31 | concepts.wiki {Fossil Core Concepts} |
| 32 | 32 | contribute.wiki {Contributing Code or Documentation To The Fossil Project} |
| 33 | + css-tricks.md {Fossil CSS Tips and Tricks} | |
| 33 | 34 | customgraph.md {Theming: Customizing the Timeline Graph} |
| 34 | 35 | customskin.md {Theming: Customizing The Appearance of Web Pages} |
| 35 | 36 | customskin.md {Custom Skins} |
| 36 | 37 | custom_ticket.wiki {Customizing The Ticket System} |
| 37 | 38 | defcsp.md {The Default Content Security Policy} |
| 38 | 39 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -28,10 +28,11 @@ | |
| 28 | checkin.wiki {Check-in Checklist} |
| 29 | childprojects.wiki {Child Projects} |
| 30 | copyright-release.html {Contributor License Agreement} |
| 31 | concepts.wiki {Fossil Core Concepts} |
| 32 | contribute.wiki {Contributing Code or Documentation To The Fossil Project} |
| 33 | customgraph.md {Theming: Customizing the Timeline Graph} |
| 34 | customskin.md {Theming: Customizing The Appearance of Web Pages} |
| 35 | customskin.md {Custom Skins} |
| 36 | custom_ticket.wiki {Customizing The Ticket System} |
| 37 | defcsp.md {The Default Content Security Policy} |
| 38 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -28,10 +28,11 @@ | |
| 28 | checkin.wiki {Check-in Checklist} |
| 29 | childprojects.wiki {Child Projects} |
| 30 | copyright-release.html {Contributor License Agreement} |
| 31 | concepts.wiki {Fossil Core Concepts} |
| 32 | contribute.wiki {Contributing Code or Documentation To The Fossil Project} |
| 33 | css-tricks.md {Fossil CSS Tips and Tricks} |
| 34 | customgraph.md {Theming: Customizing the Timeline Graph} |
| 35 | customskin.md {Theming: Customizing The Appearance of Web Pages} |
| 36 | customskin.md {Custom Skins} |
| 37 | custom_ticket.wiki {Customizing The Ticket System} |
| 38 | defcsp.md {The Default Content Security Policy} |
| 39 |
| --- www/permutedindex.html | ||
| +++ www/permutedindex.html | ||
| @@ -76,10 +76,11 @@ | ||
| 76 | 76 | <li><a href="whyusefossil.wiki">Control — Benefits Of Version</a></li> |
| 77 | 77 | <li><a href="concepts.wiki">Core Concepts — Fossil</a></li> |
| 78 | 78 | <li><a href="newrepo.wiki">Create A New Fossil Repository — How To</a></li> |
| 79 | 79 | <li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li> |
| 80 | 80 | <li><a href="qandc.wiki">Criticisms — Questions And</a></li> |
| 81 | +<li><a href="css-tricks.md">CSS Tips and Tricks — Fossil</a></li> | |
| 81 | 82 | <li><a href="customskin.md"><b>Custom Skins</b></a></li> |
| 82 | 83 | <li><a href="customskin.md">Customizing The Appearance of Web Pages — Theming:</a></li> |
| 83 | 84 | <li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li> |
| 84 | 85 | <li><a href="customgraph.md">Customizing the Timeline Graph — Theming:</a></li> |
| 85 | 86 | <li><a href="tech_overview.wiki">Databases Used By Fossil — SQLite</a></li> |
| @@ -121,10 +122,11 @@ | ||
| 121 | 122 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 122 | 123 | <li><a href="forum.wiki">Forums — Fossil</a></li> |
| 123 | 124 | <li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li> |
| 124 | 125 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 125 | 126 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 127 | +<li><a href="css-tricks.md"><b>Fossil CSS Tips and Tricks</b></a></li> | |
| 126 | 128 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 127 | 129 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 128 | 130 | <li><a href="hacker-howto.wiki"><b>Fossil Developers Guide</b></a></li> |
| 129 | 131 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 130 | 132 | <li><a href="forum.wiki"><b>Fossil Forums</b></a></li> |
| @@ -284,12 +286,14 @@ | ||
| 284 | 286 | <li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li> |
| 285 | 287 | <li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li> |
| 286 | 288 | <li><a href="custom_ticket.wiki">Ticket System — Customizing The</a></li> |
| 287 | 289 | <li><a href="tickets.wiki">Ticket System — The Fossil</a></li> |
| 288 | 290 | <li><a href="customgraph.md">Timeline Graph — Theming: Customizing the</a></li> |
| 291 | +<li><a href="css-tricks.md">Tips and Tricks — Fossil CSS</a></li> | |
| 289 | 292 | <li><a href="hints.wiki">Tips And Usage Hints — Fossil</a></li> |
| 290 | 293 | <li><a href="bugtheory.wiki">Tracking In Fossil — Bug</a></li> |
| 294 | +<li><a href="css-tricks.md">Tricks — Fossil CSS Tips and</a></li> | |
| 291 | 295 | <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li> |
| 292 | 296 | <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li> |
| 293 | 297 | <li><a href="hints.wiki">Usage Hints — Fossil Tips And</a></li> |
| 294 | 298 | <li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li> |
| 295 | 299 | <li><a href="fiveminutes.wiki">User — Up and Running in 5 Minutes as a Single</a></li> |
| 296 | 300 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -76,10 +76,11 @@ | |
| 76 | <li><a href="whyusefossil.wiki">Control — Benefits Of Version</a></li> |
| 77 | <li><a href="concepts.wiki">Core Concepts — Fossil</a></li> |
| 78 | <li><a href="newrepo.wiki">Create A New Fossil Repository — How To</a></li> |
| 79 | <li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li> |
| 80 | <li><a href="qandc.wiki">Criticisms — Questions And</a></li> |
| 81 | <li><a href="customskin.md"><b>Custom Skins</b></a></li> |
| 82 | <li><a href="customskin.md">Customizing The Appearance of Web Pages — Theming:</a></li> |
| 83 | <li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li> |
| 84 | <li><a href="customgraph.md">Customizing the Timeline Graph — Theming:</a></li> |
| 85 | <li><a href="tech_overview.wiki">Databases Used By Fossil — SQLite</a></li> |
| @@ -121,10 +122,11 @@ | |
| 121 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 122 | <li><a href="forum.wiki">Forums — Fossil</a></li> |
| 123 | <li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li> |
| 124 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 125 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 126 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 127 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 128 | <li><a href="hacker-howto.wiki"><b>Fossil Developers Guide</b></a></li> |
| 129 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 130 | <li><a href="forum.wiki"><b>Fossil Forums</b></a></li> |
| @@ -284,12 +286,14 @@ | |
| 284 | <li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li> |
| 285 | <li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li> |
| 286 | <li><a href="custom_ticket.wiki">Ticket System — Customizing The</a></li> |
| 287 | <li><a href="tickets.wiki">Ticket System — The Fossil</a></li> |
| 288 | <li><a href="customgraph.md">Timeline Graph — Theming: Customizing the</a></li> |
| 289 | <li><a href="hints.wiki">Tips And Usage Hints — Fossil</a></li> |
| 290 | <li><a href="bugtheory.wiki">Tracking In Fossil — Bug</a></li> |
| 291 | <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li> |
| 292 | <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li> |
| 293 | <li><a href="hints.wiki">Usage Hints — Fossil Tips And</a></li> |
| 294 | <li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li> |
| 295 | <li><a href="fiveminutes.wiki">User — Up and Running in 5 Minutes as a Single</a></li> |
| 296 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -76,10 +76,11 @@ | |
| 76 | <li><a href="whyusefossil.wiki">Control — Benefits Of Version</a></li> |
| 77 | <li><a href="concepts.wiki">Core Concepts — Fossil</a></li> |
| 78 | <li><a href="newrepo.wiki">Create A New Fossil Repository — How To</a></li> |
| 79 | <li><a href="private.wiki"><b>Creating, Syncing, and Deleting Private Branches</b></a></li> |
| 80 | <li><a href="qandc.wiki">Criticisms — Questions And</a></li> |
| 81 | <li><a href="css-tricks.md">CSS Tips and Tricks — Fossil</a></li> |
| 82 | <li><a href="customskin.md"><b>Custom Skins</b></a></li> |
| 83 | <li><a href="customskin.md">Customizing The Appearance of Web Pages — Theming:</a></li> |
| 84 | <li><a href="custom_ticket.wiki"><b>Customizing The Ticket System</b></a></li> |
| 85 | <li><a href="customgraph.md">Customizing the Timeline Graph — Theming:</a></li> |
| 86 | <li><a href="tech_overview.wiki">Databases Used By Fossil — SQLite</a></li> |
| @@ -121,10 +122,11 @@ | |
| 122 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 123 | <li><a href="forum.wiki">Forums — Fossil</a></li> |
| 124 | <li><a href="blockchain.md"><b>Fossil As Blockchain</b></a></li> |
| 125 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 126 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 127 | <li><a href="css-tricks.md"><b>Fossil CSS Tips and Tricks</b></a></li> |
| 128 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 129 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 130 | <li><a href="hacker-howto.wiki"><b>Fossil Developers Guide</b></a></li> |
| 131 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 132 | <li><a href="forum.wiki"><b>Fossil Forums</b></a></li> |
| @@ -284,12 +286,14 @@ | |
| 286 | <li><a href="customgraph.md"><b>Theming: Customizing the Timeline Graph</b></a></li> |
| 287 | <li><a href="theory1.wiki"><b>Thoughts On The Design Of The Fossil DVCS</b></a></li> |
| 288 | <li><a href="custom_ticket.wiki">Ticket System — Customizing The</a></li> |
| 289 | <li><a href="tickets.wiki">Ticket System — The Fossil</a></li> |
| 290 | <li><a href="customgraph.md">Timeline Graph — Theming: Customizing the</a></li> |
| 291 | <li><a href="css-tricks.md">Tips and Tricks — Fossil CSS</a></li> |
| 292 | <li><a href="hints.wiki">Tips And Usage Hints — Fossil</a></li> |
| 293 | <li><a href="bugtheory.wiki">Tracking In Fossil — Bug</a></li> |
| 294 | <li><a href="css-tricks.md">Tricks — Fossil CSS Tips and</a></li> |
| 295 | <li><a href="unvers.wiki"><b>Unversioned Files</b></a></li> |
| 296 | <li><a href="fiveminutes.wiki"><b>Up and Running in 5 Minutes as a Single User</b></a></li> |
| 297 | <li><a href="hints.wiki">Usage Hints — Fossil Tips And</a></li> |
| 298 | <li><a href="javascript.md"><b>Use of JavaScript in Fossil</b></a></li> |
| 299 | <li><a href="fiveminutes.wiki">User — Up and Running in 5 Minutes as a Single</a></li> |
| 300 |