Fossil SCM

Supply elements in submenus with additional specific CSS classes. For each submenu element a corresponding classname is derived either from the visible label (for hyperlink-like submenu elements) or from the name of the distinguishing query parameter (for other items).

george 2022-06-04 23:09 trunk
Commit e8a051e6a943a26c9c33a30df8ceda069c06c1747714cda73e1f10f4efce310d
1 file changed +42 -7
+42 -7
--- src/style.c
+++ src/style.c
@@ -921,10 +921,41 @@
921921
cgi_append_content("\n}\n", -1);
922922
}
923923
@ </script>
924924
builtin_fulfill_js_requests();
925925
}
926
+
927
+/*
928
+** Transorm input string into a token that is safe for inclusion into
929
+** class attribute. Digits and low-case letter are passed unchanged,
930
+** upper-case letters are transformed to low-case, everything else is
931
+** tranformed into hyphens; consequtive and pending hyphens are squeezed.
932
+** If result does not fit into szOut chars then it is truncated.
933
+** Result is always terminated with null.
934
+*/
935
+void style_derive_classname(const char *zIn, char *zOut, int szOut){
936
+ assert( zOut );
937
+ assert( szOut>0 );
938
+ if( zIn ){
939
+ int n = 0; /* number of chars written to zOut */
940
+ char c;
941
+ for(--szOut; (c=*zIn) && n<szOut; zIn++) {
942
+ if( ('a'<=c && c<='z') || ('0'<=c && c<='9') ){
943
+ *zOut = c;
944
+ }else if( 'A'<=c && c<='Z' ){
945
+ *zOut = c - 'A' + 'a';
946
+ }else{
947
+ if( n==0 || zOut[-1]=='-' ) continue;
948
+ *zOut = '-';
949
+ }
950
+ zOut++;
951
+ n++;
952
+ }
953
+ if( n && zOut[-1]=='-' ) zOut--;
954
+ }
955
+ *zOut = 0;
956
+}
926957
927958
/*
928959
** Invoke this routine after all of the content for a webpage has been
929960
** generated. This routine should be called once for every webpage, at
930961
** or near the end of page generation. This routine does the following:
@@ -950,10 +981,11 @@
950981
** to the submenu while generating page text.
951982
*/
952983
cgi_destination(CGI_HEADER);
953984
if( submenuEnable && nSubmenu+nSubmenuCtrl>0 ){
954985
int i;
986
+ char zClass[32]; /* reduced form of the main attribute */
955987
if( nSubmenuCtrl ){
956988
@ <form id='f01' method='GET' action='%R/%s(g.zPath)'>
957989
@ <input type='hidden' name='udc' value='1'>
958990
cgi_tag_query_parameter("udc");
959991
}
@@ -960,33 +992,36 @@
960992
@ <div class="submenu">
961993
if( nSubmenu>0 ){
962994
qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
963995
for(i=0; i<nSubmenu; i++){
964996
struct Submenu *p = &aSubmenu[i];
997
+ style_derive_classname(p->zLabel, zClass, sizeof zClass);
965998
/* switching away from the %h formatting below might be dangerous
966999
** because some places use %s to compose zLabel and zLink;
967
- ** e.g. /rptview page
1000
+ ** e.g. /rptview page. "sml" stands for submenu link.
9681001
*/
9691002
if( p->zLink==0 ){
970
- @ <span class="label">%h(p->zLabel)</span>
1003
+ @ <span class="label sml-%s(zClass)">%h(p->zLabel)</span>
9711004
}else{
972
- @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a>
1005
+ @ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
9731006
}
9741007
}
9751008
}
1009
+ strcpy(zClass,"smc-"); /* common prefix for submenu controls */
9761010
for(i=0; i<nSubmenuCtrl; i++){
9771011
const char *zQPN = aSubmenuCtrl[i].zName;
9781012
const char *zDisabled = "";
9791013
const char *zXtraClass = "";
9801014
if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
9811015
zDisabled = " disabled";
9821016
}else if( zQPN ){
9831017
cgi_tag_query_parameter(zQPN);
9841018
}
1019
+ style_derive_classname(zQPN, zClass+4, sizeof(zClass)-4);
9851020
switch( aSubmenuCtrl[i].eType ){
9861021
case FF_ENTRY:
987
- @ <span class='submenuctrl%s(zXtraClass)'>\
1022
+ @ <span class='submenuctrl%s(zXtraClass) %s(zClass)'>\
9881023
@ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
9891024
@ <input type='text' name='%s(zQPN)' value='%h(PD(zQPN, ""))' \
9901025
if( aSubmenuCtrl[i].iSize<0 ){
9911026
@ size='%d(-aSubmenuCtrl[i].iSize)' \
9921027
}else if( aSubmenuCtrl[i].iSize>0 ){
@@ -997,16 +1032,16 @@
9971032
break;
9981033
case FF_MULTI: {
9991034
int j;
10001035
const char *zVal = P(zQPN);
10011036
if( zXtraClass[0] ){
1002
- @ <span class='%s(zXtraClass+1)'>
1037
+ @ <span class='%s(zXtraClass+1) %s(zClass)'>
10031038
}
10041039
if( aSubmenuCtrl[i].zLabel ){
10051040
@ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
10061041
}
1007
- @ <select class='submenuctrl' size='1' name='%s(zQPN)' \
1042
+ @ <select class='submenuctrl %s(zClass)' size='1' name='%s(zQPN)' \
10081043
@ id='submenuctrl-%d(i)'%s(zDisabled)>
10091044
for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){
10101045
const char *zQPV = aSubmenuCtrl[i].azChoice[j];
10111046
@ <option value='%h(zQPV)'\
10121047
if( fossil_strcmp(zVal, zQPV)==0 ){
@@ -1036,11 +1071,11 @@
10361071
@ >%h(aSubmenuCtrl[i].zFalse)</option>
10371072
@ </select>
10381073
break;
10391074
}
10401075
case FF_CHECKBOX: {
1041
- @ <label class='submenuctrl submenuckbox%s(zXtraClass)'>\
1076
+ @ <label class='submenuctrl submenuckbox%s(zXtraClass) %s(zClass)'>\
10421077
@ <input type='checkbox' name='%s(zQPN)' id='submenuctrl-%d(i)' \
10431078
if( PB(zQPN) ){
10441079
@ checked \
10451080
}
10461081
if( aSubmenuCtrl[i].zJS ){
10471082
--- src/style.c
+++ src/style.c
@@ -921,10 +921,41 @@
921 cgi_append_content("\n}\n", -1);
922 }
923 @ </script>
924 builtin_fulfill_js_requests();
925 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
927 /*
928 ** Invoke this routine after all of the content for a webpage has been
929 ** generated. This routine should be called once for every webpage, at
930 ** or near the end of page generation. This routine does the following:
@@ -950,10 +981,11 @@
950 ** to the submenu while generating page text.
951 */
952 cgi_destination(CGI_HEADER);
953 if( submenuEnable && nSubmenu+nSubmenuCtrl>0 ){
954 int i;
 
955 if( nSubmenuCtrl ){
956 @ <form id='f01' method='GET' action='%R/%s(g.zPath)'>
957 @ <input type='hidden' name='udc' value='1'>
958 cgi_tag_query_parameter("udc");
959 }
@@ -960,33 +992,36 @@
960 @ <div class="submenu">
961 if( nSubmenu>0 ){
962 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
963 for(i=0; i<nSubmenu; i++){
964 struct Submenu *p = &aSubmenu[i];
 
965 /* switching away from the %h formatting below might be dangerous
966 ** because some places use %s to compose zLabel and zLink;
967 ** e.g. /rptview page
968 */
969 if( p->zLink==0 ){
970 @ <span class="label">%h(p->zLabel)</span>
971 }else{
972 @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a>
973 }
974 }
975 }
 
976 for(i=0; i<nSubmenuCtrl; i++){
977 const char *zQPN = aSubmenuCtrl[i].zName;
978 const char *zDisabled = "";
979 const char *zXtraClass = "";
980 if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
981 zDisabled = " disabled";
982 }else if( zQPN ){
983 cgi_tag_query_parameter(zQPN);
984 }
 
985 switch( aSubmenuCtrl[i].eType ){
986 case FF_ENTRY:
987 @ <span class='submenuctrl%s(zXtraClass)'>\
988 @ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
989 @ <input type='text' name='%s(zQPN)' value='%h(PD(zQPN, ""))' \
990 if( aSubmenuCtrl[i].iSize<0 ){
991 @ size='%d(-aSubmenuCtrl[i].iSize)' \
992 }else if( aSubmenuCtrl[i].iSize>0 ){
@@ -997,16 +1032,16 @@
997 break;
998 case FF_MULTI: {
999 int j;
1000 const char *zVal = P(zQPN);
1001 if( zXtraClass[0] ){
1002 @ <span class='%s(zXtraClass+1)'>
1003 }
1004 if( aSubmenuCtrl[i].zLabel ){
1005 @ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
1006 }
1007 @ <select class='submenuctrl' size='1' name='%s(zQPN)' \
1008 @ id='submenuctrl-%d(i)'%s(zDisabled)>
1009 for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){
1010 const char *zQPV = aSubmenuCtrl[i].azChoice[j];
1011 @ <option value='%h(zQPV)'\
1012 if( fossil_strcmp(zVal, zQPV)==0 ){
@@ -1036,11 +1071,11 @@
1036 @ >%h(aSubmenuCtrl[i].zFalse)</option>
1037 @ </select>
1038 break;
1039 }
1040 case FF_CHECKBOX: {
1041 @ <label class='submenuctrl submenuckbox%s(zXtraClass)'>\
1042 @ <input type='checkbox' name='%s(zQPN)' id='submenuctrl-%d(i)' \
1043 if( PB(zQPN) ){
1044 @ checked \
1045 }
1046 if( aSubmenuCtrl[i].zJS ){
1047
--- src/style.c
+++ src/style.c
@@ -921,10 +921,41 @@
921 cgi_append_content("\n}\n", -1);
922 }
923 @ </script>
924 builtin_fulfill_js_requests();
925 }
926
927 /*
928 ** Transorm input string into a token that is safe for inclusion into
929 ** class attribute. Digits and low-case letter are passed unchanged,
930 ** upper-case letters are transformed to low-case, everything else is
931 ** tranformed into hyphens; consequtive and pending hyphens are squeezed.
932 ** If result does not fit into szOut chars then it is truncated.
933 ** Result is always terminated with null.
934 */
935 void style_derive_classname(const char *zIn, char *zOut, int szOut){
936 assert( zOut );
937 assert( szOut>0 );
938 if( zIn ){
939 int n = 0; /* number of chars written to zOut */
940 char c;
941 for(--szOut; (c=*zIn) && n<szOut; zIn++) {
942 if( ('a'<=c && c<='z') || ('0'<=c && c<='9') ){
943 *zOut = c;
944 }else if( 'A'<=c && c<='Z' ){
945 *zOut = c - 'A' + 'a';
946 }else{
947 if( n==0 || zOut[-1]=='-' ) continue;
948 *zOut = '-';
949 }
950 zOut++;
951 n++;
952 }
953 if( n && zOut[-1]=='-' ) zOut--;
954 }
955 *zOut = 0;
956 }
957
958 /*
959 ** Invoke this routine after all of the content for a webpage has been
960 ** generated. This routine should be called once for every webpage, at
961 ** or near the end of page generation. This routine does the following:
@@ -950,10 +981,11 @@
981 ** to the submenu while generating page text.
982 */
983 cgi_destination(CGI_HEADER);
984 if( submenuEnable && nSubmenu+nSubmenuCtrl>0 ){
985 int i;
986 char zClass[32]; /* reduced form of the main attribute */
987 if( nSubmenuCtrl ){
988 @ <form id='f01' method='GET' action='%R/%s(g.zPath)'>
989 @ <input type='hidden' name='udc' value='1'>
990 cgi_tag_query_parameter("udc");
991 }
@@ -960,33 +992,36 @@
992 @ <div class="submenu">
993 if( nSubmenu>0 ){
994 qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare);
995 for(i=0; i<nSubmenu; i++){
996 struct Submenu *p = &aSubmenu[i];
997 style_derive_classname(p->zLabel, zClass, sizeof zClass);
998 /* switching away from the %h formatting below might be dangerous
999 ** because some places use %s to compose zLabel and zLink;
1000 ** e.g. /rptview page. "sml" stands for submenu link.
1001 */
1002 if( p->zLink==0 ){
1003 @ <span class="label sml-%s(zClass)">%h(p->zLabel)</span>
1004 }else{
1005 @ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
1006 }
1007 }
1008 }
1009 strcpy(zClass,"smc-"); /* common prefix for submenu controls */
1010 for(i=0; i<nSubmenuCtrl; i++){
1011 const char *zQPN = aSubmenuCtrl[i].zName;
1012 const char *zDisabled = "";
1013 const char *zXtraClass = "";
1014 if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
1015 zDisabled = " disabled";
1016 }else if( zQPN ){
1017 cgi_tag_query_parameter(zQPN);
1018 }
1019 style_derive_classname(zQPN, zClass+4, sizeof(zClass)-4);
1020 switch( aSubmenuCtrl[i].eType ){
1021 case FF_ENTRY:
1022 @ <span class='submenuctrl%s(zXtraClass) %s(zClass)'>\
1023 @ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
1024 @ <input type='text' name='%s(zQPN)' value='%h(PD(zQPN, ""))' \
1025 if( aSubmenuCtrl[i].iSize<0 ){
1026 @ size='%d(-aSubmenuCtrl[i].iSize)' \
1027 }else if( aSubmenuCtrl[i].iSize>0 ){
@@ -997,16 +1032,16 @@
1032 break;
1033 case FF_MULTI: {
1034 int j;
1035 const char *zVal = P(zQPN);
1036 if( zXtraClass[0] ){
1037 @ <span class='%s(zXtraClass+1) %s(zClass)'>
1038 }
1039 if( aSubmenuCtrl[i].zLabel ){
1040 @ &nbsp;%h(aSubmenuCtrl[i].zLabel)\
1041 }
1042 @ <select class='submenuctrl %s(zClass)' size='1' name='%s(zQPN)' \
1043 @ id='submenuctrl-%d(i)'%s(zDisabled)>
1044 for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){
1045 const char *zQPV = aSubmenuCtrl[i].azChoice[j];
1046 @ <option value='%h(zQPV)'\
1047 if( fossil_strcmp(zVal, zQPV)==0 ){
@@ -1036,11 +1071,11 @@
1071 @ >%h(aSubmenuCtrl[i].zFalse)</option>
1072 @ </select>
1073 break;
1074 }
1075 case FF_CHECKBOX: {
1076 @ <label class='submenuctrl submenuckbox%s(zXtraClass) %s(zClass)'>\
1077 @ <input type='checkbox' name='%s(zQPN)' id='submenuctrl-%d(i)' \
1078 if( PB(zQPN) ){
1079 @ checked \
1080 }
1081 if( aSubmenuCtrl[i].zJS ){
1082

Keyboard Shortcuts

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