Fossil SCM
merge trunk
bddc40ced26df1b8e5e520103527c26267db8f73
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
Binary file
Binary file
Binary file
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -52,10 +52,11 @@ | ||
| 52 | 52 | */ |
| 53 | 53 | #define P(x) cgi_parameter((x),0) |
| 54 | 54 | #define PD(x,y) cgi_parameter((x),(y)) |
| 55 | 55 | #define PT(x) cgi_parameter_trimmed((x),0) |
| 56 | 56 | #define PDT(x,y) cgi_parameter_trimmed((x),(y)) |
| 57 | +#define PB(x) cgi_parameter_boolean(x) | |
| 57 | 58 | |
| 58 | 59 | |
| 59 | 60 | /* |
| 60 | 61 | ** Destinations for output text. |
| 61 | 62 | */ |
| @@ -436,11 +437,12 @@ | ||
| 436 | 437 | static int seqQP = 0; /* Sequence numbers */ |
| 437 | 438 | static struct QParam { /* One entry for each query parameter or cookie */ |
| 438 | 439 | const char *zName; /* Parameter or cookie name */ |
| 439 | 440 | const char *zValue; /* Value of the query parameter or cookie */ |
| 440 | 441 | int seq; /* Order of insertion */ |
| 441 | - int isQP; /* True for query parameters */ | |
| 442 | + char isQP; /* True for query parameters */ | |
| 443 | + char cTag; /* Tag on query parameters */ | |
| 442 | 444 | } *aParamQP; /* An array of all parameters and cookies */ |
| 443 | 445 | |
| 444 | 446 | /* |
| 445 | 447 | ** Add another query parameter or cookie to the parameter set. |
| 446 | 448 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -490,10 +492,21 @@ | ||
| 490 | 492 | aParamQP[i].zValue = zValue; |
| 491 | 493 | return; |
| 492 | 494 | } |
| 493 | 495 | } |
| 494 | 496 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 497 | +} | |
| 498 | +void cgi_replace_query_parameter(const char *zName, const char *zValue){ | |
| 499 | + int i; | |
| 500 | + for(i=0; i<nUsedQP; i++){ | |
| 501 | + if( fossil_strcmp(aParamQP[i].zName,zName)==0 ){ | |
| 502 | + aParamQP[i].zValue = zValue; | |
| 503 | + assert( aParamQP[i].isQP ); | |
| 504 | + return; | |
| 505 | + } | |
| 506 | + } | |
| 507 | + cgi_set_parameter_nocopy(zName, zValue, 1); | |
| 495 | 508 | } |
| 496 | 509 | |
| 497 | 510 | /* |
| 498 | 511 | ** Add a query parameter. The zName portion is fixed but a copy |
| 499 | 512 | ** must be made of zValue. |
| @@ -1064,10 +1077,20 @@ | ||
| 1064 | 1077 | zOut = fossil_strdup(zIn); |
| 1065 | 1078 | for(i=0; zOut[i]; i++){} |
| 1066 | 1079 | while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; |
| 1067 | 1080 | return zOut; |
| 1068 | 1081 | } |
| 1082 | + | |
| 1083 | +/* | |
| 1084 | +** Return true if the CGI parameter zName exists and is not equal to 0, | |
| 1085 | +** or "no" or "off". | |
| 1086 | +*/ | |
| 1087 | +int cgi_parameter_boolean(const char *zName){ | |
| 1088 | + const char *zIn = cgi_parameter(zName, 0); | |
| 1089 | + if( zIn==0 ) return 0; | |
| 1090 | + return zIn[0]==0 || is_truth(zIn); | |
| 1091 | +} | |
| 1069 | 1092 | |
| 1070 | 1093 | /* |
| 1071 | 1094 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 1072 | 1095 | ** are fewer than i registered CGI parameters. |
| 1073 | 1096 | */ |
| @@ -1142,23 +1165,51 @@ | ||
| 1142 | 1165 | cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); |
| 1143 | 1166 | } |
| 1144 | 1167 | } |
| 1145 | 1168 | |
| 1146 | 1169 | /* |
| 1147 | -** Export all query parameters (but not cookies or environment variables) | |
| 1148 | -** as hidden values of a form. | |
| 1170 | +** Export all untagged query parameters (but not cookies or environment | |
| 1171 | +** variables) as hidden values of a form. | |
| 1149 | 1172 | */ |
| 1150 | 1173 | void cgi_query_parameters_to_hidden(void){ |
| 1151 | 1174 | int i; |
| 1152 | 1175 | const char *zN, *zV; |
| 1153 | 1176 | for(i=0; i<nUsedQP; i++){ |
| 1154 | - if( aParamQP[i].isQP==0 ) continue; | |
| 1177 | + if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; | |
| 1155 | 1178 | zN = aParamQP[i].zName; |
| 1156 | 1179 | zV = aParamQP[i].zValue; |
| 1157 | 1180 | @ <input type="hidden" name="%h(zN)" value="%h(zV)"> |
| 1158 | 1181 | } |
| 1159 | 1182 | } |
| 1183 | + | |
| 1184 | +/* | |
| 1185 | +** Export all untagged query parameters (but not cookies or environment | |
| 1186 | +** variables) to the HQuery object. | |
| 1187 | +*/ | |
| 1188 | +void cgi_query_parameters_to_url(HQuery *p){ | |
| 1189 | + int i; | |
| 1190 | + for(i=0; i<nUsedQP; i++){ | |
| 1191 | + if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; | |
| 1192 | + url_add_parameter(p, aParamQP[i].zName, aParamQP[i].zValue); | |
| 1193 | + } | |
| 1194 | +} | |
| 1195 | + | |
| 1196 | +/* | |
| 1197 | +** Tag query parameter zName so that it is not exported by | |
| 1198 | +** cgi_query_parameters_to_hidden(). Or if zName==0, then | |
| 1199 | +** untag all query parameters. | |
| 1200 | +*/ | |
| 1201 | +void cgi_tag_query_parameter(const char *zName){ | |
| 1202 | + int i; | |
| 1203 | + if( zName==0 ){ | |
| 1204 | + for(i=0; i<nUsedQP; i++) aParamQP[i].cTag = 0; | |
| 1205 | + }else{ | |
| 1206 | + for(i=0; i<nUsedQP; i++){ | |
| 1207 | + if( strcmp(zName,aParamQP[i].zName)==0 ) aParamQP[i].cTag = 1; | |
| 1208 | + } | |
| 1209 | + } | |
| 1210 | +} | |
| 1160 | 1211 | |
| 1161 | 1212 | /* |
| 1162 | 1213 | ** This routine works like "printf" except that it has the |
| 1163 | 1214 | ** extra formatting capabilities such as %h and %t. |
| 1164 | 1215 | */ |
| 1165 | 1216 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -52,10 +52,11 @@ | |
| 52 | */ |
| 53 | #define P(x) cgi_parameter((x),0) |
| 54 | #define PD(x,y) cgi_parameter((x),(y)) |
| 55 | #define PT(x) cgi_parameter_trimmed((x),0) |
| 56 | #define PDT(x,y) cgi_parameter_trimmed((x),(y)) |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | ** Destinations for output text. |
| 61 | */ |
| @@ -436,11 +437,12 @@ | |
| 436 | static int seqQP = 0; /* Sequence numbers */ |
| 437 | static struct QParam { /* One entry for each query parameter or cookie */ |
| 438 | const char *zName; /* Parameter or cookie name */ |
| 439 | const char *zValue; /* Value of the query parameter or cookie */ |
| 440 | int seq; /* Order of insertion */ |
| 441 | int isQP; /* True for query parameters */ |
| 442 | } *aParamQP; /* An array of all parameters and cookies */ |
| 443 | |
| 444 | /* |
| 445 | ** Add another query parameter or cookie to the parameter set. |
| 446 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -490,10 +492,21 @@ | |
| 490 | aParamQP[i].zValue = zValue; |
| 491 | return; |
| 492 | } |
| 493 | } |
| 494 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 495 | } |
| 496 | |
| 497 | /* |
| 498 | ** Add a query parameter. The zName portion is fixed but a copy |
| 499 | ** must be made of zValue. |
| @@ -1064,10 +1077,20 @@ | |
| 1064 | zOut = fossil_strdup(zIn); |
| 1065 | for(i=0; zOut[i]; i++){} |
| 1066 | while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; |
| 1067 | return zOut; |
| 1068 | } |
| 1069 | |
| 1070 | /* |
| 1071 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 1072 | ** are fewer than i registered CGI parameters. |
| 1073 | */ |
| @@ -1142,23 +1165,51 @@ | |
| 1142 | cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); |
| 1143 | } |
| 1144 | } |
| 1145 | |
| 1146 | /* |
| 1147 | ** Export all query parameters (but not cookies or environment variables) |
| 1148 | ** as hidden values of a form. |
| 1149 | */ |
| 1150 | void cgi_query_parameters_to_hidden(void){ |
| 1151 | int i; |
| 1152 | const char *zN, *zV; |
| 1153 | for(i=0; i<nUsedQP; i++){ |
| 1154 | if( aParamQP[i].isQP==0 ) continue; |
| 1155 | zN = aParamQP[i].zName; |
| 1156 | zV = aParamQP[i].zValue; |
| 1157 | @ <input type="hidden" name="%h(zN)" value="%h(zV)"> |
| 1158 | } |
| 1159 | } |
| 1160 | |
| 1161 | /* |
| 1162 | ** This routine works like "printf" except that it has the |
| 1163 | ** extra formatting capabilities such as %h and %t. |
| 1164 | */ |
| 1165 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -52,10 +52,11 @@ | |
| 52 | */ |
| 53 | #define P(x) cgi_parameter((x),0) |
| 54 | #define PD(x,y) cgi_parameter((x),(y)) |
| 55 | #define PT(x) cgi_parameter_trimmed((x),0) |
| 56 | #define PDT(x,y) cgi_parameter_trimmed((x),(y)) |
| 57 | #define PB(x) cgi_parameter_boolean(x) |
| 58 | |
| 59 | |
| 60 | /* |
| 61 | ** Destinations for output text. |
| 62 | */ |
| @@ -436,11 +437,12 @@ | |
| 437 | static int seqQP = 0; /* Sequence numbers */ |
| 438 | static struct QParam { /* One entry for each query parameter or cookie */ |
| 439 | const char *zName; /* Parameter or cookie name */ |
| 440 | const char *zValue; /* Value of the query parameter or cookie */ |
| 441 | int seq; /* Order of insertion */ |
| 442 | char isQP; /* True for query parameters */ |
| 443 | char cTag; /* Tag on query parameters */ |
| 444 | } *aParamQP; /* An array of all parameters and cookies */ |
| 445 | |
| 446 | /* |
| 447 | ** Add another query parameter or cookie to the parameter set. |
| 448 | ** zName is the name of the query parameter or cookie and zValue |
| @@ -490,10 +492,21 @@ | |
| 492 | aParamQP[i].zValue = zValue; |
| 493 | return; |
| 494 | } |
| 495 | } |
| 496 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 497 | } |
| 498 | void cgi_replace_query_parameter(const char *zName, const char *zValue){ |
| 499 | int i; |
| 500 | for(i=0; i<nUsedQP; i++){ |
| 501 | if( fossil_strcmp(aParamQP[i].zName,zName)==0 ){ |
| 502 | aParamQP[i].zValue = zValue; |
| 503 | assert( aParamQP[i].isQP ); |
| 504 | return; |
| 505 | } |
| 506 | } |
| 507 | cgi_set_parameter_nocopy(zName, zValue, 1); |
| 508 | } |
| 509 | |
| 510 | /* |
| 511 | ** Add a query parameter. The zName portion is fixed but a copy |
| 512 | ** must be made of zValue. |
| @@ -1064,10 +1077,20 @@ | |
| 1077 | zOut = fossil_strdup(zIn); |
| 1078 | for(i=0; zOut[i]; i++){} |
| 1079 | while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; |
| 1080 | return zOut; |
| 1081 | } |
| 1082 | |
| 1083 | /* |
| 1084 | ** Return true if the CGI parameter zName exists and is not equal to 0, |
| 1085 | ** or "no" or "off". |
| 1086 | */ |
| 1087 | int cgi_parameter_boolean(const char *zName){ |
| 1088 | const char *zIn = cgi_parameter(zName, 0); |
| 1089 | if( zIn==0 ) return 0; |
| 1090 | return zIn[0]==0 || is_truth(zIn); |
| 1091 | } |
| 1092 | |
| 1093 | /* |
| 1094 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 1095 | ** are fewer than i registered CGI parameters. |
| 1096 | */ |
| @@ -1142,23 +1165,51 @@ | |
| 1165 | cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); |
| 1166 | } |
| 1167 | } |
| 1168 | |
| 1169 | /* |
| 1170 | ** Export all untagged query parameters (but not cookies or environment |
| 1171 | ** variables) as hidden values of a form. |
| 1172 | */ |
| 1173 | void cgi_query_parameters_to_hidden(void){ |
| 1174 | int i; |
| 1175 | const char *zN, *zV; |
| 1176 | for(i=0; i<nUsedQP; i++){ |
| 1177 | if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; |
| 1178 | zN = aParamQP[i].zName; |
| 1179 | zV = aParamQP[i].zValue; |
| 1180 | @ <input type="hidden" name="%h(zN)" value="%h(zV)"> |
| 1181 | } |
| 1182 | } |
| 1183 | |
| 1184 | /* |
| 1185 | ** Export all untagged query parameters (but not cookies or environment |
| 1186 | ** variables) to the HQuery object. |
| 1187 | */ |
| 1188 | void cgi_query_parameters_to_url(HQuery *p){ |
| 1189 | int i; |
| 1190 | for(i=0; i<nUsedQP; i++){ |
| 1191 | if( aParamQP[i].isQP==0 || aParamQP[i].cTag ) continue; |
| 1192 | url_add_parameter(p, aParamQP[i].zName, aParamQP[i].zValue); |
| 1193 | } |
| 1194 | } |
| 1195 | |
| 1196 | /* |
| 1197 | ** Tag query parameter zName so that it is not exported by |
| 1198 | ** cgi_query_parameters_to_hidden(). Or if zName==0, then |
| 1199 | ** untag all query parameters. |
| 1200 | */ |
| 1201 | void cgi_tag_query_parameter(const char *zName){ |
| 1202 | int i; |
| 1203 | if( zName==0 ){ |
| 1204 | for(i=0; i<nUsedQP; i++) aParamQP[i].cTag = 0; |
| 1205 | }else{ |
| 1206 | for(i=0; i<nUsedQP; i++){ |
| 1207 | if( strcmp(zName,aParamQP[i].zName)==0 ) aParamQP[i].cTag = 1; |
| 1208 | } |
| 1209 | } |
| 1210 | } |
| 1211 | |
| 1212 | /* |
| 1213 | ** This routine works like "printf" except that it has the |
| 1214 | ** extra formatting capabilities such as %h and %t. |
| 1215 | */ |
| 1216 |
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -785,8 +785,8 @@ | ||
| 785 | 785 | ** Search for documents that match a user-supplied pattern. |
| 786 | 786 | */ |
| 787 | 787 | void doc_search_page(void){ |
| 788 | 788 | login_check_credentials(); |
| 789 | 789 | style_header("Document Search"); |
| 790 | - search_screen(SRCH_DOC, "docsrch"); | |
| 790 | + search_screen(SRCH_DOC, 0); | |
| 791 | 791 | style_footer(); |
| 792 | 792 | } |
| 793 | 793 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -785,8 +785,8 @@ | |
| 785 | ** Search for documents that match a user-supplied pattern. |
| 786 | */ |
| 787 | void doc_search_page(void){ |
| 788 | login_check_credentials(); |
| 789 | style_header("Document Search"); |
| 790 | search_screen(SRCH_DOC, "docsrch"); |
| 791 | style_footer(); |
| 792 | } |
| 793 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -785,8 +785,8 @@ | |
| 785 | ** Search for documents that match a user-supplied pattern. |
| 786 | */ |
| 787 | void doc_search_page(void){ |
| 788 | login_check_credentials(); |
| 789 | style_header("Document Search"); |
| 790 | search_screen(SRCH_DOC, 0); |
| 791 | style_footer(); |
| 792 | } |
| 793 |
| --- src/event.c | ||
| +++ src/event.c | ||
| @@ -129,36 +129,32 @@ | ||
| 129 | 129 | if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ |
| 130 | 130 | style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s", |
| 131 | 131 | g.zTop, zEventId); |
| 132 | 132 | } |
| 133 | 133 | zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); |
| 134 | - style_submenu_element("Context", "Context", "%s/timeline?c=%T", | |
| 135 | - g.zTop, zETime); | |
| 134 | + style_submenu_element("Context", 0, "%R/timeline?c=%.20s", zEventId); | |
| 136 | 135 | if( g.perm.Hyperlink ){ |
| 137 | 136 | if( verboseFlag ){ |
| 138 | - style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", | |
| 139 | - g.zTop, zEventId, zUuid); | |
| 137 | + style_submenu_element("Plain", 0, "%R/event?name=%.20s&aid=%s", | |
| 138 | + zEventId, zUuid); | |
| 140 | 139 | if( nextRid ){ |
| 141 | 140 | char *zNext; |
| 142 | 141 | zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); |
| 143 | - style_submenu_element("Next", "Next", | |
| 144 | - "%s/event?name=%s&aid=%s&v", | |
| 145 | - g.zTop, zEventId, zNext); | |
| 142 | + style_submenu_element("Next", 0,"%R/event?name=%.20s&aid=%s&v", | |
| 143 | + zEventId, zNext); | |
| 146 | 144 | free(zNext); |
| 147 | 145 | } |
| 148 | 146 | if( prevRid ){ |
| 149 | 147 | char *zPrev; |
| 150 | 148 | zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); |
| 151 | - style_submenu_element("Prev", "Prev", | |
| 152 | - "%s/event?name=%s&aid=%s&v", | |
| 153 | - g.zTop, zEventId, zPrev); | |
| 149 | + style_submenu_element("Prev", 0, "%R/event?name=%s&aid=%s&v", | |
| 150 | + zEventId, zPrev); | |
| 154 | 151 | free(zPrev); |
| 155 | 152 | } |
| 156 | 153 | }else{ |
| 157 | - style_submenu_element("Detail", "Detail", | |
| 158 | - "%s/event?name=%s&aid=%s&v", | |
| 159 | - g.zTop, zEventId, zUuid); | |
| 154 | + style_submenu_element("Detail", 0, "%R/event?name=%.20s&aid=%s&v", | |
| 155 | + zEventId, zUuid); | |
| 160 | 156 | } |
| 161 | 157 | } |
| 162 | 158 | |
| 163 | 159 | if( verboseFlag && g.perm.Hyperlink ){ |
| 164 | 160 | int i; |
| 165 | 161 |
| --- src/event.c | |
| +++ src/event.c | |
| @@ -129,36 +129,32 @@ | |
| 129 | if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ |
| 130 | style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s", |
| 131 | g.zTop, zEventId); |
| 132 | } |
| 133 | zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); |
| 134 | style_submenu_element("Context", "Context", "%s/timeline?c=%T", |
| 135 | g.zTop, zETime); |
| 136 | if( g.perm.Hyperlink ){ |
| 137 | if( verboseFlag ){ |
| 138 | style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", |
| 139 | g.zTop, zEventId, zUuid); |
| 140 | if( nextRid ){ |
| 141 | char *zNext; |
| 142 | zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); |
| 143 | style_submenu_element("Next", "Next", |
| 144 | "%s/event?name=%s&aid=%s&v", |
| 145 | g.zTop, zEventId, zNext); |
| 146 | free(zNext); |
| 147 | } |
| 148 | if( prevRid ){ |
| 149 | char *zPrev; |
| 150 | zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); |
| 151 | style_submenu_element("Prev", "Prev", |
| 152 | "%s/event?name=%s&aid=%s&v", |
| 153 | g.zTop, zEventId, zPrev); |
| 154 | free(zPrev); |
| 155 | } |
| 156 | }else{ |
| 157 | style_submenu_element("Detail", "Detail", |
| 158 | "%s/event?name=%s&aid=%s&v", |
| 159 | g.zTop, zEventId, zUuid); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | if( verboseFlag && g.perm.Hyperlink ){ |
| 164 | int i; |
| 165 |
| --- src/event.c | |
| +++ src/event.c | |
| @@ -129,36 +129,32 @@ | |
| 129 | if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ |
| 130 | style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s", |
| 131 | g.zTop, zEventId); |
| 132 | } |
| 133 | zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); |
| 134 | style_submenu_element("Context", 0, "%R/timeline?c=%.20s", zEventId); |
| 135 | if( g.perm.Hyperlink ){ |
| 136 | if( verboseFlag ){ |
| 137 | style_submenu_element("Plain", 0, "%R/event?name=%.20s&aid=%s", |
| 138 | zEventId, zUuid); |
| 139 | if( nextRid ){ |
| 140 | char *zNext; |
| 141 | zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); |
| 142 | style_submenu_element("Next", 0,"%R/event?name=%.20s&aid=%s&v", |
| 143 | zEventId, zNext); |
| 144 | free(zNext); |
| 145 | } |
| 146 | if( prevRid ){ |
| 147 | char *zPrev; |
| 148 | zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); |
| 149 | style_submenu_element("Prev", 0, "%R/event?name=%s&aid=%s&v", |
| 150 | zEventId, zPrev); |
| 151 | free(zPrev); |
| 152 | } |
| 153 | }else{ |
| 154 | style_submenu_element("Detail", 0, "%R/event?name=%.20s&aid=%s&v", |
| 155 | zEventId, zUuid); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if( verboseFlag && g.perm.Hyperlink ){ |
| 160 | int i; |
| 161 |
No diff available
No diff available
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -1515,46 +1515,10 @@ | ||
| 1515 | 1515 | db_open_config(0); |
| 1516 | 1516 | |
| 1517 | 1517 | db_begin_transaction(); |
| 1518 | 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | 1519 | |
| 1520 | - if( strncmp(g.argv[2], "git", 3)==0 ){ | |
| 1521 | - /* The following temp-tables are used to hold information needed for | |
| 1522 | - ** the import. | |
| 1523 | - ** | |
| 1524 | - ** The XMARK table provides a mapping from fast-import "marks" and symbols | |
| 1525 | - ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). | |
| 1526 | - ** Given any valid fast-import symbol, the corresponding fossil rid and | |
| 1527 | - ** uuid can found by searching against the xmark.tname field. | |
| 1528 | - ** | |
| 1529 | - ** The XBRANCH table maps commit marks and symbols into the branch those | |
| 1530 | - ** commits belong to. If xbranch.tname is a fast-import symbol for a | |
| 1531 | - ** checkin then xbranch.brnm is the branch that checkin is part of. | |
| 1532 | - ** | |
| 1533 | - ** The XTAG table records information about tags that need to be applied | |
| 1534 | - ** to various branches after the import finishes. The xtag.tcontent field | |
| 1535 | - ** contains the text of an artifact that will add a tag to a check-in. | |
| 1536 | - ** The git-fast-export file format might specify the same tag multiple | |
| 1537 | - ** times but only the last tag should be used. And we do not know which | |
| 1538 | - ** occurrence of the tag is the last until the import finishes. | |
| 1539 | - */ | |
| 1540 | - db_multi_exec( | |
| 1541 | - "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" | |
| 1542 | - "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" | |
| 1543 | - "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" | |
| 1544 | - ); | |
| 1545 | - | |
| 1546 | - git_fast_import(pIn); | |
| 1547 | - db_prepare(&q, "SELECT tcontent FROM xtag"); | |
| 1548 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 1549 | - Blob record; | |
| 1550 | - db_ephemeral_blob(&q, 0, &record); | |
| 1551 | - fast_insert_content(&record, 0, 0); | |
| 1552 | - import_reset(0); | |
| 1553 | - } | |
| 1554 | - db_finalize(&q); | |
| 1555 | - }else | |
| 1556 | 1520 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1557 | 1521 | db_multi_exec( |
| 1558 | 1522 | "CREATE TEMP TABLE xrevisions(" |
| 1559 | 1523 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1560 | 1524 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | ||
| 1605 | 1569 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1606 | 1570 | gsvn.lenTags++; |
| 1607 | 1571 | } |
| 1608 | 1572 | } |
| 1609 | 1573 | svn_dump_import(pIn); |
| 1574 | + }else if( strncmp(g.argv[2], "git", 3)==0 ){ | |
| 1575 | + /* The following temp-tables are used to hold information needed for | |
| 1576 | + ** the import. | |
| 1577 | + ** | |
| 1578 | + ** The XMARK table provides a mapping from fast-import "marks" and symbols | |
| 1579 | + ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). | |
| 1580 | + ** Given any valid fast-import symbol, the corresponding fossil rid and | |
| 1581 | + ** uuid can found by searching against the xmark.tname field. | |
| 1582 | + ** | |
| 1583 | + ** The XBRANCH table maps commit marks and symbols into the branch those | |
| 1584 | + ** commits belong to. If xbranch.tname is a fast-import symbol for a | |
| 1585 | + ** checkin then xbranch.brnm is the branch that checkin is part of. | |
| 1586 | + ** | |
| 1587 | + ** The XTAG table records information about tags that need to be applied | |
| 1588 | + ** to various branches after the import finishes. The xtag.tcontent field | |
| 1589 | + ** contains the text of an artifact that will add a tag to a check-in. | |
| 1590 | + ** The git-fast-export file format might specify the same tag multiple | |
| 1591 | + ** times but only the last tag should be used. And we do not know which | |
| 1592 | + ** occurrence of the tag is the last until the import finishes. | |
| 1593 | + */ | |
| 1594 | + db_multi_exec( | |
| 1595 | + "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" | |
| 1596 | + "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" | |
| 1597 | + "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" | |
| 1598 | + ); | |
| 1599 | + | |
| 1600 | + git_fast_import(pIn); | |
| 1601 | + db_prepare(&q, "SELECT tcontent FROM xtag"); | |
| 1602 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1603 | + Blob record; | |
| 1604 | + db_ephemeral_blob(&q, 0, &record); | |
| 1605 | + fast_insert_content(&record, 0, 0); | |
| 1606 | + import_reset(0); | |
| 1607 | + } | |
| 1608 | + db_finalize(&q); | |
| 1610 | 1609 | } |
| 1611 | 1610 | |
| 1612 | 1611 | verify_cancel(); |
| 1613 | 1612 | db_end_transaction(0); |
| 1614 | 1613 | db_begin_transaction(); |
| 1615 | 1614 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -1515,46 +1515,10 @@ | |
| 1515 | db_open_config(0); |
| 1516 | |
| 1517 | db_begin_transaction(); |
| 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | |
| 1520 | if( strncmp(g.argv[2], "git", 3)==0 ){ |
| 1521 | /* The following temp-tables are used to hold information needed for |
| 1522 | ** the import. |
| 1523 | ** |
| 1524 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| 1525 | ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). |
| 1526 | ** Given any valid fast-import symbol, the corresponding fossil rid and |
| 1527 | ** uuid can found by searching against the xmark.tname field. |
| 1528 | ** |
| 1529 | ** The XBRANCH table maps commit marks and symbols into the branch those |
| 1530 | ** commits belong to. If xbranch.tname is a fast-import symbol for a |
| 1531 | ** checkin then xbranch.brnm is the branch that checkin is part of. |
| 1532 | ** |
| 1533 | ** The XTAG table records information about tags that need to be applied |
| 1534 | ** to various branches after the import finishes. The xtag.tcontent field |
| 1535 | ** contains the text of an artifact that will add a tag to a check-in. |
| 1536 | ** The git-fast-export file format might specify the same tag multiple |
| 1537 | ** times but only the last tag should be used. And we do not know which |
| 1538 | ** occurrence of the tag is the last until the import finishes. |
| 1539 | */ |
| 1540 | db_multi_exec( |
| 1541 | "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" |
| 1542 | "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" |
| 1543 | "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" |
| 1544 | ); |
| 1545 | |
| 1546 | git_fast_import(pIn); |
| 1547 | db_prepare(&q, "SELECT tcontent FROM xtag"); |
| 1548 | while( db_step(&q)==SQLITE_ROW ){ |
| 1549 | Blob record; |
| 1550 | db_ephemeral_blob(&q, 0, &record); |
| 1551 | fast_insert_content(&record, 0, 0); |
| 1552 | import_reset(0); |
| 1553 | } |
| 1554 | db_finalize(&q); |
| 1555 | }else |
| 1556 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1557 | db_multi_exec( |
| 1558 | "CREATE TEMP TABLE xrevisions(" |
| 1559 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1560 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | |
| 1605 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1606 | gsvn.lenTags++; |
| 1607 | } |
| 1608 | } |
| 1609 | svn_dump_import(pIn); |
| 1610 | } |
| 1611 | |
| 1612 | verify_cancel(); |
| 1613 | db_end_transaction(0); |
| 1614 | db_begin_transaction(); |
| 1615 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -1515,46 +1515,10 @@ | |
| 1515 | db_open_config(0); |
| 1516 | |
| 1517 | db_begin_transaction(); |
| 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | |
| 1520 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1521 | db_multi_exec( |
| 1522 | "CREATE TEMP TABLE xrevisions(" |
| 1523 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1524 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | |
| 1569 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1570 | gsvn.lenTags++; |
| 1571 | } |
| 1572 | } |
| 1573 | svn_dump_import(pIn); |
| 1574 | }else if( strncmp(g.argv[2], "git", 3)==0 ){ |
| 1575 | /* The following temp-tables are used to hold information needed for |
| 1576 | ** the import. |
| 1577 | ** |
| 1578 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| 1579 | ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). |
| 1580 | ** Given any valid fast-import symbol, the corresponding fossil rid and |
| 1581 | ** uuid can found by searching against the xmark.tname field. |
| 1582 | ** |
| 1583 | ** The XBRANCH table maps commit marks and symbols into the branch those |
| 1584 | ** commits belong to. If xbranch.tname is a fast-import symbol for a |
| 1585 | ** checkin then xbranch.brnm is the branch that checkin is part of. |
| 1586 | ** |
| 1587 | ** The XTAG table records information about tags that need to be applied |
| 1588 | ** to various branches after the import finishes. The xtag.tcontent field |
| 1589 | ** contains the text of an artifact that will add a tag to a check-in. |
| 1590 | ** The git-fast-export file format might specify the same tag multiple |
| 1591 | ** times but only the last tag should be used. And we do not know which |
| 1592 | ** occurrence of the tag is the last until the import finishes. |
| 1593 | */ |
| 1594 | db_multi_exec( |
| 1595 | "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" |
| 1596 | "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" |
| 1597 | "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" |
| 1598 | ); |
| 1599 | |
| 1600 | git_fast_import(pIn); |
| 1601 | db_prepare(&q, "SELECT tcontent FROM xtag"); |
| 1602 | while( db_step(&q)==SQLITE_ROW ){ |
| 1603 | Blob record; |
| 1604 | db_ephemeral_blob(&q, 0, &record); |
| 1605 | fast_insert_content(&record, 0, 0); |
| 1606 | import_reset(0); |
| 1607 | } |
| 1608 | db_finalize(&q); |
| 1609 | } |
| 1610 | |
| 1611 | verify_cancel(); |
| 1612 | db_end_transaction(0); |
| 1613 | db_begin_transaction(); |
| 1614 |
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -1515,46 +1515,10 @@ | ||
| 1515 | 1515 | db_open_config(0); |
| 1516 | 1516 | |
| 1517 | 1517 | db_begin_transaction(); |
| 1518 | 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | 1519 | |
| 1520 | - if( strncmp(g.argv[2], "git", 3)==0 ){ | |
| 1521 | - /* The following temp-tables are used to hold information needed for | |
| 1522 | - ** the import. | |
| 1523 | - ** | |
| 1524 | - ** The XMARK table provides a mapping from fast-import "marks" and symbols | |
| 1525 | - ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). | |
| 1526 | - ** Given any valid fast-import symbol, the corresponding fossil rid and | |
| 1527 | - ** uuid can found by searching against the xmark.tname field. | |
| 1528 | - ** | |
| 1529 | - ** The XBRANCH table maps commit marks and symbols into the branch those | |
| 1530 | - ** commits belong to. If xbranch.tname is a fast-import symbol for a | |
| 1531 | - ** checkin then xbranch.brnm is the branch that checkin is part of. | |
| 1532 | - ** | |
| 1533 | - ** The XTAG table records information about tags that need to be applied | |
| 1534 | - ** to various branches after the import finishes. The xtag.tcontent field | |
| 1535 | - ** contains the text of an artifact that will add a tag to a check-in. | |
| 1536 | - ** The git-fast-export file format might specify the same tag multiple | |
| 1537 | - ** times but only the last tag should be used. And we do not know which | |
| 1538 | - ** occurrence of the tag is the last until the import finishes. | |
| 1539 | - */ | |
| 1540 | - db_multi_exec( | |
| 1541 | - "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" | |
| 1542 | - "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" | |
| 1543 | - "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" | |
| 1544 | - ); | |
| 1545 | - | |
| 1546 | - git_fast_import(pIn); | |
| 1547 | - db_prepare(&q, "SELECT tcontent FROM xtag"); | |
| 1548 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 1549 | - Blob record; | |
| 1550 | - db_ephemeral_blob(&q, 0, &record); | |
| 1551 | - fast_insert_content(&record, 0, 0); | |
| 1552 | - import_reset(0); | |
| 1553 | - } | |
| 1554 | - db_finalize(&q); | |
| 1555 | - }else | |
| 1556 | 1520 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1557 | 1521 | db_multi_exec( |
| 1558 | 1522 | "CREATE TEMP TABLE xrevisions(" |
| 1559 | 1523 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1560 | 1524 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | ||
| 1605 | 1569 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1606 | 1570 | gsvn.lenTags++; |
| 1607 | 1571 | } |
| 1608 | 1572 | } |
| 1609 | 1573 | svn_dump_import(pIn); |
| 1574 | + }else if( strncmp(g.argv[2], "git", 3)==0 ){ | |
| 1575 | + /* The following temp-tables are used to hold information needed for | |
| 1576 | + ** the import. | |
| 1577 | + ** | |
| 1578 | + ** The XMARK table provides a mapping from fast-import "marks" and symbols | |
| 1579 | + ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). | |
| 1580 | + ** Given any valid fast-import symbol, the corresponding fossil rid and | |
| 1581 | + ** uuid can found by searching against the xmark.tname field. | |
| 1582 | + ** | |
| 1583 | + ** The XBRANCH table maps commit marks and symbols into the branch those | |
| 1584 | + ** commits belong to. If xbranch.tname is a fast-import symbol for a | |
| 1585 | + ** checkin then xbranch.brnm is the branch that checkin is part of. | |
| 1586 | + ** | |
| 1587 | + ** The XTAG table records information about tags that need to be applied | |
| 1588 | + ** to various branches after the import finishes. The xtag.tcontent field | |
| 1589 | + ** contains the text of an artifact that will add a tag to a check-in. | |
| 1590 | + ** The git-fast-export file format might specify the same tag multiple | |
| 1591 | + ** times but only the last tag should be used. And we do not know which | |
| 1592 | + ** occurrence of the tag is the last until the import finishes. | |
| 1593 | + */ | |
| 1594 | + db_multi_exec( | |
| 1595 | + "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" | |
| 1596 | + "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" | |
| 1597 | + "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" | |
| 1598 | + ); | |
| 1599 | + | |
| 1600 | + git_fast_import(pIn); | |
| 1601 | + db_prepare(&q, "SELECT tcontent FROM xtag"); | |
| 1602 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1603 | + Blob record; | |
| 1604 | + db_ephemeral_blob(&q, 0, &record); | |
| 1605 | + fast_insert_content(&record, 0, 0); | |
| 1606 | + import_reset(0); | |
| 1607 | + } | |
| 1608 | + db_finalize(&q); | |
| 1610 | 1609 | } |
| 1611 | 1610 | |
| 1612 | 1611 | verify_cancel(); |
| 1613 | 1612 | db_end_transaction(0); |
| 1614 | 1613 | db_begin_transaction(); |
| 1615 | 1614 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -1515,46 +1515,10 @@ | |
| 1515 | db_open_config(0); |
| 1516 | |
| 1517 | db_begin_transaction(); |
| 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | |
| 1520 | if( strncmp(g.argv[2], "git", 3)==0 ){ |
| 1521 | /* The following temp-tables are used to hold information needed for |
| 1522 | ** the import. |
| 1523 | ** |
| 1524 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| 1525 | ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). |
| 1526 | ** Given any valid fast-import symbol, the corresponding fossil rid and |
| 1527 | ** uuid can found by searching against the xmark.tname field. |
| 1528 | ** |
| 1529 | ** The XBRANCH table maps commit marks and symbols into the branch those |
| 1530 | ** commits belong to. If xbranch.tname is a fast-import symbol for a |
| 1531 | ** checkin then xbranch.brnm is the branch that checkin is part of. |
| 1532 | ** |
| 1533 | ** The XTAG table records information about tags that need to be applied |
| 1534 | ** to various branches after the import finishes. The xtag.tcontent field |
| 1535 | ** contains the text of an artifact that will add a tag to a check-in. |
| 1536 | ** The git-fast-export file format might specify the same tag multiple |
| 1537 | ** times but only the last tag should be used. And we do not know which |
| 1538 | ** occurrence of the tag is the last until the import finishes. |
| 1539 | */ |
| 1540 | db_multi_exec( |
| 1541 | "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" |
| 1542 | "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" |
| 1543 | "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" |
| 1544 | ); |
| 1545 | |
| 1546 | git_fast_import(pIn); |
| 1547 | db_prepare(&q, "SELECT tcontent FROM xtag"); |
| 1548 | while( db_step(&q)==SQLITE_ROW ){ |
| 1549 | Blob record; |
| 1550 | db_ephemeral_blob(&q, 0, &record); |
| 1551 | fast_insert_content(&record, 0, 0); |
| 1552 | import_reset(0); |
| 1553 | } |
| 1554 | db_finalize(&q); |
| 1555 | }else |
| 1556 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1557 | db_multi_exec( |
| 1558 | "CREATE TEMP TABLE xrevisions(" |
| 1559 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1560 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | |
| 1605 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1606 | gsvn.lenTags++; |
| 1607 | } |
| 1608 | } |
| 1609 | svn_dump_import(pIn); |
| 1610 | } |
| 1611 | |
| 1612 | verify_cancel(); |
| 1613 | db_end_transaction(0); |
| 1614 | db_begin_transaction(); |
| 1615 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -1515,46 +1515,10 @@ | |
| 1515 | db_open_config(0); |
| 1516 | |
| 1517 | db_begin_transaction(); |
| 1518 | if( !incrFlag ) db_initial_setup(0, 0, 0, 1); |
| 1519 | |
| 1520 | if( strncmp(g.argv[2], "svn", 3)==0 ){ |
| 1521 | db_multi_exec( |
| 1522 | "CREATE TEMP TABLE xrevisions(" |
| 1523 | " trev INTEGER, tbranch INT, trid INT, tparent INT DEFAULT 0," |
| 1524 | " UNIQUE(tbranch, trev)" |
| @@ -1605,10 +1569,45 @@ | |
| 1569 | gsvn.zTags = mprintf("%s/", gsvn.zTags); |
| 1570 | gsvn.lenTags++; |
| 1571 | } |
| 1572 | } |
| 1573 | svn_dump_import(pIn); |
| 1574 | }else if( strncmp(g.argv[2], "git", 3)==0 ){ |
| 1575 | /* The following temp-tables are used to hold information needed for |
| 1576 | ** the import. |
| 1577 | ** |
| 1578 | ** The XMARK table provides a mapping from fast-import "marks" and symbols |
| 1579 | ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts). |
| 1580 | ** Given any valid fast-import symbol, the corresponding fossil rid and |
| 1581 | ** uuid can found by searching against the xmark.tname field. |
| 1582 | ** |
| 1583 | ** The XBRANCH table maps commit marks and symbols into the branch those |
| 1584 | ** commits belong to. If xbranch.tname is a fast-import symbol for a |
| 1585 | ** checkin then xbranch.brnm is the branch that checkin is part of. |
| 1586 | ** |
| 1587 | ** The XTAG table records information about tags that need to be applied |
| 1588 | ** to various branches after the import finishes. The xtag.tcontent field |
| 1589 | ** contains the text of an artifact that will add a tag to a check-in. |
| 1590 | ** The git-fast-export file format might specify the same tag multiple |
| 1591 | ** times but only the last tag should be used. And we do not know which |
| 1592 | ** occurrence of the tag is the last until the import finishes. |
| 1593 | */ |
| 1594 | db_multi_exec( |
| 1595 | "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);" |
| 1596 | "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);" |
| 1597 | "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);" |
| 1598 | ); |
| 1599 | |
| 1600 | git_fast_import(pIn); |
| 1601 | db_prepare(&q, "SELECT tcontent FROM xtag"); |
| 1602 | while( db_step(&q)==SQLITE_ROW ){ |
| 1603 | Blob record; |
| 1604 | db_ephemeral_blob(&q, 0, &record); |
| 1605 | fast_insert_content(&record, 0, 0); |
| 1606 | import_reset(0); |
| 1607 | } |
| 1608 | db_finalize(&q); |
| 1609 | } |
| 1610 | |
| 1611 | verify_cancel(); |
| 1612 | db_end_transaction(0); |
| 1613 | db_begin_transaction(); |
| 1614 |
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -567,26 +567,33 @@ | ||
| 567 | 567 | /* |
| 568 | 568 | ** Remove bits from srchFlags which are disallowed by either the |
| 569 | 569 | ** current server configuration or by user permissions. |
| 570 | 570 | */ |
| 571 | 571 | unsigned int search_restrict(unsigned int srchFlags){ |
| 572 | + static unsigned int knownGood = 0; | |
| 573 | + static unsigned int knownBad = 0; | |
| 574 | + static const struct { unsigned m; const char *zKey; } aSetng[] = { | |
| 575 | + { SRCH_CKIN, "search-ci" }, | |
| 576 | + { SRCH_DOC, "search-doc" }, | |
| 577 | + { SRCH_TKT, "search-tkt" }, | |
| 578 | + { SRCH_WIKI, "search-wiki" }, | |
| 579 | + }; | |
| 580 | + int i; | |
| 572 | 581 | if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC); |
| 573 | 582 | if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT); |
| 574 | 583 | if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI); |
| 575 | - if( (srchFlags & SRCH_CKIN)!=0 && db_get_boolean("search-ci",0)==0 ){ | |
| 576 | - srchFlags &= ~SRCH_CKIN; | |
| 577 | - } | |
| 578 | - if( (srchFlags & SRCH_DOC)!=0 && db_get_boolean("search-doc",0)==0 ){ | |
| 579 | - srchFlags &= ~SRCH_DOC; | |
| 580 | - } | |
| 581 | - if( (srchFlags & SRCH_TKT)!=0 && db_get_boolean("search-tkt",0)==0 ){ | |
| 582 | - srchFlags &= ~SRCH_TKT; | |
| 583 | - } | |
| 584 | - if( (srchFlags & SRCH_WIKI)!=0 && db_get_boolean("search-wiki",0)==0 ){ | |
| 585 | - srchFlags &= ~SRCH_WIKI; | |
| 586 | - } | |
| 587 | - return srchFlags; | |
| 584 | + for(i=0; i<ArraySize(aSetng); i++){ | |
| 585 | + unsigned int m = aSetng[i].m; | |
| 586 | + if( (srchFlags & m)==0 ) continue; | |
| 587 | + if( ((knownGood|knownBad) & m)!=0 ) continue; | |
| 588 | + if( db_get_boolean(aSetng[i].zKey,0) ){ | |
| 589 | + knownGood |= m; | |
| 590 | + }else{ | |
| 591 | + knownBad |= m; | |
| 592 | + } | |
| 593 | + } | |
| 594 | + return srchFlags & ~knownBad; | |
| 588 | 595 | } |
| 589 | 596 | |
| 590 | 597 | /* |
| 591 | 598 | ** When this routine is called, there already exists a table |
| 592 | 599 | ** |
| @@ -875,46 +882,75 @@ | ||
| 875 | 882 | /* |
| 876 | 883 | ** Generate some HTML for doing search. At a minimum include the |
| 877 | 884 | ** Search-Text entry form. If the "s" query parameter is present, also |
| 878 | 885 | ** show search results. |
| 879 | 886 | ** |
| 880 | -** The srchFlags parameter is used to customize some of the text of the | |
| 881 | -** form and the results. srchFlags should be either a single search | |
| 882 | -** category or all categories. Any srchFlags with two or more bits set | |
| 887 | +** The srchFlags parameter restricts the set of documents to be searched. | |
| 888 | +** srchFlags should normally be either a single search category or all | |
| 889 | +** categories. Any srchFlags with two or more bits set | |
| 883 | 890 | ** is treated like SRCH_ALL for display purposes. |
| 884 | 891 | ** |
| 885 | -** The entry box is shown disabled if srchFlags is 0. | |
| 892 | +** This routine automatically restricts srchFlag according to user | |
| 893 | +** permissions and the server configuration. The entry box is shown | |
| 894 | +** disabled if srchFlags is 0 after these restrictions are applied. | |
| 895 | +** | |
| 896 | +** If useYparam is true, then this routine also looks at the y= query | |
| 897 | +** parameter for further search restrictions. | |
| 886 | 898 | */ |
| 887 | -void search_screen(unsigned srchFlags, const char *zAction){ | |
| 899 | +void search_screen(unsigned srchFlags, int useYparam){ | |
| 888 | 900 | const char *zType = 0; |
| 889 | 901 | const char *zClass = 0; |
| 890 | 902 | const char *zDisable1; |
| 891 | 903 | const char *zDisable2; |
| 892 | 904 | const char *zPattern; |
| 905 | + srchFlags = search_restrict(srchFlags); | |
| 893 | 906 | switch( srchFlags ){ |
| 894 | 907 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 895 | 908 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 896 | 909 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| 897 | 910 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 898 | 911 | } |
| 899 | - srchFlags = search_restrict(srchFlags); | |
| 900 | 912 | if( srchFlags==0 ){ |
| 901 | 913 | zDisable1 = " disabled"; |
| 902 | 914 | zDisable2 = " disabled"; |
| 903 | 915 | zPattern = ""; |
| 904 | 916 | }else{ |
| 905 | 917 | zDisable1 = " autofocus"; |
| 906 | 918 | zDisable2 = ""; |
| 907 | 919 | zPattern = PD("s",""); |
| 908 | 920 | } |
| 909 | - @ <form method='GET' action='%s(zAction)'> | |
| 921 | + @ <form method='GET' action='%R/%t(g.zPath)'> | |
| 910 | 922 | if( zClass ){ |
| 911 | 923 | @ <div class='searchForm searchForm%s(zClass)'> |
| 912 | 924 | }else{ |
| 913 | 925 | @ <div class='searchForm'> |
| 914 | 926 | } |
| 915 | 927 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 928 | + if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){ | |
| 929 | + static const struct { char *z; char *zNm; unsigned m; } aY[] = { | |
| 930 | + { "all", "All", SRCH_ALL }, | |
| 931 | + { "c", "Check-ins", SRCH_CKIN }, | |
| 932 | + { "d", "Docs", SRCH_DOC }, | |
| 933 | + { "t", "Tickets", SRCH_TKT }, | |
| 934 | + { "w", "Wiki", SRCH_WIKI }, | |
| 935 | + }; | |
| 936 | + const char *zY = PD("y","all"); | |
| 937 | + unsigned newFlags = srchFlags; | |
| 938 | + int i; | |
| 939 | + @ <select size='1' name='y'> | |
| 940 | + for(i=0; i<ArraySize(aY); i++){ | |
| 941 | + if( (aY[i].m & srchFlags)==0 ) continue; | |
| 942 | + cgi_printf("<option value='%s'", aY[i].z); | |
| 943 | + if( fossil_strcmp(zY,aY[i].z)==0 ){ | |
| 944 | + newFlags &= aY[i].m; | |
| 945 | + cgi_printf(" selected"); | |
| 946 | + } | |
| 947 | + cgi_printf(">%s</option>\n", aY[i].zNm); | |
| 948 | + } | |
| 949 | + @ </select> | |
| 950 | + srchFlags = newFlags; | |
| 951 | + } | |
| 916 | 952 | @ <input type="submit" value="Search%s(zType)"%s(zDisable2)> |
| 917 | 953 | if( srchFlags==0 ){ |
| 918 | 954 | @ <p class="generalError">Search is disabled</p> |
| 919 | 955 | } |
| 920 | 956 | @ </div></form> |
| @@ -937,22 +973,13 @@ | ||
| 937 | 973 | ** |
| 938 | 974 | ** Search for check-in comments, documents, tickets, or wiki that |
| 939 | 975 | ** match a user-supplied pattern. |
| 940 | 976 | */ |
| 941 | 977 | void search_page(void){ |
| 942 | - unsigned srchFlags = SRCH_ALL; | |
| 943 | - const char *zOnly = P("only"); | |
| 944 | - | |
| 945 | 978 | login_check_credentials(); |
| 946 | - if( zOnly ){ | |
| 947 | - if( strchr(zOnly,'c') ) srchFlags &= SRCH_CKIN; | |
| 948 | - if( strchr(zOnly,'d') ) srchFlags &= SRCH_DOC; | |
| 949 | - if( strchr(zOnly,'t') ) srchFlags &= SRCH_TKT; | |
| 950 | - if( strchr(zOnly,'w') ) srchFlags &= SRCH_WIKI; | |
| 951 | - } | |
| 952 | 979 | style_header("Search"); |
| 953 | - search_screen(srchFlags, "search"); | |
| 980 | + search_screen(SRCH_ALL, 1); | |
| 954 | 981 | style_footer(); |
| 955 | 982 | } |
| 956 | 983 | |
| 957 | 984 | |
| 958 | 985 | /* |
| @@ -1295,11 +1322,11 @@ | ||
| 1295 | 1322 | ); |
| 1296 | 1323 | db_multi_exec( |
| 1297 | 1324 | "REPLACE INTO ftsdocs(rowid,idxed,type,rid,name,label,url,mtime)" |
| 1298 | 1325 | " SELECT ftsdocs.rowid, 1, 'c', ftsdocs.rid, NULL," |
| 1299 | 1326 | " printf('Check-in [%%.16s] on %%s',blob.uuid,datetime(event.mtime))," |
| 1300 | - " printf('/timeline?y=ci&n=9&c=%%.20s',blob.uuid)," | |
| 1327 | + " printf('/timeline?y=ci&c=%%.20s',blob.uuid)," | |
| 1301 | 1328 | " event.mtime" |
| 1302 | 1329 | " FROM ftsdocs, event, blob" |
| 1303 | 1330 | " WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed" |
| 1304 | 1331 | " AND event.objid=ftsdocs.rid" |
| 1305 | 1332 | " AND blob.rid=ftsdocs.rid" |
| 1306 | 1333 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -567,26 +567,33 @@ | |
| 567 | /* |
| 568 | ** Remove bits from srchFlags which are disallowed by either the |
| 569 | ** current server configuration or by user permissions. |
| 570 | */ |
| 571 | unsigned int search_restrict(unsigned int srchFlags){ |
| 572 | if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC); |
| 573 | if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT); |
| 574 | if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI); |
| 575 | if( (srchFlags & SRCH_CKIN)!=0 && db_get_boolean("search-ci",0)==0 ){ |
| 576 | srchFlags &= ~SRCH_CKIN; |
| 577 | } |
| 578 | if( (srchFlags & SRCH_DOC)!=0 && db_get_boolean("search-doc",0)==0 ){ |
| 579 | srchFlags &= ~SRCH_DOC; |
| 580 | } |
| 581 | if( (srchFlags & SRCH_TKT)!=0 && db_get_boolean("search-tkt",0)==0 ){ |
| 582 | srchFlags &= ~SRCH_TKT; |
| 583 | } |
| 584 | if( (srchFlags & SRCH_WIKI)!=0 && db_get_boolean("search-wiki",0)==0 ){ |
| 585 | srchFlags &= ~SRCH_WIKI; |
| 586 | } |
| 587 | return srchFlags; |
| 588 | } |
| 589 | |
| 590 | /* |
| 591 | ** When this routine is called, there already exists a table |
| 592 | ** |
| @@ -875,46 +882,75 @@ | |
| 875 | /* |
| 876 | ** Generate some HTML for doing search. At a minimum include the |
| 877 | ** Search-Text entry form. If the "s" query parameter is present, also |
| 878 | ** show search results. |
| 879 | ** |
| 880 | ** The srchFlags parameter is used to customize some of the text of the |
| 881 | ** form and the results. srchFlags should be either a single search |
| 882 | ** category or all categories. Any srchFlags with two or more bits set |
| 883 | ** is treated like SRCH_ALL for display purposes. |
| 884 | ** |
| 885 | ** The entry box is shown disabled if srchFlags is 0. |
| 886 | */ |
| 887 | void search_screen(unsigned srchFlags, const char *zAction){ |
| 888 | const char *zType = 0; |
| 889 | const char *zClass = 0; |
| 890 | const char *zDisable1; |
| 891 | const char *zDisable2; |
| 892 | const char *zPattern; |
| 893 | switch( srchFlags ){ |
| 894 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 895 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 896 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| 897 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 898 | } |
| 899 | srchFlags = search_restrict(srchFlags); |
| 900 | if( srchFlags==0 ){ |
| 901 | zDisable1 = " disabled"; |
| 902 | zDisable2 = " disabled"; |
| 903 | zPattern = ""; |
| 904 | }else{ |
| 905 | zDisable1 = " autofocus"; |
| 906 | zDisable2 = ""; |
| 907 | zPattern = PD("s",""); |
| 908 | } |
| 909 | @ <form method='GET' action='%s(zAction)'> |
| 910 | if( zClass ){ |
| 911 | @ <div class='searchForm searchForm%s(zClass)'> |
| 912 | }else{ |
| 913 | @ <div class='searchForm'> |
| 914 | } |
| 915 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 916 | @ <input type="submit" value="Search%s(zType)"%s(zDisable2)> |
| 917 | if( srchFlags==0 ){ |
| 918 | @ <p class="generalError">Search is disabled</p> |
| 919 | } |
| 920 | @ </div></form> |
| @@ -937,22 +973,13 @@ | |
| 937 | ** |
| 938 | ** Search for check-in comments, documents, tickets, or wiki that |
| 939 | ** match a user-supplied pattern. |
| 940 | */ |
| 941 | void search_page(void){ |
| 942 | unsigned srchFlags = SRCH_ALL; |
| 943 | const char *zOnly = P("only"); |
| 944 | |
| 945 | login_check_credentials(); |
| 946 | if( zOnly ){ |
| 947 | if( strchr(zOnly,'c') ) srchFlags &= SRCH_CKIN; |
| 948 | if( strchr(zOnly,'d') ) srchFlags &= SRCH_DOC; |
| 949 | if( strchr(zOnly,'t') ) srchFlags &= SRCH_TKT; |
| 950 | if( strchr(zOnly,'w') ) srchFlags &= SRCH_WIKI; |
| 951 | } |
| 952 | style_header("Search"); |
| 953 | search_screen(srchFlags, "search"); |
| 954 | style_footer(); |
| 955 | } |
| 956 | |
| 957 | |
| 958 | /* |
| @@ -1295,11 +1322,11 @@ | |
| 1295 | ); |
| 1296 | db_multi_exec( |
| 1297 | "REPLACE INTO ftsdocs(rowid,idxed,type,rid,name,label,url,mtime)" |
| 1298 | " SELECT ftsdocs.rowid, 1, 'c', ftsdocs.rid, NULL," |
| 1299 | " printf('Check-in [%%.16s] on %%s',blob.uuid,datetime(event.mtime))," |
| 1300 | " printf('/timeline?y=ci&n=9&c=%%.20s',blob.uuid)," |
| 1301 | " event.mtime" |
| 1302 | " FROM ftsdocs, event, blob" |
| 1303 | " WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed" |
| 1304 | " AND event.objid=ftsdocs.rid" |
| 1305 | " AND blob.rid=ftsdocs.rid" |
| 1306 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -567,26 +567,33 @@ | |
| 567 | /* |
| 568 | ** Remove bits from srchFlags which are disallowed by either the |
| 569 | ** current server configuration or by user permissions. |
| 570 | */ |
| 571 | unsigned int search_restrict(unsigned int srchFlags){ |
| 572 | static unsigned int knownGood = 0; |
| 573 | static unsigned int knownBad = 0; |
| 574 | static const struct { unsigned m; const char *zKey; } aSetng[] = { |
| 575 | { SRCH_CKIN, "search-ci" }, |
| 576 | { SRCH_DOC, "search-doc" }, |
| 577 | { SRCH_TKT, "search-tkt" }, |
| 578 | { SRCH_WIKI, "search-wiki" }, |
| 579 | }; |
| 580 | int i; |
| 581 | if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC); |
| 582 | if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT); |
| 583 | if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI); |
| 584 | for(i=0; i<ArraySize(aSetng); i++){ |
| 585 | unsigned int m = aSetng[i].m; |
| 586 | if( (srchFlags & m)==0 ) continue; |
| 587 | if( ((knownGood|knownBad) & m)!=0 ) continue; |
| 588 | if( db_get_boolean(aSetng[i].zKey,0) ){ |
| 589 | knownGood |= m; |
| 590 | }else{ |
| 591 | knownBad |= m; |
| 592 | } |
| 593 | } |
| 594 | return srchFlags & ~knownBad; |
| 595 | } |
| 596 | |
| 597 | /* |
| 598 | ** When this routine is called, there already exists a table |
| 599 | ** |
| @@ -875,46 +882,75 @@ | |
| 882 | /* |
| 883 | ** Generate some HTML for doing search. At a minimum include the |
| 884 | ** Search-Text entry form. If the "s" query parameter is present, also |
| 885 | ** show search results. |
| 886 | ** |
| 887 | ** The srchFlags parameter restricts the set of documents to be searched. |
| 888 | ** srchFlags should normally be either a single search category or all |
| 889 | ** categories. Any srchFlags with two or more bits set |
| 890 | ** is treated like SRCH_ALL for display purposes. |
| 891 | ** |
| 892 | ** This routine automatically restricts srchFlag according to user |
| 893 | ** permissions and the server configuration. The entry box is shown |
| 894 | ** disabled if srchFlags is 0 after these restrictions are applied. |
| 895 | ** |
| 896 | ** If useYparam is true, then this routine also looks at the y= query |
| 897 | ** parameter for further search restrictions. |
| 898 | */ |
| 899 | void search_screen(unsigned srchFlags, int useYparam){ |
| 900 | const char *zType = 0; |
| 901 | const char *zClass = 0; |
| 902 | const char *zDisable1; |
| 903 | const char *zDisable2; |
| 904 | const char *zPattern; |
| 905 | srchFlags = search_restrict(srchFlags); |
| 906 | switch( srchFlags ){ |
| 907 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 908 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 909 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| 910 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 911 | } |
| 912 | if( srchFlags==0 ){ |
| 913 | zDisable1 = " disabled"; |
| 914 | zDisable2 = " disabled"; |
| 915 | zPattern = ""; |
| 916 | }else{ |
| 917 | zDisable1 = " autofocus"; |
| 918 | zDisable2 = ""; |
| 919 | zPattern = PD("s",""); |
| 920 | } |
| 921 | @ <form method='GET' action='%R/%t(g.zPath)'> |
| 922 | if( zClass ){ |
| 923 | @ <div class='searchForm searchForm%s(zClass)'> |
| 924 | }else{ |
| 925 | @ <div class='searchForm'> |
| 926 | } |
| 927 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 928 | if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){ |
| 929 | static const struct { char *z; char *zNm; unsigned m; } aY[] = { |
| 930 | { "all", "All", SRCH_ALL }, |
| 931 | { "c", "Check-ins", SRCH_CKIN }, |
| 932 | { "d", "Docs", SRCH_DOC }, |
| 933 | { "t", "Tickets", SRCH_TKT }, |
| 934 | { "w", "Wiki", SRCH_WIKI }, |
| 935 | }; |
| 936 | const char *zY = PD("y","all"); |
| 937 | unsigned newFlags = srchFlags; |
| 938 | int i; |
| 939 | @ <select size='1' name='y'> |
| 940 | for(i=0; i<ArraySize(aY); i++){ |
| 941 | if( (aY[i].m & srchFlags)==0 ) continue; |
| 942 | cgi_printf("<option value='%s'", aY[i].z); |
| 943 | if( fossil_strcmp(zY,aY[i].z)==0 ){ |
| 944 | newFlags &= aY[i].m; |
| 945 | cgi_printf(" selected"); |
| 946 | } |
| 947 | cgi_printf(">%s</option>\n", aY[i].zNm); |
| 948 | } |
| 949 | @ </select> |
| 950 | srchFlags = newFlags; |
| 951 | } |
| 952 | @ <input type="submit" value="Search%s(zType)"%s(zDisable2)> |
| 953 | if( srchFlags==0 ){ |
| 954 | @ <p class="generalError">Search is disabled</p> |
| 955 | } |
| 956 | @ </div></form> |
| @@ -937,22 +973,13 @@ | |
| 973 | ** |
| 974 | ** Search for check-in comments, documents, tickets, or wiki that |
| 975 | ** match a user-supplied pattern. |
| 976 | */ |
| 977 | void search_page(void){ |
| 978 | login_check_credentials(); |
| 979 | style_header("Search"); |
| 980 | search_screen(SRCH_ALL, 1); |
| 981 | style_footer(); |
| 982 | } |
| 983 | |
| 984 | |
| 985 | /* |
| @@ -1295,11 +1322,11 @@ | |
| 1322 | ); |
| 1323 | db_multi_exec( |
| 1324 | "REPLACE INTO ftsdocs(rowid,idxed,type,rid,name,label,url,mtime)" |
| 1325 | " SELECT ftsdocs.rowid, 1, 'c', ftsdocs.rid, NULL," |
| 1326 | " printf('Check-in [%%.16s] on %%s',blob.uuid,datetime(event.mtime))," |
| 1327 | " printf('/timeline?y=ci&c=%%.20s',blob.uuid)," |
| 1328 | " event.mtime" |
| 1329 | " FROM ftsdocs, event, blob" |
| 1330 | " WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed" |
| 1331 | " AND event.objid=ftsdocs.rid" |
| 1332 | " AND blob.rid=ftsdocs.rid" |
| 1333 |
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -1263,10 +1263,27 @@ | ||
| 1263 | 1263 | @ <p><form action="%s(g.zTop)/setup_login_group" method="post"><div> |
| 1264 | 1264 | login_insert_csrf_secret(); |
| 1265 | 1265 | @ To leave this login group press |
| 1266 | 1266 | @ <input type="submit" value="Leave Login Group" name="leave"> |
| 1267 | 1267 | @ </form></p> |
| 1268 | + @ <hr><h2>Implementation Details</h2> | |
| 1269 | + @ <p>The following are fields from the CONFIG table related to login-groups, | |
| 1270 | + @ provided here for instructional and debugging purposes:</p> | |
| 1271 | + @ <table border='1' id='configTab'> | |
| 1272 | + @ <thead><tr><th>Config.Name<th>Config.Value<th>Config.mtime</tr></thead><tbody> | |
| 1273 | + db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config" | |
| 1274 | + " WHERE name GLOB 'peer-*'" | |
| 1275 | + " OR name GLOB 'project-*'" | |
| 1276 | + " ORDER BY name"); | |
| 1277 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1278 | + @ <tr><td>%h(db_column_text(&q,0))</td> | |
| 1279 | + @ <td>%h(db_column_text(&q,1))</td> | |
| 1280 | + @ <td>%h(db_column_text(&q,2))</td></tr> | |
| 1281 | + } | |
| 1282 | + db_finalize(&q); | |
| 1283 | + @ </tbody></table> | |
| 1284 | + output_table_sorting_javascript("configTab","ttt",1); | |
| 1268 | 1285 | } |
| 1269 | 1286 | style_footer(); |
| 1270 | 1287 | } |
| 1271 | 1288 | |
| 1272 | 1289 | /* |
| 1273 | 1290 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1263,10 +1263,27 @@ | |
| 1263 | @ <p><form action="%s(g.zTop)/setup_login_group" method="post"><div> |
| 1264 | login_insert_csrf_secret(); |
| 1265 | @ To leave this login group press |
| 1266 | @ <input type="submit" value="Leave Login Group" name="leave"> |
| 1267 | @ </form></p> |
| 1268 | } |
| 1269 | style_footer(); |
| 1270 | } |
| 1271 | |
| 1272 | /* |
| 1273 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1263,10 +1263,27 @@ | |
| 1263 | @ <p><form action="%s(g.zTop)/setup_login_group" method="post"><div> |
| 1264 | login_insert_csrf_secret(); |
| 1265 | @ To leave this login group press |
| 1266 | @ <input type="submit" value="Leave Login Group" name="leave"> |
| 1267 | @ </form></p> |
| 1268 | @ <hr><h2>Implementation Details</h2> |
| 1269 | @ <p>The following are fields from the CONFIG table related to login-groups, |
| 1270 | @ provided here for instructional and debugging purposes:</p> |
| 1271 | @ <table border='1' id='configTab'> |
| 1272 | @ <thead><tr><th>Config.Name<th>Config.Value<th>Config.mtime</tr></thead><tbody> |
| 1273 | db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config" |
| 1274 | " WHERE name GLOB 'peer-*'" |
| 1275 | " OR name GLOB 'project-*'" |
| 1276 | " ORDER BY name"); |
| 1277 | while( db_step(&q)==SQLITE_ROW ){ |
| 1278 | @ <tr><td>%h(db_column_text(&q,0))</td> |
| 1279 | @ <td>%h(db_column_text(&q,1))</td> |
| 1280 | @ <td>%h(db_column_text(&q,2))</td></tr> |
| 1281 | } |
| 1282 | db_finalize(&q); |
| 1283 | @ </tbody></table> |
| 1284 | output_table_sorting_javascript("configTab","ttt",1); |
| 1285 | } |
| 1286 | style_footer(); |
| 1287 | } |
| 1288 | |
| 1289 | /* |
| 1290 |
No diff available
| --- src/sitemap.c | ||
| +++ src/sitemap.c | ||
| @@ -44,11 +44,11 @@ | ||
| 44 | 44 | @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li> |
| 45 | 45 | @ </ul> |
| 46 | 46 | @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li> |
| 47 | 47 | @ <ul> |
| 48 | 48 | @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10 checkins</a></li> |
| 49 | - @ <li>%z(href("%R/timeline?n=0&namechng"))All checkins with file name | |
| 49 | + @ <li>%z(href("%R/timeline?n=all&namechng"))All checkins with file name | |
| 50 | 50 | @ changes</a></li> |
| 51 | 51 | @ <li>%z(href("%R/reports"))Activity Reports</a></li> |
| 52 | 52 | @ </ul> |
| 53 | 53 | @ <li>Branches and Tags</a> |
| 54 | 54 | @ <ul> |
| 55 | 55 |
| --- src/sitemap.c | |
| +++ src/sitemap.c | |
| @@ -44,11 +44,11 @@ | |
| 44 | @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li> |
| 45 | @ </ul> |
| 46 | @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li> |
| 47 | @ <ul> |
| 48 | @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10 checkins</a></li> |
| 49 | @ <li>%z(href("%R/timeline?n=0&namechng"))All checkins with file name |
| 50 | @ changes</a></li> |
| 51 | @ <li>%z(href("%R/reports"))Activity Reports</a></li> |
| 52 | @ </ul> |
| 53 | @ <li>Branches and Tags</a> |
| 54 | @ <ul> |
| 55 |
| --- src/sitemap.c | |
| +++ src/sitemap.c | |
| @@ -44,11 +44,11 @@ | |
| 44 | @ <li>%z(href("%R/fileage?name=trunk"))File ages for Trunk</a></li> |
| 45 | @ </ul> |
| 46 | @ <li>%z(href("%R/timeline?n=200"))Project Timeline</a></li> |
| 47 | @ <ul> |
| 48 | @ <li>%z(href("%R/timeline?a=1970-01-01&y=ci&n=10"))First 10 checkins</a></li> |
| 49 | @ <li>%z(href("%R/timeline?n=all&namechng"))All checkins with file name |
| 50 | @ changes</a></li> |
| 51 | @ <li>%z(href("%R/reports"))Activity Reports</a></li> |
| 52 | @ </ul> |
| 53 | @ <li>Branches and Tags</a> |
| 54 | @ <ul> |
| 55 |
No diff available
No diff available
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -23,21 +23,42 @@ | ||
| 23 | 23 | #include "style.h" |
| 24 | 24 | |
| 25 | 25 | |
| 26 | 26 | /* |
| 27 | 27 | ** Elements of the submenu are collected into the following |
| 28 | -** structure and displayed below the main menu by style_header(). | |
| 28 | +** structure and displayed below the main menu. | |
| 29 | +** | |
| 30 | +** Populate these structure with calls to | |
| 31 | +** | |
| 32 | +** style_submenu_element() | |
| 33 | +** style_submenu_entry() | |
| 34 | +** style_submenu_checkbox() | |
| 35 | +** style_submenu_multichoice() | |
| 29 | 36 | ** |
| 30 | -** Populate this structure with calls to style_submenu_element() | |
| 31 | -** prior to calling style_header(). | |
| 37 | +** prior to calling style_footer(). The style_footer() routine | |
| 38 | +** will generate the appropriate HTML text just below the main | |
| 39 | +** menu. | |
| 32 | 40 | */ |
| 33 | 41 | static struct Submenu { |
| 34 | - const char *zLabel; | |
| 42 | + const char *zLabel; /* Button label */ | |
| 35 | 43 | const char *zTitle; |
| 36 | - const char *zLink; | |
| 44 | + const char *zLink; /* Jump to this link when button is pressed */ | |
| 37 | 45 | } aSubmenu[30]; |
| 38 | -static int nSubmenu = 0; | |
| 46 | +static int nSubmenu = 0; /* Number of buttons */ | |
| 47 | +static struct SubmenuCtrl { | |
| 48 | + const char *zName; /* Form query parameter */ | |
| 49 | + const char *zLabel; /* Label. Might be NULL for FF_MULTI */ | |
| 50 | + int eType; /* FF_ENTRY, FF_CKBOX, FF_MULTI */ | |
| 51 | + int iSize; /* Width for FF_ENTRY. Count for FF_MULTI */ | |
| 52 | + const char **azChoice; /* value/display pairs for FF_MULTI */ | |
| 53 | + const char *zFalse; /* FF_BINARY label when false */ | |
| 54 | +} aSubmenuCtrl[20]; | |
| 55 | +static int nSubmenuCtrl = 0; | |
| 56 | +#define FF_ENTRY 1 | |
| 57 | +#define FF_CKBOX 2 | |
| 58 | +#define FF_MULTI 3 | |
| 59 | +#define FF_BINARY 4 | |
| 39 | 60 | |
| 40 | 61 | /* |
| 41 | 62 | ** Remember that the header has been generated. The footer is omitted |
| 42 | 63 | ** if an error occurs before the header. |
| 43 | 64 | */ |
| @@ -216,16 +237,63 @@ | ||
| 216 | 237 | ... |
| 217 | 238 | ){ |
| 218 | 239 | va_list ap; |
| 219 | 240 | assert( nSubmenu < sizeof(aSubmenu)/sizeof(aSubmenu[0]) ); |
| 220 | 241 | aSubmenu[nSubmenu].zLabel = zLabel; |
| 221 | - aSubmenu[nSubmenu].zTitle = zTitle; | |
| 242 | + aSubmenu[nSubmenu].zTitle = zTitle ? zTitle : zLabel; | |
| 222 | 243 | va_start(ap, zLink); |
| 223 | 244 | aSubmenu[nSubmenu].zLink = vmprintf(zLink, ap); |
| 224 | 245 | va_end(ap); |
| 225 | 246 | nSubmenu++; |
| 226 | 247 | } |
| 248 | +void style_submenu_entry( | |
| 249 | + const char *zName, /* Query parameter name */ | |
| 250 | + const char *zLabel, /* Label before the entry box */ | |
| 251 | + int iSize /* Size of the entry box */ | |
| 252 | +){ | |
| 253 | + assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); | |
| 254 | + aSubmenuCtrl[nSubmenuCtrl].zName = zName; | |
| 255 | + aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel; | |
| 256 | + aSubmenuCtrl[nSubmenuCtrl].iSize = iSize; | |
| 257 | + aSubmenuCtrl[nSubmenuCtrl].eType = FF_ENTRY; | |
| 258 | + nSubmenuCtrl++; | |
| 259 | +} | |
| 260 | +void style_submenu_checkbox( | |
| 261 | + const char *zName, /* Query parameter name */ | |
| 262 | + const char *zLabel /* Label before the checkbox */ | |
| 263 | +){ | |
| 264 | + assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); | |
| 265 | + aSubmenuCtrl[nSubmenuCtrl].zName = zName; | |
| 266 | + aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel; | |
| 267 | + aSubmenuCtrl[nSubmenuCtrl].eType = FF_CKBOX; | |
| 268 | + nSubmenuCtrl++; | |
| 269 | +} | |
| 270 | +void style_submenu_binary( | |
| 271 | + const char *zName, /* Query parameter name */ | |
| 272 | + const char *zTrue, /* Label to show when parameter is true */ | |
| 273 | + const char *zFalse /* Label to show when the parameter is false */ | |
| 274 | +){ | |
| 275 | + assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); | |
| 276 | + aSubmenuCtrl[nSubmenuCtrl].zName = zName; | |
| 277 | + aSubmenuCtrl[nSubmenuCtrl].zLabel = zTrue; | |
| 278 | + aSubmenuCtrl[nSubmenuCtrl].zFalse = zFalse; | |
| 279 | + aSubmenuCtrl[nSubmenuCtrl].eType = FF_BINARY; | |
| 280 | + nSubmenuCtrl++; | |
| 281 | +} | |
| 282 | +void style_submenu_multichoice( | |
| 283 | + const char *zName, /* Query parameter name */ | |
| 284 | + int nChoice, /* Number of options */ | |
| 285 | + const char **azChoice /* value/display pairs. 2*nChoice entries */ | |
| 286 | +){ | |
| 287 | + assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); | |
| 288 | + aSubmenuCtrl[nSubmenuCtrl].zName = zName; | |
| 289 | + aSubmenuCtrl[nSubmenuCtrl].iSize = nChoice; | |
| 290 | + aSubmenuCtrl[nSubmenuCtrl].azChoice = azChoice; | |
| 291 | + aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI; | |
| 292 | + nSubmenuCtrl++; | |
| 293 | +} | |
| 294 | + | |
| 227 | 295 | |
| 228 | 296 | /* |
| 229 | 297 | ** Compare two submenu items for sorting purposes |
| 230 | 298 | */ |
| 231 | 299 | static int submenuCompare(const void *a, const void *b){ |
| @@ -411,23 +479,102 @@ | ||
| 411 | 479 | /* Go back and put the submenu at the top of the page. We delay the |
| 412 | 480 | ** creation of the submenu until the end so that we can add elements |
| 413 | 481 | ** to the submenu while generating page text. |
| 414 | 482 | */ |
| 415 | 483 | cgi_destination(CGI_HEADER); |
| 416 | - if( nSubmenu>0 ){ | |
| 484 | + if( nSubmenu+nSubmenuCtrl>0 ){ | |
| 417 | 485 | int i; |
| 486 | + if( nSubmenuCtrl ){ | |
| 487 | + cgi_printf("<form id='f01' method='GET' action='%R/%s'>", g.zPath); | |
| 488 | + } | |
| 418 | 489 | @ <div class="submenu"> |
| 419 | - qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); | |
| 420 | - for(i=0; i<nSubmenu; i++){ | |
| 421 | - struct Submenu *p = &aSubmenu[i]; | |
| 422 | - if( p->zLink==0 ){ | |
| 423 | - @ <span class="label">%h(p->zLabel)</span> | |
| 424 | - }else{ | |
| 425 | - @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a> | |
| 490 | + if( nSubmenu>0 ){ | |
| 491 | + qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); | |
| 492 | + for(i=0; i<nSubmenu; i++){ | |
| 493 | + struct Submenu *p = &aSubmenu[i]; | |
| 494 | + if( p->zLink==0 ){ | |
| 495 | + @ <span class="label">%h(p->zLabel)</span> | |
| 496 | + }else{ | |
| 497 | + @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a> | |
| 498 | + } | |
| 499 | + } | |
| 500 | + } | |
| 501 | + if( nSubmenuCtrl>0 ){ | |
| 502 | + for(i=0; i<nSubmenuCtrl; i++){ | |
| 503 | + const char *zQPN = aSubmenuCtrl[i].zName; | |
| 504 | + cgi_tag_query_parameter(zQPN); | |
| 505 | + switch( aSubmenuCtrl[i].eType ){ | |
| 506 | + case FF_ENTRY: { | |
| 507 | + cgi_printf( | |
| 508 | + "<span class='submenuctrl'>" | |
| 509 | + "%h: <input type='text' name='%s' size='%d' " | |
| 510 | + "value='%h'></span>\n", | |
| 511 | + aSubmenuCtrl[i].zLabel, | |
| 512 | + zQPN, | |
| 513 | + aSubmenuCtrl[i].iSize, | |
| 514 | + PD(zQPN,"") | |
| 515 | + ); | |
| 516 | + break; | |
| 517 | + } | |
| 518 | + case FF_CKBOX: { | |
| 519 | + cgi_printf( | |
| 520 | + "<span class='submenuctrl'>" | |
| 521 | + "%h: <input type='checkbox' name='%s'%s " | |
| 522 | + "onchange='gebi(\"f01\").submit();'></span>\n", | |
| 523 | + aSubmenuCtrl[i].zLabel, | |
| 524 | + zQPN, | |
| 525 | + PB(zQPN) ? " checked":"" | |
| 526 | + ); | |
| 527 | + break; | |
| 528 | + } | |
| 529 | + case FF_MULTI: { | |
| 530 | + int j; | |
| 531 | + const char *zVal = P(zQPN); | |
| 532 | + cgi_printf( | |
| 533 | + "<select class='submenuctrl' size='1' name='%s' " | |
| 534 | + "onchange='gebi(\"f01\").submit();'>\n", | |
| 535 | + zQPN | |
| 536 | + ); | |
| 537 | + for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){ | |
| 538 | + const char *zQPV = aSubmenuCtrl[i].azChoice[j]; | |
| 539 | + cgi_printf( | |
| 540 | + "<option value='%h'%s>%h</option>\n", | |
| 541 | + zQPV, | |
| 542 | + fossil_strcmp(zVal,zQPV)==0 ? " selected" : "", | |
| 543 | + aSubmenuCtrl[i].azChoice[j+1] | |
| 544 | + ); | |
| 545 | + } | |
| 546 | + @ </select> | |
| 547 | + break; | |
| 548 | + } | |
| 549 | + case FF_BINARY: { | |
| 550 | + int isTrue = PB(zQPN); | |
| 551 | + cgi_printf( | |
| 552 | + "<select class='submenuctrl' size='1' name='%s' " | |
| 553 | + "onchange='gebi(\"f01\").submit();'>\n", | |
| 554 | + zQPN | |
| 555 | + ); | |
| 556 | + cgi_printf( | |
| 557 | + "<option value='1'%s>%h</option>\n", | |
| 558 | + isTrue ? " selected":"", aSubmenuCtrl[i].zLabel | |
| 559 | + ); | |
| 560 | + cgi_printf( | |
| 561 | + "<option value='0'%s>%h</option>\n", | |
| 562 | + (!isTrue) ? " selected":"", aSubmenuCtrl[i].zFalse | |
| 563 | + ); | |
| 564 | + @ </select> | |
| 565 | + break; | |
| 566 | + } | |
| 567 | + } | |
| 426 | 568 | } |
| 427 | 569 | } |
| 428 | 570 | @ </div> |
| 571 | + if( nSubmenuCtrl ){ | |
| 572 | + cgi_query_parameters_to_hidden(); | |
| 573 | + cgi_tag_query_parameter(0); | |
| 574 | + @ </form> | |
| 575 | + } | |
| 429 | 576 | } |
| 430 | 577 | |
| 431 | 578 | zAd = style_adunit_text(&mAdFlags); |
| 432 | 579 | if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){ |
| 433 | 580 | @ <div class="content adunit_right_container"> |
| @@ -1183,11 +1330,11 @@ | ||
| 1183 | 1330 | } |
| 1184 | 1331 | zHaystack = z + n; |
| 1185 | 1332 | } |
| 1186 | 1333 | return 0; |
| 1187 | 1334 | } |
| 1188 | - | |
| 1335 | + | |
| 1189 | 1336 | |
| 1190 | 1337 | /* |
| 1191 | 1338 | ** WEBPAGE: style.css |
| 1192 | 1339 | */ |
| 1193 | 1340 | void page_style_css(void){ |
| @@ -1246,22 +1393,21 @@ | ||
| 1246 | 1393 | } |
| 1247 | 1394 | for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); |
| 1248 | 1395 | style_header("Environment Test"); |
| 1249 | 1396 | showAll = atoi(PD("showall","0")); |
| 1250 | 1397 | if( !showAll ){ |
| 1251 | - style_submenu_element("Show Cookies", "Show Cookies", | |
| 1252 | - "%s/test_env?showall=1", g.zTop); | |
| 1398 | + style_submenu_element("Show Cookies", 0, "%R/test_env?showall=1"); | |
| 1253 | 1399 | }else{ |
| 1254 | - style_submenu_element("Hide Cookies", "Hide Cookies", | |
| 1255 | - "%s/test_env", g.zTop); | |
| 1400 | + style_submenu_element("Hide Cookies", 0, "%R/test_env"); | |
| 1256 | 1401 | } |
| 1257 | 1402 | #if !defined(_WIN32) |
| 1258 | 1403 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 1259 | 1404 | #endif |
| 1260 | 1405 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 1261 | 1406 | @ g.zHttpsURL = %h(g.zHttpsURL)<br /> |
| 1262 | 1407 | @ g.zTop = %h(g.zTop)<br /> |
| 1408 | + @ g.zPath = %h(g.zPath)<br /> | |
| 1263 | 1409 | for(i=0, c='a'; c<='z'; c++){ |
| 1264 | 1410 | if( login_has_capability(&c, 1) ) zCap[i++] = c; |
| 1265 | 1411 | } |
| 1266 | 1412 | zCap[i] = 0; |
| 1267 | 1413 | @ g.userUid = %d(g.userUid)<br /> |
| 1268 | 1414 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -23,21 +23,42 @@ | |
| 23 | #include "style.h" |
| 24 | |
| 25 | |
| 26 | /* |
| 27 | ** Elements of the submenu are collected into the following |
| 28 | ** structure and displayed below the main menu by style_header(). |
| 29 | ** |
| 30 | ** Populate this structure with calls to style_submenu_element() |
| 31 | ** prior to calling style_header(). |
| 32 | */ |
| 33 | static struct Submenu { |
| 34 | const char *zLabel; |
| 35 | const char *zTitle; |
| 36 | const char *zLink; |
| 37 | } aSubmenu[30]; |
| 38 | static int nSubmenu = 0; |
| 39 | |
| 40 | /* |
| 41 | ** Remember that the header has been generated. The footer is omitted |
| 42 | ** if an error occurs before the header. |
| 43 | */ |
| @@ -216,16 +237,63 @@ | |
| 216 | ... |
| 217 | ){ |
| 218 | va_list ap; |
| 219 | assert( nSubmenu < sizeof(aSubmenu)/sizeof(aSubmenu[0]) ); |
| 220 | aSubmenu[nSubmenu].zLabel = zLabel; |
| 221 | aSubmenu[nSubmenu].zTitle = zTitle; |
| 222 | va_start(ap, zLink); |
| 223 | aSubmenu[nSubmenu].zLink = vmprintf(zLink, ap); |
| 224 | va_end(ap); |
| 225 | nSubmenu++; |
| 226 | } |
| 227 | |
| 228 | /* |
| 229 | ** Compare two submenu items for sorting purposes |
| 230 | */ |
| 231 | static int submenuCompare(const void *a, const void *b){ |
| @@ -411,23 +479,102 @@ | |
| 411 | /* Go back and put the submenu at the top of the page. We delay the |
| 412 | ** creation of the submenu until the end so that we can add elements |
| 413 | ** to the submenu while generating page text. |
| 414 | */ |
| 415 | cgi_destination(CGI_HEADER); |
| 416 | if( nSubmenu>0 ){ |
| 417 | int i; |
| 418 | @ <div class="submenu"> |
| 419 | qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); |
| 420 | for(i=0; i<nSubmenu; i++){ |
| 421 | struct Submenu *p = &aSubmenu[i]; |
| 422 | if( p->zLink==0 ){ |
| 423 | @ <span class="label">%h(p->zLabel)</span> |
| 424 | }else{ |
| 425 | @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a> |
| 426 | } |
| 427 | } |
| 428 | @ </div> |
| 429 | } |
| 430 | |
| 431 | zAd = style_adunit_text(&mAdFlags); |
| 432 | if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){ |
| 433 | @ <div class="content adunit_right_container"> |
| @@ -1183,11 +1330,11 @@ | |
| 1183 | } |
| 1184 | zHaystack = z + n; |
| 1185 | } |
| 1186 | return 0; |
| 1187 | } |
| 1188 | |
| 1189 | |
| 1190 | /* |
| 1191 | ** WEBPAGE: style.css |
| 1192 | */ |
| 1193 | void page_style_css(void){ |
| @@ -1246,22 +1393,21 @@ | |
| 1246 | } |
| 1247 | for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); |
| 1248 | style_header("Environment Test"); |
| 1249 | showAll = atoi(PD("showall","0")); |
| 1250 | if( !showAll ){ |
| 1251 | style_submenu_element("Show Cookies", "Show Cookies", |
| 1252 | "%s/test_env?showall=1", g.zTop); |
| 1253 | }else{ |
| 1254 | style_submenu_element("Hide Cookies", "Hide Cookies", |
| 1255 | "%s/test_env", g.zTop); |
| 1256 | } |
| 1257 | #if !defined(_WIN32) |
| 1258 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 1259 | #endif |
| 1260 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 1261 | @ g.zHttpsURL = %h(g.zHttpsURL)<br /> |
| 1262 | @ g.zTop = %h(g.zTop)<br /> |
| 1263 | for(i=0, c='a'; c<='z'; c++){ |
| 1264 | if( login_has_capability(&c, 1) ) zCap[i++] = c; |
| 1265 | } |
| 1266 | zCap[i] = 0; |
| 1267 | @ g.userUid = %d(g.userUid)<br /> |
| 1268 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -23,21 +23,42 @@ | |
| 23 | #include "style.h" |
| 24 | |
| 25 | |
| 26 | /* |
| 27 | ** Elements of the submenu are collected into the following |
| 28 | ** structure and displayed below the main menu. |
| 29 | ** |
| 30 | ** Populate these structure with calls to |
| 31 | ** |
| 32 | ** style_submenu_element() |
| 33 | ** style_submenu_entry() |
| 34 | ** style_submenu_checkbox() |
| 35 | ** style_submenu_multichoice() |
| 36 | ** |
| 37 | ** prior to calling style_footer(). The style_footer() routine |
| 38 | ** will generate the appropriate HTML text just below the main |
| 39 | ** menu. |
| 40 | */ |
| 41 | static struct Submenu { |
| 42 | const char *zLabel; /* Button label */ |
| 43 | const char *zTitle; |
| 44 | const char *zLink; /* Jump to this link when button is pressed */ |
| 45 | } aSubmenu[30]; |
| 46 | static int nSubmenu = 0; /* Number of buttons */ |
| 47 | static struct SubmenuCtrl { |
| 48 | const char *zName; /* Form query parameter */ |
| 49 | const char *zLabel; /* Label. Might be NULL for FF_MULTI */ |
| 50 | int eType; /* FF_ENTRY, FF_CKBOX, FF_MULTI */ |
| 51 | int iSize; /* Width for FF_ENTRY. Count for FF_MULTI */ |
| 52 | const char **azChoice; /* value/display pairs for FF_MULTI */ |
| 53 | const char *zFalse; /* FF_BINARY label when false */ |
| 54 | } aSubmenuCtrl[20]; |
| 55 | static int nSubmenuCtrl = 0; |
| 56 | #define FF_ENTRY 1 |
| 57 | #define FF_CKBOX 2 |
| 58 | #define FF_MULTI 3 |
| 59 | #define FF_BINARY 4 |
| 60 | |
| 61 | /* |
| 62 | ** Remember that the header has been generated. The footer is omitted |
| 63 | ** if an error occurs before the header. |
| 64 | */ |
| @@ -216,16 +237,63 @@ | |
| 237 | ... |
| 238 | ){ |
| 239 | va_list ap; |
| 240 | assert( nSubmenu < sizeof(aSubmenu)/sizeof(aSubmenu[0]) ); |
| 241 | aSubmenu[nSubmenu].zLabel = zLabel; |
| 242 | aSubmenu[nSubmenu].zTitle = zTitle ? zTitle : zLabel; |
| 243 | va_start(ap, zLink); |
| 244 | aSubmenu[nSubmenu].zLink = vmprintf(zLink, ap); |
| 245 | va_end(ap); |
| 246 | nSubmenu++; |
| 247 | } |
| 248 | void style_submenu_entry( |
| 249 | const char *zName, /* Query parameter name */ |
| 250 | const char *zLabel, /* Label before the entry box */ |
| 251 | int iSize /* Size of the entry box */ |
| 252 | ){ |
| 253 | assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); |
| 254 | aSubmenuCtrl[nSubmenuCtrl].zName = zName; |
| 255 | aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel; |
| 256 | aSubmenuCtrl[nSubmenuCtrl].iSize = iSize; |
| 257 | aSubmenuCtrl[nSubmenuCtrl].eType = FF_ENTRY; |
| 258 | nSubmenuCtrl++; |
| 259 | } |
| 260 | void style_submenu_checkbox( |
| 261 | const char *zName, /* Query parameter name */ |
| 262 | const char *zLabel /* Label before the checkbox */ |
| 263 | ){ |
| 264 | assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); |
| 265 | aSubmenuCtrl[nSubmenuCtrl].zName = zName; |
| 266 | aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel; |
| 267 | aSubmenuCtrl[nSubmenuCtrl].eType = FF_CKBOX; |
| 268 | nSubmenuCtrl++; |
| 269 | } |
| 270 | void style_submenu_binary( |
| 271 | const char *zName, /* Query parameter name */ |
| 272 | const char *zTrue, /* Label to show when parameter is true */ |
| 273 | const char *zFalse /* Label to show when the parameter is false */ |
| 274 | ){ |
| 275 | assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); |
| 276 | aSubmenuCtrl[nSubmenuCtrl].zName = zName; |
| 277 | aSubmenuCtrl[nSubmenuCtrl].zLabel = zTrue; |
| 278 | aSubmenuCtrl[nSubmenuCtrl].zFalse = zFalse; |
| 279 | aSubmenuCtrl[nSubmenuCtrl].eType = FF_BINARY; |
| 280 | nSubmenuCtrl++; |
| 281 | } |
| 282 | void style_submenu_multichoice( |
| 283 | const char *zName, /* Query parameter name */ |
| 284 | int nChoice, /* Number of options */ |
| 285 | const char **azChoice /* value/display pairs. 2*nChoice entries */ |
| 286 | ){ |
| 287 | assert( nSubmenuCtrl < ArraySize(aSubmenuCtrl) ); |
| 288 | aSubmenuCtrl[nSubmenuCtrl].zName = zName; |
| 289 | aSubmenuCtrl[nSubmenuCtrl].iSize = nChoice; |
| 290 | aSubmenuCtrl[nSubmenuCtrl].azChoice = azChoice; |
| 291 | aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI; |
| 292 | nSubmenuCtrl++; |
| 293 | } |
| 294 | |
| 295 | |
| 296 | /* |
| 297 | ** Compare two submenu items for sorting purposes |
| 298 | */ |
| 299 | static int submenuCompare(const void *a, const void *b){ |
| @@ -411,23 +479,102 @@ | |
| 479 | /* Go back and put the submenu at the top of the page. We delay the |
| 480 | ** creation of the submenu until the end so that we can add elements |
| 481 | ** to the submenu while generating page text. |
| 482 | */ |
| 483 | cgi_destination(CGI_HEADER); |
| 484 | if( nSubmenu+nSubmenuCtrl>0 ){ |
| 485 | int i; |
| 486 | if( nSubmenuCtrl ){ |
| 487 | cgi_printf("<form id='f01' method='GET' action='%R/%s'>", g.zPath); |
| 488 | } |
| 489 | @ <div class="submenu"> |
| 490 | if( nSubmenu>0 ){ |
| 491 | qsort(aSubmenu, nSubmenu, sizeof(aSubmenu[0]), submenuCompare); |
| 492 | for(i=0; i<nSubmenu; i++){ |
| 493 | struct Submenu *p = &aSubmenu[i]; |
| 494 | if( p->zLink==0 ){ |
| 495 | @ <span class="label">%h(p->zLabel)</span> |
| 496 | }else{ |
| 497 | @ <a class="label" href="%h(p->zLink)">%h(p->zLabel)</a> |
| 498 | } |
| 499 | } |
| 500 | } |
| 501 | if( nSubmenuCtrl>0 ){ |
| 502 | for(i=0; i<nSubmenuCtrl; i++){ |
| 503 | const char *zQPN = aSubmenuCtrl[i].zName; |
| 504 | cgi_tag_query_parameter(zQPN); |
| 505 | switch( aSubmenuCtrl[i].eType ){ |
| 506 | case FF_ENTRY: { |
| 507 | cgi_printf( |
| 508 | "<span class='submenuctrl'>" |
| 509 | "%h: <input type='text' name='%s' size='%d' " |
| 510 | "value='%h'></span>\n", |
| 511 | aSubmenuCtrl[i].zLabel, |
| 512 | zQPN, |
| 513 | aSubmenuCtrl[i].iSize, |
| 514 | PD(zQPN,"") |
| 515 | ); |
| 516 | break; |
| 517 | } |
| 518 | case FF_CKBOX: { |
| 519 | cgi_printf( |
| 520 | "<span class='submenuctrl'>" |
| 521 | "%h: <input type='checkbox' name='%s'%s " |
| 522 | "onchange='gebi(\"f01\").submit();'></span>\n", |
| 523 | aSubmenuCtrl[i].zLabel, |
| 524 | zQPN, |
| 525 | PB(zQPN) ? " checked":"" |
| 526 | ); |
| 527 | break; |
| 528 | } |
| 529 | case FF_MULTI: { |
| 530 | int j; |
| 531 | const char *zVal = P(zQPN); |
| 532 | cgi_printf( |
| 533 | "<select class='submenuctrl' size='1' name='%s' " |
| 534 | "onchange='gebi(\"f01\").submit();'>\n", |
| 535 | zQPN |
| 536 | ); |
| 537 | for(j=0; j<aSubmenuCtrl[i].iSize*2; j+=2){ |
| 538 | const char *zQPV = aSubmenuCtrl[i].azChoice[j]; |
| 539 | cgi_printf( |
| 540 | "<option value='%h'%s>%h</option>\n", |
| 541 | zQPV, |
| 542 | fossil_strcmp(zVal,zQPV)==0 ? " selected" : "", |
| 543 | aSubmenuCtrl[i].azChoice[j+1] |
| 544 | ); |
| 545 | } |
| 546 | @ </select> |
| 547 | break; |
| 548 | } |
| 549 | case FF_BINARY: { |
| 550 | int isTrue = PB(zQPN); |
| 551 | cgi_printf( |
| 552 | "<select class='submenuctrl' size='1' name='%s' " |
| 553 | "onchange='gebi(\"f01\").submit();'>\n", |
| 554 | zQPN |
| 555 | ); |
| 556 | cgi_printf( |
| 557 | "<option value='1'%s>%h</option>\n", |
| 558 | isTrue ? " selected":"", aSubmenuCtrl[i].zLabel |
| 559 | ); |
| 560 | cgi_printf( |
| 561 | "<option value='0'%s>%h</option>\n", |
| 562 | (!isTrue) ? " selected":"", aSubmenuCtrl[i].zFalse |
| 563 | ); |
| 564 | @ </select> |
| 565 | break; |
| 566 | } |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | @ </div> |
| 571 | if( nSubmenuCtrl ){ |
| 572 | cgi_query_parameters_to_hidden(); |
| 573 | cgi_tag_query_parameter(0); |
| 574 | @ </form> |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | zAd = style_adunit_text(&mAdFlags); |
| 579 | if( (mAdFlags & ADUNIT_RIGHT_OK)!=0 ){ |
| 580 | @ <div class="content adunit_right_container"> |
| @@ -1183,11 +1330,11 @@ | |
| 1330 | } |
| 1331 | zHaystack = z + n; |
| 1332 | } |
| 1333 | return 0; |
| 1334 | } |
| 1335 | |
| 1336 | |
| 1337 | /* |
| 1338 | ** WEBPAGE: style.css |
| 1339 | */ |
| 1340 | void page_style_css(void){ |
| @@ -1246,22 +1393,21 @@ | |
| 1393 | } |
| 1394 | for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); |
| 1395 | style_header("Environment Test"); |
| 1396 | showAll = atoi(PD("showall","0")); |
| 1397 | if( !showAll ){ |
| 1398 | style_submenu_element("Show Cookies", 0, "%R/test_env?showall=1"); |
| 1399 | }else{ |
| 1400 | style_submenu_element("Hide Cookies", 0, "%R/test_env"); |
| 1401 | } |
| 1402 | #if !defined(_WIN32) |
| 1403 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 1404 | #endif |
| 1405 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 1406 | @ g.zHttpsURL = %h(g.zHttpsURL)<br /> |
| 1407 | @ g.zTop = %h(g.zTop)<br /> |
| 1408 | @ g.zPath = %h(g.zPath)<br /> |
| 1409 | for(i=0, c='a'; c<='z'; c++){ |
| 1410 | if( login_has_capability(&c, 1) ) zCap[i++] = c; |
| 1411 | } |
| 1412 | zCap[i] = 0; |
| 1413 | @ g.userUid = %d(g.userUid)<br /> |
| 1414 |
No diff available
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -365,10 +365,69 @@ | ||
| 365 | 365 | Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc); |
| 366 | 366 | } |
| 367 | 367 | Th_SetResultInt(interp, rc); |
| 368 | 368 | return TH_OK; |
| 369 | 369 | } |
| 370 | + | |
| 371 | +/* | |
| 372 | +** TH1 command: searchable STRING... | |
| 373 | +** | |
| 374 | +** Return true if searching in any of the document classes identified | |
| 375 | +** by STRING is enabled for the repository and user has the necessary | |
| 376 | +** capabilities to perform the search. | |
| 377 | +** | |
| 378 | +** Document classes: | |
| 379 | +** | |
| 380 | +** c Check-in comments | |
| 381 | +** d Embedded documentation | |
| 382 | +** t Tickets | |
| 383 | +** w Wiki | |
| 384 | +** | |
| 385 | +** To be clear, only one of the document classes identified by each STRING | |
| 386 | +** needs to be searchable in order for that argument to be true. But | |
| 387 | +** all arguments must be true for this routine to return true. Hence, to | |
| 388 | +** see if ALL document classes are searchable: | |
| 389 | +** | |
| 390 | +** if {[searchable c d t w]} {...} | |
| 391 | +** | |
| 392 | +** But to see if ANY document class is searchable: | |
| 393 | +** | |
| 394 | +** if {[searchable cdtw]} {...} | |
| 395 | +** | |
| 396 | +** This command is useful for enabling or disabling a "Search" entry | |
| 397 | +** on the menu bar. | |
| 398 | +*/ | |
| 399 | +static int searchableCmd( | |
| 400 | + Th_Interp *interp, | |
| 401 | + void *p, | |
| 402 | + int argc, | |
| 403 | + const char **argv, | |
| 404 | + int *argl | |
| 405 | +){ | |
| 406 | + int rc = 1, i, j; | |
| 407 | + unsigned int searchCap = search_restrict(SRCH_ALL); | |
| 408 | + if( argc<2 ){ | |
| 409 | + return Th_WrongNumArgs(interp, "hascap STRING ..."); | |
| 410 | + } | |
| 411 | + for(i=1; i<argc && rc; i++){ | |
| 412 | + int match = 0; | |
| 413 | + for(j=0; j<argl[i]; j++){ | |
| 414 | + switch( argv[i][j] ){ | |
| 415 | + case 'c': match |= searchCap & SRCH_CKIN; break; | |
| 416 | + case 'd': match |= searchCap & SRCH_DOC; break; | |
| 417 | + case 't': match |= searchCap & SRCH_TKT; break; | |
| 418 | + case 'w': match |= searchCap & SRCH_WIKI; break; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + if( !match ) rc = 0; | |
| 422 | + } | |
| 423 | + if( g.thTrace ){ | |
| 424 | + Th_Trace("[searchable %#h] => %d<br />\n", argl[1], argv[1], rc); | |
| 425 | + } | |
| 426 | + Th_SetResultInt(interp, rc); | |
| 427 | + return TH_OK; | |
| 428 | +} | |
| 370 | 429 | |
| 371 | 430 | /* |
| 372 | 431 | ** TH1 command: hasfeature STRING |
| 373 | 432 | ** |
| 374 | 433 | ** Return true if the fossil binary has the given compile-time feature |
| @@ -1419,10 +1478,11 @@ | ||
| 1419 | 1478 | {"randhex", randhexCmd, 0}, |
| 1420 | 1479 | {"regexp", regexpCmd, 0}, |
| 1421 | 1480 | {"reinitialize", reinitializeCmd, 0}, |
| 1422 | 1481 | {"render", renderCmd, 0}, |
| 1423 | 1482 | {"repository", repositoryCmd, 0}, |
| 1483 | + {"searchable", searchableCmd, 0}, | |
| 1424 | 1484 | {"setParameter", setParameterCmd, 0}, |
| 1425 | 1485 | {"setting", settingCmd, 0}, |
| 1426 | 1486 | {"styleHeader", styleHeaderCmd, 0}, |
| 1427 | 1487 | {"styleFooter", styleFooterCmd, 0}, |
| 1428 | 1488 | {"tclReady", tclReadyCmd, 0}, |
| 1429 | 1489 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -365,10 +365,69 @@ | |
| 365 | Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc); |
| 366 | } |
| 367 | Th_SetResultInt(interp, rc); |
| 368 | return TH_OK; |
| 369 | } |
| 370 | |
| 371 | /* |
| 372 | ** TH1 command: hasfeature STRING |
| 373 | ** |
| 374 | ** Return true if the fossil binary has the given compile-time feature |
| @@ -1419,10 +1478,11 @@ | |
| 1419 | {"randhex", randhexCmd, 0}, |
| 1420 | {"regexp", regexpCmd, 0}, |
| 1421 | {"reinitialize", reinitializeCmd, 0}, |
| 1422 | {"render", renderCmd, 0}, |
| 1423 | {"repository", repositoryCmd, 0}, |
| 1424 | {"setParameter", setParameterCmd, 0}, |
| 1425 | {"setting", settingCmd, 0}, |
| 1426 | {"styleHeader", styleHeaderCmd, 0}, |
| 1427 | {"styleFooter", styleFooterCmd, 0}, |
| 1428 | {"tclReady", tclReadyCmd, 0}, |
| 1429 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -365,10 +365,69 @@ | |
| 365 | Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc); |
| 366 | } |
| 367 | Th_SetResultInt(interp, rc); |
| 368 | return TH_OK; |
| 369 | } |
| 370 | |
| 371 | /* |
| 372 | ** TH1 command: searchable STRING... |
| 373 | ** |
| 374 | ** Return true if searching in any of the document classes identified |
| 375 | ** by STRING is enabled for the repository and user has the necessary |
| 376 | ** capabilities to perform the search. |
| 377 | ** |
| 378 | ** Document classes: |
| 379 | ** |
| 380 | ** c Check-in comments |
| 381 | ** d Embedded documentation |
| 382 | ** t Tickets |
| 383 | ** w Wiki |
| 384 | ** |
| 385 | ** To be clear, only one of the document classes identified by each STRING |
| 386 | ** needs to be searchable in order for that argument to be true. But |
| 387 | ** all arguments must be true for this routine to return true. Hence, to |
| 388 | ** see if ALL document classes are searchable: |
| 389 | ** |
| 390 | ** if {[searchable c d t w]} {...} |
| 391 | ** |
| 392 | ** But to see if ANY document class is searchable: |
| 393 | ** |
| 394 | ** if {[searchable cdtw]} {...} |
| 395 | ** |
| 396 | ** This command is useful for enabling or disabling a "Search" entry |
| 397 | ** on the menu bar. |
| 398 | */ |
| 399 | static int searchableCmd( |
| 400 | Th_Interp *interp, |
| 401 | void *p, |
| 402 | int argc, |
| 403 | const char **argv, |
| 404 | int *argl |
| 405 | ){ |
| 406 | int rc = 1, i, j; |
| 407 | unsigned int searchCap = search_restrict(SRCH_ALL); |
| 408 | if( argc<2 ){ |
| 409 | return Th_WrongNumArgs(interp, "hascap STRING ..."); |
| 410 | } |
| 411 | for(i=1; i<argc && rc; i++){ |
| 412 | int match = 0; |
| 413 | for(j=0; j<argl[i]; j++){ |
| 414 | switch( argv[i][j] ){ |
| 415 | case 'c': match |= searchCap & SRCH_CKIN; break; |
| 416 | case 'd': match |= searchCap & SRCH_DOC; break; |
| 417 | case 't': match |= searchCap & SRCH_TKT; break; |
| 418 | case 'w': match |= searchCap & SRCH_WIKI; break; |
| 419 | } |
| 420 | } |
| 421 | if( !match ) rc = 0; |
| 422 | } |
| 423 | if( g.thTrace ){ |
| 424 | Th_Trace("[searchable %#h] => %d<br />\n", argl[1], argv[1], rc); |
| 425 | } |
| 426 | Th_SetResultInt(interp, rc); |
| 427 | return TH_OK; |
| 428 | } |
| 429 | |
| 430 | /* |
| 431 | ** TH1 command: hasfeature STRING |
| 432 | ** |
| 433 | ** Return true if the fossil binary has the given compile-time feature |
| @@ -1419,10 +1478,11 @@ | |
| 1478 | {"randhex", randhexCmd, 0}, |
| 1479 | {"regexp", regexpCmd, 0}, |
| 1480 | {"reinitialize", reinitializeCmd, 0}, |
| 1481 | {"render", renderCmd, 0}, |
| 1482 | {"repository", repositoryCmd, 0}, |
| 1483 | {"searchable", searchableCmd, 0}, |
| 1484 | {"setParameter", setParameterCmd, 0}, |
| 1485 | {"setting", settingCmd, 0}, |
| 1486 | {"styleHeader", styleHeaderCmd, 0}, |
| 1487 | {"styleFooter", styleFooterCmd, 0}, |
| 1488 | {"tclReady", tclReadyCmd, 0}, |
| 1489 |
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -494,10 +494,11 @@ | ||
| 494 | 494 | " (SELECT name FROM filename WHERE fnid=mlink.pfnid) AS oldnm" |
| 495 | 495 | " FROM mlink" |
| 496 | 496 | " WHERE mid=:mid AND (pid!=fid OR pfnid>0)" |
| 497 | 497 | " AND (fid>0 OR" |
| 498 | 498 | " fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=:mid))" |
| 499 | + " AND NOT mlink.isaux" | |
| 499 | 500 | " ORDER BY 3 /*sort*/" |
| 500 | 501 | ); |
| 501 | 502 | fchngQueryInit = 1; |
| 502 | 503 | } |
| 503 | 504 | db_bind_int(&fchngQuery, ":mid", rid); |
| @@ -666,16 +667,16 @@ | ||
| 666 | 667 | if( cSep=='[' ) cgi_printf("["); |
| 667 | 668 | cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 668 | 669 | } |
| 669 | 670 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 670 | 671 | graph_free(pGraph); |
| 671 | - @ var canvasDiv = gebi("canvas"); | |
| 672 | - @ var canvasStyle = window.getComputedStyle && window.getComputedStyle(canvasDiv,null); | |
| 673 | - @ var lineColor = (canvasStyle && canvasStyle.getPropertyValue('color')) || 'black'; | |
| 674 | - @ var bgColor = (canvasStyle && canvasStyle.getPropertyValue('background-color')) || 'white'; | |
| 675 | - @ if( bgColor=='transparent' ) bgColor = 'white'; | |
| 676 | - @ var boxColor = lineColor; | |
| 672 | + @ var cDiv = gebi("canvas"); | |
| 673 | + @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null); | |
| 674 | + @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black'; | |
| 675 | + @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white'; | |
| 676 | + @ if( bgClr=='transparent' ) bgClr = 'white'; | |
| 677 | + @ var boxColor = lineClr; | |
| 677 | 678 | @ function drawBox(color,x0,y0,x1,y1){ |
| 678 | 679 | @ var n = document.createElement("div"); |
| 679 | 680 | @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } |
| 680 | 681 | @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } |
| 681 | 682 | @ var w = x1-x0+1; |
| @@ -685,11 +686,11 @@ | ||
| 685 | 686 | @ n.style.left = x0+"px"; |
| 686 | 687 | @ n.style.top = y0+"px"; |
| 687 | 688 | @ n.style.width = w+"px"; |
| 688 | 689 | @ n.style.height = h+"px"; |
| 689 | 690 | @ n.style.backgroundColor = color; |
| 690 | - @ canvasDiv.appendChild(n); | |
| 691 | + @ cDiv.appendChild(n); | |
| 691 | 692 | @ return n; |
| 692 | 693 | @ } |
| 693 | 694 | @ function absoluteY(id){ |
| 694 | 695 | @ var obj = gebi(id); |
| 695 | 696 | @ if( !obj ) return; |
| @@ -711,39 +712,39 @@ | ||
| 711 | 712 | @ }while( obj = obj.offsetParent ); |
| 712 | 713 | @ } |
| 713 | 714 | @ return left; |
| 714 | 715 | @ } |
| 715 | 716 | @ function drawUpArrow(x,y0,y1){ |
| 716 | - @ drawBox(lineColor,x,y0,x+1,y1); | |
| 717 | + @ drawBox(lineClr,x,y0,x+1,y1); | |
| 717 | 718 | @ if( y0+10>=y1 ){ |
| 718 | - @ drawBox(lineColor,x-1,y0+1,x+2,y0+2); | |
| 719 | - @ drawBox(lineColor,x-2,y0+3,x+3,y0+4); | |
| 719 | + @ drawBox(lineClr,x-1,y0+1,x+2,y0+2); | |
| 720 | + @ drawBox(lineClr,x-2,y0+3,x+3,y0+4); | |
| 720 | 721 | @ }else{ |
| 721 | - @ drawBox(lineColor,x-1,y0+2,x+2,y0+4); | |
| 722 | - @ drawBox(lineColor,x-2,y0+5,x+3,y0+7); | |
| 722 | + @ drawBox(lineClr,x-1,y0+2,x+2,y0+4); | |
| 723 | + @ drawBox(lineClr,x-2,y0+5,x+3,y0+7); | |
| 723 | 724 | @ } |
| 724 | 725 | @ } |
| 725 | 726 | @ function drawThinArrow(y,xFrom,xTo){ |
| 726 | 727 | @ if( xFrom<xTo ){ |
| 727 | - @ drawBox(lineColor,xFrom,y,xTo,y); | |
| 728 | - @ drawBox(lineColor,xTo-3,y-1,xTo-2,y+1); | |
| 729 | - @ drawBox(lineColor,xTo-4,y-2,xTo-4,y+2); | |
| 728 | + @ drawBox(lineClr,xFrom,y,xTo,y); | |
| 729 | + @ drawBox(lineClr,xTo-3,y-1,xTo-2,y+1); | |
| 730 | + @ drawBox(lineClr,xTo-4,y-2,xTo-4,y+2); | |
| 730 | 731 | @ }else{ |
| 731 | - @ drawBox(lineColor,xTo,y,xFrom,y); | |
| 732 | - @ drawBox(lineColor,xTo+2,y-1,xTo+3,y+1); | |
| 733 | - @ drawBox(lineColor,xTo+4,y-2,xTo+4,y+2); | |
| 732 | + @ drawBox(lineClr,xTo,y,xFrom,y); | |
| 733 | + @ drawBox(lineClr,xTo+2,y-1,xTo+3,y+1); | |
| 734 | + @ drawBox(lineClr,xTo+4,y-2,xTo+4,y+2); | |
| 734 | 735 | @ } |
| 735 | 736 | @ } |
| 736 | 737 | @ function drawThinLine(x0,y0,x1,y1){ |
| 737 | - @ drawBox(lineColor,x0,y0,x1,y1); | |
| 738 | + @ drawBox(lineClr,x0,y0,x1,y1); | |
| 738 | 739 | @ } |
| 739 | 740 | @ function drawNodeBox(color,x0,y0,x1,y1){ |
| 740 | 741 | @ drawBox(color,x0,y0,x1,y1).style.cursor = "pointer"; |
| 741 | 742 | @ } |
| 742 | 743 | @ function drawNode(p, left, btm){ |
| 743 | 744 | @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6); |
| 744 | - @ drawNodeBox(p.bg||bgColor,p.x-4,p.y-4,p.x+5,p.y+5); | |
| 745 | + @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5); | |
| 745 | 746 | @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5); |
| 746 | 747 | @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2); |
| 747 | 748 | if( !omitDescenders ){ |
| 748 | 749 | @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5); |
| 749 | 750 | @ if( p.d ) drawUpArrow(p.x, p.y+6, btm); |
| @@ -765,11 +766,11 @@ | ||
| 765 | 766 | @ for(var i=0; i<n; i+=2){ |
| 766 | 767 | @ var x1 = p.au[i]*railPitch + left; |
| 767 | 768 | @ var x0 = x1>p.x ? p.x+7 : p.x-6; |
| 768 | 769 | @ var u = rowinfo[p.au[i+1]-1]; |
| 769 | 770 | @ if(u.id<p.id){ |
| 770 | - @ drawBox(lineColor,x0,p.y,x1,p.y+1); | |
| 771 | + @ drawBox(lineClr,x0,p.y,x1,p.y+1); | |
| 771 | 772 | @ drawUpArrow(x1, u.y+6, p.y); |
| 772 | 773 | @ }else{ |
| 773 | 774 | @ drawBox("#600000",x0,p.y,x1,p.y+1); |
| 774 | 775 | @ drawBox("#600000",x1-1,p.y,x1,u.y+1); |
| 775 | 776 | @ drawBox("#600000",x1,u.y,u.x-6,u.y+1); |
| @@ -952,13 +953,22 @@ | ||
| 952 | 953 | if( z==0 ) return -1.0; |
| 953 | 954 | if( fossil_isdate(z) ){ |
| 954 | 955 | mtime = db_double(0.0, "SELECT julianday(%Q,'utc')", z); |
| 955 | 956 | if( mtime>0.0 ) return mtime; |
| 956 | 957 | } |
| 957 | - rid = symbolic_name_to_rid(z, "ci"); | |
| 958 | - if( rid==0 ) return -1.0; | |
| 959 | - mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 958 | + rid = symbolic_name_to_rid(z, "*"); | |
| 959 | + if( rid ){ | |
| 960 | + mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 961 | + }else{ | |
| 962 | + mtime = db_double(-1.0, | |
| 963 | + "SELECT max(event.mtime) FROM event, tag, tagxref" | |
| 964 | + " WHERE tag.tagname GLOB 'event-%q*'" | |
| 965 | + " AND tagxref.tagid=tag.tagid AND tagxref.tagtype" | |
| 966 | + " AND event.objid=tagxref.rid", | |
| 967 | + z | |
| 968 | + ); | |
| 969 | + } | |
| 960 | 970 | return mtime; |
| 961 | 971 | } |
| 962 | 972 | |
| 963 | 973 | /* |
| 964 | 974 | ** The value of one second in julianday notation |
| @@ -1011,10 +1021,47 @@ | ||
| 1011 | 1021 | } |
| 1012 | 1022 | db_finalize(&q); |
| 1013 | 1023 | return blob_str(&out); |
| 1014 | 1024 | } |
| 1015 | 1025 | |
| 1026 | + | |
| 1027 | +/* | |
| 1028 | +** Add the select/option box to the timeline submenu that is used to | |
| 1029 | +** set the y= parameter that determines which elements to display | |
| 1030 | +** on the timeline. | |
| 1031 | +*/ | |
| 1032 | +static void timeline_y_submenu(void){ | |
| 1033 | + static int i = 0; | |
| 1034 | + static const char *az[12]; | |
| 1035 | + if( i==0 ){ | |
| 1036 | + az[0] = "all"; | |
| 1037 | + az[1] = "All Types"; | |
| 1038 | + i = 2; | |
| 1039 | + if( g.perm.Read ){ | |
| 1040 | + az[i++] = "ci"; | |
| 1041 | + az[i++] = "Check-ins"; | |
| 1042 | + az[i++] = "g"; | |
| 1043 | + az[i++] = "Tags"; | |
| 1044 | + } | |
| 1045 | + if( g.perm.RdWiki ){ | |
| 1046 | + az[i++] = "e"; | |
| 1047 | + az[i++] = "Tech Notes"; | |
| 1048 | + } | |
| 1049 | + if( g.perm.RdTkt ){ | |
| 1050 | + az[i++] = "t"; | |
| 1051 | + az[i++] = "Tickets"; | |
| 1052 | + } | |
| 1053 | + if( g.perm.RdWiki ){ | |
| 1054 | + az[i++] = "w"; | |
| 1055 | + az[i++] = "Wiki"; | |
| 1056 | + } | |
| 1057 | + assert( i<=ArraySize(az) ); | |
| 1058 | + } | |
| 1059 | + if( i>2 ){ | |
| 1060 | + style_submenu_multichoice("y", i/2, az); | |
| 1061 | + } | |
| 1062 | +} | |
| 1016 | 1063 | |
| 1017 | 1064 | /* |
| 1018 | 1065 | ** WEBPAGE: timeline |
| 1019 | 1066 | ** |
| 1020 | 1067 | ** Query parameters: |
| @@ -1055,11 +1102,11 @@ | ||
| 1055 | 1102 | */ |
| 1056 | 1103 | void page_timeline(void){ |
| 1057 | 1104 | Stmt q; /* Query used to generate the timeline */ |
| 1058 | 1105 | Blob sql; /* text of SQL used to generate timeline */ |
| 1059 | 1106 | Blob desc; /* Description of the timeline */ |
| 1060 | - int nEntry = atoi(PD("n","20")); /* Max number of entries on timeline */ | |
| 1107 | + int nEntry; /* Max number of entries on timeline */ | |
| 1061 | 1108 | int p_rid = name_to_typed_rid(P("p"),"ci"); /* artifact p and its parents */ |
| 1062 | 1109 | int d_rid = name_to_typed_rid(P("d"),"ci"); /* artifact d and descendants */ |
| 1063 | 1110 | int f_rid = name_to_typed_rid(P("f"),"ci"); /* artifact f and close family */ |
| 1064 | 1111 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 1065 | 1112 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| @@ -1069,11 +1116,11 @@ | ||
| 1069 | 1116 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 1070 | 1117 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 1071 | 1118 | const char *zSearch = P("s"); /* Search string */ |
| 1072 | 1119 | const char *zUses = P("uf"); /* Only show checkins hold this file */ |
| 1073 | 1120 | const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */ |
| 1074 | - const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (week-of-year)*/ | |
| 1121 | + const char *zYearWeek = P("yw"); /* Checkins for YYYY-WW (week-of-year) */ | |
| 1075 | 1122 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1076 | 1123 | int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */ |
| 1077 | 1124 | int tagid; /* Tag ID */ |
| 1078 | 1125 | int tmFlags = 0; /* Timeline flags */ |
| 1079 | 1126 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| @@ -1084,10 +1131,32 @@ | ||
| 1084 | 1131 | int noMerge = P("shortest")==0; /* Follow merge links if shorter */ |
| 1085 | 1132 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1086 | 1133 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1087 | 1134 | int pd_rid; |
| 1088 | 1135 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1136 | + const char *z; | |
| 1137 | + char *zOlderButton = 0; /* URL for Older button at the bottom */ | |
| 1138 | + | |
| 1139 | + /* Set number of rows to display */ | |
| 1140 | + z = P("n"); | |
| 1141 | + if( z ){ | |
| 1142 | + if( fossil_strcmp(z,"all")==0 ){ | |
| 1143 | + nEntry = 0; | |
| 1144 | + }else{ | |
| 1145 | + nEntry = atoi(z); | |
| 1146 | + if( nEntry<=0 ){ | |
| 1147 | + cgi_replace_query_parameter("n","10"); | |
| 1148 | + nEntry = 10; | |
| 1149 | + } | |
| 1150 | + } | |
| 1151 | + }else if( zCirca ){ | |
| 1152 | + cgi_replace_query_parameter("n","11"); | |
| 1153 | + nEntry = 11; | |
| 1154 | + }else{ | |
| 1155 | + cgi_replace_query_parameter("n","50"); | |
| 1156 | + nEntry = 50; | |
| 1157 | + } | |
| 1089 | 1158 | |
| 1090 | 1159 | /* To view the timeline, must have permission to read project data. |
| 1091 | 1160 | */ |
| 1092 | 1161 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1093 | 1162 | if( pd_rid ){ |
| @@ -1097,20 +1166,21 @@ | ||
| 1097 | 1166 | if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ |
| 1098 | 1167 | login_needed(); |
| 1099 | 1168 | return; |
| 1100 | 1169 | } |
| 1101 | 1170 | url_initialize(&url, "timeline"); |
| 1171 | + cgi_query_parameters_to_url(&url); | |
| 1102 | 1172 | if( zTagName && g.perm.Read ){ |
| 1103 | 1173 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 1104 | 1174 | zThisTag = zTagName; |
| 1105 | 1175 | }else if( zBrName && g.perm.Read ){ |
| 1106 | 1176 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| 1107 | 1177 | zThisTag = zBrName; |
| 1108 | 1178 | }else{ |
| 1109 | 1179 | tagid = 0; |
| 1110 | 1180 | } |
| 1111 | - if( tagid>0 | |
| 1181 | + if( tagid>0 | |
| 1112 | 1182 | && db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry |
| 1113 | 1183 | ){ |
| 1114 | 1184 | zCirca = zBefore = zAfter = 0; |
| 1115 | 1185 | nEntry = -1; |
| 1116 | 1186 | } |
| @@ -1117,32 +1187,26 @@ | ||
| 1117 | 1187 | if( zType[0]=='a' ){ |
| 1118 | 1188 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1119 | 1189 | }else{ |
| 1120 | 1190 | tmFlags |= TIMELINE_GRAPH; |
| 1121 | 1191 | } |
| 1122 | - if( nEntry>0 ) url_add_parameter(&url, "n", mprintf("%d", nEntry)); | |
| 1123 | - if( P("ng")!=0 || zSearch!=0 ){ | |
| 1192 | + if( PB("ng") || zSearch!=0 ){ | |
| 1124 | 1193 | tmFlags &= ~TIMELINE_GRAPH; |
| 1125 | - url_add_parameter(&url, "ng", 0); | |
| 1126 | 1194 | } |
| 1127 | - if( P("brbg")!=0 ){ | |
| 1195 | + if( PB("brbg") ){ | |
| 1128 | 1196 | tmFlags |= TIMELINE_BRCOLOR; |
| 1129 | - url_add_parameter(&url, "brbg", 0); | |
| 1130 | 1197 | } |
| 1131 | - if( P("unhide")!=0 ){ | |
| 1198 | + if( PB("unhide") ){ | |
| 1132 | 1199 | tmFlags |= TIMELINE_UNHIDE; |
| 1133 | - url_add_parameter(&url, "unhide", 0); | |
| 1134 | 1200 | } |
| 1135 | - if( P("ubg")!=0 ){ | |
| 1201 | + if( PB("ubg") ){ | |
| 1136 | 1202 | tmFlags |= TIMELINE_UCOLOR; |
| 1137 | - url_add_parameter(&url, "ubg", 0); | |
| 1138 | 1203 | } |
| 1139 | 1204 | if( zUses!=0 ){ |
| 1140 | 1205 | int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); |
| 1141 | 1206 | if( ufid ){ |
| 1142 | 1207 | zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); |
| 1143 | - url_add_parameter(&url, "uf", zUses); | |
| 1144 | 1208 | db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); |
| 1145 | 1209 | compute_uses_file("usesfile", ufid, 0); |
| 1146 | 1210 | zType = "ci"; |
| 1147 | 1211 | }else{ |
| 1148 | 1212 | zUses = 0; |
| @@ -1161,22 +1225,20 @@ | ||
| 1161 | 1225 | timeline_temp_table(); |
| 1162 | 1226 | blob_zero(&sql); |
| 1163 | 1227 | blob_zero(&desc); |
| 1164 | 1228 | blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); |
| 1165 | 1229 | blob_append(&sql, timeline_query_for_www(), -1); |
| 1166 | - if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){ | |
| 1230 | + if( PB("fc") || PB("v") || PB("detail") ){ | |
| 1167 | 1231 | tmFlags |= TIMELINE_FCHANGES; |
| 1168 | - url_add_parameter(&url, "v", 0); | |
| 1169 | 1232 | } |
| 1170 | 1233 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1171 | 1234 | blob_append_sql(&sql, |
| 1172 | 1235 | " AND NOT EXISTS(SELECT 1 FROM tagxref" |
| 1173 | 1236 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", |
| 1174 | 1237 | TAG_HIDDEN |
| 1175 | 1238 | ); |
| 1176 | 1239 | } |
| 1177 | - if( !useDividers ) url_add_parameter(&url, "nd", 0); | |
| 1178 | 1240 | if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){ |
| 1179 | 1241 | /* If from= and to= are present, display all nodes on a path connecting |
| 1180 | 1242 | ** the two */ |
| 1181 | 1243 | PathNode *p = 0; |
| 1182 | 1244 | const char *zFrom = 0; |
| @@ -1241,34 +1303,19 @@ | ||
| 1241 | 1303 | } |
| 1242 | 1304 | if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); |
| 1243 | 1305 | } |
| 1244 | 1306 | blob_appendf(&desc, " of %z[%S]</a>", |
| 1245 | 1307 | href("%R/info/%s", zUuid), zUuid); |
| 1246 | - if( p_rid ){ | |
| 1247 | - url_add_parameter(&url, "p", zUuid); | |
| 1248 | - } | |
| 1249 | 1308 | if( d_rid ){ |
| 1250 | 1309 | if( p_rid ){ |
| 1251 | 1310 | /* If both p= and d= are set, we don't have the uuid of d yet. */ |
| 1252 | 1311 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); |
| 1253 | 1312 | } |
| 1254 | - url_add_parameter(&url, "d", zUuid); | |
| 1255 | - } | |
| 1256 | - if( nEntry>20 ){ | |
| 1257 | - timeline_submenu(&url, "20 Entries", "n", "20", 0); | |
| 1258 | - } | |
| 1259 | - if( nEntry<200 && nEntry>0 ){ | |
| 1260 | - timeline_submenu(&url, "200 Entries", "n", "200", 0); | |
| 1261 | - } | |
| 1262 | - if( tmFlags & TIMELINE_FCHANGES ){ | |
| 1263 | - timeline_submenu(&url, "Hide Files", "v", 0, 0); | |
| 1264 | - }else{ | |
| 1265 | - timeline_submenu(&url, "Show Files", "v", "", 0); | |
| 1266 | - } | |
| 1267 | - if( (tmFlags & TIMELINE_UNHIDE)==0 ){ | |
| 1268 | - timeline_submenu(&url, "Unhide", "unhide", "", 0); | |
| 1269 | - } | |
| 1313 | + } | |
| 1314 | + style_submenu_binary("v","With Files","Without Files"); | |
| 1315 | + style_submenu_entry("n","Lines",1); | |
| 1316 | + timeline_y_submenu(); | |
| 1270 | 1317 | }else if( f_rid && g.perm.Read ){ |
| 1271 | 1318 | /* If f= is present, ignore all other parameters other than n= */ |
| 1272 | 1319 | char *zUuid; |
| 1273 | 1320 | db_multi_exec( |
| 1274 | 1321 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" |
| @@ -1282,16 +1329,11 @@ | ||
| 1282 | 1329 | if( useDividers ) timeline_add_dividers(0, f_rid); |
| 1283 | 1330 | blob_appendf(&desc, "Parents and children of check-in "); |
| 1284 | 1331 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); |
| 1285 | 1332 | blob_appendf(&desc, "%z[%S]</a>", href("%R/info/%s", zUuid), zUuid); |
| 1286 | 1333 | tmFlags |= TIMELINE_DISJOINT; |
| 1287 | - url_add_parameter(&url, "f", zUuid); | |
| 1288 | - if( tmFlags & TIMELINE_FCHANGES ){ | |
| 1289 | - timeline_submenu(&url, "Hide Files", "v", 0, 0); | |
| 1290 | - }else{ | |
| 1291 | - timeline_submenu(&url, "Show Files", "v", "", 0); | |
| 1292 | - } | |
| 1334 | + style_submenu_binary("v","With Files","Without Files"); | |
| 1293 | 1335 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1294 | 1336 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1295 | 1337 | } |
| 1296 | 1338 | }else{ |
| 1297 | 1339 | /* Otherwise, a timeline based on a span of time */ |
| @@ -1316,11 +1358,10 @@ | ||
| 1316 | 1358 | blob_append_sql(&sql, |
| 1317 | 1359 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1318 | 1360 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1319 | 1361 | |
| 1320 | 1362 | if( zBrName ){ |
| 1321 | - url_add_parameter(&url, "r", zBrName); | |
| 1322 | 1363 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 1323 | 1364 | ** are not part of the branch which are parents or children of the |
| 1324 | 1365 | ** branch to be included in the report. This related check-ins are |
| 1325 | 1366 | ** useful in helping to visualize what has happened on a quiescent |
| 1326 | 1367 | ** branch that is infrequently merged with a much more activate branch. |
| @@ -1342,21 +1383,17 @@ | ||
| 1342 | 1383 | " OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid" |
| 1343 | 1384 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1344 | 1385 | tagid |
| 1345 | 1386 | ); |
| 1346 | 1387 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1347 | - blob_append_sql(&sql, | |
| 1388 | + blob_append_sql(&sql, | |
| 1348 | 1389 | " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid" |
| 1349 | 1390 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1350 | 1391 | TAG_HIDDEN |
| 1351 | 1392 | ); |
| 1352 | 1393 | } |
| 1353 | - }else{ | |
| 1354 | - url_add_parameter(&url, "mionly", "1"); | |
| 1355 | 1394 | } |
| 1356 | - }else{ | |
| 1357 | - url_add_parameter(&url, "t", zTagName); | |
| 1358 | 1395 | } |
| 1359 | 1396 | blob_append_sql(&sql, ")"); |
| 1360 | 1397 | } |
| 1361 | 1398 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1362 | 1399 | || (zType[0]=='t' && !g.perm.RdTkt) |
| @@ -1384,11 +1421,10 @@ | ||
| 1384 | 1421 | } |
| 1385 | 1422 | blob_append_sql(&sql, ")"); |
| 1386 | 1423 | } |
| 1387 | 1424 | }else{ /* zType!="all" */ |
| 1388 | 1425 | blob_append_sql(&sql, " AND event.type=%Q", zType); |
| 1389 | - url_add_parameter(&url, "y", zType); | |
| 1390 | 1426 | if( zType[0]=='c' ){ |
| 1391 | 1427 | zEType = "checkin"; |
| 1392 | 1428 | }else if( zType[0]=='w' ){ |
| 1393 | 1429 | zEType = "wiki edit"; |
| 1394 | 1430 | }else if( zType[0]=='t' ){ |
| @@ -1406,41 +1442,35 @@ | ||
| 1406 | 1442 | zCirca = zBefore = zAfter = 0; |
| 1407 | 1443 | nEntry = -1; |
| 1408 | 1444 | } |
| 1409 | 1445 | blob_append_sql(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1410 | 1446 | zUser, zUser); |
| 1411 | - url_add_parameter(&url, "u", zUser); | |
| 1412 | 1447 | zThisUser = zUser; |
| 1413 | 1448 | } |
| 1414 | 1449 | if( zSearch ){ |
| 1415 | 1450 | blob_append_sql(&sql, |
| 1416 | 1451 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1417 | 1452 | zSearch, zSearch); |
| 1418 | - url_add_parameter(&url, "s", zSearch); | |
| 1419 | 1453 | } |
| 1420 | 1454 | rBefore = symbolic_name_to_mtime(zBefore); |
| 1421 | 1455 | rAfter = symbolic_name_to_mtime(zAfter); |
| 1422 | 1456 | rCirca = symbolic_name_to_mtime(zCirca); |
| 1423 | 1457 | if( rAfter>0.0 ){ |
| 1424 | 1458 | if( rBefore>0.0 ){ |
| 1425 | 1459 | blob_append_sql(&sql, |
| 1426 | 1460 | " AND event.mtime>=%.17g AND event.mtime<=%.17g" |
| 1427 | 1461 | " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); |
| 1428 | - url_add_parameter(&url, "a", zAfter); | |
| 1429 | - url_add_parameter(&url, "b", zBefore); | |
| 1430 | 1462 | nEntry = -1; |
| 1431 | 1463 | }else{ |
| 1432 | 1464 | blob_append_sql(&sql, |
| 1433 | 1465 | " AND event.mtime>=%.17g ORDER BY event.mtime ASC", |
| 1434 | 1466 | rAfter-ONE_SECOND); |
| 1435 | - url_add_parameter(&url, "a", zAfter); | |
| 1436 | 1467 | } |
| 1437 | 1468 | }else if( rBefore>0.0 ){ |
| 1438 | 1469 | blob_append_sql(&sql, |
| 1439 | 1470 | " AND event.mtime<=%.17g ORDER BY event.mtime DESC", |
| 1440 | 1471 | rBefore+ONE_SECOND); |
| 1441 | - url_add_parameter(&url, "b", zBefore); | |
| 1442 | 1472 | }else if( rCirca>0.0 ){ |
| 1443 | 1473 | Blob sql2; |
| 1444 | 1474 | blob_init(&sql2, blob_sql_text(&sql), -1); |
| 1445 | 1475 | blob_append_sql(&sql2, |
| 1446 | 1476 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| @@ -1452,11 +1482,10 @@ | ||
| 1452 | 1482 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 1453 | 1483 | rCirca |
| 1454 | 1484 | ); |
| 1455 | 1485 | nEntry -= (nEntry+1)/2; |
| 1456 | 1486 | if( useDividers ) timeline_add_dividers(rCirca, 0); |
| 1457 | - url_add_parameter(&url, "c", zCirca); | |
| 1458 | 1487 | }else{ |
| 1459 | 1488 | blob_append_sql(&sql, " ORDER BY event.mtime DESC"); |
| 1460 | 1489 | } |
| 1461 | 1490 | if( nEntry>0 ) blob_append_sql(&sql, " LIMIT %d", nEntry); |
| 1462 | 1491 | db_multi_exec("%s", blob_sql_text(&sql)); |
| @@ -1509,64 +1538,44 @@ | ||
| 1509 | 1538 | } |
| 1510 | 1539 | if( g.perm.Hyperlink ){ |
| 1511 | 1540 | if( zAfter || n==nEntry ){ |
| 1512 | 1541 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1513 | 1542 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| 1543 | + zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); | |
| 1514 | 1544 | free(zDate); |
| 1515 | 1545 | } |
| 1516 | 1546 | if( zBefore || (zAfter && n==nEntry) ){ |
| 1517 | 1547 | zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); |
| 1518 | 1548 | timeline_submenu(&url, "Newer", "a", zDate, "b"); |
| 1519 | 1549 | free(zDate); |
| 1520 | - }else if( tagid==0 && zUses==0 ){ | |
| 1521 | - if( zType[0]!='a' ){ | |
| 1522 | - timeline_submenu(&url, "All Types", "y", "all", 0); | |
| 1523 | - } | |
| 1524 | - if( zType[0]!='w' && g.perm.RdWiki ){ | |
| 1525 | - timeline_submenu(&url, "Wiki Only", "y", "w", 0); | |
| 1526 | - } | |
| 1527 | - if( zType[0]!='c' && g.perm.Read ){ | |
| 1528 | - timeline_submenu(&url, "Checkins Only", "y", "ci", 0); | |
| 1529 | - } | |
| 1530 | - if( zType[0]!='t' && g.perm.RdTkt ){ | |
| 1531 | - timeline_submenu(&url, "Tickets Only", "y", "t", 0); | |
| 1532 | - } | |
| 1533 | - if( zType[0]!='e' && g.perm.RdWiki ){ | |
| 1534 | - timeline_submenu(&url, "Events Only", "y", "e", 0); | |
| 1535 | - } | |
| 1536 | - if( zType[0]!='g' && g.perm.Read ){ | |
| 1537 | - timeline_submenu(&url, "Tags Only", "y", "g", 0); | |
| 1538 | - } | |
| 1539 | - } | |
| 1540 | - if( nEntry>20 ){ | |
| 1541 | - timeline_submenu(&url, "20 Entries", "n", "20", 0); | |
| 1542 | - } | |
| 1543 | - if( nEntry<200 && nEntry>0 ){ | |
| 1544 | - timeline_submenu(&url, "200 Entries", "n", "200", 0); | |
| 1545 | 1550 | } |
| 1546 | 1551 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1547 | - if( tmFlags & TIMELINE_FCHANGES ){ | |
| 1548 | - timeline_submenu(&url, "Hide Files", "v", 0, 0); | |
| 1549 | - }else{ | |
| 1550 | - timeline_submenu(&url, "Show Files", "v", "", 0); | |
| 1551 | - } | |
| 1552 | 1552 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1553 | 1553 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1554 | 1554 | } |
| 1555 | 1555 | } |
| 1556 | + style_submenu_binary("v","With Files","Without Files"); | |
| 1557 | + if( zUses==0 ) timeline_y_submenu(); | |
| 1558 | + style_submenu_entry("n","Lines",1); | |
| 1556 | 1559 | } |
| 1557 | 1560 | } |
| 1558 | 1561 | if( P("showsql") ){ |
| 1559 | 1562 | @ <blockquote>%h(blob_sql_text(&sql))</blockquote> |
| 1560 | 1563 | } |
| 1564 | + if( search_restrict(SRCH_CKIN)!=0 ){ | |
| 1565 | + style_submenu_element("Search", 0, "%R/search?y=c"); | |
| 1566 | + } | |
| 1561 | 1567 | if( P("showid") ) tmFlags |= TIMELINE_SHOWRID; |
| 1562 | 1568 | blob_zero(&sql); |
| 1563 | 1569 | db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/"); |
| 1564 | 1570 | @ <h2>%b(&desc)</h2> |
| 1565 | 1571 | blob_reset(&desc); |
| 1566 | 1572 | www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0); |
| 1567 | 1573 | db_finalize(&q); |
| 1574 | + if( zOlderButton ){ | |
| 1575 | + @ %z(xhref("class='button'","%z",zOlderButton))Older</a> | |
| 1576 | + } | |
| 1568 | 1577 | style_footer(); |
| 1569 | 1578 | } |
| 1570 | 1579 | |
| 1571 | 1580 | /* |
| 1572 | 1581 | ** The input query q selects various records. Print a human-readable |
| @@ -1771,11 +1780,11 @@ | ||
| 1771 | 1780 | ** for the current version or "now" for the current time. |
| 1772 | 1781 | ** |
| 1773 | 1782 | ** Options: |
| 1774 | 1783 | ** -n|--limit N Output the first N entries (default 20 lines). |
| 1775 | 1784 | ** N=0 means no limit. |
| 1776 | -** -p|--path PATH Output items affecting PATH only. | |
| 1785 | +** -p|--path PATH Output items affecting PATH only. | |
| 1777 | 1786 | ** PATH can be a file or a sub directory. |
| 1778 | 1787 | ** --offset P skip P changes |
| 1779 | 1788 | ** -t|--type TYPE Output items from the given types only, such as: |
| 1780 | 1789 | ** ci = file commits only |
| 1781 | 1790 | ** e = events only |
| @@ -1893,11 +1902,11 @@ | ||
| 1893 | 1902 | if( mode==0 ){ |
| 1894 | 1903 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1895 | 1904 | } |
| 1896 | 1905 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1897 | 1906 | } |
| 1898 | - | |
| 1907 | + | |
| 1899 | 1908 | if( zFilePattern ){ |
| 1900 | 1909 | if( zType==0 ){ |
| 1901 | 1910 | /* When zFilePattern is specified and type is not specified, only show |
| 1902 | 1911 | * file checkins */ |
| 1903 | 1912 | zType="ci"; |
| @@ -2041,10 +2050,10 @@ | ||
| 2041 | 2050 | " AND blob.rid=c.cid" |
| 2042 | 2051 | ); |
| 2043 | 2052 | while( db_step(&q)==SQLITE_ROW ){ |
| 2044 | 2053 | const char *zUuid = db_column_text(&q, 0); |
| 2045 | 2054 | @ <li> |
| 2046 | - @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&d=%s(zUuid)&unhide">%S(zUuid)</a> | |
| 2055 | + @ <a href="%s(g.zTop)/timeline?dp=%s(zUuid)&unhide">%S(zUuid)</a> | |
| 2047 | 2056 | } |
| 2048 | 2057 | db_finalize(&q); |
| 2049 | 2058 | style_footer(); |
| 2050 | 2059 | } |
| 2051 | 2060 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -494,10 +494,11 @@ | |
| 494 | " (SELECT name FROM filename WHERE fnid=mlink.pfnid) AS oldnm" |
| 495 | " FROM mlink" |
| 496 | " WHERE mid=:mid AND (pid!=fid OR pfnid>0)" |
| 497 | " AND (fid>0 OR" |
| 498 | " fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=:mid))" |
| 499 | " ORDER BY 3 /*sort*/" |
| 500 | ); |
| 501 | fchngQueryInit = 1; |
| 502 | } |
| 503 | db_bind_int(&fchngQuery, ":mid", rid); |
| @@ -666,16 +667,16 @@ | |
| 666 | if( cSep=='[' ) cgi_printf("["); |
| 667 | cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 668 | } |
| 669 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 670 | graph_free(pGraph); |
| 671 | @ var canvasDiv = gebi("canvas"); |
| 672 | @ var canvasStyle = window.getComputedStyle && window.getComputedStyle(canvasDiv,null); |
| 673 | @ var lineColor = (canvasStyle && canvasStyle.getPropertyValue('color')) || 'black'; |
| 674 | @ var bgColor = (canvasStyle && canvasStyle.getPropertyValue('background-color')) || 'white'; |
| 675 | @ if( bgColor=='transparent' ) bgColor = 'white'; |
| 676 | @ var boxColor = lineColor; |
| 677 | @ function drawBox(color,x0,y0,x1,y1){ |
| 678 | @ var n = document.createElement("div"); |
| 679 | @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } |
| 680 | @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } |
| 681 | @ var w = x1-x0+1; |
| @@ -685,11 +686,11 @@ | |
| 685 | @ n.style.left = x0+"px"; |
| 686 | @ n.style.top = y0+"px"; |
| 687 | @ n.style.width = w+"px"; |
| 688 | @ n.style.height = h+"px"; |
| 689 | @ n.style.backgroundColor = color; |
| 690 | @ canvasDiv.appendChild(n); |
| 691 | @ return n; |
| 692 | @ } |
| 693 | @ function absoluteY(id){ |
| 694 | @ var obj = gebi(id); |
| 695 | @ if( !obj ) return; |
| @@ -711,39 +712,39 @@ | |
| 711 | @ }while( obj = obj.offsetParent ); |
| 712 | @ } |
| 713 | @ return left; |
| 714 | @ } |
| 715 | @ function drawUpArrow(x,y0,y1){ |
| 716 | @ drawBox(lineColor,x,y0,x+1,y1); |
| 717 | @ if( y0+10>=y1 ){ |
| 718 | @ drawBox(lineColor,x-1,y0+1,x+2,y0+2); |
| 719 | @ drawBox(lineColor,x-2,y0+3,x+3,y0+4); |
| 720 | @ }else{ |
| 721 | @ drawBox(lineColor,x-1,y0+2,x+2,y0+4); |
| 722 | @ drawBox(lineColor,x-2,y0+5,x+3,y0+7); |
| 723 | @ } |
| 724 | @ } |
| 725 | @ function drawThinArrow(y,xFrom,xTo){ |
| 726 | @ if( xFrom<xTo ){ |
| 727 | @ drawBox(lineColor,xFrom,y,xTo,y); |
| 728 | @ drawBox(lineColor,xTo-3,y-1,xTo-2,y+1); |
| 729 | @ drawBox(lineColor,xTo-4,y-2,xTo-4,y+2); |
| 730 | @ }else{ |
| 731 | @ drawBox(lineColor,xTo,y,xFrom,y); |
| 732 | @ drawBox(lineColor,xTo+2,y-1,xTo+3,y+1); |
| 733 | @ drawBox(lineColor,xTo+4,y-2,xTo+4,y+2); |
| 734 | @ } |
| 735 | @ } |
| 736 | @ function drawThinLine(x0,y0,x1,y1){ |
| 737 | @ drawBox(lineColor,x0,y0,x1,y1); |
| 738 | @ } |
| 739 | @ function drawNodeBox(color,x0,y0,x1,y1){ |
| 740 | @ drawBox(color,x0,y0,x1,y1).style.cursor = "pointer"; |
| 741 | @ } |
| 742 | @ function drawNode(p, left, btm){ |
| 743 | @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6); |
| 744 | @ drawNodeBox(p.bg||bgColor,p.x-4,p.y-4,p.x+5,p.y+5); |
| 745 | @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5); |
| 746 | @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2); |
| 747 | if( !omitDescenders ){ |
| 748 | @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5); |
| 749 | @ if( p.d ) drawUpArrow(p.x, p.y+6, btm); |
| @@ -765,11 +766,11 @@ | |
| 765 | @ for(var i=0; i<n; i+=2){ |
| 766 | @ var x1 = p.au[i]*railPitch + left; |
| 767 | @ var x0 = x1>p.x ? p.x+7 : p.x-6; |
| 768 | @ var u = rowinfo[p.au[i+1]-1]; |
| 769 | @ if(u.id<p.id){ |
| 770 | @ drawBox(lineColor,x0,p.y,x1,p.y+1); |
| 771 | @ drawUpArrow(x1, u.y+6, p.y); |
| 772 | @ }else{ |
| 773 | @ drawBox("#600000",x0,p.y,x1,p.y+1); |
| 774 | @ drawBox("#600000",x1-1,p.y,x1,u.y+1); |
| 775 | @ drawBox("#600000",x1,u.y,u.x-6,u.y+1); |
| @@ -952,13 +953,22 @@ | |
| 952 | if( z==0 ) return -1.0; |
| 953 | if( fossil_isdate(z) ){ |
| 954 | mtime = db_double(0.0, "SELECT julianday(%Q,'utc')", z); |
| 955 | if( mtime>0.0 ) return mtime; |
| 956 | } |
| 957 | rid = symbolic_name_to_rid(z, "ci"); |
| 958 | if( rid==0 ) return -1.0; |
| 959 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 960 | return mtime; |
| 961 | } |
| 962 | |
| 963 | /* |
| 964 | ** The value of one second in julianday notation |
| @@ -1011,10 +1021,47 @@ | |
| 1011 | } |
| 1012 | db_finalize(&q); |
| 1013 | return blob_str(&out); |
| 1014 | } |
| 1015 | |
| 1016 | |
| 1017 | /* |
| 1018 | ** WEBPAGE: timeline |
| 1019 | ** |
| 1020 | ** Query parameters: |
| @@ -1055,11 +1102,11 @@ | |
| 1055 | */ |
| 1056 | void page_timeline(void){ |
| 1057 | Stmt q; /* Query used to generate the timeline */ |
| 1058 | Blob sql; /* text of SQL used to generate timeline */ |
| 1059 | Blob desc; /* Description of the timeline */ |
| 1060 | int nEntry = atoi(PD("n","20")); /* Max number of entries on timeline */ |
| 1061 | int p_rid = name_to_typed_rid(P("p"),"ci"); /* artifact p and its parents */ |
| 1062 | int d_rid = name_to_typed_rid(P("d"),"ci"); /* artifact d and descendants */ |
| 1063 | int f_rid = name_to_typed_rid(P("f"),"ci"); /* artifact f and close family */ |
| 1064 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 1065 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| @@ -1069,11 +1116,11 @@ | |
| 1069 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 1070 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 1071 | const char *zSearch = P("s"); /* Search string */ |
| 1072 | const char *zUses = P("uf"); /* Only show checkins hold this file */ |
| 1073 | const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */ |
| 1074 | const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (week-of-year)*/ |
| 1075 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1076 | int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */ |
| 1077 | int tagid; /* Tag ID */ |
| 1078 | int tmFlags = 0; /* Timeline flags */ |
| 1079 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| @@ -1084,10 +1131,32 @@ | |
| 1084 | int noMerge = P("shortest")==0; /* Follow merge links if shorter */ |
| 1085 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1086 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1087 | int pd_rid; |
| 1088 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1089 | |
| 1090 | /* To view the timeline, must have permission to read project data. |
| 1091 | */ |
| 1092 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1093 | if( pd_rid ){ |
| @@ -1097,20 +1166,21 @@ | |
| 1097 | if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ |
| 1098 | login_needed(); |
| 1099 | return; |
| 1100 | } |
| 1101 | url_initialize(&url, "timeline"); |
| 1102 | if( zTagName && g.perm.Read ){ |
| 1103 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 1104 | zThisTag = zTagName; |
| 1105 | }else if( zBrName && g.perm.Read ){ |
| 1106 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| 1107 | zThisTag = zBrName; |
| 1108 | }else{ |
| 1109 | tagid = 0; |
| 1110 | } |
| 1111 | if( tagid>0 |
| 1112 | && db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry |
| 1113 | ){ |
| 1114 | zCirca = zBefore = zAfter = 0; |
| 1115 | nEntry = -1; |
| 1116 | } |
| @@ -1117,32 +1187,26 @@ | |
| 1117 | if( zType[0]=='a' ){ |
| 1118 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1119 | }else{ |
| 1120 | tmFlags |= TIMELINE_GRAPH; |
| 1121 | } |
| 1122 | if( nEntry>0 ) url_add_parameter(&url, "n", mprintf("%d", nEntry)); |
| 1123 | if( P("ng")!=0 || zSearch!=0 ){ |
| 1124 | tmFlags &= ~TIMELINE_GRAPH; |
| 1125 | url_add_parameter(&url, "ng", 0); |
| 1126 | } |
| 1127 | if( P("brbg")!=0 ){ |
| 1128 | tmFlags |= TIMELINE_BRCOLOR; |
| 1129 | url_add_parameter(&url, "brbg", 0); |
| 1130 | } |
| 1131 | if( P("unhide")!=0 ){ |
| 1132 | tmFlags |= TIMELINE_UNHIDE; |
| 1133 | url_add_parameter(&url, "unhide", 0); |
| 1134 | } |
| 1135 | if( P("ubg")!=0 ){ |
| 1136 | tmFlags |= TIMELINE_UCOLOR; |
| 1137 | url_add_parameter(&url, "ubg", 0); |
| 1138 | } |
| 1139 | if( zUses!=0 ){ |
| 1140 | int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); |
| 1141 | if( ufid ){ |
| 1142 | zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); |
| 1143 | url_add_parameter(&url, "uf", zUses); |
| 1144 | db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); |
| 1145 | compute_uses_file("usesfile", ufid, 0); |
| 1146 | zType = "ci"; |
| 1147 | }else{ |
| 1148 | zUses = 0; |
| @@ -1161,22 +1225,20 @@ | |
| 1161 | timeline_temp_table(); |
| 1162 | blob_zero(&sql); |
| 1163 | blob_zero(&desc); |
| 1164 | blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); |
| 1165 | blob_append(&sql, timeline_query_for_www(), -1); |
| 1166 | if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){ |
| 1167 | tmFlags |= TIMELINE_FCHANGES; |
| 1168 | url_add_parameter(&url, "v", 0); |
| 1169 | } |
| 1170 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1171 | blob_append_sql(&sql, |
| 1172 | " AND NOT EXISTS(SELECT 1 FROM tagxref" |
| 1173 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", |
| 1174 | TAG_HIDDEN |
| 1175 | ); |
| 1176 | } |
| 1177 | if( !useDividers ) url_add_parameter(&url, "nd", 0); |
| 1178 | if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){ |
| 1179 | /* If from= and to= are present, display all nodes on a path connecting |
| 1180 | ** the two */ |
| 1181 | PathNode *p = 0; |
| 1182 | const char *zFrom = 0; |
| @@ -1241,34 +1303,19 @@ | |
| 1241 | } |
| 1242 | if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); |
| 1243 | } |
| 1244 | blob_appendf(&desc, " of %z[%S]</a>", |
| 1245 | href("%R/info/%s", zUuid), zUuid); |
| 1246 | if( p_rid ){ |
| 1247 | url_add_parameter(&url, "p", zUuid); |
| 1248 | } |
| 1249 | if( d_rid ){ |
| 1250 | if( p_rid ){ |
| 1251 | /* If both p= and d= are set, we don't have the uuid of d yet. */ |
| 1252 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); |
| 1253 | } |
| 1254 | url_add_parameter(&url, "d", zUuid); |
| 1255 | } |
| 1256 | if( nEntry>20 ){ |
| 1257 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 1258 | } |
| 1259 | if( nEntry<200 && nEntry>0 ){ |
| 1260 | timeline_submenu(&url, "200 Entries", "n", "200", 0); |
| 1261 | } |
| 1262 | if( tmFlags & TIMELINE_FCHANGES ){ |
| 1263 | timeline_submenu(&url, "Hide Files", "v", 0, 0); |
| 1264 | }else{ |
| 1265 | timeline_submenu(&url, "Show Files", "v", "", 0); |
| 1266 | } |
| 1267 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1268 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1269 | } |
| 1270 | }else if( f_rid && g.perm.Read ){ |
| 1271 | /* If f= is present, ignore all other parameters other than n= */ |
| 1272 | char *zUuid; |
| 1273 | db_multi_exec( |
| 1274 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" |
| @@ -1282,16 +1329,11 @@ | |
| 1282 | if( useDividers ) timeline_add_dividers(0, f_rid); |
| 1283 | blob_appendf(&desc, "Parents and children of check-in "); |
| 1284 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); |
| 1285 | blob_appendf(&desc, "%z[%S]</a>", href("%R/info/%s", zUuid), zUuid); |
| 1286 | tmFlags |= TIMELINE_DISJOINT; |
| 1287 | url_add_parameter(&url, "f", zUuid); |
| 1288 | if( tmFlags & TIMELINE_FCHANGES ){ |
| 1289 | timeline_submenu(&url, "Hide Files", "v", 0, 0); |
| 1290 | }else{ |
| 1291 | timeline_submenu(&url, "Show Files", "v", "", 0); |
| 1292 | } |
| 1293 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1294 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1295 | } |
| 1296 | }else{ |
| 1297 | /* Otherwise, a timeline based on a span of time */ |
| @@ -1316,11 +1358,10 @@ | |
| 1316 | blob_append_sql(&sql, |
| 1317 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1318 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1319 | |
| 1320 | if( zBrName ){ |
| 1321 | url_add_parameter(&url, "r", zBrName); |
| 1322 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 1323 | ** are not part of the branch which are parents or children of the |
| 1324 | ** branch to be included in the report. This related check-ins are |
| 1325 | ** useful in helping to visualize what has happened on a quiescent |
| 1326 | ** branch that is infrequently merged with a much more activate branch. |
| @@ -1342,21 +1383,17 @@ | |
| 1342 | " OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid" |
| 1343 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1344 | tagid |
| 1345 | ); |
| 1346 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1347 | blob_append_sql(&sql, |
| 1348 | " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid" |
| 1349 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1350 | TAG_HIDDEN |
| 1351 | ); |
| 1352 | } |
| 1353 | }else{ |
| 1354 | url_add_parameter(&url, "mionly", "1"); |
| 1355 | } |
| 1356 | }else{ |
| 1357 | url_add_parameter(&url, "t", zTagName); |
| 1358 | } |
| 1359 | blob_append_sql(&sql, ")"); |
| 1360 | } |
| 1361 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1362 | || (zType[0]=='t' && !g.perm.RdTkt) |
| @@ -1384,11 +1421,10 @@ | |
| 1384 | } |
| 1385 | blob_append_sql(&sql, ")"); |
| 1386 | } |
| 1387 | }else{ /* zType!="all" */ |
| 1388 | blob_append_sql(&sql, " AND event.type=%Q", zType); |
| 1389 | url_add_parameter(&url, "y", zType); |
| 1390 | if( zType[0]=='c' ){ |
| 1391 | zEType = "checkin"; |
| 1392 | }else if( zType[0]=='w' ){ |
| 1393 | zEType = "wiki edit"; |
| 1394 | }else if( zType[0]=='t' ){ |
| @@ -1406,41 +1442,35 @@ | |
| 1406 | zCirca = zBefore = zAfter = 0; |
| 1407 | nEntry = -1; |
| 1408 | } |
| 1409 | blob_append_sql(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1410 | zUser, zUser); |
| 1411 | url_add_parameter(&url, "u", zUser); |
| 1412 | zThisUser = zUser; |
| 1413 | } |
| 1414 | if( zSearch ){ |
| 1415 | blob_append_sql(&sql, |
| 1416 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1417 | zSearch, zSearch); |
| 1418 | url_add_parameter(&url, "s", zSearch); |
| 1419 | } |
| 1420 | rBefore = symbolic_name_to_mtime(zBefore); |
| 1421 | rAfter = symbolic_name_to_mtime(zAfter); |
| 1422 | rCirca = symbolic_name_to_mtime(zCirca); |
| 1423 | if( rAfter>0.0 ){ |
| 1424 | if( rBefore>0.0 ){ |
| 1425 | blob_append_sql(&sql, |
| 1426 | " AND event.mtime>=%.17g AND event.mtime<=%.17g" |
| 1427 | " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); |
| 1428 | url_add_parameter(&url, "a", zAfter); |
| 1429 | url_add_parameter(&url, "b", zBefore); |
| 1430 | nEntry = -1; |
| 1431 | }else{ |
| 1432 | blob_append_sql(&sql, |
| 1433 | " AND event.mtime>=%.17g ORDER BY event.mtime ASC", |
| 1434 | rAfter-ONE_SECOND); |
| 1435 | url_add_parameter(&url, "a", zAfter); |
| 1436 | } |
| 1437 | }else if( rBefore>0.0 ){ |
| 1438 | blob_append_sql(&sql, |
| 1439 | " AND event.mtime<=%.17g ORDER BY event.mtime DESC", |
| 1440 | rBefore+ONE_SECOND); |
| 1441 | url_add_parameter(&url, "b", zBefore); |
| 1442 | }else if( rCirca>0.0 ){ |
| 1443 | Blob sql2; |
| 1444 | blob_init(&sql2, blob_sql_text(&sql), -1); |
| 1445 | blob_append_sql(&sql2, |
| 1446 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| @@ -1452,11 +1482,10 @@ | |
| 1452 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 1453 | rCirca |
| 1454 | ); |
| 1455 | nEntry -= (nEntry+1)/2; |
| 1456 | if( useDividers ) timeline_add_dividers(rCirca, 0); |
| 1457 | url_add_parameter(&url, "c", zCirca); |
| 1458 | }else{ |
| 1459 | blob_append_sql(&sql, " ORDER BY event.mtime DESC"); |
| 1460 | } |
| 1461 | if( nEntry>0 ) blob_append_sql(&sql, " LIMIT %d", nEntry); |
| 1462 | db_multi_exec("%s", blob_sql_text(&sql)); |
| @@ -1509,64 +1538,44 @@ | |
| 1509 | } |
| 1510 | if( g.perm.Hyperlink ){ |
| 1511 | if( zAfter || n==nEntry ){ |
| 1512 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1513 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| 1514 | free(zDate); |
| 1515 | } |
| 1516 | if( zBefore || (zAfter && n==nEntry) ){ |
| 1517 | zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); |
| 1518 | timeline_submenu(&url, "Newer", "a", zDate, "b"); |
| 1519 | free(zDate); |
| 1520 | }else if( tagid==0 && zUses==0 ){ |
| 1521 | if( zType[0]!='a' ){ |
| 1522 | timeline_submenu(&url, "All Types", "y", "all", 0); |
| 1523 | } |
| 1524 | if( zType[0]!='w' && g.perm.RdWiki ){ |
| 1525 | timeline_submenu(&url, "Wiki Only", "y", "w", 0); |
| 1526 | } |
| 1527 | if( zType[0]!='c' && g.perm.Read ){ |
| 1528 | timeline_submenu(&url, "Checkins Only", "y", "ci", 0); |
| 1529 | } |
| 1530 | if( zType[0]!='t' && g.perm.RdTkt ){ |
| 1531 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 1532 | } |
| 1533 | if( zType[0]!='e' && g.perm.RdWiki ){ |
| 1534 | timeline_submenu(&url, "Events Only", "y", "e", 0); |
| 1535 | } |
| 1536 | if( zType[0]!='g' && g.perm.Read ){ |
| 1537 | timeline_submenu(&url, "Tags Only", "y", "g", 0); |
| 1538 | } |
| 1539 | } |
| 1540 | if( nEntry>20 ){ |
| 1541 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 1542 | } |
| 1543 | if( nEntry<200 && nEntry>0 ){ |
| 1544 | timeline_submenu(&url, "200 Entries", "n", "200", 0); |
| 1545 | } |
| 1546 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1547 | if( tmFlags & TIMELINE_FCHANGES ){ |
| 1548 | timeline_submenu(&url, "Hide Files", "v", 0, 0); |
| 1549 | }else{ |
| 1550 | timeline_submenu(&url, "Show Files", "v", "", 0); |
| 1551 | } |
| 1552 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1553 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1554 | } |
| 1555 | } |
| 1556 | } |
| 1557 | } |
| 1558 | if( P("showsql") ){ |
| 1559 | @ <blockquote>%h(blob_sql_text(&sql))</blockquote> |
| 1560 | } |
| 1561 | if( P("showid") ) tmFlags |= TIMELINE_SHOWRID; |
| 1562 | blob_zero(&sql); |
| 1563 | db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/"); |
| 1564 | @ <h2>%b(&desc)</h2> |
| 1565 | blob_reset(&desc); |
| 1566 | www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0); |
| 1567 | db_finalize(&q); |
| 1568 | style_footer(); |
| 1569 | } |
| 1570 | |
| 1571 | /* |
| 1572 | ** The input query q selects various records. Print a human-readable |
| @@ -1771,11 +1780,11 @@ | |
| 1771 | ** for the current version or "now" for the current time. |
| 1772 | ** |
| 1773 | ** Options: |
| 1774 | ** -n|--limit N Output the first N entries (default 20 lines). |
| 1775 | ** N=0 means no limit. |
| 1776 | ** -p|--path PATH Output items affecting PATH only. |
| 1777 | ** PATH can be a file or a sub directory. |
| 1778 | ** --offset P skip P changes |
| 1779 | ** -t|--type TYPE Output items from the given types only, such as: |
| 1780 | ** ci = file commits only |
| 1781 | ** e = events only |
| @@ -1893,11 +1902,11 @@ | |
| 1893 | if( mode==0 ){ |
| 1894 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1895 | } |
| 1896 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1897 | } |
| 1898 | |
| 1899 | if( zFilePattern ){ |
| 1900 | if( zType==0 ){ |
| 1901 | /* When zFilePattern is specified and type is not specified, only show |
| 1902 | * file checkins */ |
| 1903 | zType="ci"; |
| @@ -2041,10 +2050,10 @@ | |
| 2041 | " AND blob.rid=c.cid" |
| 2042 | ); |
| 2043 | while( db_step(&q)==SQLITE_ROW ){ |
| 2044 | const char *zUuid = db_column_text(&q, 0); |
| 2045 | @ <li> |
| 2046 | @ <a href="%s(g.zTop)/timeline?p=%s(zUuid)&d=%s(zUuid)&unhide">%S(zUuid)</a> |
| 2047 | } |
| 2048 | db_finalize(&q); |
| 2049 | style_footer(); |
| 2050 | } |
| 2051 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -494,10 +494,11 @@ | |
| 494 | " (SELECT name FROM filename WHERE fnid=mlink.pfnid) AS oldnm" |
| 495 | " FROM mlink" |
| 496 | " WHERE mid=:mid AND (pid!=fid OR pfnid>0)" |
| 497 | " AND (fid>0 OR" |
| 498 | " fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=:mid))" |
| 499 | " AND NOT mlink.isaux" |
| 500 | " ORDER BY 3 /*sort*/" |
| 501 | ); |
| 502 | fchngQueryInit = 1; |
| 503 | } |
| 504 | db_bind_int(&fchngQuery, ":mid", rid); |
| @@ -666,16 +667,16 @@ | |
| 667 | if( cSep=='[' ) cgi_printf("["); |
| 668 | cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n"); |
| 669 | } |
| 670 | cgi_printf("var nrail = %d\n", pGraph->mxRail+1); |
| 671 | graph_free(pGraph); |
| 672 | @ var cDiv = gebi("canvas"); |
| 673 | @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null); |
| 674 | @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black'; |
| 675 | @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white'; |
| 676 | @ if( bgClr=='transparent' ) bgClr = 'white'; |
| 677 | @ var boxColor = lineClr; |
| 678 | @ function drawBox(color,x0,y0,x1,y1){ |
| 679 | @ var n = document.createElement("div"); |
| 680 | @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; } |
| 681 | @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; } |
| 682 | @ var w = x1-x0+1; |
| @@ -685,11 +686,11 @@ | |
| 686 | @ n.style.left = x0+"px"; |
| 687 | @ n.style.top = y0+"px"; |
| 688 | @ n.style.width = w+"px"; |
| 689 | @ n.style.height = h+"px"; |
| 690 | @ n.style.backgroundColor = color; |
| 691 | @ cDiv.appendChild(n); |
| 692 | @ return n; |
| 693 | @ } |
| 694 | @ function absoluteY(id){ |
| 695 | @ var obj = gebi(id); |
| 696 | @ if( !obj ) return; |
| @@ -711,39 +712,39 @@ | |
| 712 | @ }while( obj = obj.offsetParent ); |
| 713 | @ } |
| 714 | @ return left; |
| 715 | @ } |
| 716 | @ function drawUpArrow(x,y0,y1){ |
| 717 | @ drawBox(lineClr,x,y0,x+1,y1); |
| 718 | @ if( y0+10>=y1 ){ |
| 719 | @ drawBox(lineClr,x-1,y0+1,x+2,y0+2); |
| 720 | @ drawBox(lineClr,x-2,y0+3,x+3,y0+4); |
| 721 | @ }else{ |
| 722 | @ drawBox(lineClr,x-1,y0+2,x+2,y0+4); |
| 723 | @ drawBox(lineClr,x-2,y0+5,x+3,y0+7); |
| 724 | @ } |
| 725 | @ } |
| 726 | @ function drawThinArrow(y,xFrom,xTo){ |
| 727 | @ if( xFrom<xTo ){ |
| 728 | @ drawBox(lineClr,xFrom,y,xTo,y); |
| 729 | @ drawBox(lineClr,xTo-3,y-1,xTo-2,y+1); |
| 730 | @ drawBox(lineClr,xTo-4,y-2,xTo-4,y+2); |
| 731 | @ }else{ |
| 732 | @ drawBox(lineClr,xTo,y,xFrom,y); |
| 733 | @ drawBox(lineClr,xTo+2,y-1,xTo+3,y+1); |
| 734 | @ drawBox(lineClr,xTo+4,y-2,xTo+4,y+2); |
| 735 | @ } |
| 736 | @ } |
| 737 | @ function drawThinLine(x0,y0,x1,y1){ |
| 738 | @ drawBox(lineClr,x0,y0,x1,y1); |
| 739 | @ } |
| 740 | @ function drawNodeBox(color,x0,y0,x1,y1){ |
| 741 | @ drawBox(color,x0,y0,x1,y1).style.cursor = "pointer"; |
| 742 | @ } |
| 743 | @ function drawNode(p, left, btm){ |
| 744 | @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6); |
| 745 | @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5); |
| 746 | @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5); |
| 747 | @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2); |
| 748 | if( !omitDescenders ){ |
| 749 | @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5); |
| 750 | @ if( p.d ) drawUpArrow(p.x, p.y+6, btm); |
| @@ -765,11 +766,11 @@ | |
| 766 | @ for(var i=0; i<n; i+=2){ |
| 767 | @ var x1 = p.au[i]*railPitch + left; |
| 768 | @ var x0 = x1>p.x ? p.x+7 : p.x-6; |
| 769 | @ var u = rowinfo[p.au[i+1]-1]; |
| 770 | @ if(u.id<p.id){ |
| 771 | @ drawBox(lineClr,x0,p.y,x1,p.y+1); |
| 772 | @ drawUpArrow(x1, u.y+6, p.y); |
| 773 | @ }else{ |
| 774 | @ drawBox("#600000",x0,p.y,x1,p.y+1); |
| 775 | @ drawBox("#600000",x1-1,p.y,x1,u.y+1); |
| 776 | @ drawBox("#600000",x1,u.y,u.x-6,u.y+1); |
| @@ -952,13 +953,22 @@ | |
| 953 | if( z==0 ) return -1.0; |
| 954 | if( fossil_isdate(z) ){ |
| 955 | mtime = db_double(0.0, "SELECT julianday(%Q,'utc')", z); |
| 956 | if( mtime>0.0 ) return mtime; |
| 957 | } |
| 958 | rid = symbolic_name_to_rid(z, "*"); |
| 959 | if( rid ){ |
| 960 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 961 | }else{ |
| 962 | mtime = db_double(-1.0, |
| 963 | "SELECT max(event.mtime) FROM event, tag, tagxref" |
| 964 | " WHERE tag.tagname GLOB 'event-%q*'" |
| 965 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype" |
| 966 | " AND event.objid=tagxref.rid", |
| 967 | z |
| 968 | ); |
| 969 | } |
| 970 | return mtime; |
| 971 | } |
| 972 | |
| 973 | /* |
| 974 | ** The value of one second in julianday notation |
| @@ -1011,10 +1021,47 @@ | |
| 1021 | } |
| 1022 | db_finalize(&q); |
| 1023 | return blob_str(&out); |
| 1024 | } |
| 1025 | |
| 1026 | |
| 1027 | /* |
| 1028 | ** Add the select/option box to the timeline submenu that is used to |
| 1029 | ** set the y= parameter that determines which elements to display |
| 1030 | ** on the timeline. |
| 1031 | */ |
| 1032 | static void timeline_y_submenu(void){ |
| 1033 | static int i = 0; |
| 1034 | static const char *az[12]; |
| 1035 | if( i==0 ){ |
| 1036 | az[0] = "all"; |
| 1037 | az[1] = "All Types"; |
| 1038 | i = 2; |
| 1039 | if( g.perm.Read ){ |
| 1040 | az[i++] = "ci"; |
| 1041 | az[i++] = "Check-ins"; |
| 1042 | az[i++] = "g"; |
| 1043 | az[i++] = "Tags"; |
| 1044 | } |
| 1045 | if( g.perm.RdWiki ){ |
| 1046 | az[i++] = "e"; |
| 1047 | az[i++] = "Tech Notes"; |
| 1048 | } |
| 1049 | if( g.perm.RdTkt ){ |
| 1050 | az[i++] = "t"; |
| 1051 | az[i++] = "Tickets"; |
| 1052 | } |
| 1053 | if( g.perm.RdWiki ){ |
| 1054 | az[i++] = "w"; |
| 1055 | az[i++] = "Wiki"; |
| 1056 | } |
| 1057 | assert( i<=ArraySize(az) ); |
| 1058 | } |
| 1059 | if( i>2 ){ |
| 1060 | style_submenu_multichoice("y", i/2, az); |
| 1061 | } |
| 1062 | } |
| 1063 | |
| 1064 | /* |
| 1065 | ** WEBPAGE: timeline |
| 1066 | ** |
| 1067 | ** Query parameters: |
| @@ -1055,11 +1102,11 @@ | |
| 1102 | */ |
| 1103 | void page_timeline(void){ |
| 1104 | Stmt q; /* Query used to generate the timeline */ |
| 1105 | Blob sql; /* text of SQL used to generate timeline */ |
| 1106 | Blob desc; /* Description of the timeline */ |
| 1107 | int nEntry; /* Max number of entries on timeline */ |
| 1108 | int p_rid = name_to_typed_rid(P("p"),"ci"); /* artifact p and its parents */ |
| 1109 | int d_rid = name_to_typed_rid(P("d"),"ci"); /* artifact d and descendants */ |
| 1110 | int f_rid = name_to_typed_rid(P("f"),"ci"); /* artifact f and close family */ |
| 1111 | const char *zUser = P("u"); /* All entries by this user if not NULL */ |
| 1112 | const char *zType = PD("y","all"); /* Type of events. All if NULL */ |
| @@ -1069,11 +1116,11 @@ | |
| 1116 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 1117 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 1118 | const char *zSearch = P("s"); /* Search string */ |
| 1119 | const char *zUses = P("uf"); /* Only show checkins hold this file */ |
| 1120 | const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */ |
| 1121 | const char *zYearWeek = P("yw"); /* Checkins for YYYY-WW (week-of-year) */ |
| 1122 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 1123 | int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */ |
| 1124 | int tagid; /* Tag ID */ |
| 1125 | int tmFlags = 0; /* Timeline flags */ |
| 1126 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| @@ -1084,10 +1131,32 @@ | |
| 1131 | int noMerge = P("shortest")==0; /* Follow merge links if shorter */ |
| 1132 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 1133 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 1134 | int pd_rid; |
| 1135 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 1136 | const char *z; |
| 1137 | char *zOlderButton = 0; /* URL for Older button at the bottom */ |
| 1138 | |
| 1139 | /* Set number of rows to display */ |
| 1140 | z = P("n"); |
| 1141 | if( z ){ |
| 1142 | if( fossil_strcmp(z,"all")==0 ){ |
| 1143 | nEntry = 0; |
| 1144 | }else{ |
| 1145 | nEntry = atoi(z); |
| 1146 | if( nEntry<=0 ){ |
| 1147 | cgi_replace_query_parameter("n","10"); |
| 1148 | nEntry = 10; |
| 1149 | } |
| 1150 | } |
| 1151 | }else if( zCirca ){ |
| 1152 | cgi_replace_query_parameter("n","11"); |
| 1153 | nEntry = 11; |
| 1154 | }else{ |
| 1155 | cgi_replace_query_parameter("n","50"); |
| 1156 | nEntry = 50; |
| 1157 | } |
| 1158 | |
| 1159 | /* To view the timeline, must have permission to read project data. |
| 1160 | */ |
| 1161 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 1162 | if( pd_rid ){ |
| @@ -1097,20 +1166,21 @@ | |
| 1166 | if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ |
| 1167 | login_needed(); |
| 1168 | return; |
| 1169 | } |
| 1170 | url_initialize(&url, "timeline"); |
| 1171 | cgi_query_parameters_to_url(&url); |
| 1172 | if( zTagName && g.perm.Read ){ |
| 1173 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 1174 | zThisTag = zTagName; |
| 1175 | }else if( zBrName && g.perm.Read ){ |
| 1176 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| 1177 | zThisTag = zBrName; |
| 1178 | }else{ |
| 1179 | tagid = 0; |
| 1180 | } |
| 1181 | if( tagid>0 |
| 1182 | && db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry |
| 1183 | ){ |
| 1184 | zCirca = zBefore = zAfter = 0; |
| 1185 | nEntry = -1; |
| 1186 | } |
| @@ -1117,32 +1187,26 @@ | |
| 1187 | if( zType[0]=='a' ){ |
| 1188 | tmFlags |= TIMELINE_BRIEF | TIMELINE_GRAPH; |
| 1189 | }else{ |
| 1190 | tmFlags |= TIMELINE_GRAPH; |
| 1191 | } |
| 1192 | if( PB("ng") || zSearch!=0 ){ |
| 1193 | tmFlags &= ~TIMELINE_GRAPH; |
| 1194 | } |
| 1195 | if( PB("brbg") ){ |
| 1196 | tmFlags |= TIMELINE_BRCOLOR; |
| 1197 | } |
| 1198 | if( PB("unhide") ){ |
| 1199 | tmFlags |= TIMELINE_UNHIDE; |
| 1200 | } |
| 1201 | if( PB("ubg") ){ |
| 1202 | tmFlags |= TIMELINE_UCOLOR; |
| 1203 | } |
| 1204 | if( zUses!=0 ){ |
| 1205 | int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); |
| 1206 | if( ufid ){ |
| 1207 | zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); |
| 1208 | db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); |
| 1209 | compute_uses_file("usesfile", ufid, 0); |
| 1210 | zType = "ci"; |
| 1211 | }else{ |
| 1212 | zUses = 0; |
| @@ -1161,22 +1225,20 @@ | |
| 1225 | timeline_temp_table(); |
| 1226 | blob_zero(&sql); |
| 1227 | blob_zero(&desc); |
| 1228 | blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); |
| 1229 | blob_append(&sql, timeline_query_for_www(), -1); |
| 1230 | if( PB("fc") || PB("v") || PB("detail") ){ |
| 1231 | tmFlags |= TIMELINE_FCHANGES; |
| 1232 | } |
| 1233 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1234 | blob_append_sql(&sql, |
| 1235 | " AND NOT EXISTS(SELECT 1 FROM tagxref" |
| 1236 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", |
| 1237 | TAG_HIDDEN |
| 1238 | ); |
| 1239 | } |
| 1240 | if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){ |
| 1241 | /* If from= and to= are present, display all nodes on a path connecting |
| 1242 | ** the two */ |
| 1243 | PathNode *p = 0; |
| 1244 | const char *zFrom = 0; |
| @@ -1241,34 +1303,19 @@ | |
| 1303 | } |
| 1304 | if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); |
| 1305 | } |
| 1306 | blob_appendf(&desc, " of %z[%S]</a>", |
| 1307 | href("%R/info/%s", zUuid), zUuid); |
| 1308 | if( d_rid ){ |
| 1309 | if( p_rid ){ |
| 1310 | /* If both p= and d= are set, we don't have the uuid of d yet. */ |
| 1311 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid); |
| 1312 | } |
| 1313 | } |
| 1314 | style_submenu_binary("v","With Files","Without Files"); |
| 1315 | style_submenu_entry("n","Lines",1); |
| 1316 | timeline_y_submenu(); |
| 1317 | }else if( f_rid && g.perm.Read ){ |
| 1318 | /* If f= is present, ignore all other parameters other than n= */ |
| 1319 | char *zUuid; |
| 1320 | db_multi_exec( |
| 1321 | "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" |
| @@ -1282,16 +1329,11 @@ | |
| 1329 | if( useDividers ) timeline_add_dividers(0, f_rid); |
| 1330 | blob_appendf(&desc, "Parents and children of check-in "); |
| 1331 | zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); |
| 1332 | blob_appendf(&desc, "%z[%S]</a>", href("%R/info/%s", zUuid), zUuid); |
| 1333 | tmFlags |= TIMELINE_DISJOINT; |
| 1334 | style_submenu_binary("v","With Files","Without Files"); |
| 1335 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1336 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1337 | } |
| 1338 | }else{ |
| 1339 | /* Otherwise, a timeline based on a span of time */ |
| @@ -1316,11 +1358,10 @@ | |
| 1358 | blob_append_sql(&sql, |
| 1359 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1360 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1361 | |
| 1362 | if( zBrName ){ |
| 1363 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 1364 | ** are not part of the branch which are parents or children of the |
| 1365 | ** branch to be included in the report. This related check-ins are |
| 1366 | ** useful in helping to visualize what has happened on a quiescent |
| 1367 | ** branch that is infrequently merged with a much more activate branch. |
| @@ -1342,21 +1383,17 @@ | |
| 1383 | " OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid" |
| 1384 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1385 | tagid |
| 1386 | ); |
| 1387 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1388 | blob_append_sql(&sql, |
| 1389 | " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid" |
| 1390 | " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", |
| 1391 | TAG_HIDDEN |
| 1392 | ); |
| 1393 | } |
| 1394 | } |
| 1395 | } |
| 1396 | blob_append_sql(&sql, ")"); |
| 1397 | } |
| 1398 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1399 | || (zType[0]=='t' && !g.perm.RdTkt) |
| @@ -1384,11 +1421,10 @@ | |
| 1421 | } |
| 1422 | blob_append_sql(&sql, ")"); |
| 1423 | } |
| 1424 | }else{ /* zType!="all" */ |
| 1425 | blob_append_sql(&sql, " AND event.type=%Q", zType); |
| 1426 | if( zType[0]=='c' ){ |
| 1427 | zEType = "checkin"; |
| 1428 | }else if( zType[0]=='w' ){ |
| 1429 | zEType = "wiki edit"; |
| 1430 | }else if( zType[0]=='t' ){ |
| @@ -1406,41 +1442,35 @@ | |
| 1442 | zCirca = zBefore = zAfter = 0; |
| 1443 | nEntry = -1; |
| 1444 | } |
| 1445 | blob_append_sql(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1446 | zUser, zUser); |
| 1447 | zThisUser = zUser; |
| 1448 | } |
| 1449 | if( zSearch ){ |
| 1450 | blob_append_sql(&sql, |
| 1451 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1452 | zSearch, zSearch); |
| 1453 | } |
| 1454 | rBefore = symbolic_name_to_mtime(zBefore); |
| 1455 | rAfter = symbolic_name_to_mtime(zAfter); |
| 1456 | rCirca = symbolic_name_to_mtime(zCirca); |
| 1457 | if( rAfter>0.0 ){ |
| 1458 | if( rBefore>0.0 ){ |
| 1459 | blob_append_sql(&sql, |
| 1460 | " AND event.mtime>=%.17g AND event.mtime<=%.17g" |
| 1461 | " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); |
| 1462 | nEntry = -1; |
| 1463 | }else{ |
| 1464 | blob_append_sql(&sql, |
| 1465 | " AND event.mtime>=%.17g ORDER BY event.mtime ASC", |
| 1466 | rAfter-ONE_SECOND); |
| 1467 | } |
| 1468 | }else if( rBefore>0.0 ){ |
| 1469 | blob_append_sql(&sql, |
| 1470 | " AND event.mtime<=%.17g ORDER BY event.mtime DESC", |
| 1471 | rBefore+ONE_SECOND); |
| 1472 | }else if( rCirca>0.0 ){ |
| 1473 | Blob sql2; |
| 1474 | blob_init(&sql2, blob_sql_text(&sql), -1); |
| 1475 | blob_append_sql(&sql2, |
| 1476 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| @@ -1452,11 +1482,10 @@ | |
| 1482 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 1483 | rCirca |
| 1484 | ); |
| 1485 | nEntry -= (nEntry+1)/2; |
| 1486 | if( useDividers ) timeline_add_dividers(rCirca, 0); |
| 1487 | }else{ |
| 1488 | blob_append_sql(&sql, " ORDER BY event.mtime DESC"); |
| 1489 | } |
| 1490 | if( nEntry>0 ) blob_append_sql(&sql, " LIMIT %d", nEntry); |
| 1491 | db_multi_exec("%s", blob_sql_text(&sql)); |
| @@ -1509,64 +1538,44 @@ | |
| 1538 | } |
| 1539 | if( g.perm.Hyperlink ){ |
| 1540 | if( zAfter || n==nEntry ){ |
| 1541 | zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); |
| 1542 | timeline_submenu(&url, "Older", "b", zDate, "a"); |
| 1543 | zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0)); |
| 1544 | free(zDate); |
| 1545 | } |
| 1546 | if( zBefore || (zAfter && n==nEntry) ){ |
| 1547 | zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); |
| 1548 | timeline_submenu(&url, "Newer", "a", zDate, "b"); |
| 1549 | free(zDate); |
| 1550 | } |
| 1551 | if( zType[0]=='a' || zType[0]=='c' ){ |
| 1552 | if( (tmFlags & TIMELINE_UNHIDE)==0 ){ |
| 1553 | timeline_submenu(&url, "Unhide", "unhide", "", 0); |
| 1554 | } |
| 1555 | } |
| 1556 | style_submenu_binary("v","With Files","Without Files"); |
| 1557 | if( zUses==0 ) timeline_y_submenu(); |
| 1558 | style_submenu_entry("n","Lines",1); |
| 1559 | } |
| 1560 | } |
| 1561 | if( P("showsql") ){ |
| 1562 | @ <blockquote>%h(blob_sql_text(&sql))</blockquote> |
| 1563 | } |
| 1564 | if( search_restrict(SRCH_CKIN)!=0 ){ |
| 1565 | style_submenu_element("Search", 0, "%R/search?y=c"); |
| 1566 | } |
| 1567 | if( P("showid") ) tmFlags |= TIMELINE_SHOWRID; |
| 1568 | blob_zero(&sql); |
| 1569 | db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/"); |
| 1570 | @ <h2>%b(&desc)</h2> |
| 1571 | blob_reset(&desc); |
| 1572 | www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0); |
| 1573 | db_finalize(&q); |
| 1574 | if( zOlderButton ){ |
| 1575 | @ %z(xhref("class='button'","%z",zOlderButton))Older</a> |
| 1576 | } |
| 1577 | style_footer(); |
| 1578 | } |
| 1579 | |
| 1580 | /* |
| 1581 | ** The input query q selects various records. Print a human-readable |
| @@ -1771,11 +1780,11 @@ | |
| 1780 | ** for the current version or "now" for the current time. |
| 1781 | ** |
| 1782 | ** Options: |
| 1783 | ** -n|--limit N Output the first N entries (default 20 lines). |
| 1784 | ** N=0 means no limit. |
| 1785 | ** -p|--path PATH Output items affecting PATH only. |
| 1786 | ** PATH can be a file or a sub directory. |
| 1787 | ** --offset P skip P changes |
| 1788 | ** -t|--type TYPE Output items from the given types only, such as: |
| 1789 | ** ci = file commits only |
| 1790 | ** e = events only |
| @@ -1893,11 +1902,11 @@ | |
| 1902 | if( mode==0 ){ |
| 1903 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1904 | } |
| 1905 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1906 | } |
| 1907 | |
| 1908 | if( zFilePattern ){ |
| 1909 | if( zType==0 ){ |
| 1910 | /* When zFilePattern is specified and type is not specified, only show |
| 1911 | * file checkins */ |
| 1912 | zType="ci"; |
| @@ -2041,10 +2050,10 @@ | |
| 2050 | " AND blob.rid=c.cid" |
| 2051 | ); |
| 2052 | while( db_step(&q)==SQLITE_ROW ){ |
| 2053 | const char *zUuid = db_column_text(&q, 0); |
| 2054 | @ <li> |
| 2055 | @ <a href="%s(g.zTop)/timeline?dp=%s(zUuid)&unhide">%S(zUuid)</a> |
| 2056 | } |
| 2057 | db_finalize(&q); |
| 2058 | style_footer(); |
| 2059 | } |
| 2060 |
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -1434,8 +1434,8 @@ | ||
| 1434 | 1434 | */ |
| 1435 | 1435 | void tkt_srchpage(void){ |
| 1436 | 1436 | login_check_credentials(); |
| 1437 | 1437 | style_header("Ticket Search"); |
| 1438 | 1438 | ticket_standard_submenu(T_ALL_BUT(T_SRCH)); |
| 1439 | - search_screen(SRCH_TKT, "tktsrch"); | |
| 1439 | + search_screen(SRCH_TKT, 0); | |
| 1440 | 1440 | style_footer(); |
| 1441 | 1441 | } |
| 1442 | 1442 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -1434,8 +1434,8 @@ | |
| 1434 | */ |
| 1435 | void tkt_srchpage(void){ |
| 1436 | login_check_credentials(); |
| 1437 | style_header("Ticket Search"); |
| 1438 | ticket_standard_submenu(T_ALL_BUT(T_SRCH)); |
| 1439 | search_screen(SRCH_TKT, "tktsrch"); |
| 1440 | style_footer(); |
| 1441 | } |
| 1442 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -1434,8 +1434,8 @@ | |
| 1434 | */ |
| 1435 | void tkt_srchpage(void){ |
| 1436 | login_check_credentials(); |
| 1437 | style_header("Ticket Search"); |
| 1438 | ticket_standard_submenu(T_ALL_BUT(T_SRCH)); |
| 1439 | search_screen(SRCH_TKT, 0); |
| 1440 | style_footer(); |
| 1441 | } |
| 1442 |
No diff available
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -432,47 +432,64 @@ | ||
| 432 | 432 | ** An instance of this object is used to build a URL with query parameters. |
| 433 | 433 | */ |
| 434 | 434 | struct HQuery { |
| 435 | 435 | Blob url; /* The URL */ |
| 436 | 436 | const char *zBase; /* The base URL */ |
| 437 | - int nParam; /* Number of parameters. Max 10 */ | |
| 438 | - const char *azName[15]; /* Parameter names */ | |
| 439 | - const char *azValue[15]; /* Parameter values */ | |
| 437 | + int nParam; /* Number of parameters. */ | |
| 438 | + int nAlloc; /* Number of allocated slots */ | |
| 439 | + const char **azName; /* Parameter names */ | |
| 440 | + const char **azValue; /* Parameter values */ | |
| 440 | 441 | }; |
| 441 | 442 | #endif |
| 442 | 443 | |
| 443 | 444 | /* |
| 444 | 445 | ** Initialize the URL object. |
| 445 | 446 | */ |
| 446 | 447 | void url_initialize(HQuery *p, const char *zBase){ |
| 448 | + memset(p, 0, sizeof(*p)); | |
| 447 | 449 | blob_zero(&p->url); |
| 448 | 450 | p->zBase = zBase; |
| 449 | - p->nParam = 0; | |
| 450 | 451 | } |
| 451 | 452 | |
| 452 | 453 | /* |
| 453 | 454 | ** Resets the given URL object, deallocating any memory |
| 454 | 455 | ** it uses. |
| 455 | 456 | */ |
| 456 | 457 | void url_reset(HQuery *p){ |
| 457 | 458 | blob_reset(&p->url); |
| 459 | + fossil_free(p->azName); | |
| 460 | + fossil_free(p->azValue); | |
| 458 | 461 | url_initialize(p, p->zBase); |
| 459 | 462 | } |
| 460 | 463 | |
| 461 | 464 | /* |
| 462 | 465 | ** Add a fixed parameter to an HQuery. |
| 463 | 466 | */ |
| 464 | 467 | void url_add_parameter(HQuery *p, const char *zName, const char *zValue){ |
| 465 | - assert( p->nParam < count(p->azName) ); | |
| 466 | - assert( p->nParam < count(p->azValue) ); | |
| 467 | - p->azName[p->nParam] = zName; | |
| 468 | - p->azValue[p->nParam] = zValue; | |
| 468 | + int i; | |
| 469 | + for(i=0; i<p->nParam; i++){ | |
| 470 | + if( fossil_strcmp(p->azName[i],zName)==0 ){ | |
| 471 | + p->azValue[i] = zValue; | |
| 472 | + return; | |
| 473 | + } | |
| 474 | + } | |
| 475 | + assert( i==p->nParam ); | |
| 476 | + if( i>=p->nAlloc ){ | |
| 477 | + p->nAlloc = p->nAlloc*2 + 10; | |
| 478 | + p->azName = fossil_realloc(p->azName, sizeof(p->azName[0])*p->nAlloc); | |
| 479 | + p->azValue = fossil_realloc(p->azValue, sizeof(p->azValue[0])*p->nAlloc); | |
| 480 | + } | |
| 481 | + p->azName[i] = zName; | |
| 482 | + p->azValue[i] = zValue; | |
| 469 | 483 | p->nParam++; |
| 470 | 484 | } |
| 471 | 485 | |
| 472 | 486 | /* |
| 473 | 487 | ** Render the URL with a parameter override. |
| 488 | +** | |
| 489 | +** Returned memory is transient and is overwritten on the next call to this | |
| 490 | +** routine for the same HQuery, or until the HQuery object is destroyed. | |
| 474 | 491 | */ |
| 475 | 492 | char *url_render( |
| 476 | 493 | HQuery *p, /* Base URL */ |
| 477 | 494 | const char *zName1, /* First override */ |
| 478 | 495 | const char *zValue1, /* First override value */ |
| 479 | 496 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -432,47 +432,64 @@ | |
| 432 | ** An instance of this object is used to build a URL with query parameters. |
| 433 | */ |
| 434 | struct HQuery { |
| 435 | Blob url; /* The URL */ |
| 436 | const char *zBase; /* The base URL */ |
| 437 | int nParam; /* Number of parameters. Max 10 */ |
| 438 | const char *azName[15]; /* Parameter names */ |
| 439 | const char *azValue[15]; /* Parameter values */ |
| 440 | }; |
| 441 | #endif |
| 442 | |
| 443 | /* |
| 444 | ** Initialize the URL object. |
| 445 | */ |
| 446 | void url_initialize(HQuery *p, const char *zBase){ |
| 447 | blob_zero(&p->url); |
| 448 | p->zBase = zBase; |
| 449 | p->nParam = 0; |
| 450 | } |
| 451 | |
| 452 | /* |
| 453 | ** Resets the given URL object, deallocating any memory |
| 454 | ** it uses. |
| 455 | */ |
| 456 | void url_reset(HQuery *p){ |
| 457 | blob_reset(&p->url); |
| 458 | url_initialize(p, p->zBase); |
| 459 | } |
| 460 | |
| 461 | /* |
| 462 | ** Add a fixed parameter to an HQuery. |
| 463 | */ |
| 464 | void url_add_parameter(HQuery *p, const char *zName, const char *zValue){ |
| 465 | assert( p->nParam < count(p->azName) ); |
| 466 | assert( p->nParam < count(p->azValue) ); |
| 467 | p->azName[p->nParam] = zName; |
| 468 | p->azValue[p->nParam] = zValue; |
| 469 | p->nParam++; |
| 470 | } |
| 471 | |
| 472 | /* |
| 473 | ** Render the URL with a parameter override. |
| 474 | */ |
| 475 | char *url_render( |
| 476 | HQuery *p, /* Base URL */ |
| 477 | const char *zName1, /* First override */ |
| 478 | const char *zValue1, /* First override value */ |
| 479 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -432,47 +432,64 @@ | |
| 432 | ** An instance of this object is used to build a URL with query parameters. |
| 433 | */ |
| 434 | struct HQuery { |
| 435 | Blob url; /* The URL */ |
| 436 | const char *zBase; /* The base URL */ |
| 437 | int nParam; /* Number of parameters. */ |
| 438 | int nAlloc; /* Number of allocated slots */ |
| 439 | const char **azName; /* Parameter names */ |
| 440 | const char **azValue; /* Parameter values */ |
| 441 | }; |
| 442 | #endif |
| 443 | |
| 444 | /* |
| 445 | ** Initialize the URL object. |
| 446 | */ |
| 447 | void url_initialize(HQuery *p, const char *zBase){ |
| 448 | memset(p, 0, sizeof(*p)); |
| 449 | blob_zero(&p->url); |
| 450 | p->zBase = zBase; |
| 451 | } |
| 452 | |
| 453 | /* |
| 454 | ** Resets the given URL object, deallocating any memory |
| 455 | ** it uses. |
| 456 | */ |
| 457 | void url_reset(HQuery *p){ |
| 458 | blob_reset(&p->url); |
| 459 | fossil_free(p->azName); |
| 460 | fossil_free(p->azValue); |
| 461 | url_initialize(p, p->zBase); |
| 462 | } |
| 463 | |
| 464 | /* |
| 465 | ** Add a fixed parameter to an HQuery. |
| 466 | */ |
| 467 | void url_add_parameter(HQuery *p, const char *zName, const char *zValue){ |
| 468 | int i; |
| 469 | for(i=0; i<p->nParam; i++){ |
| 470 | if( fossil_strcmp(p->azName[i],zName)==0 ){ |
| 471 | p->azValue[i] = zValue; |
| 472 | return; |
| 473 | } |
| 474 | } |
| 475 | assert( i==p->nParam ); |
| 476 | if( i>=p->nAlloc ){ |
| 477 | p->nAlloc = p->nAlloc*2 + 10; |
| 478 | p->azName = fossil_realloc(p->azName, sizeof(p->azName[0])*p->nAlloc); |
| 479 | p->azValue = fossil_realloc(p->azValue, sizeof(p->azValue[0])*p->nAlloc); |
| 480 | } |
| 481 | p->azName[i] = zName; |
| 482 | p->azValue[i] = zValue; |
| 483 | p->nParam++; |
| 484 | } |
| 485 | |
| 486 | /* |
| 487 | ** Render the URL with a parameter override. |
| 488 | ** |
| 489 | ** Returned memory is transient and is overwritten on the next call to this |
| 490 | ** routine for the same HQuery, or until the HQuery object is destroyed. |
| 491 | */ |
| 492 | char *url_render( |
| 493 | HQuery *p, /* Base URL */ |
| 494 | const char *zName1, /* First override */ |
| 495 | const char *zValue1, /* First override value */ |
| 496 |
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -291,11 +291,11 @@ | ||
| 291 | 291 | */ |
| 292 | 292 | void wiki_srchpage(void){ |
| 293 | 293 | login_check_credentials(); |
| 294 | 294 | style_header("Wiki Search"); |
| 295 | 295 | wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX); |
| 296 | - search_screen(SRCH_WIKI, "wikisrch"); | |
| 296 | + search_screen(SRCH_WIKI, 0); | |
| 297 | 297 | style_footer(); |
| 298 | 298 | } |
| 299 | 299 | |
| 300 | 300 | /* |
| 301 | 301 | ** WEBPAGE: wiki |
| 302 | 302 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -291,11 +291,11 @@ | |
| 291 | */ |
| 292 | void wiki_srchpage(void){ |
| 293 | login_check_credentials(); |
| 294 | style_header("Wiki Search"); |
| 295 | wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX); |
| 296 | search_screen(SRCH_WIKI, "wikisrch"); |
| 297 | style_footer(); |
| 298 | } |
| 299 | |
| 300 | /* |
| 301 | ** WEBPAGE: wiki |
| 302 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -291,11 +291,11 @@ | |
| 291 | */ |
| 292 | void wiki_srchpage(void){ |
| 293 | login_check_credentials(); |
| 294 | style_header("Wiki Search"); |
| 295 | wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX); |
| 296 | search_screen(SRCH_WIKI, 0); |
| 297 | style_footer(); |
| 298 | } |
| 299 | |
| 300 | /* |
| 301 | ** WEBPAGE: wiki |
| 302 |
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
Binary file
Binary file
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
Binary file
No diff available
Binary file
Binary file
Binary file
Binary file
No diff available
No diff available
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
Binary file
Binary file
No diff available
No diff available
No diff available
Binary file
No diff available
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
No diff available
No diff available
No diff available
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
Binary file
No diff available
Binary file
Binary file
Binary file
Binary file
Binary file
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
| --- www/mkindex.tcl | ||
| +++ www/mkindex.tcl | ||
| @@ -96,11 +96,11 @@ | ||
| 96 | 96 | <li> <a href='faq.wiki'>FAQ</a> |
| 97 | 97 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 98 | 98 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 99 | 99 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 100 | 100 | book</a> |
| 101 | -<li> <a href='../../help'>Command-line help</a> | |
| 101 | +<li> <a href='../../../help'>Command-line help</a> | |
| 102 | 102 | </ul> |
| 103 | 103 | <a name="pindex"></a> |
| 104 | 104 | <h2>Permuted Index:</h2> |
| 105 | 105 | <ul>} |
| 106 | 106 | foreach entry $permindex { |
| 107 | 107 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -96,11 +96,11 @@ | |
| 96 | <li> <a href='faq.wiki'>FAQ</a> |
| 97 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 98 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 99 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 100 | book</a> |
| 101 | <li> <a href='../../help'>Command-line help</a> |
| 102 | </ul> |
| 103 | <a name="pindex"></a> |
| 104 | <h2>Permuted Index:</h2> |
| 105 | <ul>} |
| 106 | foreach entry $permindex { |
| 107 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -96,11 +96,11 @@ | |
| 96 | <li> <a href='faq.wiki'>FAQ</a> |
| 97 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 98 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 99 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 100 | book</a> |
| 101 | <li> <a href='../../../help'>Command-line help</a> |
| 102 | </ul> |
| 103 | <a name="pindex"></a> |
| 104 | <h2>Permuted Index:</h2> |
| 105 | <ul>} |
| 106 | foreach entry $permindex { |
| 107 |
No diff available
No diff available
| --- www/permutedindex.html | ||
| +++ www/permutedindex.html | ||
| @@ -12,11 +12,11 @@ | ||
| 12 | 12 | <li> <a href='faq.wiki'>FAQ</a> |
| 13 | 13 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 14 | 14 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 15 | 15 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 16 | 16 | book</a> |
| 17 | -<li> <a href='../../help'>Command-line help</a> | |
| 17 | +<li> <a href='../../../help'>Command-line help</a> | |
| 18 | 18 | </ul> |
| 19 | 19 | <a name="pindex"></a> |
| 20 | 20 | <h2>Permuted Index:</h2> |
| 21 | 21 | <ul> |
| 22 | 22 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Update and Running in</a></li> |
| 23 | 23 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -12,11 +12,11 @@ | |
| 12 | <li> <a href='faq.wiki'>FAQ</a> |
| 13 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 14 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 15 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 16 | book</a> |
| 17 | <li> <a href='../../help'>Command-line help</a> |
| 18 | </ul> |
| 19 | <a name="pindex"></a> |
| 20 | <h2>Permuted Index:</h2> |
| 21 | <ul> |
| 22 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Update and Running in</a></li> |
| 23 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -12,11 +12,11 @@ | |
| 12 | <li> <a href='faq.wiki'>FAQ</a> |
| 13 | <li> <a href='build.wiki'>Compiling and installing Fossil</a> |
| 14 | <li> <a href='COPYRIGHT-BSD2.txt'>License</a> |
| 15 | <li> <a href='http://www.fossil-scm.org/schimpf-book/home'>Jim Schimpf's |
| 16 | book</a> |
| 17 | <li> <a href='../../../help'>Command-line help</a> |
| 18 | </ul> |
| 19 | <a name="pindex"></a> |
| 20 | <h2>Permuted Index:</h2> |
| 21 | <ul> |
| 22 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Update and Running in</a></li> |
| 23 |
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available
No diff available