Fossil SCM
All the a=, b=, and c= query parameters of the timeline webpage to be tags and labels in addition to timestamps.
Commit
66f4fa9bd5a5c4bc748d45b10ad476f8c5f2014c
Parent
d7736649cdd0577…
2 files changed
+2
-2
+78
-64
+2
-2
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -107,19 +107,19 @@ | ||
| 107 | 107 | |
| 108 | 108 | /* Date and times */ |
| 109 | 109 | if( memcmp(zTag, "date:", 5)==0 ){ |
| 110 | 110 | rid = db_int(0, |
| 111 | 111 | "SELECT objid FROM event" |
| 112 | - " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" | |
| 112 | + " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" | |
| 113 | 113 | " ORDER BY mtime DESC LIMIT 1", |
| 114 | 114 | &zTag[5], zType); |
| 115 | 115 | return rid; |
| 116 | 116 | } |
| 117 | 117 | if( is_date(zTag) ){ |
| 118 | 118 | rid = db_int(0, |
| 119 | 119 | "SELECT objid FROM event" |
| 120 | - " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" | |
| 120 | + " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" | |
| 121 | 121 | " ORDER BY mtime DESC LIMIT 1", |
| 122 | 122 | zTag, zType); |
| 123 | 123 | if( rid) return rid; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -107,19 +107,19 @@ | |
| 107 | |
| 108 | /* Date and times */ |
| 109 | if( memcmp(zTag, "date:", 5)==0 ){ |
| 110 | rid = db_int(0, |
| 111 | "SELECT objid FROM event" |
| 112 | " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" |
| 113 | " ORDER BY mtime DESC LIMIT 1", |
| 114 | &zTag[5], zType); |
| 115 | return rid; |
| 116 | } |
| 117 | if( is_date(zTag) ){ |
| 118 | rid = db_int(0, |
| 119 | "SELECT objid FROM event" |
| 120 | " WHERE mtime<=julianday(%Q) AND type GLOB '%q'" |
| 121 | " ORDER BY mtime DESC LIMIT 1", |
| 122 | zTag, zType); |
| 123 | if( rid) return rid; |
| 124 | } |
| 125 | |
| 126 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -107,19 +107,19 @@ | |
| 107 | |
| 108 | /* Date and times */ |
| 109 | if( memcmp(zTag, "date:", 5)==0 ){ |
| 110 | rid = db_int(0, |
| 111 | "SELECT objid FROM event" |
| 112 | " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" |
| 113 | " ORDER BY mtime DESC LIMIT 1", |
| 114 | &zTag[5], zType); |
| 115 | return rid; |
| 116 | } |
| 117 | if( is_date(zTag) ){ |
| 118 | rid = db_int(0, |
| 119 | "SELECT objid FROM event" |
| 120 | " WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'" |
| 121 | " ORDER BY mtime DESC LIMIT 1", |
| 122 | zTag, zType); |
| 123 | if( rid) return rid; |
| 124 | } |
| 125 | |
| 126 |
+78
-64
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -810,33 +810,49 @@ | ||
| 810 | 810 | style_submenu_element(zMenuName, zMenuName, "%s", |
| 811 | 811 | url_render(pUrl, zParam, zValue, zRemove, 0)); |
| 812 | 812 | } |
| 813 | 813 | |
| 814 | 814 | |
| 815 | +/* | |
| 816 | +** Convert a symbolic name used as an argument to the a=, b=, or c= | |
| 817 | +** query parameters of timeline into a julianday mtime value. | |
| 818 | +*/ | |
| 819 | +double symbolic_name_to_mtime(const char *z){ | |
| 820 | + double mtime; | |
| 821 | + int rid; | |
| 822 | + if( z==0 ) return -1.0; | |
| 823 | + rid = symbolic_name_to_rid(z, "ci"); | |
| 824 | + if( rid==0 ) return -1.0; | |
| 825 | + mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 826 | + return mtime; | |
| 827 | +} | |
| 828 | + | |
| 829 | +/* | |
| 830 | +** The value of one second in julianday notation | |
| 831 | +*/ | |
| 832 | +#define ONE_SECOND (1.0/86400.0) | |
| 833 | + | |
| 815 | 834 | /* |
| 816 | 835 | ** zDate is a localtime date. Insert records into the |
| 817 | 836 | ** "timeline" table to cause <hr> to be inserted before and after |
| 818 | 837 | ** entries of that date. If zDate==NULL then put dividers around |
| 819 | 838 | ** the event identified by rid. |
| 820 | 839 | */ |
| 821 | -static void timeline_add_dividers(const char *zDate, int rid){ | |
| 840 | +static void timeline_add_dividers(double rDate, int rid){ | |
| 822 | 841 | char *zToDel = 0; |
| 823 | - if( zDate==0 ){ | |
| 824 | - zToDel = db_text(0,"SELECT julianday(mtime,'localtime') FROM event" | |
| 825 | - " WHERE objid=%d", rid); | |
| 826 | - zDate = zToDel; | |
| 827 | - if( zDate==0 ) zDate = "1"; | |
| 842 | + if( rDate==0 ){ | |
| 843 | + rDate = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 828 | 844 | } |
| 829 | 845 | db_multi_exec( |
| 830 | 846 | "INSERT INTO timeline(rid,sortby,etype)" |
| 831 | - "VALUES(-1,julianday(%Q,'utc')-1.0e-5,'div')", | |
| 832 | - zDate | |
| 847 | + "VALUES(-1,%.16g,'div')", | |
| 848 | + rDate-ONE_SECOND | |
| 833 | 849 | ); |
| 834 | 850 | db_multi_exec( |
| 835 | 851 | "INSERT INTO timeline(rid,sortby,etype)" |
| 836 | - "VALUES(-2,julianday(%Q,'utc')+1.0e-5,'div')", | |
| 837 | - zDate | |
| 852 | + "VALUES(-2,%.17g,'div')", | |
| 853 | + rDate+ONE_SECOND | |
| 838 | 854 | ); |
| 839 | 855 | fossil_free(zToDel); |
| 840 | 856 | } |
| 841 | 857 | |
| 842 | 858 | |
| @@ -843,14 +859,14 @@ | ||
| 843 | 859 | /* |
| 844 | 860 | ** WEBPAGE: timeline |
| 845 | 861 | ** |
| 846 | 862 | ** Query parameters: |
| 847 | 863 | ** |
| 848 | -** a=TIMESTAMP after this date | |
| 849 | -** b=TIMESTAMP before this date. | |
| 850 | -** c=TIMESTAMP "circa" this date. | |
| 851 | -** n=COUNT number of events in output | |
| 864 | +** a=TIMEORTAG after this event | |
| 865 | +** b=TIMEORTAG before this event | |
| 866 | +** c=TIMEORTAG "circa" this event | |
| 867 | +** n=COUNT max number of events in output | |
| 852 | 868 | ** p=UUID artifact and up to COUNT parents and ancestors |
| 853 | 869 | ** d=UUID artifact and up to COUNT descendants |
| 854 | 870 | ** dp=UUUID The same as d=UUID&p=UUID |
| 855 | 871 | ** t=TAGID show only check-ins with the given tagid |
| 856 | 872 | ** r=TAGID show check-ins related to tagid |
| @@ -901,10 +917,11 @@ | ||
| 901 | 917 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 902 | 918 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 903 | 919 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 904 | 920 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 905 | 921 | int pd_rid; |
| 922 | + double rBefore, rAfter, rCirca; /* Boundary times */ | |
| 906 | 923 | |
| 907 | 924 | /* To view the timeline, must have permission to read project data. |
| 908 | 925 | */ |
| 909 | 926 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 910 | 927 | if( pd_rid ){ |
| @@ -1121,63 +1138,55 @@ | ||
| 1121 | 1138 | blob_appendf(&sql, |
| 1122 | 1139 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1123 | 1140 | zSearch, zSearch); |
| 1124 | 1141 | url_add_parameter(&url, "s", zSearch); |
| 1125 | 1142 | } |
| 1126 | - if( zAfter ){ | |
| 1127 | - while( fossil_isspace(zAfter[0]) ){ zAfter++; } | |
| 1128 | - if( zAfter[0] ){ | |
| 1129 | - blob_appendf(&sql, | |
| 1130 | - " AND event.mtime>=(SELECT julianday(%Q, 'utc'))" | |
| 1131 | - " ORDER BY event.mtime ASC", zAfter); | |
| 1132 | - url_add_parameter(&url, "a", zAfter); | |
| 1133 | - zBefore = 0; | |
| 1134 | - }else{ | |
| 1135 | - zAfter = 0; | |
| 1136 | - } | |
| 1137 | - }else if( zBefore ){ | |
| 1138 | - while( fossil_isspace(zBefore[0]) ){ zBefore++; } | |
| 1139 | - if( zBefore[0] ){ | |
| 1140 | - blob_appendf(&sql, | |
| 1141 | - " AND event.mtime<=(SELECT julianday(%Q, 'utc'))" | |
| 1142 | - " ORDER BY event.mtime DESC", zBefore); | |
| 1143 | - url_add_parameter(&url, "b", zBefore); | |
| 1144 | - }else{ | |
| 1145 | - zBefore = 0; | |
| 1146 | - } | |
| 1147 | - }else if( zCirca ){ | |
| 1148 | - while( fossil_isspace(zCirca[0]) ){ zCirca++; } | |
| 1149 | - if( zCirca[0] ){ | |
| 1150 | - double rCirca = db_double(0.0, "SELECT julianday(%Q, 'utc')", zCirca); | |
| 1151 | - Blob sql2; | |
| 1152 | - blob_init(&sql2, blob_str(&sql), -1); | |
| 1153 | - blob_appendf(&sql2, | |
| 1154 | - " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", | |
| 1155 | - rCirca, (nEntry+1)/2 | |
| 1156 | - ); | |
| 1157 | - db_multi_exec("%s", blob_str(&sql2)); | |
| 1158 | - blob_reset(&sql2); | |
| 1159 | - blob_appendf(&sql, | |
| 1160 | - " AND event.mtime>=%f ORDER BY event.mtime ASC", | |
| 1161 | - rCirca | |
| 1162 | - ); | |
| 1163 | - nEntry -= (nEntry+1)/2; | |
| 1164 | - if( useDividers ) timeline_add_dividers(zCirca, 0); | |
| 1165 | - url_add_parameter(&url, "c", zCirca); | |
| 1166 | - }else{ | |
| 1167 | - zCirca = 0; | |
| 1168 | - } | |
| 1143 | + rBefore = symbolic_name_to_mtime(zBefore); | |
| 1144 | + rAfter = symbolic_name_to_mtime(zAfter); | |
| 1145 | + rCirca = symbolic_name_to_mtime(zCirca); | |
| 1146 | + if( rAfter>0.0 ){ | |
| 1147 | + if( rBefore>0.0 ){ | |
| 1148 | + blob_appendf(&sql, | |
| 1149 | + " AND event.mtime>=%.17g AND event.mtime<=%.17g" | |
| 1150 | + " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); | |
| 1151 | + url_add_parameter(&url, "a", zAfter); | |
| 1152 | + url_add_parameter(&url, "b", zBefore); | |
| 1153 | + nEntry = 1000000; | |
| 1154 | + }else{ | |
| 1155 | + blob_appendf(&sql, | |
| 1156 | + " AND event.mtime>=%.17g ORDER BY event.mtime ASC", | |
| 1157 | + rAfter-ONE_SECOND); | |
| 1158 | + url_add_parameter(&url, "a", zAfter); | |
| 1159 | + } | |
| 1160 | + }else if( rBefore>0.0 ){ | |
| 1161 | + blob_appendf(&sql, | |
| 1162 | + " AND event.mtime<=%.17g ORDER BY event.mtime DESC", | |
| 1163 | + rBefore+ONE_SECOND); | |
| 1164 | + url_add_parameter(&url, "b", zBefore); | |
| 1165 | + }else if( rCirca>0.0 ){ | |
| 1166 | + Blob sql2; | |
| 1167 | + blob_init(&sql2, blob_str(&sql), -1); | |
| 1168 | + blob_appendf(&sql2, | |
| 1169 | + " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", | |
| 1170 | + rCirca, (nEntry+1)/2 | |
| 1171 | + ); | |
| 1172 | + db_multi_exec("%s", blob_str(&sql2)); | |
| 1173 | + blob_reset(&sql2); | |
| 1174 | + blob_appendf(&sql, | |
| 1175 | + " AND event.mtime>=%f ORDER BY event.mtime ASC", | |
| 1176 | + rCirca | |
| 1177 | + ); | |
| 1178 | + nEntry -= (nEntry+1)/2; | |
| 1179 | + if( useDividers ) timeline_add_dividers(rCirca, 0); | |
| 1180 | + url_add_parameter(&url, "c", zCirca); | |
| 1169 | 1181 | }else{ |
| 1170 | 1182 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 1171 | 1183 | } |
| 1172 | 1184 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 1173 | 1185 | db_multi_exec("%s", blob_str(&sql)); |
| 1174 | 1186 | |
| 1175 | 1187 | n = db_int(0, "SELECT count(*) FROM timeline /*scan*/"); |
| 1176 | - if( n<nEntry && zAfter ){ | |
| 1177 | - cgi_redirect(url_render(&url, "a", 0, "b", 0)); | |
| 1178 | - } | |
| 1179 | 1188 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1180 | 1189 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1181 | 1190 | }else{ |
| 1182 | 1191 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1183 | 1192 | } |
| @@ -1190,15 +1199,20 @@ | ||
| 1190 | 1199 | tmFlags |= TIMELINE_DISJOINT; |
| 1191 | 1200 | }else if( zBrName ){ |
| 1192 | 1201 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1193 | 1202 | tmFlags |= TIMELINE_DISJOINT; |
| 1194 | 1203 | } |
| 1195 | - if( zAfter ){ | |
| 1196 | - blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); | |
| 1197 | - }else if( zBefore ){ | |
| 1204 | + if( rAfter>0.0 ){ | |
| 1205 | + if( rBefore>0.0 ){ | |
| 1206 | + blob_appendf(&desc, " occurring between %h and %h.<br>", | |
| 1207 | + zAfter, zBefore); | |
| 1208 | + }else{ | |
| 1209 | + blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); | |
| 1210 | + } | |
| 1211 | + }else if( rBefore>0.0 ){ | |
| 1198 | 1212 | blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); |
| 1199 | - }else if( zCirca ){ | |
| 1213 | + }else if( rCirca>0.0 ){ | |
| 1200 | 1214 | blob_appendf(&desc, " occurring around %h.<br />", zCirca); |
| 1201 | 1215 | } |
| 1202 | 1216 | if( zSearch ){ |
| 1203 | 1217 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1204 | 1218 | } |
| 1205 | 1219 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -810,33 +810,49 @@ | |
| 810 | style_submenu_element(zMenuName, zMenuName, "%s", |
| 811 | url_render(pUrl, zParam, zValue, zRemove, 0)); |
| 812 | } |
| 813 | |
| 814 | |
| 815 | /* |
| 816 | ** zDate is a localtime date. Insert records into the |
| 817 | ** "timeline" table to cause <hr> to be inserted before and after |
| 818 | ** entries of that date. If zDate==NULL then put dividers around |
| 819 | ** the event identified by rid. |
| 820 | */ |
| 821 | static void timeline_add_dividers(const char *zDate, int rid){ |
| 822 | char *zToDel = 0; |
| 823 | if( zDate==0 ){ |
| 824 | zToDel = db_text(0,"SELECT julianday(mtime,'localtime') FROM event" |
| 825 | " WHERE objid=%d", rid); |
| 826 | zDate = zToDel; |
| 827 | if( zDate==0 ) zDate = "1"; |
| 828 | } |
| 829 | db_multi_exec( |
| 830 | "INSERT INTO timeline(rid,sortby,etype)" |
| 831 | "VALUES(-1,julianday(%Q,'utc')-1.0e-5,'div')", |
| 832 | zDate |
| 833 | ); |
| 834 | db_multi_exec( |
| 835 | "INSERT INTO timeline(rid,sortby,etype)" |
| 836 | "VALUES(-2,julianday(%Q,'utc')+1.0e-5,'div')", |
| 837 | zDate |
| 838 | ); |
| 839 | fossil_free(zToDel); |
| 840 | } |
| 841 | |
| 842 | |
| @@ -843,14 +859,14 @@ | |
| 843 | /* |
| 844 | ** WEBPAGE: timeline |
| 845 | ** |
| 846 | ** Query parameters: |
| 847 | ** |
| 848 | ** a=TIMESTAMP after this date |
| 849 | ** b=TIMESTAMP before this date. |
| 850 | ** c=TIMESTAMP "circa" this date. |
| 851 | ** n=COUNT number of events in output |
| 852 | ** p=UUID artifact and up to COUNT parents and ancestors |
| 853 | ** d=UUID artifact and up to COUNT descendants |
| 854 | ** dp=UUUID The same as d=UUID&p=UUID |
| 855 | ** t=TAGID show only check-ins with the given tagid |
| 856 | ** r=TAGID show check-ins related to tagid |
| @@ -901,10 +917,11 @@ | |
| 901 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 902 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 903 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 904 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 905 | int pd_rid; |
| 906 | |
| 907 | /* To view the timeline, must have permission to read project data. |
| 908 | */ |
| 909 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 910 | if( pd_rid ){ |
| @@ -1121,63 +1138,55 @@ | |
| 1121 | blob_appendf(&sql, |
| 1122 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1123 | zSearch, zSearch); |
| 1124 | url_add_parameter(&url, "s", zSearch); |
| 1125 | } |
| 1126 | if( zAfter ){ |
| 1127 | while( fossil_isspace(zAfter[0]) ){ zAfter++; } |
| 1128 | if( zAfter[0] ){ |
| 1129 | blob_appendf(&sql, |
| 1130 | " AND event.mtime>=(SELECT julianday(%Q, 'utc'))" |
| 1131 | " ORDER BY event.mtime ASC", zAfter); |
| 1132 | url_add_parameter(&url, "a", zAfter); |
| 1133 | zBefore = 0; |
| 1134 | }else{ |
| 1135 | zAfter = 0; |
| 1136 | } |
| 1137 | }else if( zBefore ){ |
| 1138 | while( fossil_isspace(zBefore[0]) ){ zBefore++; } |
| 1139 | if( zBefore[0] ){ |
| 1140 | blob_appendf(&sql, |
| 1141 | " AND event.mtime<=(SELECT julianday(%Q, 'utc'))" |
| 1142 | " ORDER BY event.mtime DESC", zBefore); |
| 1143 | url_add_parameter(&url, "b", zBefore); |
| 1144 | }else{ |
| 1145 | zBefore = 0; |
| 1146 | } |
| 1147 | }else if( zCirca ){ |
| 1148 | while( fossil_isspace(zCirca[0]) ){ zCirca++; } |
| 1149 | if( zCirca[0] ){ |
| 1150 | double rCirca = db_double(0.0, "SELECT julianday(%Q, 'utc')", zCirca); |
| 1151 | Blob sql2; |
| 1152 | blob_init(&sql2, blob_str(&sql), -1); |
| 1153 | blob_appendf(&sql2, |
| 1154 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| 1155 | rCirca, (nEntry+1)/2 |
| 1156 | ); |
| 1157 | db_multi_exec("%s", blob_str(&sql2)); |
| 1158 | blob_reset(&sql2); |
| 1159 | blob_appendf(&sql, |
| 1160 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 1161 | rCirca |
| 1162 | ); |
| 1163 | nEntry -= (nEntry+1)/2; |
| 1164 | if( useDividers ) timeline_add_dividers(zCirca, 0); |
| 1165 | url_add_parameter(&url, "c", zCirca); |
| 1166 | }else{ |
| 1167 | zCirca = 0; |
| 1168 | } |
| 1169 | }else{ |
| 1170 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 1171 | } |
| 1172 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 1173 | db_multi_exec("%s", blob_str(&sql)); |
| 1174 | |
| 1175 | n = db_int(0, "SELECT count(*) FROM timeline /*scan*/"); |
| 1176 | if( n<nEntry && zAfter ){ |
| 1177 | cgi_redirect(url_render(&url, "a", 0, "b", 0)); |
| 1178 | } |
| 1179 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1180 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1181 | }else{ |
| 1182 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1183 | } |
| @@ -1190,15 +1199,20 @@ | |
| 1190 | tmFlags |= TIMELINE_DISJOINT; |
| 1191 | }else if( zBrName ){ |
| 1192 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1193 | tmFlags |= TIMELINE_DISJOINT; |
| 1194 | } |
| 1195 | if( zAfter ){ |
| 1196 | blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); |
| 1197 | }else if( zBefore ){ |
| 1198 | blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); |
| 1199 | }else if( zCirca ){ |
| 1200 | blob_appendf(&desc, " occurring around %h.<br />", zCirca); |
| 1201 | } |
| 1202 | if( zSearch ){ |
| 1203 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1204 | } |
| 1205 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -810,33 +810,49 @@ | |
| 810 | style_submenu_element(zMenuName, zMenuName, "%s", |
| 811 | url_render(pUrl, zParam, zValue, zRemove, 0)); |
| 812 | } |
| 813 | |
| 814 | |
| 815 | /* |
| 816 | ** Convert a symbolic name used as an argument to the a=, b=, or c= |
| 817 | ** query parameters of timeline into a julianday mtime value. |
| 818 | */ |
| 819 | double symbolic_name_to_mtime(const char *z){ |
| 820 | double mtime; |
| 821 | int rid; |
| 822 | if( z==0 ) return -1.0; |
| 823 | rid = symbolic_name_to_rid(z, "ci"); |
| 824 | if( rid==0 ) return -1.0; |
| 825 | mtime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 826 | return mtime; |
| 827 | } |
| 828 | |
| 829 | /* |
| 830 | ** The value of one second in julianday notation |
| 831 | */ |
| 832 | #define ONE_SECOND (1.0/86400.0) |
| 833 | |
| 834 | /* |
| 835 | ** zDate is a localtime date. Insert records into the |
| 836 | ** "timeline" table to cause <hr> to be inserted before and after |
| 837 | ** entries of that date. If zDate==NULL then put dividers around |
| 838 | ** the event identified by rid. |
| 839 | */ |
| 840 | static void timeline_add_dividers(double rDate, int rid){ |
| 841 | char *zToDel = 0; |
| 842 | if( rDate==0 ){ |
| 843 | rDate = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 844 | } |
| 845 | db_multi_exec( |
| 846 | "INSERT INTO timeline(rid,sortby,etype)" |
| 847 | "VALUES(-1,%.16g,'div')", |
| 848 | rDate-ONE_SECOND |
| 849 | ); |
| 850 | db_multi_exec( |
| 851 | "INSERT INTO timeline(rid,sortby,etype)" |
| 852 | "VALUES(-2,%.17g,'div')", |
| 853 | rDate+ONE_SECOND |
| 854 | ); |
| 855 | fossil_free(zToDel); |
| 856 | } |
| 857 | |
| 858 | |
| @@ -843,14 +859,14 @@ | |
| 859 | /* |
| 860 | ** WEBPAGE: timeline |
| 861 | ** |
| 862 | ** Query parameters: |
| 863 | ** |
| 864 | ** a=TIMEORTAG after this event |
| 865 | ** b=TIMEORTAG before this event |
| 866 | ** c=TIMEORTAG "circa" this event |
| 867 | ** n=COUNT max number of events in output |
| 868 | ** p=UUID artifact and up to COUNT parents and ancestors |
| 869 | ** d=UUID artifact and up to COUNT descendants |
| 870 | ** dp=UUUID The same as d=UUID&p=UUID |
| 871 | ** t=TAGID show only check-ins with the given tagid |
| 872 | ** r=TAGID show check-ins related to tagid |
| @@ -901,10 +917,11 @@ | |
| 917 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 918 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 919 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 920 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 921 | int pd_rid; |
| 922 | double rBefore, rAfter, rCirca; /* Boundary times */ |
| 923 | |
| 924 | /* To view the timeline, must have permission to read project data. |
| 925 | */ |
| 926 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 927 | if( pd_rid ){ |
| @@ -1121,63 +1138,55 @@ | |
| 1138 | blob_appendf(&sql, |
| 1139 | " AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')", |
| 1140 | zSearch, zSearch); |
| 1141 | url_add_parameter(&url, "s", zSearch); |
| 1142 | } |
| 1143 | rBefore = symbolic_name_to_mtime(zBefore); |
| 1144 | rAfter = symbolic_name_to_mtime(zAfter); |
| 1145 | rCirca = symbolic_name_to_mtime(zCirca); |
| 1146 | if( rAfter>0.0 ){ |
| 1147 | if( rBefore>0.0 ){ |
| 1148 | blob_appendf(&sql, |
| 1149 | " AND event.mtime>=%.17g AND event.mtime<=%.17g" |
| 1150 | " ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND); |
| 1151 | url_add_parameter(&url, "a", zAfter); |
| 1152 | url_add_parameter(&url, "b", zBefore); |
| 1153 | nEntry = 1000000; |
| 1154 | }else{ |
| 1155 | blob_appendf(&sql, |
| 1156 | " AND event.mtime>=%.17g ORDER BY event.mtime ASC", |
| 1157 | rAfter-ONE_SECOND); |
| 1158 | url_add_parameter(&url, "a", zAfter); |
| 1159 | } |
| 1160 | }else if( rBefore>0.0 ){ |
| 1161 | blob_appendf(&sql, |
| 1162 | " AND event.mtime<=%.17g ORDER BY event.mtime DESC", |
| 1163 | rBefore+ONE_SECOND); |
| 1164 | url_add_parameter(&url, "b", zBefore); |
| 1165 | }else if( rCirca>0.0 ){ |
| 1166 | Blob sql2; |
| 1167 | blob_init(&sql2, blob_str(&sql), -1); |
| 1168 | blob_appendf(&sql2, |
| 1169 | " AND event.mtime<=%f ORDER BY event.mtime DESC LIMIT %d", |
| 1170 | rCirca, (nEntry+1)/2 |
| 1171 | ); |
| 1172 | db_multi_exec("%s", blob_str(&sql2)); |
| 1173 | blob_reset(&sql2); |
| 1174 | blob_appendf(&sql, |
| 1175 | " AND event.mtime>=%f ORDER BY event.mtime ASC", |
| 1176 | rCirca |
| 1177 | ); |
| 1178 | nEntry -= (nEntry+1)/2; |
| 1179 | if( useDividers ) timeline_add_dividers(rCirca, 0); |
| 1180 | url_add_parameter(&url, "c", zCirca); |
| 1181 | }else{ |
| 1182 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 1183 | } |
| 1184 | blob_appendf(&sql, " LIMIT %d", nEntry); |
| 1185 | db_multi_exec("%s", blob_str(&sql)); |
| 1186 | |
| 1187 | n = db_int(0, "SELECT count(*) FROM timeline /*scan*/"); |
| 1188 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1189 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1190 | }else{ |
| 1191 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1192 | } |
| @@ -1190,15 +1199,20 @@ | |
| 1199 | tmFlags |= TIMELINE_DISJOINT; |
| 1200 | }else if( zBrName ){ |
| 1201 | blob_appendf(&desc, " related to \"%h\"", zBrName); |
| 1202 | tmFlags |= TIMELINE_DISJOINT; |
| 1203 | } |
| 1204 | if( rAfter>0.0 ){ |
| 1205 | if( rBefore>0.0 ){ |
| 1206 | blob_appendf(&desc, " occurring between %h and %h.<br>", |
| 1207 | zAfter, zBefore); |
| 1208 | }else{ |
| 1209 | blob_appendf(&desc, " occurring on or after %h.<br />", zAfter); |
| 1210 | } |
| 1211 | }else if( rBefore>0.0 ){ |
| 1212 | blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); |
| 1213 | }else if( rCirca>0.0 ){ |
| 1214 | blob_appendf(&desc, " occurring around %h.<br />", zCirca); |
| 1215 | } |
| 1216 | if( zSearch ){ |
| 1217 | blob_appendf(&desc, " matching \"%h\"", zSearch); |
| 1218 | } |
| 1219 |