Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Further enhancements to the file browsing UX. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
cd05cb20dbfc54939ea6b29b8b036826 |
| User & Date: | drh 2020-05-11 19:24:08.772 |
Context
|
2020-05-11
| ||
| 19:24 | Fix a compiler warning in the previous check-in. ... (check-in: e07b10919b user: drh tags: trunk) | |
| 19:24 | Further enhancements to the file browsing UX. ... (check-in: cd05cb20db user: drh tags: trunk) | |
| 18:12 | Continuing UX improvements on the /file, /artifact, and /whatis pages. More needs to be done. ... (check-in: 1b5d0b0e18 user: drh tags: trunk) | |
Changes
Changes to src/browse.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
sqlite3_result_text(context, (char*)&z[n], len-n, SQLITE_TRANSIENT);
}else{
zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
}
}
/*
** Given a pathname which is a relative path from the root of
** the repository to a file or directory, compute a string which
** is an HTML rendering of that path with hyperlinks on each
** directory component of the path where the hyperlink redirects
** to the "dir" page for the directory.
**
** There is no hyperlink on the file element of the path.
**
** The computed string is appended to the pOut blob. pOut should
** have already been initialized.
*/
void hyperlinked_path(
const char *zPath, /* Path to render */
Blob *pOut, /* Write into this blob */
const char *zCI, /* check-in name, or NULL */
const char *zURI, /* "dir" or "tree" */
| > > > > > > > > | > | > > > > > > > > > | | | | | | | | < < < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
sqlite3_result_text(context, (char*)&z[n], len-n, SQLITE_TRANSIENT);
}else{
zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
}
}
/*
** Flag arguments for hyperlinked_path()
*/
#if INTERFACE
# define LINKPATH_FINFO 0x0001 /* Link final term to /finfo */
# define LINKPATH_FILE 0x0002 /* Link final term to /file */
#endif
/*
** Given a pathname which is a relative path from the root of
** the repository to a file or directory, compute a string which
** is an HTML rendering of that path with hyperlinks on each
** directory component of the path where the hyperlink redirects
** to the "dir" page for the directory.
**
** There is no hyperlink on the file element of the path.
**
** The computed string is appended to the pOut blob. pOut should
** have already been initialized.
*/
void hyperlinked_path(
const char *zPath, /* Path to render */
Blob *pOut, /* Write into this blob */
const char *zCI, /* check-in name, or NULL */
const char *zURI, /* "dir" or "tree" */
const char *zREx, /* Extra query parameters */
unsigned int mFlags /* Extra flags */
){
int i, j;
char *zSep = "";
for(i=0; zPath[i]; i=j){
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
if( zPath[j]==0 ){
if( mFlags & LINKPATH_FILE ){
zURI = "file";
}else if( mFlags & LINKPATH_FINFO ){
zURI = "finfo";
}else{
blob_appendf(pOut, "/%h", zPath+i);
break;
}
}
if( zCI ){
char *zLink = href("%R/%s?name=%#T%s&ci=%!S", zURI, j, zPath, zREx,zCI);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}else{
char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}
zSep = "/";
while( zPath[j]=='/' ){ j++; }
}
}
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
url_initialize(&sURI, "dir");
cgi_query_parameters_to_url(&sURI);
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
blob_append(&dirname, "in directory ", -1);
| | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
url_initialize(&sURI, "dir");
cgi_query_parameters_to_url(&sURI);
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
blob_append(&dirname, "in directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "dir", "", 0);
zPrefix = mprintf("%s/", zD);
style_submenu_element("Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
blob_append(&dirname, "in the top-level directory", -1);
zPrefix = "";
}
|
| ︙ | ︙ | |||
700 701 702 703 704 705 706 |
style_header("%s", zHeader);
fossil_free(zHeader);
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
blob_append(&dirname, "within directory ", -1);
| | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
style_header("%s", zHeader);
fossil_free(zHeader);
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
blob_append(&dirname, "within directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "tree", zREx, 0);
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
style_submenu_element("Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
if( zRE ){
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
436 437 438 439 440 441 442 |
if( origCheckin ){
blob_appendf(&title, "Changes to file ");
}else if( n>0 ){
blob_appendf(&title, "First %d ancestors of file ", n);
}else{
blob_appendf(&title, "Ancestors of file ");
}
| | > | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
if( origCheckin ){
blob_appendf(&title, "Changes to file ");
}else if( n>0 ){
blob_appendf(&title, "First %d ancestors of file ", n);
}else{
blob_appendf(&title, "Ancestors of file ");
}
blob_appendf(&title,"%z%h</a>",
href("%R/file?name=%T&ci=%!S", zFilename, zUuid),
zFilename);
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
blob_append(&title, origCheckin ? " between " : " from ", -1);
blob_appendf(&title, "check-in %z%S</a>", zLink, zUuid);
if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
fossil_free(zUuid);
if( origCheckin ){
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", origCheckin);
zLink = href("%R/info/%!S", zUuid);
blob_appendf(&title, " and check-in %z%S</a>", zLink, zUuid);
fossil_free(zUuid);
}
}else{
blob_appendf(&title, "History for ");
hyperlinked_path(zFilename, &title, 0, "tree", "", LINKPATH_FILE);
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
}
if( uBg ){
blob_append(&title, " (color-coded by user)", -1);
}
@ <h2>%b(&title)</h2>
blob_reset(&title);
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 | ** ** The /artifact page show the complete content of a file ** identified by HASH. The /whatis page shows only a description ** of how the artifact is used. The /file page shows the most recent ** version of the file or directory called NAME, or a list of the ** top-level directory if NAME is omitted. ** | | | | | > | < | | | 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 |
**
** The /artifact page show the complete content of a file
** identified by HASH. The /whatis page shows only a description
** of how the artifact is used. The /file page shows the most recent
** version of the file or directory called NAME, or a list of the
** top-level directory if NAME is omitted.
**
** For /artifact and /whatis, the name= query parameter can refer to
** either the name of a file, or an artifact hash. If the ci= query
** parameter is also present, then name= must refer to a file name.
** If ci= is omitted, then the hash interpretation is preferred but
** if name= cannot be understood as a hash, a default "tip" value is
** used for ci=.
**
** For /file, name= can only be interpreted as a filename. As before,
** a default value of "tip" is used for ci= if ci= is omitted.
*/
void artifact_page(void){
int rid = 0;
Blob content;
const char *zMime;
Blob downloadName;
int renderAsWiki = 0;
|
| ︙ | ︙ | |||
2187 2188 2189 2190 2191 2192 2193 |
** For /file, a name= without a ci= while prefer to use the default
** "tip" value for ci=. */
rid = name_to_rid(zName);
}
if( rid==0 ){
rid = artifact_from_ci_and_filename(0);
}
| < < < < | > | | | | | | | | | | | | | | < | < > > | | > > | > | > | > > > > > > < | | | | > > | 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 |
** For /file, a name= without a ci= while prefer to use the default
** "tip" value for ci=. */
rid = name_to_rid(zName);
}
if( rid==0 ){
rid = artifact_from_ci_and_filename(0);
}
if( rid==0 ){ /* Artifact not found */
if( isFile ){
/* For /file, also check to see if name= refers to a directory,
** and if so, do a listing for that directory */
int nName = (int)strlen(zName);
if( nName && zName[nName-1]=='/' ) nName--;
if( db_exists(
"SELECT 1 FROM filename"
" WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
nName, zName, nName+1, nName, zName
) ){
if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
page_tree();
return;
}
style_header("No such file");
@ File '%h(zName)' does not exist in this repository.
}else{
style_header("No such artifact");
@ Artifact '%h(zName)' does not exist in this repository.
}
style_footer();
return;
}
if( descOnly || P("verbose")!=0 ){
url_add_parameter(&url, "verbose", "1");
objdescFlags |= OBJDESC_DETAIL;
}
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( isFile ){
if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
zCI = "tip";
@ <h2>Latest version of file \
@ '%z(href("/finfo?name=%T&m=%T",zName,zCI))%h(zName)</a>':</h2>
}else{
const char *zPath;
Blob path;
blob_zero(&path);
hyperlinked_path(zName, &path, zCI, "dir", "", LINKPATH_FINFO);
zPath = blob_str(&path);
@ <h2>File %s(zPath) \
if( isBranchCI ){
@ on branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2>
}else if( isSymbolicCI ){
@ as of check-in %z(href("/info/%!S",zCIUuid))%s(zCI)</a></h2>
}else{
@ as of check-in [%z(href("/info/%!S",zCIUuid))%S(zCIUuid)</a>]</h2>
}
blob_reset(&path);
}
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
style_submenu_element("Annotate", "%R/annotate?filename=%T&ci=%T",
zName, zCI);
style_submenu_element("Blame", "%R/blame?filename=%T&ci=%T",
zName, zCI);
blob_init(&downloadName, zName, -1);
objType = OBJTYPE_CONTENT;
}else{
@ <h2>Artifact
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
if( g.perm.Setup ){
@ (%d(rid)):</h2>
}else{
@ :</h2>
}
blob_zero(&downloadName);
asText = P("txt")!=0;
if( asText ) objdescFlags &= ~OBJDESC_BASE;
objType = object_description(rid, objdescFlags,
(isFile?zName:0), &downloadName);
}
if( !descOnly && P("download")!=0 ){
cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName),
db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
/*NOTREACHED*/
}
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
|
| ︙ | ︙ | |||
2284 2285 2286 2287 2288 2289 2290 |
zHeader = mprintf("Artifact Description [%S]", zUuid);
}else{
zHeader = mprintf("Artifact [%S]", zUuid);
}
style_header("%s", zHeader);
fossil_free(zCIUuid);
fossil_free(zHeader);
| | | 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 |
zHeader = mprintf("Artifact Description [%S]", zUuid);
}else{
zHeader = mprintf("Artifact [%S]", zUuid);
}
style_header("%s", zHeader);
fossil_free(zCIUuid);
fossil_free(zHeader);
if( !isFile && g.perm.Admin ){
Stmt q;
db_prepare(&q,
"SELECT coalesce(user.login,rcvfrom.uid),"
" datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr"
" FROM blob, rcvfrom LEFT JOIN user ON user.uid=rcvfrom.uid"
" WHERE blob.rid=%d"
" AND rcvfrom.rcvid=blob.rcvid;", rid);
|
| ︙ | ︙ |