Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch wcontent-subsets Excluding Merge-Ins
This is equivalent to a diff from 96bf76a4b1 to 76844c35fc
2022-05-14
| ||
20:52 | Handle a possible existence of the additional checkbox introduced in [29a24941ed9bf4]. ... (Leaf check-in: 76844c35fc user: george tags: wcontent-subsets) | |
2022-02-10
| ||
15:50 | Update the built-in SQLite to the latest 3.38.0 beta that includes the performance enhancements on the datetime() function. ... (check-in: 740d655e55 user: drh tags: trunk) | |
00:29 | Merge from trunk ... (Leaf check-in: 2b5f9b211c user: george tags: search-terms-highlighting) | |
00:22 | Merge from trunk ... (Leaf check-in: a961a67ba7 user: george tags: rptview-submenu-paralink) | |
00:17 | Merge from trunk ... (check-in: 88ff4e5dea user: george tags: wcontent-subsets) | |
00:12 | Merge from trunk ... (Leaf check-in: 9b76469b38 user: george tags: th1-doc-vars) | |
00:05 | Remove unused local variable from cgi_parse_POST_JSON() to fix a compiler warning. ... (check-in: 96bf76a4b1 user: george tags: trunk) | |
2022-02-09
| ||
20:23 | Cherrypicked [92221aaa192e82] and [7283ae6e120c10] on behalf of George. ... (check-in: f902814db6 user: stephan tags: trunk) | |
Changes to src/db.c.
︙ | ︙ | |||
4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 | /* ** SETTING: large-file-size width=10 default=200000000 ** Fossil considers any file whose size is greater than this value ** to be a "large file". Fossil might issue warnings if you try to ** "add" or "commit" a "large file". Set this value to 0 or less ** to disable all such warnings. */ /* ** Look up a control setting by its name. Return a pointer to the Setting ** object, or NULL if there is no such setting. ** ** If allowPrefix is true, then the Setting returned is the first one for ** which zName is a prefix of the Setting name. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 | /* ** SETTING: large-file-size width=10 default=200000000 ** Fossil considers any file whose size is greater than this value ** to be a "large file". Fossil might issue warnings if you try to ** "add" or "commit" a "large file". Set this value to 0 or less ** to disable all such warnings. */ /* ** SETTING: wiki-classes width=40 block-text ** Defines classes for wiki pages that are recognized by the list ** of available wiki pages (displayed by /wcontent web page). ** ** Each line defines a single rule for a class using a triplet: ** Visibility Label Pattern ** ** Visibility is one of the following letters: ** ** s show on load, may be toggled afterwards ** h hide on load, may be toggled afterwards ** d hide permanently, checkbox disabled ** x exclude completely, no control in the submenu ** ** Label is a spaces-free name of the class shown in the submenu. ** This very same string is used as a value for HTML's class="" ** atributes on the corresponding rows (thus beware of mangling). ** ** Pattern is a GLOB pattern against which wiki page names are ** matched to distinguish a class. Case-sensitive pattern matching ** is performed if the Visibility is specified by a lowercase letter, ** otherwise pattern matching is case-insensitive (in which case ** the syntax of SQLite's LIKE operator applies). ** Pattern that consists of just a single * is a special case for ** catching all wiki pages that do not fall into any other class ** (this fallback does not depend on the case of the Visibility letter). ** ** If several consequtive lines share the same Label then this defines ** a single class that spans accross several patterns. In that case ** all Visibilities must also be equal (modulus upper/lower cases). ** ** Patterns are matched in the order of their appearance in the list. ** If a repository manages thousands of wiki pages and the /wcontent ** page is requested very frequently then server's CPU load may become ** a concern. In that case an administrator is advised to rearrange ** classes in the list in such a way that more patterns are matched ** earlier. In all cases it is advised to keep a special "catch-all" ** class in the bottom of the list. */ /* ** Look up a control setting by its name. Return a pointer to the Setting ** object, or NULL if there is no such setting. ** ** If allowPrefix is true, then the Setting returned is the first one for ** which zName is a prefix of the Setting name. |
︙ | ︙ |
Added src/fossil.page.wcontent.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* This script implements interactivity of checkboxes that * toggle visibilitiy of user-defined classes of wikipage. * * For the sake of compatibility with ascetic browsers the code tries * to avoid modern API and ECMAScript constructs. This makes it less * readable and may be reconsidered in the future. */ window.addEventListener( 'load', function() { var tbody = document.querySelector( "body.wiki div.content table.sortable > tbody"); var prc = document.getElementById("page-reload-canary"); if( !tbody || !prc ) return; var reloading = prc.checked; // console.log("Reloading:",reloading); var onChange = function(event){ var display = event.target.checked ? "" : "none"; var rows = event.target.matchingRows; for(var i=0; i<rows.length; i++) rows[i].style.display = display; } var checkboxes = []; document.querySelectorAll( "body.wiki .submenu > label.submenuckbox > input") .forEach(function(cbx){ checkboxes.push(cbx); }); for(var j=0; j<checkboxes.length; j++){ var cbx = checkboxes[j]; // see also https://caniuse.com/mdn-css_selectors_attribute var attr = cbx.getAttribute("data-ctrl"); if( 'undefined' == typeof attr || !attr ) continue; var ctrl = attr.toString(); var cname = cbx.parentElement.innerText.toString(); var hidden = ( ctrl == 'h' || ctrl == 'd' ); if( reloading ) hidden = !cbx.checked; else cbx.checked = !hidden; cbx.matchingRows = []; tbody.querySelectorAll("tr."+cname).forEach(function (tr){ tr.style.display = ( hidden ? "none" : "" ); cbx.matchingRows.push(tr); }); cbx.addEventListener("change", onChange ); // console.log( cbx.matchingRows.length, cname, ctrl ); } prc.checked = true; }); // window.addEventListener( 'load' ... |
Changes to src/main.mk.
︙ | ︙ | |||
229 230 231 232 233 234 235 236 237 238 239 240 241 242 | $(SRCDIR)/fossil.fetch.js \ $(SRCDIR)/fossil.numbered-lines.js \ $(SRCDIR)/fossil.page.brlist.js \ $(SRCDIR)/fossil.page.chat.js \ $(SRCDIR)/fossil.page.fileedit.js \ $(SRCDIR)/fossil.page.forumpost.js \ $(SRCDIR)/fossil.page.pikchrshow.js \ $(SRCDIR)/fossil.page.whistory.js \ $(SRCDIR)/fossil.page.wikiedit.js \ $(SRCDIR)/fossil.pikchr.js \ $(SRCDIR)/fossil.popupwidget.js \ $(SRCDIR)/fossil.storage.js \ $(SRCDIR)/fossil.tabs.js \ $(SRCDIR)/fossil.wikiedit-wysiwyg.js \ | > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | $(SRCDIR)/fossil.fetch.js \ $(SRCDIR)/fossil.numbered-lines.js \ $(SRCDIR)/fossil.page.brlist.js \ $(SRCDIR)/fossil.page.chat.js \ $(SRCDIR)/fossil.page.fileedit.js \ $(SRCDIR)/fossil.page.forumpost.js \ $(SRCDIR)/fossil.page.pikchrshow.js \ $(SRCDIR)/fossil.page.wcontent.js \ $(SRCDIR)/fossil.page.whistory.js \ $(SRCDIR)/fossil.page.wikiedit.js \ $(SRCDIR)/fossil.pikchr.js \ $(SRCDIR)/fossil.popupwidget.js \ $(SRCDIR)/fossil.storage.js \ $(SRCDIR)/fossil.tabs.js \ $(SRCDIR)/fossil.wikiedit-wysiwyg.js \ |
︙ | ︙ |
Changes to src/wiki.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** This file contains code to do formatting of wiki text. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wiki.h" /* ** Return true if the input string is a well-formed wiki page name. ** ** Well-formed wiki page names do not begin or end with whitespace, ** and do not contain tabs or other control characters and do not ** contain more than a single space character in a row. Well-formed ** names must be between 1 and 100 characters in length, inclusive. | > > > > > > > > > > > > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ** This file contains code to do formatting of wiki text. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wiki.h" #if INTERFACE /* ** WikiClass struct holds information for matching a wiki page name. ** It is constructed by load_wiki_classes() function and represents a ** single well-formed line obtained from the 'wiki-classes' setting. */ struct WikiClass { const char * zPattern; /* pattern to match against */ int isCaseIns; /* syntax flag: 0 for GLOB, 1 for LIKE */ short isAltPat; /* indicates an additional pattern for a class */ const char * zVisblty; /* visibility flag, one of: "s" "h" "d" "x" */ const char * zLabel; /* user-visible class name, same in HTML attrs */ const char * zParam; /* checkbox attr, like in <input name="..." /> */ }; #endif /* ** Return true if the input string is a well-formed wiki page name. ** ** Well-formed wiki page names do not begin or end with whitespace, ** and do not contain tabs or other control characters and do not ** contain more than a single space character in a row. Well-formed ** names must be between 1 and 100 characters in length, inclusive. |
︙ | ︙ | |||
437 438 439 440 441 442 443 444 445 446 447 448 449 450 | case WIKITYPE_CHECKIN: return "checkin"; case WIKITYPE_BRANCH: return "branch"; case WIKITYPE_TAG: return "tag"; case WIKITYPE_NORMAL: default: return "normal"; } } /* ** Add an appropriate style_header() for either the /wiki or /wikiedit page ** for zPageName. zExtra is an empty string for /wiki but has the text ** "Edit: " for /wikiedit. ** ** If the page is /wiki and the page is one of the special times (check-in, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | case WIKITYPE_CHECKIN: return "checkin"; case WIKITYPE_BRANCH: return "branch"; case WIKITYPE_TAG: return "tag"; case WIKITYPE_NORMAL: default: return "normal"; } } /* ** load_wiki_classes() loads and parses the value of the 'wiki-classes' ** setting. Retrurns either NULL or a dynamically allocated array of ** WikiClasses (thus fossil_free() for the returned value is advised). */ WikiClass* load_wiki_classes( int *nWC, /* number of well-formed elements in the returned array */ Blob *wcs /* holds a buffer for strings in the returned WikiClass'es */ ){ static const char *zPN[] = { /* no malloc() for the common cases */ "wc0", "wc1", "wc2", "wc3", "wc4", "wc5", "wc6", "wc7", "wc8", "wc9","wc10","wc11","wc12","wc13","wc14","wc15", "wc16","wc17","wc18","wc19","wc20","wc21","wc22","wc23" }; WikiClass* aWC = 0; int n = 0; char *zWCS = db_get("wiki-classes",0); if( zWCS && strlen(zWCS) >= 5 ){ Blob line = empty_blob; int nAlloc = 0; blob_set_dynamic(wcs,zWCS); while( blob_line(wcs,&line) > 0 ){ Blob vis = empty_blob; Blob lbl = empty_blob; Blob pat = empty_blob; WikiClass * wc; const char *z; int cins = 0; char v; if( blob_token(&line,&vis) != 1 ){ continue; } v = vis.aData[0]; switch( v ){ case 'D': case 'H': case 'S': case 'X': cins = 1; vis.aData[0] = (char)tolower(v); case 'd': case 'h': case 's': case 'x': break; default: v = 0; } if( v == 0 ) continue; if( blob_token(&line,&lbl) <= 0 ){ continue; } blob_tail(&line,&pat); /* blob_to_lf_only(&pre); <-- this is redundant, isn't it ? */ blob_trim(&pat); z = blob_terminate(&pat); while(fossil_isspace(z[0])) z++; if( z[0] == 0 ){ continue; } if( n >= nAlloc ){ nAlloc += count(zPN); aWC = (WikiClass*)( aWC ? fossil_realloc(aWC,sizeof(WikiClass)*nAlloc) : fossil_malloc_zero(sizeof(WikiClass)*nAlloc) ); } wc = aWC + n; wc->zPattern = z; wc->isCaseIns = cins; wc->zVisblty = blob_terminate(&vis); wc->zLabel = blob_terminate(&lbl); wc->zParam = ( n < count(zPN) ? zPN[n] : mprintf("wc%d",n) ); if( n > 0 && strcmp( wc->zLabel, wc[-1].zLabel ) == 0 ){ if( wc->zVisblty[0] != wc[-1].zVisblty[0] || strcmp( wc->zPattern, wc[-1].zPattern ) == 0 ){ continue; } wc->isAltPat = 1; }else{ wc->isAltPat = 0; } n++; } } if( nWC ) *nWC = n; return aWC; } /* ** Find and return a WikiClass that matches a name of a wiki page. ** Returns 0 if "fallback" pattern was not provisioned. */ const WikiClass* resolve_wiki_class( const char *zName, /* name of a wiki page that should be classified */ const WikiClass *aWC, /* pointer to the array of WikiClass'es */ int nWC /* number of elements in the above array */ ){ const WikiClass* fallback = 0; if( aWC && zName ){ int i; for( i=0; i<nWC; i++ ){ const WikiClass* wc = aWC + i; if( wc->zPattern[0] == '*' && wc->zPattern[1] == 0 ){ if( !fallback ) fallback = wc; }else if( wc->isCaseIns ){ if( sqlite3_strlike( wc->zPattern, zName, 0 ) == 0 ) return wc; }else{ if( sqlite3_strglob( wc->zPattern, zName ) == 0 ) return wc; } } } return fallback; } /* ** Add an appropriate style_header() for either the /wiki or /wikiedit page ** for zPageName. zExtra is an empty string for /wiki but has the text ** "Edit: " for /wikiedit. ** ** If the page is /wiki and the page is one of the special times (check-in, |
︙ | ︙ | |||
1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | ** List all available wiki pages with date created and last modified. */ void wcontent_page(void){ Stmt q; double rNow; int showAll = P("all")!=0; int showRid = P("showid")!=0; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } style_set_current_feature("wiki"); style_header("Available Wiki Pages"); if( showAll ){ style_submenu_element("Active", "%R/wcontent"); }else{ style_submenu_element("All", "%R/wcontent?all=1"); } wiki_standard_submenu(W_ALL_BUT(W_LIST)); db_prepare(&q, listAllWikiPages/*works-like:""*/); @ <div class="brlist"> @ <table class='sortable' data-column-types='tKN' data-init-sort='1'> @ <thead><tr> @ <th>Name</th> @ <th>Last Change</th> @ <th>Versions</th> if( showRid ){ @ <th>RID</th> } @ </tr></thead><tbody> rNow = db_double(0.0, "SELECT julianday('now')"); while( db_step(&q)==SQLITE_ROW ){ const char *zWName = db_column_text(&q, 0); const char *zSort = db_column_text(&q, 1); int wrid = db_column_int(&q, 2); double rWmtime = db_column_double(&q, 3); sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0); char *zAge; int wcnt = db_column_int(&q, 4); char *zWDisplayName; | > > > > > > > > > > > > > > | > | | > > > > > > | > > > > > | > > > | 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 | ** List all available wiki pages with date created and last modified. */ void wcontent_page(void){ Stmt q; double rNow; int showAll = P("all")!=0; int showRid = P("showid")!=0; Blob wcs = empty_blob; int i, nWC = 0; WikiClass* aWC; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } style_set_current_feature("wiki"); style_header("Available Wiki Pages"); if( showAll ){ style_submenu_element("Active", "%R/wcontent"); }else{ style_submenu_element("All", "%R/wcontent?all=1"); } aWC = load_wiki_classes(&nWC,&wcs); for( i=0; i<nWC; i++ ){ const WikiClass * c = aWC + i; if( c->isAltPat || c->zVisblty[0] == 'x' ) continue; style_submenu_checkbox( c->zParam, c->zLabel, c->zVisblty[0]=='d' ? STYLE_DISABLED : STYLE_NORMAL, c->zVisblty); } wiki_standard_submenu(W_ALL_BUT(W_LIST)); db_prepare(&q, listAllWikiPages/*works-like:""*/); @ <input hidden="hidden" id="page-reload-canary" type="checkbox"/> @ <div class="brlist"> @ <table class='sortable' data-column-types='tKN' data-init-sort='1'> @ <thead><tr> @ <th>Name</th> @ <th>Last Change</th> @ <th>Versions</th> if( showRid ){ @ <th>RID</th> } @ </tr></thead><tbody> rNow = db_double(0.0, "SELECT julianday('now')"); while( db_step(&q)==SQLITE_ROW ){ const char *zWName = db_column_text(&q, 0); const char *zSort = db_column_text(&q, 1); int wrid = db_column_int(&q, 2); double rWmtime = db_column_double(&q, 3); sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0); char *zAge; int wcnt = db_column_int(&q, 4); char *zWDisplayName; const WikiClass * wc = resolve_wiki_class(zWName,aWC,nWC); if( wc && (wc->zVisblty[0] == 'x' || wc->zVisblty[0] == 'd') ){ continue; } if( sqlite3_strglob("checkin/*", zWName)==0 ){ /* --?--> strncmp() */ zWDisplayName = mprintf("%.25s...", zWName); }else{ zWDisplayName = mprintf("%s", zWName); /* --?--> fossil_strdup() */ } if( wrid==0 ){ if( !showAll ) continue; if(wc){ @ <tr class="%h(wc->zLabel)"> }else{ @ <tr> } @ <td data-sortkey="%h(zSort)">\ @ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td> }else{ if(wc){ @ <tr class="%h(wc->zLabel)"> }else{ @ <tr> } @ <td data-sortkey="%h(zSort)">\ @ %z(href("%R/wiki?name=%T&p",zWName))%h(zWDisplayName)</a></td> } zAge = human_readable_age(rNow - rWmtime); @ <td data-sortkey="%016llx(iMtime)">%s(zAge)</td> fossil_free(zAge); @ <td>%z(href("%R/whistory?name=%T",zWName))%d(wcnt)</a></td> if( showRid ){ @ <td>%d(wrid)</td> } @ </tr> fossil_free(zWDisplayName); } @ </tbody></table></div> db_finalize(&q); builtin_request_js("fossil.page.wcontent.js"); style_table_sorter(); style_finish_page(); if(aWC) fossil_free(aWC); blob_reset(&wcs); /* FIXME: it's an analog of fossil_free(), isn't it? */ } /* ** WEBPAGE: wfind ** ** URL: /wfind?title=TITLE ** List all wiki pages whose titles contain the search text |
︙ | ︙ |
Changes to www/javascript.md.
︙ | ︙ | |||
593 594 595 596 597 598 599 600 601 602 603 604 605 606 | Clicking this hyperlink loads a `/timeline` page that shows only these selected branches (and the related check-ins). _Potential Workaround:_ A user can manually construct an appropriate regular expession and put it into the "Tag Filter" entry of the `/timeline` page (in its advanced mode). ---- ## <a id="future"></a>Future Plans for JavaScript in Fossil As of mid-2020, the informal provisional plan is to increase Fossil UI's use of JavaScript considerably compared to its historically minimal uses. To that end, a framework of Fossil-centric APIs is being developed | > > > > > > > > > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | Clicking this hyperlink loads a `/timeline` page that shows only these selected branches (and the related check-ins). _Potential Workaround:_ A user can manually construct an appropriate regular expession and put it into the "Tag Filter" entry of the `/timeline` page (in its advanced mode). ### <a id="wcontent"></a>Wiki content listing [Since](/timeline?r=wcontent-subsets) version 2.18 it is possible to add [configurable](/help?cmd=wiki-classes) checkbox controls to the submenu of [available wiki pages](/wcontent) for the interactive adjustment of a subset of wiki pages that are shown. Client-side script is used to toggle visibility of the corresponding rows according to the state of these checkboxes. ---- ## <a id="future"></a>Future Plans for JavaScript in Fossil As of mid-2020, the informal provisional plan is to increase Fossil UI's use of JavaScript considerably compared to its historically minimal uses. To that end, a framework of Fossil-centric APIs is being developed |
︙ | ︙ |