Fossil SCM
Merge updates from trunk.
Commit
63bd6754a5136fd98ca35e8f74a9cad89e4e8d66
Parent
2ed75739a5b140c…
6 files changed
+40
-29
+10
-3
+41
+1
+35
-12
+35
-12
+40
-29
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -81,45 +81,56 @@ | ||
| 81 | 81 | ** On Win32 systems, the file is named "_fossil" and is located in |
| 82 | 82 | ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. |
| 83 | 83 | ** |
| 84 | 84 | ** Available operations are: |
| 85 | 85 | ** |
| 86 | -** changes Shows all local checkouts that have uncommitted changes | |
| 86 | +** changes Shows all local checkouts that have uncommitted changes. | |
| 87 | +** This operation has no additional options. | |
| 87 | 88 | ** |
| 88 | 89 | ** clean Delete all "extra" files in all local checkouts. Extreme |
| 89 | 90 | ** caution should be exercised with this command because its |
| 90 | -** effects cannot be undone. Use of the -dry-run option to | |
| 91 | -** carefully review the local checkouts to be operated upon | |
| 92 | -** and the -whatif option to carefully review the files to | |
| 93 | -** be deleted beforehand is highly recommended. | |
| 94 | -** | |
| 95 | -** extra Shows extra files from all local checkouts | |
| 96 | -** | |
| 97 | -** ignore Arguments are repositories that should be ignored | |
| 98 | -** by subsequent list, pull, push, rebuild, and sync. | |
| 99 | -** The -c|--ckout option causes the listed local checkouts | |
| 100 | -** to be ignored instead. | |
| 101 | -** | |
| 102 | -** list | ls Display the location of all repositories. | |
| 103 | -** The -c|--ckout option causes all local checkouts to be | |
| 104 | -** list instead. | |
| 105 | -** | |
| 106 | -** pull Run a "pull" operation on all repositories | |
| 107 | -** | |
| 108 | -** push Run a "push" on all repositories | |
| 109 | -** | |
| 110 | -** rebuild Rebuild on all repositories | |
| 111 | -** | |
| 112 | -** sync Run a "sync" on all repositories | |
| 91 | +** effects cannot be undone. Use of the --dry-run option to | |
| 92 | +** carefully review the local checkouts to be operated upon | |
| 93 | +** and the --whatif option to carefully review the files to | |
| 94 | +** be deleted beforehand is highly recommended. The command | |
| 95 | +** line options supported by the clean command itself, if any | |
| 96 | +** are present, are passed along verbatim. | |
| 97 | +** | |
| 98 | +** extra Shows extra files from all local checkouts. The command | |
| 99 | +** line options supported by the extra command itself, if any | |
| 100 | +** are present, are passed along verbatim. | |
| 101 | +** | |
| 102 | +** ignore Arguments are repositories that should be ignored by | |
| 103 | +** subsequent clean, extra, list, pull, push, rebuild, and | |
| 104 | +** sync operations. The -c|--ckout option causes the listed | |
| 105 | +** local checkouts to be ignored instead. | |
| 106 | +** | |
| 107 | +** list | ls Display the location of all repositories. The -c|--ckout | |
| 108 | +** option causes all local checkouts to be listed instead. | |
| 109 | +** | |
| 110 | +** pull Run a "pull" operation on all repositories. Only the | |
| 111 | +** --verbose option is supported. | |
| 112 | +** | |
| 113 | +** push Run a "push" on all repositories. Only the --verbose | |
| 114 | +** option is supported. | |
| 115 | +** | |
| 116 | +** rebuild Rebuild on all repositories. The command line options | |
| 117 | +** supported by the rebuild command itself, if any are | |
| 118 | +** present, are passed along verbatim. The --force and | |
| 119 | +** --randomize options are not supported. | |
| 120 | +** | |
| 121 | +** sync Run a "sync" on all repositories. Only the --verbose | |
| 122 | +** option is supported. | |
| 113 | 123 | ** |
| 114 | 124 | ** Repositories are automatically added to the set of known repositories |
| 115 | -** when one of the following commands are run against the repository: clone, | |
| 116 | -** info, pull, push, or sync. Even previously ignored repositories are | |
| 117 | -** added back to the list of repositories by these commands. | |
| 125 | +** when one of the following commands are run against the repository: | |
| 126 | +** clone, info, pull, push, or sync. Even previously ignored repositories | |
| 127 | +** are added back to the list of repositories by these commands. | |
| 118 | 128 | ** |
| 119 | 129 | ** Options: |
| 120 | -** --dontstop Continue with other repositories even after an error | |
| 130 | +** --dontstop Continue with other repositories even after an error. | |
| 131 | +** --dry-run If given, display instead of run actions. | |
| 121 | 132 | */ |
| 122 | 133 | void all_cmd(void){ |
| 123 | 134 | int n; |
| 124 | 135 | Stmt q; |
| 125 | 136 | const char *zCmd; |
| @@ -226,11 +237,11 @@ | ||
| 226 | 237 | } |
| 227 | 238 | db_end_transaction(0); |
| 228 | 239 | return; |
| 229 | 240 | }else{ |
| 230 | 241 | fossil_fatal("\"all\" subcommand should be one of: " |
| 231 | - "changes ignore list ls push pull rebuild sync"); | |
| 242 | + "changes clean extra ignore list ls push pull rebuild sync"); | |
| 232 | 243 | } |
| 233 | 244 | verify_all_options(); |
| 234 | 245 | zFossil = quoteFilename(g.nameOfExe); |
| 235 | 246 | if( useCheckouts ){ |
| 236 | 247 | db_prepare(&q, |
| 237 | 248 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -81,45 +81,56 @@ | |
| 81 | ** On Win32 systems, the file is named "_fossil" and is located in |
| 82 | ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. |
| 83 | ** |
| 84 | ** Available operations are: |
| 85 | ** |
| 86 | ** changes Shows all local checkouts that have uncommitted changes |
| 87 | ** |
| 88 | ** clean Delete all "extra" files in all local checkouts. Extreme |
| 89 | ** caution should be exercised with this command because its |
| 90 | ** effects cannot be undone. Use of the -dry-run option to |
| 91 | ** carefully review the local checkouts to be operated upon |
| 92 | ** and the -whatif option to carefully review the files to |
| 93 | ** be deleted beforehand is highly recommended. |
| 94 | ** |
| 95 | ** extra Shows extra files from all local checkouts |
| 96 | ** |
| 97 | ** ignore Arguments are repositories that should be ignored |
| 98 | ** by subsequent list, pull, push, rebuild, and sync. |
| 99 | ** The -c|--ckout option causes the listed local checkouts |
| 100 | ** to be ignored instead. |
| 101 | ** |
| 102 | ** list | ls Display the location of all repositories. |
| 103 | ** The -c|--ckout option causes all local checkouts to be |
| 104 | ** list instead. |
| 105 | ** |
| 106 | ** pull Run a "pull" operation on all repositories |
| 107 | ** |
| 108 | ** push Run a "push" on all repositories |
| 109 | ** |
| 110 | ** rebuild Rebuild on all repositories |
| 111 | ** |
| 112 | ** sync Run a "sync" on all repositories |
| 113 | ** |
| 114 | ** Repositories are automatically added to the set of known repositories |
| 115 | ** when one of the following commands are run against the repository: clone, |
| 116 | ** info, pull, push, or sync. Even previously ignored repositories are |
| 117 | ** added back to the list of repositories by these commands. |
| 118 | ** |
| 119 | ** Options: |
| 120 | ** --dontstop Continue with other repositories even after an error |
| 121 | */ |
| 122 | void all_cmd(void){ |
| 123 | int n; |
| 124 | Stmt q; |
| 125 | const char *zCmd; |
| @@ -226,11 +237,11 @@ | |
| 226 | } |
| 227 | db_end_transaction(0); |
| 228 | return; |
| 229 | }else{ |
| 230 | fossil_fatal("\"all\" subcommand should be one of: " |
| 231 | "changes ignore list ls push pull rebuild sync"); |
| 232 | } |
| 233 | verify_all_options(); |
| 234 | zFossil = quoteFilename(g.nameOfExe); |
| 235 | if( useCheckouts ){ |
| 236 | db_prepare(&q, |
| 237 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -81,45 +81,56 @@ | |
| 81 | ** On Win32 systems, the file is named "_fossil" and is located in |
| 82 | ** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%. |
| 83 | ** |
| 84 | ** Available operations are: |
| 85 | ** |
| 86 | ** changes Shows all local checkouts that have uncommitted changes. |
| 87 | ** This operation has no additional options. |
| 88 | ** |
| 89 | ** clean Delete all "extra" files in all local checkouts. Extreme |
| 90 | ** caution should be exercised with this command because its |
| 91 | ** effects cannot be undone. Use of the --dry-run option to |
| 92 | ** carefully review the local checkouts to be operated upon |
| 93 | ** and the --whatif option to carefully review the files to |
| 94 | ** be deleted beforehand is highly recommended. The command |
| 95 | ** line options supported by the clean command itself, if any |
| 96 | ** are present, are passed along verbatim. |
| 97 | ** |
| 98 | ** extra Shows extra files from all local checkouts. The command |
| 99 | ** line options supported by the extra command itself, if any |
| 100 | ** are present, are passed along verbatim. |
| 101 | ** |
| 102 | ** ignore Arguments are repositories that should be ignored by |
| 103 | ** subsequent clean, extra, list, pull, push, rebuild, and |
| 104 | ** sync operations. The -c|--ckout option causes the listed |
| 105 | ** local checkouts to be ignored instead. |
| 106 | ** |
| 107 | ** list | ls Display the location of all repositories. The -c|--ckout |
| 108 | ** option causes all local checkouts to be listed instead. |
| 109 | ** |
| 110 | ** pull Run a "pull" operation on all repositories. Only the |
| 111 | ** --verbose option is supported. |
| 112 | ** |
| 113 | ** push Run a "push" on all repositories. Only the --verbose |
| 114 | ** option is supported. |
| 115 | ** |
| 116 | ** rebuild Rebuild on all repositories. The command line options |
| 117 | ** supported by the rebuild command itself, if any are |
| 118 | ** present, are passed along verbatim. The --force and |
| 119 | ** --randomize options are not supported. |
| 120 | ** |
| 121 | ** sync Run a "sync" on all repositories. Only the --verbose |
| 122 | ** option is supported. |
| 123 | ** |
| 124 | ** Repositories are automatically added to the set of known repositories |
| 125 | ** when one of the following commands are run against the repository: |
| 126 | ** clone, info, pull, push, or sync. Even previously ignored repositories |
| 127 | ** are added back to the list of repositories by these commands. |
| 128 | ** |
| 129 | ** Options: |
| 130 | ** --dontstop Continue with other repositories even after an error. |
| 131 | ** --dry-run If given, display instead of run actions. |
| 132 | */ |
| 133 | void all_cmd(void){ |
| 134 | int n; |
| 135 | Stmt q; |
| 136 | const char *zCmd; |
| @@ -226,11 +237,11 @@ | |
| 237 | } |
| 238 | db_end_transaction(0); |
| 239 | return; |
| 240 | }else{ |
| 241 | fossil_fatal("\"all\" subcommand should be one of: " |
| 242 | "changes clean extra ignore list ls push pull rebuild sync"); |
| 243 | } |
| 244 | verify_all_options(); |
| 245 | zFossil = quoteFilename(g.nameOfExe); |
| 246 | if( useCheckouts ){ |
| 247 | db_prepare(&q, |
| 248 |
+10
-3
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -41,10 +41,17 @@ | ||
| 41 | 41 | #define CONFIGSET_ALL 0x0000ff /* Everything */ |
| 42 | 42 | |
| 43 | 43 | #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ |
| 44 | 44 | #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ |
| 45 | 45 | |
| 46 | +/* | |
| 47 | +** This mask is used for the common TH1 configuration settings (i.e. those | |
| 48 | +** that are not specific to one particular subsystem, such as the transfer | |
| 49 | +** subsystem). | |
| 50 | +*/ | |
| 51 | +#define CONFIGSET_TH1 (CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER) | |
| 52 | + | |
| 46 | 53 | #endif /* INTERFACE */ |
| 47 | 54 | |
| 48 | 55 | /* |
| 49 | 56 | ** Names of the configuration sets |
| 50 | 57 | */ |
| @@ -90,15 +97,15 @@ | ||
| 90 | 97 | { "timeline-max-comment", CONFIGSET_SKIN }, |
| 91 | 98 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 92 | 99 | { "adunit", CONFIGSET_SKIN }, |
| 93 | 100 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 94 | 101 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 95 | - { "th1-setup", CONFIGSET_ALL }, | |
| 102 | + { "th1-setup", CONFIGSET_TH1 }, | |
| 96 | 103 | |
| 97 | 104 | #ifdef FOSSIL_ENABLE_TCL |
| 98 | - { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, | |
| 99 | - { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, | |
| 105 | + { "tcl", CONFIGSET_TH1 }, | |
| 106 | + { "tcl-setup", CONFIGSET_TH1 }, | |
| 100 | 107 | #endif |
| 101 | 108 | |
| 102 | 109 | { "project-name", CONFIGSET_PROJ }, |
| 103 | 110 | { "short-project-name", CONFIGSET_PROJ }, |
| 104 | 111 | { "project-description", CONFIGSET_PROJ }, |
| 105 | 112 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -41,10 +41,17 @@ | |
| 41 | #define CONFIGSET_ALL 0x0000ff /* Everything */ |
| 42 | |
| 43 | #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ |
| 44 | #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ |
| 45 | |
| 46 | #endif /* INTERFACE */ |
| 47 | |
| 48 | /* |
| 49 | ** Names of the configuration sets |
| 50 | */ |
| @@ -90,15 +97,15 @@ | |
| 90 | { "timeline-max-comment", CONFIGSET_SKIN }, |
| 91 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 92 | { "adunit", CONFIGSET_SKIN }, |
| 93 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 94 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 95 | { "th1-setup", CONFIGSET_ALL }, |
| 96 | |
| 97 | #ifdef FOSSIL_ENABLE_TCL |
| 98 | { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, |
| 99 | { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER }, |
| 100 | #endif |
| 101 | |
| 102 | { "project-name", CONFIGSET_PROJ }, |
| 103 | { "short-project-name", CONFIGSET_PROJ }, |
| 104 | { "project-description", CONFIGSET_PROJ }, |
| 105 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -41,10 +41,17 @@ | |
| 41 | #define CONFIGSET_ALL 0x0000ff /* Everything */ |
| 42 | |
| 43 | #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ |
| 44 | #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ |
| 45 | |
| 46 | /* |
| 47 | ** This mask is used for the common TH1 configuration settings (i.e. those |
| 48 | ** that are not specific to one particular subsystem, such as the transfer |
| 49 | ** subsystem). |
| 50 | */ |
| 51 | #define CONFIGSET_TH1 (CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER) |
| 52 | |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | /* |
| 56 | ** Names of the configuration sets |
| 57 | */ |
| @@ -90,15 +97,15 @@ | |
| 97 | { "timeline-max-comment", CONFIGSET_SKIN }, |
| 98 | { "timeline-plaintext", CONFIGSET_SKIN }, |
| 99 | { "adunit", CONFIGSET_SKIN }, |
| 100 | { "adunit-omit-if-admin", CONFIGSET_SKIN }, |
| 101 | { "adunit-omit-if-user", CONFIGSET_SKIN }, |
| 102 | { "th1-setup", CONFIGSET_TH1 }, |
| 103 | |
| 104 | #ifdef FOSSIL_ENABLE_TCL |
| 105 | { "tcl", CONFIGSET_TH1 }, |
| 106 | { "tcl-setup", CONFIGSET_TH1 }, |
| 107 | #endif |
| 108 | |
| 109 | { "project-name", CONFIGSET_PROJ }, |
| 110 | { "short-project-name", CONFIGSET_PROJ }, |
| 111 | { "project-description", CONFIGSET_PROJ }, |
| 112 |
+41
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -850,10 +850,37 @@ | ||
| 850 | 850 | @ <span class="textareaLabel">%s(zLabel)</span> |
| 851 | 851 | } |
| 852 | 852 | } |
| 853 | 853 | } |
| 854 | 854 | |
| 855 | +/* | |
| 856 | +** Generate a text box for an attribute. | |
| 857 | +*/ | |
| 858 | +static void multiple_choice_attribute( | |
| 859 | + const char *zLabel, /* The text label on the menu */ | |
| 860 | + const char *zVar, /* The corresponding row in the VAR table */ | |
| 861 | + const char *zQP, /* The query parameter */ | |
| 862 | + const char *zDflt, /* Default value if VAR table entry does not exist */ | |
| 863 | + int nChoice, /* Number of choices */ | |
| 864 | + const char **azChoice /* Choices. 2 per choice: (VAR value, Display) */ | |
| 865 | +){ | |
| 866 | + const char *z = db_get(zVar, (char*)zDflt); | |
| 867 | + const char *zQ = P(zQP); | |
| 868 | + int i; | |
| 869 | + if( zQ && fossil_strcmp(zQ,z)!=0){ | |
| 870 | + login_verify_csrf_secret(); | |
| 871 | + db_set(zVar, zQ, 0); | |
| 872 | + z = zQ; | |
| 873 | + } | |
| 874 | + @ <select size="1" name="%s(zQP)" id="id%s(zQP)"> | |
| 875 | + for(i=0; i<nChoice*2; i+=2){ | |
| 876 | + const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : ""; | |
| 877 | + @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option> | |
| 878 | + } | |
| 879 | + @ </select> | |
| 880 | +} | |
| 881 | + | |
| 855 | 882 | |
| 856 | 883 | /* |
| 857 | 884 | ** WEBPAGE: setup_access |
| 858 | 885 | */ |
| 859 | 886 | void setup_access(void){ |
| @@ -1124,10 +1151,16 @@ | ||
| 1124 | 1151 | ** WEBPAGE: setup_timeline |
| 1125 | 1152 | */ |
| 1126 | 1153 | void setup_timeline(void){ |
| 1127 | 1154 | double tmDiff; |
| 1128 | 1155 | char zTmDiff[20]; |
| 1156 | + static const char *azTimeFormats[] = { | |
| 1157 | + "0", "HH:MM", | |
| 1158 | + "1", "HH:MM:SS", | |
| 1159 | + "2", "YYYY-MM-DD HH:MM", | |
| 1160 | + "3", "YYMMDD HH:MM" | |
| 1161 | + }; | |
| 1129 | 1162 | login_check_credentials(); |
| 1130 | 1163 | if( !g.perm.Setup ){ |
| 1131 | 1164 | login_needed(); |
| 1132 | 1165 | } |
| 1133 | 1166 | |
| @@ -1167,10 +1200,18 @@ | ||
| 1167 | 1200 | @ %s(zTmDiff) hours behind UTC.</p> |
| 1168 | 1201 | }else{ |
| 1169 | 1202 | @ %s(zTmDiff) hours ahead of UTC.</p> |
| 1170 | 1203 | } |
| 1171 | 1204 | |
| 1205 | + @ <hr /> | |
| 1206 | + multiple_choice_attribute("Per-Item Time Format", "timeline-date-format", "tdf", "0", | |
| 1207 | + 4, azTimeFormats); | |
| 1208 | + @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown | |
| 1209 | + @ in a separate box (using CSS class "timelineDate") whenever the date changes. | |
| 1210 | + @ With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, the complete date | |
| 1211 | + @ and time is shown on every timeline entry (using the CSS class "timelineTime").</p> | |
| 1212 | + | |
| 1172 | 1213 | @ <hr /> |
| 1173 | 1214 | onoff_attribute("Show version differences by default", |
| 1174 | 1215 | "show-version-diffs", "vdiff", 0, 0); |
| 1175 | 1216 | @ <p>On the version-information pages linked from the timeline can either |
| 1176 | 1217 | @ show complete diffs of all file changes, or can just list the names of |
| 1177 | 1218 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -850,10 +850,37 @@ | |
| 850 | @ <span class="textareaLabel">%s(zLabel)</span> |
| 851 | } |
| 852 | } |
| 853 | } |
| 854 | |
| 855 | |
| 856 | /* |
| 857 | ** WEBPAGE: setup_access |
| 858 | */ |
| 859 | void setup_access(void){ |
| @@ -1124,10 +1151,16 @@ | |
| 1124 | ** WEBPAGE: setup_timeline |
| 1125 | */ |
| 1126 | void setup_timeline(void){ |
| 1127 | double tmDiff; |
| 1128 | char zTmDiff[20]; |
| 1129 | login_check_credentials(); |
| 1130 | if( !g.perm.Setup ){ |
| 1131 | login_needed(); |
| 1132 | } |
| 1133 | |
| @@ -1167,10 +1200,18 @@ | |
| 1167 | @ %s(zTmDiff) hours behind UTC.</p> |
| 1168 | }else{ |
| 1169 | @ %s(zTmDiff) hours ahead of UTC.</p> |
| 1170 | } |
| 1171 | |
| 1172 | @ <hr /> |
| 1173 | onoff_attribute("Show version differences by default", |
| 1174 | "show-version-diffs", "vdiff", 0, 0); |
| 1175 | @ <p>On the version-information pages linked from the timeline can either |
| 1176 | @ show complete diffs of all file changes, or can just list the names of |
| 1177 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -850,10 +850,37 @@ | |
| 850 | @ <span class="textareaLabel">%s(zLabel)</span> |
| 851 | } |
| 852 | } |
| 853 | } |
| 854 | |
| 855 | /* |
| 856 | ** Generate a text box for an attribute. |
| 857 | */ |
| 858 | static void multiple_choice_attribute( |
| 859 | const char *zLabel, /* The text label on the menu */ |
| 860 | const char *zVar, /* The corresponding row in the VAR table */ |
| 861 | const char *zQP, /* The query parameter */ |
| 862 | const char *zDflt, /* Default value if VAR table entry does not exist */ |
| 863 | int nChoice, /* Number of choices */ |
| 864 | const char **azChoice /* Choices. 2 per choice: (VAR value, Display) */ |
| 865 | ){ |
| 866 | const char *z = db_get(zVar, (char*)zDflt); |
| 867 | const char *zQ = P(zQP); |
| 868 | int i; |
| 869 | if( zQ && fossil_strcmp(zQ,z)!=0){ |
| 870 | login_verify_csrf_secret(); |
| 871 | db_set(zVar, zQ, 0); |
| 872 | z = zQ; |
| 873 | } |
| 874 | @ <select size="1" name="%s(zQP)" id="id%s(zQP)"> |
| 875 | for(i=0; i<nChoice*2; i+=2){ |
| 876 | const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : ""; |
| 877 | @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option> |
| 878 | } |
| 879 | @ </select> |
| 880 | } |
| 881 | |
| 882 | |
| 883 | /* |
| 884 | ** WEBPAGE: setup_access |
| 885 | */ |
| 886 | void setup_access(void){ |
| @@ -1124,10 +1151,16 @@ | |
| 1151 | ** WEBPAGE: setup_timeline |
| 1152 | */ |
| 1153 | void setup_timeline(void){ |
| 1154 | double tmDiff; |
| 1155 | char zTmDiff[20]; |
| 1156 | static const char *azTimeFormats[] = { |
| 1157 | "0", "HH:MM", |
| 1158 | "1", "HH:MM:SS", |
| 1159 | "2", "YYYY-MM-DD HH:MM", |
| 1160 | "3", "YYMMDD HH:MM" |
| 1161 | }; |
| 1162 | login_check_credentials(); |
| 1163 | if( !g.perm.Setup ){ |
| 1164 | login_needed(); |
| 1165 | } |
| 1166 | |
| @@ -1167,10 +1200,18 @@ | |
| 1200 | @ %s(zTmDiff) hours behind UTC.</p> |
| 1201 | }else{ |
| 1202 | @ %s(zTmDiff) hours ahead of UTC.</p> |
| 1203 | } |
| 1204 | |
| 1205 | @ <hr /> |
| 1206 | multiple_choice_attribute("Per-Item Time Format", "timeline-date-format", "tdf", "0", |
| 1207 | 4, azTimeFormats); |
| 1208 | @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown |
| 1209 | @ in a separate box (using CSS class "timelineDate") whenever the date changes. |
| 1210 | @ With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, the complete date |
| 1211 | @ and time is shown on every timeline entry (using the CSS class "timelineTime").</p> |
| 1212 | |
| 1213 | @ <hr /> |
| 1214 | onoff_attribute("Show version differences by default", |
| 1215 | "show-version-diffs", "vdiff", 0, 0); |
| 1216 | @ <p>On the version-information pages linked from the timeline can either |
| 1217 | @ show complete diffs of all file changes, or can just list the names of |
| 1218 |
+1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -686,10 +686,11 @@ | ||
| 686 | 686 | }, |
| 687 | 687 | { "td.timelineTime", |
| 688 | 688 | "the format for the timeline time display", |
| 689 | 689 | @ vertical-align: top; |
| 690 | 690 | @ text-align: right; |
| 691 | + @ white-space: nowrap; | |
| 691 | 692 | }, |
| 692 | 693 | { "td.timelineGraph", |
| 693 | 694 | "the format for the grap placeholder cells in timelines", |
| 694 | 695 | @ width: 20px; |
| 695 | 696 | @ text-align: left; |
| 696 | 697 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -686,10 +686,11 @@ | |
| 686 | }, |
| 687 | { "td.timelineTime", |
| 688 | "the format for the timeline time display", |
| 689 | @ vertical-align: top; |
| 690 | @ text-align: right; |
| 691 | }, |
| 692 | { "td.timelineGraph", |
| 693 | "the format for the grap placeholder cells in timelines", |
| 694 | @ width: 20px; |
| 695 | @ text-align: left; |
| 696 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -686,10 +686,11 @@ | |
| 686 | }, |
| 687 | { "td.timelineTime", |
| 688 | "the format for the timeline time display", |
| 689 | @ vertical-align: top; |
| 690 | @ text-align: right; |
| 691 | @ white-space: nowrap; |
| 692 | }, |
| 693 | { "td.timelineGraph", |
| 694 | "the format for the grap placeholder cells in timelines", |
| 695 | @ width: 20px; |
| 696 | @ text-align: left; |
| 697 |
+35
-12
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -246,16 +246,20 @@ | ||
| 246 | 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | 248 | static Stmt qbranch; |
| 249 | 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | 250 | int vid = 0; /* Current checkout version */ |
| 251 | + int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS | |
| 252 | + 2: YYYY-MM-DD HH:MM | |
| 253 | + 3: YYMMDD HH:MM */ | |
| 251 | 254 | |
| 252 | 255 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 253 | 256 | vid = db_lget_int("checkout", 0); |
| 254 | 257 | } |
| 255 | 258 | zPrevDate[0] = 0; |
| 256 | 259 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 260 | + dateFormat = db_get_int("timeline-date-format", 0); | |
| 257 | 261 | if( tmFlags & TIMELINE_GRAPH ){ |
| 258 | 262 | pGraph = graph_init(); |
| 259 | 263 | /* style is not moved to css, because this is |
| 260 | 264 | ** a technical div for the timeline graph |
| 261 | 265 | */ |
| @@ -282,11 +286,11 @@ | ||
| 282 | 286 | int tagid = db_column_int(pQuery, 9); |
| 283 | 287 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 284 | 288 | const char *zBr = 0; /* Branch */ |
| 285 | 289 | int commentColumn = 3; /* Column containing comment text */ |
| 286 | 290 | int modPending; /* Pending moderation */ |
| 287 | - char zTime[8]; | |
| 291 | + char zTime[20]; | |
| 288 | 292 | |
| 289 | 293 | modPending = moderation_pending(rid); |
| 290 | 294 | if( tagid ){ |
| 291 | 295 | if( modPending ) tagid = -tagid; |
| 292 | 296 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | ||
| 314 | 318 | } |
| 315 | 319 | prevWasDivider = 1; |
| 316 | 320 | continue; |
| 317 | 321 | } |
| 318 | 322 | prevWasDivider = 0; |
| 319 | - if( memcmp(zDate, zPrevDate, 10) ){ | |
| 320 | - sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); | |
| 321 | - @ <tr><td> | |
| 322 | - @ <div class="divider">%s(zPrevDate)</div> | |
| 323 | - @ </td><td></td><td></td></tr> | |
| 324 | - } | |
| 325 | - memcpy(zTime, &zDate[11], 5); | |
| 326 | - zTime[5] = 0; | |
| 323 | + if( dateFormat<2 ){ | |
| 324 | + if( memcmp(zDate, zPrevDate, 10) ){ | |
| 325 | + sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); | |
| 326 | + @ <tr><td> | |
| 327 | + @ <div class="divider timelineDate">%s(zPrevDate)</div> | |
| 328 | + @ </td><td></td><td></td></tr> | |
| 329 | + } | |
| 330 | + memcpy(zTime, &zDate[11], 5+dateFormat*3); | |
| 331 | + zTime[5+dateFormat*3] = 0; | |
| 332 | + }else if(3==dateFormat){ | |
| 333 | + /* YYMMDD HH:MM */ | |
| 334 | + int pos = 0; | |
| 335 | + zTime[pos++] = zDate[2]; zTime[pos++] = zDate[3]; /* YY */ | |
| 336 | + zTime[pos++] = zDate[5]; zTime[pos++] = zDate[6]; /* MM */ | |
| 337 | + zTime[pos++] = zDate[8]; zTime[pos++] = zDate[9]; /* DD */ | |
| 338 | + zTime[pos++] = ' '; | |
| 339 | + zTime[pos++] = zDate[11]; zTime[pos++] = zDate[12]; /* HH */ | |
| 340 | + zTime[pos++] = ':'; | |
| 341 | + zTime[pos++] = zDate[14]; zTime[pos++] = zDate[15]; /* MM */ | |
| 342 | + zTime[pos++] = 0; | |
| 343 | + }else{ | |
| 344 | + /* YYYY-MM-DD HH:MM */ | |
| 345 | + sqlite3_snprintf(sizeof(zTime), zTime, "%.16s", zDate); | |
| 346 | + } | |
| 327 | 347 | if( rid == vid ){ |
| 328 | 348 | @ <tr class="timelineCurrent"> |
| 329 | 349 | }else { |
| 330 | 350 | @ <tr> |
| 331 | 351 | } |
| @@ -2115,14 +2135,15 @@ | ||
| 2115 | 2135 | } |
| 2116 | 2136 | db_reset(&query); |
| 2117 | 2137 | while( SQLITE_ROW == db_step(&query) ){ |
| 2118 | 2138 | const char * zTimeframe = db_column_text(&query, 0); |
| 2119 | 2139 | const int nCount = db_column_int(&query, 1); |
| 2120 | - const int nSize = nCount | |
| 2140 | + int nSize = nCount | |
| 2121 | 2141 | ? (int)(100 * nCount / nMaxEvents) |
| 2122 | 2142 | : 1; |
| 2123 | 2143 | showYearTotal = 0; |
| 2144 | + if(!nSize) nSize = 1; | |
| 2124 | 2145 | if(includeMonth){ |
| 2125 | 2146 | /* For Month/year view, add a separator for each distinct year. */ |
| 2126 | 2147 | if(!*zPrevYear || |
| 2127 | 2148 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2128 | 2149 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | ||
| 2249 | 2270 | } |
| 2250 | 2271 | db_reset(&query); |
| 2251 | 2272 | while( SQLITE_ROW == db_step(&query) ){ |
| 2252 | 2273 | const char * zUser = db_column_text(&query, 0); |
| 2253 | 2274 | const int nCount = db_column_int(&query, 1); |
| 2254 | - const int nSize = nCount | |
| 2275 | + int nSize = nCount | |
| 2255 | 2276 | ? (int)(100 * nCount / nMaxEvents) |
| 2256 | 2277 | : 0; |
| 2257 | 2278 | if(!nCount) continue /* arguable! Possible? */; |
| 2279 | + else if(!nSize) nSize = 1; | |
| 2258 | 2280 | rowClass = ++nRowNumber % 2; |
| 2259 | 2281 | nEventTotal += nCount; |
| 2260 | 2282 | @<tr class='row%d(rowClass)'> |
| 2261 | 2283 | @ <td> |
| 2262 | 2284 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | ||
| 2365 | 2387 | } |
| 2366 | 2388 | db_reset(&stWeek); |
| 2367 | 2389 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2368 | 2390 | const char * zWeek = db_column_text(&stWeek,0); |
| 2369 | 2391 | const int nCount = db_column_int(&stWeek,1); |
| 2370 | - const int nSize = nCount | |
| 2392 | + int nSize = nCount | |
| 2371 | 2393 | ? (int)(100 * nCount / nMaxEvents) |
| 2372 | 2394 | : 0; |
| 2395 | + if(!nSize) nSize = 1; | |
| 2373 | 2396 | total += nCount; |
| 2374 | 2397 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2375 | 2398 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2376 | 2399 | g.zTop, zYear, zWeek, nCount, |
| 2377 | 2400 | statsReportTimelineYFlag); |
| 2378 | 2401 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -246,16 +246,20 @@ | |
| 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | static Stmt qbranch; |
| 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | int vid = 0; /* Current checkout version */ |
| 251 | |
| 252 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 253 | vid = db_lget_int("checkout", 0); |
| 254 | } |
| 255 | zPrevDate[0] = 0; |
| 256 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 257 | if( tmFlags & TIMELINE_GRAPH ){ |
| 258 | pGraph = graph_init(); |
| 259 | /* style is not moved to css, because this is |
| 260 | ** a technical div for the timeline graph |
| 261 | */ |
| @@ -282,11 +286,11 @@ | |
| 282 | int tagid = db_column_int(pQuery, 9); |
| 283 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 284 | const char *zBr = 0; /* Branch */ |
| 285 | int commentColumn = 3; /* Column containing comment text */ |
| 286 | int modPending; /* Pending moderation */ |
| 287 | char zTime[8]; |
| 288 | |
| 289 | modPending = moderation_pending(rid); |
| 290 | if( tagid ){ |
| 291 | if( modPending ) tagid = -tagid; |
| 292 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | |
| 314 | } |
| 315 | prevWasDivider = 1; |
| 316 | continue; |
| 317 | } |
| 318 | prevWasDivider = 0; |
| 319 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 320 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 321 | @ <tr><td> |
| 322 | @ <div class="divider">%s(zPrevDate)</div> |
| 323 | @ </td><td></td><td></td></tr> |
| 324 | } |
| 325 | memcpy(zTime, &zDate[11], 5); |
| 326 | zTime[5] = 0; |
| 327 | if( rid == vid ){ |
| 328 | @ <tr class="timelineCurrent"> |
| 329 | }else { |
| 330 | @ <tr> |
| 331 | } |
| @@ -2115,14 +2135,15 @@ | |
| 2115 | } |
| 2116 | db_reset(&query); |
| 2117 | while( SQLITE_ROW == db_step(&query) ){ |
| 2118 | const char * zTimeframe = db_column_text(&query, 0); |
| 2119 | const int nCount = db_column_int(&query, 1); |
| 2120 | const int nSize = nCount |
| 2121 | ? (int)(100 * nCount / nMaxEvents) |
| 2122 | : 1; |
| 2123 | showYearTotal = 0; |
| 2124 | if(includeMonth){ |
| 2125 | /* For Month/year view, add a separator for each distinct year. */ |
| 2126 | if(!*zPrevYear || |
| 2127 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2128 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | |
| 2249 | } |
| 2250 | db_reset(&query); |
| 2251 | while( SQLITE_ROW == db_step(&query) ){ |
| 2252 | const char * zUser = db_column_text(&query, 0); |
| 2253 | const int nCount = db_column_int(&query, 1); |
| 2254 | const int nSize = nCount |
| 2255 | ? (int)(100 * nCount / nMaxEvents) |
| 2256 | : 0; |
| 2257 | if(!nCount) continue /* arguable! Possible? */; |
| 2258 | rowClass = ++nRowNumber % 2; |
| 2259 | nEventTotal += nCount; |
| 2260 | @<tr class='row%d(rowClass)'> |
| 2261 | @ <td> |
| 2262 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | |
| 2365 | } |
| 2366 | db_reset(&stWeek); |
| 2367 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2368 | const char * zWeek = db_column_text(&stWeek,0); |
| 2369 | const int nCount = db_column_int(&stWeek,1); |
| 2370 | const int nSize = nCount |
| 2371 | ? (int)(100 * nCount / nMaxEvents) |
| 2372 | : 0; |
| 2373 | total += nCount; |
| 2374 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2375 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2376 | g.zTop, zYear, zWeek, nCount, |
| 2377 | statsReportTimelineYFlag); |
| 2378 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -246,16 +246,20 @@ | |
| 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | static Stmt qbranch; |
| 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | int vid = 0; /* Current checkout version */ |
| 251 | int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS |
| 252 | 2: YYYY-MM-DD HH:MM |
| 253 | 3: YYMMDD HH:MM */ |
| 254 | |
| 255 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 256 | vid = db_lget_int("checkout", 0); |
| 257 | } |
| 258 | zPrevDate[0] = 0; |
| 259 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 260 | dateFormat = db_get_int("timeline-date-format", 0); |
| 261 | if( tmFlags & TIMELINE_GRAPH ){ |
| 262 | pGraph = graph_init(); |
| 263 | /* style is not moved to css, because this is |
| 264 | ** a technical div for the timeline graph |
| 265 | */ |
| @@ -282,11 +286,11 @@ | |
| 286 | int tagid = db_column_int(pQuery, 9); |
| 287 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 288 | const char *zBr = 0; /* Branch */ |
| 289 | int commentColumn = 3; /* Column containing comment text */ |
| 290 | int modPending; /* Pending moderation */ |
| 291 | char zTime[20]; |
| 292 | |
| 293 | modPending = moderation_pending(rid); |
| 294 | if( tagid ){ |
| 295 | if( modPending ) tagid = -tagid; |
| 296 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | |
| 318 | } |
| 319 | prevWasDivider = 1; |
| 320 | continue; |
| 321 | } |
| 322 | prevWasDivider = 0; |
| 323 | if( dateFormat<2 ){ |
| 324 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 325 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 326 | @ <tr><td> |
| 327 | @ <div class="divider timelineDate">%s(zPrevDate)</div> |
| 328 | @ </td><td></td><td></td></tr> |
| 329 | } |
| 330 | memcpy(zTime, &zDate[11], 5+dateFormat*3); |
| 331 | zTime[5+dateFormat*3] = 0; |
| 332 | }else if(3==dateFormat){ |
| 333 | /* YYMMDD HH:MM */ |
| 334 | int pos = 0; |
| 335 | zTime[pos++] = zDate[2]; zTime[pos++] = zDate[3]; /* YY */ |
| 336 | zTime[pos++] = zDate[5]; zTime[pos++] = zDate[6]; /* MM */ |
| 337 | zTime[pos++] = zDate[8]; zTime[pos++] = zDate[9]; /* DD */ |
| 338 | zTime[pos++] = ' '; |
| 339 | zTime[pos++] = zDate[11]; zTime[pos++] = zDate[12]; /* HH */ |
| 340 | zTime[pos++] = ':'; |
| 341 | zTime[pos++] = zDate[14]; zTime[pos++] = zDate[15]; /* MM */ |
| 342 | zTime[pos++] = 0; |
| 343 | }else{ |
| 344 | /* YYYY-MM-DD HH:MM */ |
| 345 | sqlite3_snprintf(sizeof(zTime), zTime, "%.16s", zDate); |
| 346 | } |
| 347 | if( rid == vid ){ |
| 348 | @ <tr class="timelineCurrent"> |
| 349 | }else { |
| 350 | @ <tr> |
| 351 | } |
| @@ -2115,14 +2135,15 @@ | |
| 2135 | } |
| 2136 | db_reset(&query); |
| 2137 | while( SQLITE_ROW == db_step(&query) ){ |
| 2138 | const char * zTimeframe = db_column_text(&query, 0); |
| 2139 | const int nCount = db_column_int(&query, 1); |
| 2140 | int nSize = nCount |
| 2141 | ? (int)(100 * nCount / nMaxEvents) |
| 2142 | : 1; |
| 2143 | showYearTotal = 0; |
| 2144 | if(!nSize) nSize = 1; |
| 2145 | if(includeMonth){ |
| 2146 | /* For Month/year view, add a separator for each distinct year. */ |
| 2147 | if(!*zPrevYear || |
| 2148 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2149 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | |
| 2270 | } |
| 2271 | db_reset(&query); |
| 2272 | while( SQLITE_ROW == db_step(&query) ){ |
| 2273 | const char * zUser = db_column_text(&query, 0); |
| 2274 | const int nCount = db_column_int(&query, 1); |
| 2275 | int nSize = nCount |
| 2276 | ? (int)(100 * nCount / nMaxEvents) |
| 2277 | : 0; |
| 2278 | if(!nCount) continue /* arguable! Possible? */; |
| 2279 | else if(!nSize) nSize = 1; |
| 2280 | rowClass = ++nRowNumber % 2; |
| 2281 | nEventTotal += nCount; |
| 2282 | @<tr class='row%d(rowClass)'> |
| 2283 | @ <td> |
| 2284 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | |
| 2387 | } |
| 2388 | db_reset(&stWeek); |
| 2389 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2390 | const char * zWeek = db_column_text(&stWeek,0); |
| 2391 | const int nCount = db_column_int(&stWeek,1); |
| 2392 | int nSize = nCount |
| 2393 | ? (int)(100 * nCount / nMaxEvents) |
| 2394 | : 0; |
| 2395 | if(!nSize) nSize = 1; |
| 2396 | total += nCount; |
| 2397 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2398 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2399 | g.zTop, zYear, zWeek, nCount, |
| 2400 | statsReportTimelineYFlag); |
| 2401 |
+35
-12
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -246,16 +246,20 @@ | ||
| 246 | 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | 248 | static Stmt qbranch; |
| 249 | 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | 250 | int vid = 0; /* Current checkout version */ |
| 251 | + int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS | |
| 252 | + 2: YYYY-MM-DD HH:MM | |
| 253 | + 3: YYMMDD HH:MM */ | |
| 251 | 254 | |
| 252 | 255 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 253 | 256 | vid = db_lget_int("checkout", 0); |
| 254 | 257 | } |
| 255 | 258 | zPrevDate[0] = 0; |
| 256 | 259 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 260 | + dateFormat = db_get_int("timeline-date-format", 0); | |
| 257 | 261 | if( tmFlags & TIMELINE_GRAPH ){ |
| 258 | 262 | pGraph = graph_init(); |
| 259 | 263 | /* style is not moved to css, because this is |
| 260 | 264 | ** a technical div for the timeline graph |
| 261 | 265 | */ |
| @@ -282,11 +286,11 @@ | ||
| 282 | 286 | int tagid = db_column_int(pQuery, 9); |
| 283 | 287 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 284 | 288 | const char *zBr = 0; /* Branch */ |
| 285 | 289 | int commentColumn = 3; /* Column containing comment text */ |
| 286 | 290 | int modPending; /* Pending moderation */ |
| 287 | - char zTime[8]; | |
| 291 | + char zTime[20]; | |
| 288 | 292 | |
| 289 | 293 | modPending = moderation_pending(rid); |
| 290 | 294 | if( tagid ){ |
| 291 | 295 | if( modPending ) tagid = -tagid; |
| 292 | 296 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | ||
| 314 | 318 | } |
| 315 | 319 | prevWasDivider = 1; |
| 316 | 320 | continue; |
| 317 | 321 | } |
| 318 | 322 | prevWasDivider = 0; |
| 319 | - if( memcmp(zDate, zPrevDate, 10) ){ | |
| 320 | - sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); | |
| 321 | - @ <tr><td> | |
| 322 | - @ <div class="divider">%s(zPrevDate)</div> | |
| 323 | - @ </td><td></td><td></td></tr> | |
| 324 | - } | |
| 325 | - memcpy(zTime, &zDate[11], 5); | |
| 326 | - zTime[5] = 0; | |
| 323 | + if( dateFormat<2 ){ | |
| 324 | + if( memcmp(zDate, zPrevDate, 10) ){ | |
| 325 | + sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); | |
| 326 | + @ <tr><td> | |
| 327 | + @ <div class="divider timelineDate">%s(zPrevDate)</div> | |
| 328 | + @ </td><td></td><td></td></tr> | |
| 329 | + } | |
| 330 | + memcpy(zTime, &zDate[11], 5+dateFormat*3); | |
| 331 | + zTime[5+dateFormat*3] = 0; | |
| 332 | + }else if(3==dateFormat){ | |
| 333 | + /* YYMMDD HH:MM */ | |
| 334 | + int pos = 0; | |
| 335 | + zTime[pos++] = zDate[2]; zTime[pos++] = zDate[3]; /* YY */ | |
| 336 | + zTime[pos++] = zDate[5]; zTime[pos++] = zDate[6]; /* MM */ | |
| 337 | + zTime[pos++] = zDate[8]; zTime[pos++] = zDate[9]; /* DD */ | |
| 338 | + zTime[pos++] = ' '; | |
| 339 | + zTime[pos++] = zDate[11]; zTime[pos++] = zDate[12]; /* HH */ | |
| 340 | + zTime[pos++] = ':'; | |
| 341 | + zTime[pos++] = zDate[14]; zTime[pos++] = zDate[15]; /* MM */ | |
| 342 | + zTime[pos++] = 0; | |
| 343 | + }else{ | |
| 344 | + /* YYYY-MM-DD HH:MM */ | |
| 345 | + sqlite3_snprintf(sizeof(zTime), zTime, "%.16s", zDate); | |
| 346 | + } | |
| 327 | 347 | if( rid == vid ){ |
| 328 | 348 | @ <tr class="timelineCurrent"> |
| 329 | 349 | }else { |
| 330 | 350 | @ <tr> |
| 331 | 351 | } |
| @@ -2115,14 +2135,15 @@ | ||
| 2115 | 2135 | } |
| 2116 | 2136 | db_reset(&query); |
| 2117 | 2137 | while( SQLITE_ROW == db_step(&query) ){ |
| 2118 | 2138 | const char * zTimeframe = db_column_text(&query, 0); |
| 2119 | 2139 | const int nCount = db_column_int(&query, 1); |
| 2120 | - const int nSize = nCount | |
| 2140 | + int nSize = nCount | |
| 2121 | 2141 | ? (int)(100 * nCount / nMaxEvents) |
| 2122 | 2142 | : 1; |
| 2123 | 2143 | showYearTotal = 0; |
| 2144 | + if(!nSize) nSize = 1; | |
| 2124 | 2145 | if(includeMonth){ |
| 2125 | 2146 | /* For Month/year view, add a separator for each distinct year. */ |
| 2126 | 2147 | if(!*zPrevYear || |
| 2127 | 2148 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2128 | 2149 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | ||
| 2249 | 2270 | } |
| 2250 | 2271 | db_reset(&query); |
| 2251 | 2272 | while( SQLITE_ROW == db_step(&query) ){ |
| 2252 | 2273 | const char * zUser = db_column_text(&query, 0); |
| 2253 | 2274 | const int nCount = db_column_int(&query, 1); |
| 2254 | - const int nSize = nCount | |
| 2275 | + int nSize = nCount | |
| 2255 | 2276 | ? (int)(100 * nCount / nMaxEvents) |
| 2256 | 2277 | : 0; |
| 2257 | 2278 | if(!nCount) continue /* arguable! Possible? */; |
| 2279 | + else if(!nSize) nSize = 1; | |
| 2258 | 2280 | rowClass = ++nRowNumber % 2; |
| 2259 | 2281 | nEventTotal += nCount; |
| 2260 | 2282 | @<tr class='row%d(rowClass)'> |
| 2261 | 2283 | @ <td> |
| 2262 | 2284 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | ||
| 2365 | 2387 | } |
| 2366 | 2388 | db_reset(&stWeek); |
| 2367 | 2389 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2368 | 2390 | const char * zWeek = db_column_text(&stWeek,0); |
| 2369 | 2391 | const int nCount = db_column_int(&stWeek,1); |
| 2370 | - const int nSize = nCount | |
| 2392 | + int nSize = nCount | |
| 2371 | 2393 | ? (int)(100 * nCount / nMaxEvents) |
| 2372 | 2394 | : 0; |
| 2395 | + if(!nSize) nSize = 1; | |
| 2373 | 2396 | total += nCount; |
| 2374 | 2397 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2375 | 2398 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2376 | 2399 | g.zTop, zYear, zWeek, nCount, |
| 2377 | 2400 | statsReportTimelineYFlag); |
| 2378 | 2401 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -246,16 +246,20 @@ | |
| 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | static Stmt qbranch; |
| 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | int vid = 0; /* Current checkout version */ |
| 251 | |
| 252 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 253 | vid = db_lget_int("checkout", 0); |
| 254 | } |
| 255 | zPrevDate[0] = 0; |
| 256 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 257 | if( tmFlags & TIMELINE_GRAPH ){ |
| 258 | pGraph = graph_init(); |
| 259 | /* style is not moved to css, because this is |
| 260 | ** a technical div for the timeline graph |
| 261 | */ |
| @@ -282,11 +286,11 @@ | |
| 282 | int tagid = db_column_int(pQuery, 9); |
| 283 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 284 | const char *zBr = 0; /* Branch */ |
| 285 | int commentColumn = 3; /* Column containing comment text */ |
| 286 | int modPending; /* Pending moderation */ |
| 287 | char zTime[8]; |
| 288 | |
| 289 | modPending = moderation_pending(rid); |
| 290 | if( tagid ){ |
| 291 | if( modPending ) tagid = -tagid; |
| 292 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | |
| 314 | } |
| 315 | prevWasDivider = 1; |
| 316 | continue; |
| 317 | } |
| 318 | prevWasDivider = 0; |
| 319 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 320 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 321 | @ <tr><td> |
| 322 | @ <div class="divider">%s(zPrevDate)</div> |
| 323 | @ </td><td></td><td></td></tr> |
| 324 | } |
| 325 | memcpy(zTime, &zDate[11], 5); |
| 326 | zTime[5] = 0; |
| 327 | if( rid == vid ){ |
| 328 | @ <tr class="timelineCurrent"> |
| 329 | }else { |
| 330 | @ <tr> |
| 331 | } |
| @@ -2115,14 +2135,15 @@ | |
| 2115 | } |
| 2116 | db_reset(&query); |
| 2117 | while( SQLITE_ROW == db_step(&query) ){ |
| 2118 | const char * zTimeframe = db_column_text(&query, 0); |
| 2119 | const int nCount = db_column_int(&query, 1); |
| 2120 | const int nSize = nCount |
| 2121 | ? (int)(100 * nCount / nMaxEvents) |
| 2122 | : 1; |
| 2123 | showYearTotal = 0; |
| 2124 | if(includeMonth){ |
| 2125 | /* For Month/year view, add a separator for each distinct year. */ |
| 2126 | if(!*zPrevYear || |
| 2127 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2128 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | |
| 2249 | } |
| 2250 | db_reset(&query); |
| 2251 | while( SQLITE_ROW == db_step(&query) ){ |
| 2252 | const char * zUser = db_column_text(&query, 0); |
| 2253 | const int nCount = db_column_int(&query, 1); |
| 2254 | const int nSize = nCount |
| 2255 | ? (int)(100 * nCount / nMaxEvents) |
| 2256 | : 0; |
| 2257 | if(!nCount) continue /* arguable! Possible? */; |
| 2258 | rowClass = ++nRowNumber % 2; |
| 2259 | nEventTotal += nCount; |
| 2260 | @<tr class='row%d(rowClass)'> |
| 2261 | @ <td> |
| 2262 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | |
| 2365 | } |
| 2366 | db_reset(&stWeek); |
| 2367 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2368 | const char * zWeek = db_column_text(&stWeek,0); |
| 2369 | const int nCount = db_column_int(&stWeek,1); |
| 2370 | const int nSize = nCount |
| 2371 | ? (int)(100 * nCount / nMaxEvents) |
| 2372 | : 0; |
| 2373 | total += nCount; |
| 2374 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2375 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2376 | g.zTop, zYear, zWeek, nCount, |
| 2377 | statsReportTimelineYFlag); |
| 2378 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -246,16 +246,20 @@ | |
| 246 | int fchngQueryInit = 0; /* True if fchngQuery is initialized */ |
| 247 | Stmt fchngQuery; /* Query for file changes on check-ins */ |
| 248 | static Stmt qbranch; |
| 249 | int pendingEndTr = 0; /* True if a </td></tr> is needed */ |
| 250 | int vid = 0; /* Current checkout version */ |
| 251 | int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS |
| 252 | 2: YYYY-MM-DD HH:MM |
| 253 | 3: YYMMDD HH:MM */ |
| 254 | |
| 255 | if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){ |
| 256 | vid = db_lget_int("checkout", 0); |
| 257 | } |
| 258 | zPrevDate[0] = 0; |
| 259 | mxWikiLen = db_get_int("timeline-max-comment", 0); |
| 260 | dateFormat = db_get_int("timeline-date-format", 0); |
| 261 | if( tmFlags & TIMELINE_GRAPH ){ |
| 262 | pGraph = graph_init(); |
| 263 | /* style is not moved to css, because this is |
| 264 | ** a technical div for the timeline graph |
| 265 | */ |
| @@ -282,11 +286,11 @@ | |
| 286 | int tagid = db_column_int(pQuery, 9); |
| 287 | const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; |
| 288 | const char *zBr = 0; /* Branch */ |
| 289 | int commentColumn = 3; /* Column containing comment text */ |
| 290 | int modPending; /* Pending moderation */ |
| 291 | char zTime[20]; |
| 292 | |
| 293 | modPending = moderation_pending(rid); |
| 294 | if( tagid ){ |
| 295 | if( modPending ) tagid = -tagid; |
| 296 | if( tagid==prevTagid ){ |
| @@ -314,18 +318,34 @@ | |
| 318 | } |
| 319 | prevWasDivider = 1; |
| 320 | continue; |
| 321 | } |
| 322 | prevWasDivider = 0; |
| 323 | if( dateFormat<2 ){ |
| 324 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 325 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 326 | @ <tr><td> |
| 327 | @ <div class="divider timelineDate">%s(zPrevDate)</div> |
| 328 | @ </td><td></td><td></td></tr> |
| 329 | } |
| 330 | memcpy(zTime, &zDate[11], 5+dateFormat*3); |
| 331 | zTime[5+dateFormat*3] = 0; |
| 332 | }else if(3==dateFormat){ |
| 333 | /* YYMMDD HH:MM */ |
| 334 | int pos = 0; |
| 335 | zTime[pos++] = zDate[2]; zTime[pos++] = zDate[3]; /* YY */ |
| 336 | zTime[pos++] = zDate[5]; zTime[pos++] = zDate[6]; /* MM */ |
| 337 | zTime[pos++] = zDate[8]; zTime[pos++] = zDate[9]; /* DD */ |
| 338 | zTime[pos++] = ' '; |
| 339 | zTime[pos++] = zDate[11]; zTime[pos++] = zDate[12]; /* HH */ |
| 340 | zTime[pos++] = ':'; |
| 341 | zTime[pos++] = zDate[14]; zTime[pos++] = zDate[15]; /* MM */ |
| 342 | zTime[pos++] = 0; |
| 343 | }else{ |
| 344 | /* YYYY-MM-DD HH:MM */ |
| 345 | sqlite3_snprintf(sizeof(zTime), zTime, "%.16s", zDate); |
| 346 | } |
| 347 | if( rid == vid ){ |
| 348 | @ <tr class="timelineCurrent"> |
| 349 | }else { |
| 350 | @ <tr> |
| 351 | } |
| @@ -2115,14 +2135,15 @@ | |
| 2135 | } |
| 2136 | db_reset(&query); |
| 2137 | while( SQLITE_ROW == db_step(&query) ){ |
| 2138 | const char * zTimeframe = db_column_text(&query, 0); |
| 2139 | const int nCount = db_column_int(&query, 1); |
| 2140 | int nSize = nCount |
| 2141 | ? (int)(100 * nCount / nMaxEvents) |
| 2142 | : 1; |
| 2143 | showYearTotal = 0; |
| 2144 | if(!nSize) nSize = 1; |
| 2145 | if(includeMonth){ |
| 2146 | /* For Month/year view, add a separator for each distinct year. */ |
| 2147 | if(!*zPrevYear || |
| 2148 | (0!=fossil_strncmp(zPrevYear,zTimeframe,4))){ |
| 2149 | showYearTotal = *zPrevYear; |
| @@ -2249,14 +2270,15 @@ | |
| 2270 | } |
| 2271 | db_reset(&query); |
| 2272 | while( SQLITE_ROW == db_step(&query) ){ |
| 2273 | const char * zUser = db_column_text(&query, 0); |
| 2274 | const int nCount = db_column_int(&query, 1); |
| 2275 | int nSize = nCount |
| 2276 | ? (int)(100 * nCount / nMaxEvents) |
| 2277 | : 0; |
| 2278 | if(!nCount) continue /* arguable! Possible? */; |
| 2279 | else if(!nSize) nSize = 1; |
| 2280 | rowClass = ++nRowNumber % 2; |
| 2281 | nEventTotal += nCount; |
| 2282 | @<tr class='row%d(rowClass)'> |
| 2283 | @ <td> |
| 2284 | @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a> |
| @@ -2365,13 +2387,14 @@ | |
| 2387 | } |
| 2388 | db_reset(&stWeek); |
| 2389 | while( SQLITE_ROW == db_step(&stWeek) ){ |
| 2390 | const char * zWeek = db_column_text(&stWeek,0); |
| 2391 | const int nCount = db_column_int(&stWeek,1); |
| 2392 | int nSize = nCount |
| 2393 | ? (int)(100 * nCount / nMaxEvents) |
| 2394 | : 0; |
| 2395 | if(!nSize) nSize = 1; |
| 2396 | total += nCount; |
| 2397 | cgi_printf("<tr class='row%d'>", ++rowCount % 2 ); |
| 2398 | cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s", |
| 2399 | g.zTop, zYear, zWeek, nCount, |
| 2400 | statsReportTimelineYFlag); |
| 2401 |