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).
Commit
e8a051e6a943a26c9c33a30df8ceda069c06c1747714cda73e1f10f4efce310d
Parent
5f6093314bcf38d…
1 file changed
+42
-7
+42
-7
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -921,10 +921,41 @@ | ||
| 921 | 921 | cgi_append_content("\n}\n", -1); |
| 922 | 922 | } |
| 923 | 923 | @ </script> |
| 924 | 924 | builtin_fulfill_js_requests(); |
| 925 | 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 | +} | |
| 926 | 957 | |
| 927 | 958 | /* |
| 928 | 959 | ** Invoke this routine after all of the content for a webpage has been |
| 929 | 960 | ** generated. This routine should be called once for every webpage, at |
| 930 | 961 | ** or near the end of page generation. This routine does the following: |
| @@ -950,10 +981,11 @@ | ||
| 950 | 981 | ** to the submenu while generating page text. |
| 951 | 982 | */ |
| 952 | 983 | cgi_destination(CGI_HEADER); |
| 953 | 984 | if( submenuEnable && nSubmenu+nSubmenuCtrl>0 ){ |
| 954 | 985 | int i; |
| 986 | + char zClass[32]; /* reduced form of the main attribute */ | |
| 955 | 987 | if( nSubmenuCtrl ){ |
| 956 | 988 | @ <form id='f01' method='GET' action='%R/%s(g.zPath)'> |
| 957 | 989 | @ <input type='hidden' name='udc' value='1'> |
| 958 | 990 | cgi_tag_query_parameter("udc"); |
| 959 | 991 | } |
| @@ -960,33 +992,36 @@ | ||
| 960 | 992 | @ <div class="submenu"> |
| 961 | 993 | if( nSubmenu>0 ){ |
| 962 | 994 | qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); |
| 963 | 995 | for(i=0; i<nSubmenu; i++){ |
| 964 | 996 | struct Submenu *p = &aSubmenu[i]; |
| 997 | + style_derive_classname(p->zLabel, zClass, sizeof zClass); | |
| 965 | 998 | /* switching away from the %h formatting below might be dangerous |
| 966 | 999 | ** 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. | |
| 968 | 1001 | */ |
| 969 | 1002 | if( p->zLink==0 ){ |
| 970 | - @ <span class="label">%h(p->zLabel)</span> | |
| 1003 | + @ <span class="label sml-%s(zClass)">%h(p->zLabel)</span> | |
| 971 | 1004 | }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> | |
| 973 | 1006 | } |
| 974 | 1007 | } |
| 975 | 1008 | } |
| 1009 | + strcpy(zClass,"smc-"); /* common prefix for submenu controls */ | |
| 976 | 1010 | for(i=0; i<nSubmenuCtrl; i++){ |
| 977 | 1011 | const char *zQPN = aSubmenuCtrl[i].zName; |
| 978 | 1012 | const char *zDisabled = ""; |
| 979 | 1013 | const char *zXtraClass = ""; |
| 980 | 1014 | if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){ |
| 981 | 1015 | zDisabled = " disabled"; |
| 982 | 1016 | }else if( zQPN ){ |
| 983 | 1017 | cgi_tag_query_parameter(zQPN); |
| 984 | 1018 | } |
| 1019 | + style_derive_classname(zQPN, zClass+4, sizeof(zClass)-4); | |
| 985 | 1020 | switch( aSubmenuCtrl[i].eType ){ |
| 986 | 1021 | case FF_ENTRY: |
| 987 | - @ <span class='submenuctrl%s(zXtraClass)'>\ | |
| 1022 | + @ <span class='submenuctrl%s(zXtraClass) %s(zClass)'>\ | |
| 988 | 1023 | @ %h(aSubmenuCtrl[i].zLabel)\ |
| 989 | 1024 | @ <input type='text' name='%s(zQPN)' value='%h(PD(zQPN, ""))' \ |
| 990 | 1025 | if( aSubmenuCtrl[i].iSize<0 ){ |
| 991 | 1026 | @ size='%d(-aSubmenuCtrl[i].iSize)' \ |
| 992 | 1027 | }else if( aSubmenuCtrl[i].iSize>0 ){ |
| @@ -997,16 +1032,16 @@ | ||
| 997 | 1032 | break; |
| 998 | 1033 | case FF_MULTI: { |
| 999 | 1034 | int j; |
| 1000 | 1035 | const char *zVal = P(zQPN); |
| 1001 | 1036 | if( zXtraClass[0] ){ |
| 1002 | - @ <span class='%s(zXtraClass+1)'> | |
| 1037 | + @ <span class='%s(zXtraClass+1) %s(zClass)'> | |
| 1003 | 1038 | } |
| 1004 | 1039 | if( aSubmenuCtrl[i].zLabel ){ |
| 1005 | 1040 | @ %h(aSubmenuCtrl[i].zLabel)\ |
| 1006 | 1041 | } |
| 1007 | - @ <select class='submenuctrl' size='1' name='%s(zQPN)' \ | |
| 1042 | + @ <select class='submenuctrl %s(zClass)' size='1' name='%s(zQPN)' \ | |
| 1008 | 1043 | @ id='submenuctrl-%d(i)'%s(zDisabled)> |
| 1009 | 1044 | for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){ |
| 1010 | 1045 | const char *zQPV = aSubmenuCtrl[i].azChoice[j]; |
| 1011 | 1046 | @ <option value='%h(zQPV)'\ |
| 1012 | 1047 | if( fossil_strcmp(zVal, zQPV)==0 ){ |
| @@ -1036,11 +1071,11 @@ | ||
| 1036 | 1071 | @ >%h(aSubmenuCtrl[i].zFalse)</option> |
| 1037 | 1072 | @ </select> |
| 1038 | 1073 | break; |
| 1039 | 1074 | } |
| 1040 | 1075 | case FF_CHECKBOX: { |
| 1041 | - @ <label class='submenuctrl submenuckbox%s(zXtraClass)'>\ | |
| 1076 | + @ <label class='submenuctrl submenuckbox%s(zXtraClass) %s(zClass)'>\ | |
| 1042 | 1077 | @ <input type='checkbox' name='%s(zQPN)' id='submenuctrl-%d(i)' \ |
| 1043 | 1078 | if( PB(zQPN) ){ |
| 1044 | 1079 | @ checked \ |
| 1045 | 1080 | } |
| 1046 | 1081 | if( aSubmenuCtrl[i].zJS ){ |
| 1047 | 1082 |
| --- 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 | @ %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 | @ %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 | @ %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 | @ %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 |