Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Allow a page's submenu to have multiple parametric hyperlinks induced by several different query string parameters. Use a common suffixes (smpl,smpl1,...smpl9) to probe for defined parameters. Relax constraints on hyperlink values to allow linking to wiki pages (for example). As a proof of concept add support of paralinks to the /wiki page. Get rid of dangling '&' at the endings. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | rptview-submenu-paralink |
| Files: | files | file ages | folders |
| SHA3-256: |
d075801aa8629e2492133e6e4d6087d1 |
| User & Date: | george 2021-03-26 17:20:39.932 |
Context
|
2021-03-26
| ||
| 17:59 | Merge-in changes from trunk (~ version 2.15) ... (check-in: 290671078c user: george tags: rptview-submenu-paralink) | |
| 17:20 | Allow a page's submenu to have multiple parametric hyperlinks induced by several different query string parameters. Use a common suffixes (smpl,smpl1,...smpl9) to probe for defined parameters. Relax constraints on hyperlink values to allow linking to wiki pages (for example). As a proof of concept add support of paralinks to the /wiki page. Get rid of dangling '&' at the endings. ... (check-in: d075801aa8 user: george tags: rptview-submenu-paralink) | |
|
2021-03-25
| ||
| 04:11 | At /rptview page show link to /reportslist. If request's query string contains <b>rvsmpl</b> parameter then also show an auxiliary link to the page defined by the value of this parameter. Labels and links rendered via %s format specifier because %h and %T did not work properly. In this particular case this seems fine because style_finish_page() renders HTML via %h(...). Code review is very welcome though. ... (check-in: b982c00150 user: george tags: rptview-submenu-paralink) | |
Changes
Changes to src/report.c.
| ︙ | ︙ | |||
987 988 989 990 991 992 993 | char *zTitle; char *zOwner; char *zClrKey; int tabs; Stmt q; char *zErr1 = 0; char *zErr2 = 0; | < | 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
char *zTitle;
char *zOwner;
char *zClrKey;
int tabs;
Stmt q;
char *zErr1 = 0;
char *zErr2 = 0;
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
tabs = P("tablist")!=0;
db_prepare(&q,
"SELECT title, sqlcode, owner, cols, rn FROM reportfmt WHERE rn=%d",
atoi(PD("rn","0")));
|
| ︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
zSql = mprintf("SELECT * FROM (%s) ORDER BY %d %s", zSql, nField, zDir);
}
}
count = 0;
if( !tabs ){
struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_set_current_feature("report");
| > > > > > > > > | | > > > | > | > | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
zSql = mprintf("SELECT * FROM (%s) ORDER BY %d %s", zSql, nField, zDir);
}
}
count = 0;
if( !tabs ){
struct GenerateHTML sState = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const char *zQS = PD("QUERY_STRING","");
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_set_current_feature("report");
/*
** Lets use a funcy button for /reportlist since that page may be
** heavily customized by the user. Some variants: ⊚ ⦾ ❊ ⊛ ⚛ ⸎ 💠
** Enclosing it inside of square brackets makes its position
** determenistic and clearly distincts regular submenu links from
** those that are induced by the query string parameters.
*/
if( zQS[0] ){
style_submenu_element("Raw","%R/%s?tablist=1&%s",g.zPath,zQS);
style_submenu_element("[⊚]","%R/reportlist?%s",zQS);
} else {
style_submenu_element("Raw","%R/%s?tablist=1",g.zPath);
style_submenu_element("[⊚]","%R/reportlist");
}
style_submenu_parametric("rptview_",5);
style_submenu_parametric("rv",5);
if( g.perm.Admin
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
style_submenu_element("Edit", "rptedit?rn=%d", rn);
}
if( g.perm.TktFmt ){
style_submenu_element("SQL", "rptsql?rn=%d",rn);
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
328 329 330 331 332 333 334 |
aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az;
aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL;
aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
nSubmenuCtrl++;
}
}
| | | > > > > > > > > > | | > > > > > > | > | > > | > > > > > > > > > > > > > > > > | | < | > > | > > > > | > > > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char *const *)az;
aSubmenuCtrl[nSubmenuCtrl].eVisible = STYLE_NORMAL;
aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
nSubmenuCtrl++;
}
}
/* Add hyperlinks depending on the existence and values of special
** parameters in the request's query string. The names of these
** parameters that are investigated are obtainted by concatenation
** of zPrefix with suffix "smplX", where X is either nothing or
** a positive digit <= nMaxDigit. zPrefix must start with a lowercase
** letter, be short and have no strange characters. A value is
** well-formed if its first filepath segment (separated by '/')
** has no strange characters. The labels of the resulting submenu items
** are equal to the well-formed values that are prepended by "✧"
** unless a value starts with a lowercase letter.
** Malformed values are silently ignored.
*/
void style_submenu_parametric(
const char *zPrefix, /* common prefix of the query parameters names */
const int nMaxDigit /* maximal digit on the end of param names */
){
const char *zQS; /* QUERY_STRING */
const char *suffix = "smpl"; /* common suffix for all parameters */
const short sfxlen = 4; /* length of the above suffix */
char zN[32]; /* short names => no dynamic allocations */
short i,l;
/* zPrefix must be tidy and short; also filter out ENV/CGI variables */
assert( zPrefix != 0 && fossil_islower(zPrefix[0]) );
l = strnlen( zPrefix, sizeof(zN) );
assert( l+sfxlen+2 <= sizeof(zN) );
assert( fossil_no_strange_characters(zPrefix) );
/* concatenate zPrefix and suffix */
strcpy( zN, zPrefix );
strcpy( zN + l, suffix );
l += sfxlen;
zN[l+1] = 0; /* nul-terminator after digit's placeholder (if any) */
zQS = PD("QUERY_STRING","");
for( i = 0; i <= 9 && i <= nMaxDigit; i++ ){
const char *zV, *z;
zN[l] = ( i == 0 ? 0 : '0' + i ); /* ...smpl instead of ...smpl0 */
zV = PD(zN,"");
if( zV[0] == 0 || zV[0] == '/' ){
continue;
}
/* require the first path segment to be unfancy ASCII string */
for( z = zV; z[0] && z[0] != '/' ;){
if( fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-' ) z++;
else break;
}
if( z[0] != 0 && z[0] != '/' )
continue;
assert( nSubmenu < count(aSubmenu) );
if(fossil_islower(zV[0])){
aSubmenu[nSubmenu].zLabel = mprintf( "%s",zV); /* memory leak? */
}else{
aSubmenu[nSubmenu].zLabel = mprintf("✧%s",zV); /* maybe: ◦✧⸰⸎ ✨ */
}
if( zQS[0] ){
aSubmenu[nSubmenu].zLink = mprintf("%R/%s?%s",zV,zQS);
}else{
aSubmenu[nSubmenu].zLink = mprintf("%R/%s",zV);
}
nSubmenu++;
}
}
/*
** Disable or enable the submenu
*/
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 |
){
style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
}else if( rid && g.perm.ApndWiki ){
style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
}
if( g.perm.Hyperlink ){
style_submenu_element("History", "%R/whistory?name=%T", zPageName);
}
}
if( !isPopup ){
style_set_current_page("%T?name=%T", g.zPath, zPageName);
wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
if( !noSubmenu ){
wiki_standard_submenu(submenuFlags);
| > | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
){
style_submenu_element("Edit", "%R/wikiedit?name=%T", zPageName);
}else if( rid && g.perm.ApndWiki ){
style_submenu_element("Edit", "%R/wikiappend?name=%T", zPageName);
}
if( g.perm.Hyperlink ){
style_submenu_element("History", "%R/whistory?name=%T", zPageName);
style_submenu_parametric("wiki",7);
}
}
if( !isPopup ){
style_set_current_page("%T?name=%T", g.zPath, zPageName);
wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
if( !noSubmenu ){
wiki_standard_submenu(submenuFlags);
|
| ︙ | ︙ |