Fossil SCM
Split recognizable names of query parameters into three groups: 1) "...smplX" for the common use within user content 2) "...smplXa" that is provisioned to be used in aliases; 3) "...smplXs" that is provisioned to be used in custom skins. In all three groups X is a digit from {1,2,3,4,5}.
Commit
588b37656058c6b5f26ae0f8cebdd25d59b192974fae7959282cb5e73d615c5f
Parent
b75ee4f28efd8ad…
2 files changed
+9
-5
+53
-47
+9
-5
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -971,15 +971,20 @@ | ||
| 971 | 971 | ** WEBPAGE: rptview |
| 972 | 972 | ** |
| 973 | 973 | ** Generate a report. The "rn" query parameter is the report number |
| 974 | 974 | ** corresponding to REPORTFMT.RN. If the "tablist" query parameter exists, |
| 975 | 975 | ** then the output consists of lines of tab-separated fields instead of |
| 976 | -** an HTML table. If the "rvsmpl" query parameter is set then report's | |
| 977 | -** submenu will contain an extra hyperlink that have a value-driven | |
| 978 | -** label and target. | |
| 976 | +** an HTML table. | |
| 977 | +** | |
| 978 | +** Submenu of the /rptview page can be extended with additional | |
| 979 | +** hyperlinks by providing query parameter(s) of the form rvsmplXY=Z. | |
| 980 | +** Optional ending XY consists of a digit X from the set {1,2,3,4,5} | |
| 981 | +** and an optional letter Y that (if present) must be either 'a' or 's'. | |
| 982 | +** Mandatory Z is a repo-local hyperlink's target (wihout leading '/'). | |
| 979 | 983 | ** |
| 980 | -** "rvsmpl" stands for Report View SubMenu's Parametric Link. | |
| 984 | +** For details see function style_submenu_parametric() in src/style.c | |
| 985 | +** on branch "rptview-submenu-paralink". | |
| 981 | 986 | */ |
| 982 | 987 | void rptview_page(void){ |
| 983 | 988 | int count = 0; |
| 984 | 989 | int rn, rc; |
| 985 | 990 | char *zSql; |
| @@ -1045,11 +1050,10 @@ | ||
| 1045 | 1050 | style_submenu_element("Reports","%R/reportlist?%s",zQS); |
| 1046 | 1051 | } else { |
| 1047 | 1052 | style_submenu_element("Raw","%R/%s?tablist=1",g.zPath); |
| 1048 | 1053 | style_submenu_element("Reports","%R/reportlist"); |
| 1049 | 1054 | } |
| 1050 | - style_submenu_parametric("rptview_"); | |
| 1051 | 1055 | style_submenu_parametric("rv"); |
| 1052 | 1056 | |
| 1053 | 1057 | if( g.perm.Admin |
| 1054 | 1058 | || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ |
| 1055 | 1059 | style_submenu_element("Edit", "rptedit?rn=%d", rn); |
| 1056 | 1060 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -971,15 +971,20 @@ | |
| 971 | ** WEBPAGE: rptview |
| 972 | ** |
| 973 | ** Generate a report. The "rn" query parameter is the report number |
| 974 | ** corresponding to REPORTFMT.RN. If the "tablist" query parameter exists, |
| 975 | ** then the output consists of lines of tab-separated fields instead of |
| 976 | ** an HTML table. If the "rvsmpl" query parameter is set then report's |
| 977 | ** submenu will contain an extra hyperlink that have a value-driven |
| 978 | ** label and target. |
| 979 | ** |
| 980 | ** "rvsmpl" stands for Report View SubMenu's Parametric Link. |
| 981 | */ |
| 982 | void rptview_page(void){ |
| 983 | int count = 0; |
| 984 | int rn, rc; |
| 985 | char *zSql; |
| @@ -1045,11 +1050,10 @@ | |
| 1045 | style_submenu_element("Reports","%R/reportlist?%s",zQS); |
| 1046 | } else { |
| 1047 | style_submenu_element("Raw","%R/%s?tablist=1",g.zPath); |
| 1048 | style_submenu_element("Reports","%R/reportlist"); |
| 1049 | } |
| 1050 | style_submenu_parametric("rptview_"); |
| 1051 | style_submenu_parametric("rv"); |
| 1052 | |
| 1053 | if( g.perm.Admin |
| 1054 | || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ |
| 1055 | style_submenu_element("Edit", "rptedit?rn=%d", rn); |
| 1056 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -971,15 +971,20 @@ | |
| 971 | ** WEBPAGE: rptview |
| 972 | ** |
| 973 | ** Generate a report. The "rn" query parameter is the report number |
| 974 | ** corresponding to REPORTFMT.RN. If the "tablist" query parameter exists, |
| 975 | ** then the output consists of lines of tab-separated fields instead of |
| 976 | ** an HTML table. |
| 977 | ** |
| 978 | ** Submenu of the /rptview page can be extended with additional |
| 979 | ** hyperlinks by providing query parameter(s) of the form rvsmplXY=Z. |
| 980 | ** Optional ending XY consists of a digit X from the set {1,2,3,4,5} |
| 981 | ** and an optional letter Y that (if present) must be either 'a' or 's'. |
| 982 | ** Mandatory Z is a repo-local hyperlink's target (wihout leading '/'). |
| 983 | ** |
| 984 | ** For details see function style_submenu_parametric() in src/style.c |
| 985 | ** on branch "rptview-submenu-paralink". |
| 986 | */ |
| 987 | void rptview_page(void){ |
| 988 | int count = 0; |
| 989 | int rn, rc; |
| 990 | char *zSql; |
| @@ -1045,11 +1050,10 @@ | |
| 1050 | style_submenu_element("Reports","%R/reportlist?%s",zQS); |
| 1051 | } else { |
| 1052 | style_submenu_element("Raw","%R/%s?tablist=1",g.zPath); |
| 1053 | style_submenu_element("Reports","%R/reportlist"); |
| 1054 | } |
| 1055 | style_submenu_parametric("rv"); |
| 1056 | |
| 1057 | if( g.perm.Admin |
| 1058 | || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ |
| 1059 | style_submenu_element("Edit", "rptedit?rn=%d", rn); |
| 1060 |
+53
-47
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -333,13 +333,15 @@ | ||
| 333 | 333 | } |
| 334 | 334 | |
| 335 | 335 | /* Add hyperlinks depending on the existence and values of special |
| 336 | 336 | ** parameters in the request's query string. The names of a query's |
| 337 | 337 | ** parameters that are investigated are obtainted by concatenation of |
| 338 | -** the caller-provided zPrefix with suffix "smplX", where X is either | |
| 339 | -** nothing or a positive digit. zPrefix must start with a lowercase | |
| 340 | -** letter, be short and have no strange characters. Parameter's value | |
| 338 | +** the caller-provided zPrefix with suffix "smplXY", where optional | |
| 339 | +** ending XY consists of a digit X from the set {1,2,3,4,5} and an | |
| 340 | +** optional letter Y which (if present) must be either 'a' or 's'. | |
| 341 | +** zPrefix must start with a lowercase letter, | |
| 342 | +** be short and have no strange characters. Parameter's value | |
| 341 | 343 | ** is well-formed if its first filepath segment (separated by '/') |
| 342 | 344 | ** has no strange characters. Malformed values are silently ignored. |
| 343 | 345 | ** |
| 344 | 346 | ** The text for the resulting submenu label equals to the value of the |
| 345 | 347 | ** parameter modulus some prettification for better UX: |
| @@ -360,65 +362,69 @@ | ||
| 360 | 362 | void style_submenu_parametric( |
| 361 | 363 | const char *zPrefix /* common prefix of the query parameters names */ |
| 362 | 364 | ){ |
| 363 | 365 | static const char *suffix = "smpl"; /* common suffix for param names */ |
| 364 | 366 | static const short sfxlen = 4; /* length of the above suffix */ |
| 367 | + static const char sfxext[3] = {'a','s',0}; /* extra suffix ending */ | |
| 365 | 368 | const char *zQS; /* QUERY_STRING */ |
| 366 | 369 | char zN[32]; /* buffer for parameter names to probe */ |
| 367 | - short i,l; | |
| 370 | + short i,j,l; | |
| 368 | 371 | |
| 369 | 372 | /* zPrefix must be tidy and short; also filter out ENV/CGI variables */ |
| 370 | 373 | assert( zPrefix != 0 && fossil_islower(zPrefix[0]) ); |
| 371 | 374 | l = strnlen( zPrefix, sizeof(zN) ); |
| 372 | - assert( l+sfxlen+2 <= sizeof(zN) ); | |
| 375 | + assert( l+sfxlen+3 <= sizeof(zN) ); | |
| 373 | 376 | assert( fossil_no_strange_characters(zPrefix) ); |
| 374 | 377 | /* concatenate zPrefix and suffix */ |
| 375 | 378 | strcpy( zN, zPrefix ); |
| 376 | 379 | strcpy( zN + l, suffix ); |
| 377 | 380 | l += sfxlen; |
| 378 | - zN[l+1] = 0; /* nul-terminator after digit's placeholder (if any) */ | |
| 379 | - zQS = PD("QUERY_STRING",""); | |
| 380 | - for( i = 0; i <= 9; i++ ){ | |
| 381 | - const char *zV, *z; | |
| 382 | - zN[l] = ( i == 0 ? 0 : '0' + i ); /* ...smpl instead of ...smpl0 */ | |
| 383 | - zV = PD(zN,""); | |
| 384 | - if( zV[0] == 0 || zV[0] == '/' || zV[0] == '_' || zV[0] == '-' ){ | |
| 385 | - continue; | |
| 386 | - } | |
| 387 | - /* require the first path segment to be unfancy ASCII string */ | |
| 388 | - for( z = zV; z[0] && z[0] != '/' ;){ | |
| 389 | - if( fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-' ) z++; | |
| 390 | - else break; | |
| 391 | - } | |
| 392 | - if( z[0] != 0 && z[0] != '/' ) | |
| 393 | - continue; | |
| 394 | - assert( nSubmenu < count(aSubmenu) ); | |
| 395 | - if(fossil_islower(zV[0]) && z[0]=='/'){ | |
| 396 | - aSubmenu[nSubmenu].zLabel = mprintf( "%s",zV); /* memory leak? */ | |
| 397 | - }else{ | |
| 398 | - /* prepend a label with an unobtrusive symbol that "sorts-last"; | |
| 399 | - ** this clearly distincts it from the built-in elements */ | |
| 400 | - static const char *mark = "✧"; | |
| 401 | - char *z = mprintf("%s%s",mark,zV); | |
| 402 | - aSubmenu[nSubmenu].zLabel = z; | |
| 403 | - /* also prettify the first segment */ | |
| 404 | - z += strlen(mark); | |
| 405 | - z[0] = fossil_toupper(z[0]); | |
| 406 | - for(; z[0]!=0; z++ ){ | |
| 407 | - if( z[0]=='_' ) z[0] = ' '; | |
| 408 | - else if( z[0] == '/' ){ /* show just the first segment */ | |
| 409 | - z[0] = 0; | |
| 410 | - break; | |
| 411 | - } | |
| 412 | - } | |
| 413 | - } | |
| 414 | - if( zQS[0] ){ | |
| 415 | - aSubmenu[nSubmenu].zLink = mprintf("%R/%s?%s",zV,zQS); | |
| 416 | - }else{ | |
| 417 | - aSubmenu[nSubmenu].zLink = mprintf("%R/%s",zV); | |
| 418 | - } | |
| 419 | - nSubmenu++; | |
| 381 | + zN[l+2] = 0; /* nul-terminator after ...smplXY suffix */ | |
| 382 | + zQS = PD("QUERY_STRING",""); | |
| 383 | + for( i = 0; i <= 5; i++ ){ | |
| 384 | + zN[l] = ( i == 0 ? 0 : '0' + i ); /* ...smpl instead of ...smpl0 */ | |
| 385 | + for( j = (i ? 0 : sizeof(sfxext)-1); j < sizeof(sfxext); j++ ){ | |
| 386 | + const char *zV, *z; | |
| 387 | + zN[l+1] = sfxext[j]; | |
| 388 | + zV = PD(zN,""); | |
| 389 | + if( zV[0] == 0 || zV[0] == '/' || zV[0] == '_' || zV[0] == '-' ){ | |
| 390 | + continue; | |
| 391 | + } | |
| 392 | + /* require the first path segment to be unfancy ASCII string */ | |
| 393 | + for( z = zV; z[0] && z[0] != '/' ;){ | |
| 394 | + if( fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-' ) z++; | |
| 395 | + else break; | |
| 396 | + } | |
| 397 | + if( z[0] != 0 && z[0] != '/' ) | |
| 398 | + continue; | |
| 399 | + assert( nSubmenu < count(aSubmenu) ); | |
| 400 | + if(fossil_islower(zV[0]) && z[0]=='/'){ | |
| 401 | + aSubmenu[nSubmenu].zLabel = mprintf( "%s",zV); /* memory leak? */ | |
| 402 | + }else{ | |
| 403 | + /* prepend a label with an unobtrusive symbol that "sorts-last"; | |
| 404 | + ** this clearly distincts it from the built-in elements */ | |
| 405 | + static const char *mark = "✧"; | |
| 406 | + char *z = mprintf("%s%s",mark,zV); | |
| 407 | + aSubmenu[nSubmenu].zLabel = z; | |
| 408 | + /* also prettify the first segment */ | |
| 409 | + z += strlen(mark); | |
| 410 | + z[0] = fossil_toupper(z[0]); | |
| 411 | + for(; z[0]!=0; z++ ){ | |
| 412 | + if( z[0]=='_' ) z[0] = ' '; | |
| 413 | + else if( z[0] == '/' ){ /* show just the first segment */ | |
| 414 | + z[0] = 0; | |
| 415 | + break; | |
| 416 | + } | |
| 417 | + } | |
| 418 | + } | |
| 419 | + if( zQS[0] ){ | |
| 420 | + aSubmenu[nSubmenu].zLink = mprintf("%R/%s?%s",zV,zQS); | |
| 421 | + }else{ | |
| 422 | + aSubmenu[nSubmenu].zLink = mprintf("%R/%s",zV); | |
| 423 | + } | |
| 424 | + nSubmenu++; | |
| 425 | + } | |
| 420 | 426 | } |
| 421 | 427 | } |
| 422 | 428 | |
| 423 | 429 | /* |
| 424 | 430 | ** Disable or enable the submenu |
| 425 | 431 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -333,13 +333,15 @@ | |
| 333 | } |
| 334 | |
| 335 | /* Add hyperlinks depending on the existence and values of special |
| 336 | ** parameters in the request's query string. The names of a query's |
| 337 | ** parameters that are investigated are obtainted by concatenation of |
| 338 | ** the caller-provided zPrefix with suffix "smplX", where X is either |
| 339 | ** nothing or a positive digit. zPrefix must start with a lowercase |
| 340 | ** letter, be short and have no strange characters. Parameter's value |
| 341 | ** is well-formed if its first filepath segment (separated by '/') |
| 342 | ** has no strange characters. Malformed values are silently ignored. |
| 343 | ** |
| 344 | ** The text for the resulting submenu label equals to the value of the |
| 345 | ** parameter modulus some prettification for better UX: |
| @@ -360,65 +362,69 @@ | |
| 360 | void style_submenu_parametric( |
| 361 | const char *zPrefix /* common prefix of the query parameters names */ |
| 362 | ){ |
| 363 | static const char *suffix = "smpl"; /* common suffix for param names */ |
| 364 | static const short sfxlen = 4; /* length of the above suffix */ |
| 365 | const char *zQS; /* QUERY_STRING */ |
| 366 | char zN[32]; /* buffer for parameter names to probe */ |
| 367 | short i,l; |
| 368 | |
| 369 | /* zPrefix must be tidy and short; also filter out ENV/CGI variables */ |
| 370 | assert( zPrefix != 0 && fossil_islower(zPrefix[0]) ); |
| 371 | l = strnlen( zPrefix, sizeof(zN) ); |
| 372 | assert( l+sfxlen+2 <= sizeof(zN) ); |
| 373 | assert( fossil_no_strange_characters(zPrefix) ); |
| 374 | /* concatenate zPrefix and suffix */ |
| 375 | strcpy( zN, zPrefix ); |
| 376 | strcpy( zN + l, suffix ); |
| 377 | l += sfxlen; |
| 378 | zN[l+1] = 0; /* nul-terminator after digit's placeholder (if any) */ |
| 379 | zQS = PD("QUERY_STRING",""); |
| 380 | for( i = 0; i <= 9; i++ ){ |
| 381 | const char *zV, *z; |
| 382 | zN[l] = ( i == 0 ? 0 : '0' + i ); /* ...smpl instead of ...smpl0 */ |
| 383 | zV = PD(zN,""); |
| 384 | if( zV[0] == 0 || zV[0] == '/' || zV[0] == '_' || zV[0] == '-' ){ |
| 385 | continue; |
| 386 | } |
| 387 | /* require the first path segment to be unfancy ASCII string */ |
| 388 | for( z = zV; z[0] && z[0] != '/' ;){ |
| 389 | if( fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-' ) z++; |
| 390 | else break; |
| 391 | } |
| 392 | if( z[0] != 0 && z[0] != '/' ) |
| 393 | continue; |
| 394 | assert( nSubmenu < count(aSubmenu) ); |
| 395 | if(fossil_islower(zV[0]) && z[0]=='/'){ |
| 396 | aSubmenu[nSubmenu].zLabel = mprintf( "%s",zV); /* memory leak? */ |
| 397 | }else{ |
| 398 | /* prepend a label with an unobtrusive symbol that "sorts-last"; |
| 399 | ** this clearly distincts it from the built-in elements */ |
| 400 | static const char *mark = "✧"; |
| 401 | char *z = mprintf("%s%s",mark,zV); |
| 402 | aSubmenu[nSubmenu].zLabel = z; |
| 403 | /* also prettify the first segment */ |
| 404 | z += strlen(mark); |
| 405 | z[0] = fossil_toupper(z[0]); |
| 406 | for(; z[0]!=0; z++ ){ |
| 407 | if( z[0]=='_' ) z[0] = ' '; |
| 408 | else if( z[0] == '/' ){ /* show just the first segment */ |
| 409 | z[0] = 0; |
| 410 | break; |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | if( zQS[0] ){ |
| 415 | aSubmenu[nSubmenu].zLink = mprintf("%R/%s?%s",zV,zQS); |
| 416 | }else{ |
| 417 | aSubmenu[nSubmenu].zLink = mprintf("%R/%s",zV); |
| 418 | } |
| 419 | nSubmenu++; |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | /* |
| 424 | ** Disable or enable the submenu |
| 425 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -333,13 +333,15 @@ | |
| 333 | } |
| 334 | |
| 335 | /* Add hyperlinks depending on the existence and values of special |
| 336 | ** parameters in the request's query string. The names of a query's |
| 337 | ** parameters that are investigated are obtainted by concatenation of |
| 338 | ** the caller-provided zPrefix with suffix "smplXY", where optional |
| 339 | ** ending XY consists of a digit X from the set {1,2,3,4,5} and an |
| 340 | ** optional letter Y which (if present) must be either 'a' or 's'. |
| 341 | ** zPrefix must start with a lowercase letter, |
| 342 | ** be short and have no strange characters. Parameter's value |
| 343 | ** is well-formed if its first filepath segment (separated by '/') |
| 344 | ** has no strange characters. Malformed values are silently ignored. |
| 345 | ** |
| 346 | ** The text for the resulting submenu label equals to the value of the |
| 347 | ** parameter modulus some prettification for better UX: |
| @@ -360,65 +362,69 @@ | |
| 362 | void style_submenu_parametric( |
| 363 | const char *zPrefix /* common prefix of the query parameters names */ |
| 364 | ){ |
| 365 | static const char *suffix = "smpl"; /* common suffix for param names */ |
| 366 | static const short sfxlen = 4; /* length of the above suffix */ |
| 367 | static const char sfxext[3] = {'a','s',0}; /* extra suffix ending */ |
| 368 | const char *zQS; /* QUERY_STRING */ |
| 369 | char zN[32]; /* buffer for parameter names to probe */ |
| 370 | short i,j,l; |
| 371 | |
| 372 | /* zPrefix must be tidy and short; also filter out ENV/CGI variables */ |
| 373 | assert( zPrefix != 0 && fossil_islower(zPrefix[0]) ); |
| 374 | l = strnlen( zPrefix, sizeof(zN) ); |
| 375 | assert( l+sfxlen+3 <= sizeof(zN) ); |
| 376 | assert( fossil_no_strange_characters(zPrefix) ); |
| 377 | /* concatenate zPrefix and suffix */ |
| 378 | strcpy( zN, zPrefix ); |
| 379 | strcpy( zN + l, suffix ); |
| 380 | l += sfxlen; |
| 381 | zN[l+2] = 0; /* nul-terminator after ...smplXY suffix */ |
| 382 | zQS = PD("QUERY_STRING",""); |
| 383 | for( i = 0; i <= 5; i++ ){ |
| 384 | zN[l] = ( i == 0 ? 0 : '0' + i ); /* ...smpl instead of ...smpl0 */ |
| 385 | for( j = (i ? 0 : sizeof(sfxext)-1); j < sizeof(sfxext); j++ ){ |
| 386 | const char *zV, *z; |
| 387 | zN[l+1] = sfxext[j]; |
| 388 | zV = PD(zN,""); |
| 389 | if( zV[0] == 0 || zV[0] == '/' || zV[0] == '_' || zV[0] == '-' ){ |
| 390 | continue; |
| 391 | } |
| 392 | /* require the first path segment to be unfancy ASCII string */ |
| 393 | for( z = zV; z[0] && z[0] != '/' ;){ |
| 394 | if( fossil_isalnum(z[0]) || z[0]=='_' || z[0]=='-' ) z++; |
| 395 | else break; |
| 396 | } |
| 397 | if( z[0] != 0 && z[0] != '/' ) |
| 398 | continue; |
| 399 | assert( nSubmenu < count(aSubmenu) ); |
| 400 | if(fossil_islower(zV[0]) && z[0]=='/'){ |
| 401 | aSubmenu[nSubmenu].zLabel = mprintf( "%s",zV); /* memory leak? */ |
| 402 | }else{ |
| 403 | /* prepend a label with an unobtrusive symbol that "sorts-last"; |
| 404 | ** this clearly distincts it from the built-in elements */ |
| 405 | static const char *mark = "✧"; |
| 406 | char *z = mprintf("%s%s",mark,zV); |
| 407 | aSubmenu[nSubmenu].zLabel = z; |
| 408 | /* also prettify the first segment */ |
| 409 | z += strlen(mark); |
| 410 | z[0] = fossil_toupper(z[0]); |
| 411 | for(; z[0]!=0; z++ ){ |
| 412 | if( z[0]=='_' ) z[0] = ' '; |
| 413 | else if( z[0] == '/' ){ /* show just the first segment */ |
| 414 | z[0] = 0; |
| 415 | break; |
| 416 | } |
| 417 | } |
| 418 | } |
| 419 | if( zQS[0] ){ |
| 420 | aSubmenu[nSubmenu].zLink = mprintf("%R/%s?%s",zV,zQS); |
| 421 | }else{ |
| 422 | aSubmenu[nSubmenu].zLink = mprintf("%R/%s",zV); |
| 423 | } |
| 424 | nSubmenu++; |
| 425 | } |
| 426 | } |
| 427 | } |
| 428 | |
| 429 | /* |
| 430 | ** Disable or enable the submenu |
| 431 |