Fossil SCM
Add hyperlinks to the tree-view for file listings. Other improvements to the tree-view mechanism.
Commit
4564790ed7bcda5013725d4d1136e4fbc2372500
Parent
7791b704109adb8…
2 files changed
+75
-55
+2
-2
+75
-55
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -71,23 +71,29 @@ | ||
| 71 | 71 | ** There is no hyperlink on the file element of the path. |
| 72 | 72 | ** |
| 73 | 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | 74 | ** have already been initialized. |
| 75 | 75 | */ |
| 76 | -void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ | |
| 76 | +void hyperlinked_path( | |
| 77 | + const char *zPath, /* Path to render */ | |
| 78 | + Blob *pOut, /* Write into this blob */ | |
| 79 | + const char *zCI, /* check-in name, or NULL */ | |
| 80 | + const char *zURI, /* "dir" or "tree" */ | |
| 81 | + const char *zREx /* Extra query parameters */ | |
| 82 | +){ | |
| 77 | 83 | int i, j; |
| 78 | 84 | char *zSep = ""; |
| 79 | 85 | |
| 80 | 86 | for(i=0; zPath[i]; i=j){ |
| 81 | 87 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 82 | 88 | if( zPath[j] && g.perm.Hyperlink ){ |
| 83 | 89 | if( zCI ){ |
| 84 | - char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); | |
| 90 | + char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx); | |
| 85 | 91 | blob_appendf(pOut, "%s%z%#h</a>", |
| 86 | 92 | zSep, zLink, j-i, &zPath[i]); |
| 87 | 93 | }else{ |
| 88 | - char *zLink = href("%R/dir?name=%#T", j, zPath); | |
| 94 | + char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); | |
| 89 | 95 | blob_appendf(pOut, "%s%z%#h</a>", |
| 90 | 96 | zSep, zLink, j-i, &zPath[i]); |
| 91 | 97 | } |
| 92 | 98 | }else{ |
| 93 | 99 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -118,18 +124,22 @@ | ||
| 118 | 124 | int rid = 0; |
| 119 | 125 | char *zUuid = 0; |
| 120 | 126 | Blob dirname; |
| 121 | 127 | Manifest *pM = 0; |
| 122 | 128 | const char *zSubdirLink; |
| 123 | - int linkTrunk = 1, linkTip = 1; | |
| 129 | + int linkTrunk = 1; | |
| 130 | + int linkTip = 1; | |
| 131 | + HQuery sURI; | |
| 124 | 132 | |
| 133 | + if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; } | |
| 125 | 134 | login_check_credentials(); |
| 126 | 135 | if( !g.perm.Read ){ login_needed(); return; } |
| 127 | 136 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 128 | 137 | style_header("File List"); |
| 129 | 138 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 130 | 139 | pathelementFunc, 0, 0); |
| 140 | + url_initialize(&sURI, "dir"); | |
| 131 | 141 | |
| 132 | 142 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 133 | 143 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 134 | 144 | |
| 135 | 145 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | ||
| 141 | 151 | if( pM ){ |
| 142 | 152 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 143 | 153 | linkTrunk = trunkRid && rid != trunkRid; |
| 144 | 154 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 145 | 155 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 156 | + url_add_parameter(&sURI, "ci", zCI); | |
| 146 | 157 | }else{ |
| 147 | 158 | zCI = 0; |
| 148 | 159 | } |
| 149 | 160 | } |
| 150 | 161 | |
| 151 | 162 | /* Compute the title of the page */ |
| 152 | 163 | blob_zero(&dirname); |
| 153 | 164 | if( zD ){ |
| 165 | + url_add_parameter(&sURI, "name", zD); | |
| 154 | 166 | blob_append(&dirname, "in directory ", -1); |
| 155 | - hyperlinked_path(zD, &dirname, zCI); | |
| 167 | + hyperlinked_path(zD, &dirname, zCI, "dir", ""); | |
| 156 | 168 | zPrefix = mprintf("%s/", zD); |
| 157 | - if( linkTrunk ){ | |
| 158 | - style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", | |
| 159 | - zD); | |
| 160 | - } | |
| 161 | - if( linkTip ){ | |
| 162 | - style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); | |
| 163 | - } | |
| 169 | + style_submenu_element("Top", "Top", "%s", | |
| 170 | + url_render(&sURI, "name", 0, 0, 0)); | |
| 164 | 171 | }else{ |
| 165 | 172 | blob_append(&dirname, "in the top-level directory", -1); |
| 166 | 173 | zPrefix = ""; |
| 167 | - if( linkTrunk ){ | |
| 168 | - style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); | |
| 169 | - } | |
| 170 | - if( linkTip ){ | |
| 171 | - style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); | |
| 172 | - } | |
| 174 | + } | |
| 175 | + if( linkTrunk ){ | |
| 176 | + style_submenu_element("Trunk", "Trunk", "%s", | |
| 177 | + url_render(&sURI, "ci", "trunk", 0, 0)); | |
| 178 | + } | |
| 179 | + if( linkTip ){ | |
| 180 | + style_submenu_element("Tip", "Tip", "%s", | |
| 181 | + url_render(&sURI, "ci", "tip", 0, 0)); | |
| 173 | 182 | } |
| 174 | 183 | if( zCI ){ |
| 175 | 184 | char zShort[20]; |
| 176 | 185 | memcpy(zShort, zUuid, 10); |
| 177 | 186 | zShort[10] = 0; |
| 178 | 187 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 179 | 188 | @ %s(blob_str(&dirname))</h2> |
| 180 | 189 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 181 | - if( zD ){ | |
| 182 | - style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); | |
| 183 | - style_submenu_element("All", "All", "%R/dir?name=%t", zD); | |
| 184 | - }else{ | |
| 185 | - style_submenu_element("All", "All", "%R/dir"); | |
| 190 | + if( nD==0 ){ | |
| 186 | 191 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 187 | 192 | zUuid); |
| 188 | 193 | } |
| 189 | 194 | }else{ |
| 190 | 195 | @ <h2>The union of all files from all check-ins |
| 191 | 196 | @ %s(blob_str(&dirname))</h2> |
| 192 | 197 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 193 | 198 | } |
| 199 | + style_submenu_element("All", "All", "%s", | |
| 200 | + url_render(&sURI, "ci", 0, 0, 0)); | |
| 201 | + style_submenu_element("Tree-View", "Tree-View", "%s", | |
| 202 | + url_render(&sURI, "type", "tree", 0, 0)); | |
| 194 | 203 | |
| 195 | 204 | /* Compute the temporary table "localfiles" containing the names |
| 196 | 205 | ** of all files and subdirectories in the zD[] directory. |
| 197 | 206 | ** |
| 198 | 207 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -409,27 +418,37 @@ | ||
| 409 | 418 | const char *zCI = P("ci"); |
| 410 | 419 | int rid = 0; |
| 411 | 420 | char *zUuid = 0; |
| 412 | 421 | Blob dirname; |
| 413 | 422 | Manifest *pM = 0; |
| 414 | - int linkTrunk = 1, linkTip = 1; | |
| 415 | - const char *zRE; | |
| 416 | - ReCompiled *pRE = 0; | |
| 417 | - FileTreeNode *p; | |
| 418 | - FileTree sTree; | |
| 423 | + int linkTrunk = 1; /* include link to "trunk" */ | |
| 424 | + int linkTip = 1; /* include link to "tip" */ | |
| 425 | + const char *zRE; /* the value for the re=REGEXP query parameter */ | |
| 426 | + char *zPrefix; /* Prefix on all filenames */ | |
| 427 | + char *zREx = ""; /* Extra parameters for path hyperlinks */ | |
| 428 | + ReCompiled *pRE = 0; /* Compiled regular expression */ | |
| 429 | + FileTreeNode *p; /* One line of the tree */ | |
| 430 | + FileTree sTree; /* The complete tree of files */ | |
| 431 | + HQuery sURI; /* Hyperlink */ | |
| 419 | 432 | |
| 433 | + if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } | |
| 420 | 434 | memset(&sTree, 0, sizeof(sTree)); |
| 421 | 435 | login_check_credentials(); |
| 422 | 436 | if( !g.perm.Read ){ login_needed(); return; } |
| 423 | 437 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 424 | 438 | style_header("File List"); |
| 425 | 439 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 426 | 440 | pathelementFunc, 0, 0); |
| 441 | + url_initialize(&sURI, "tree"); | |
| 427 | 442 | |
| 428 | 443 | /* If a regular expression is specified, compile it */ |
| 429 | 444 | zRE = P("re"); |
| 430 | - if( zRE ) re_compile(&pRE, zRE, 0); | |
| 445 | + if( zRE ){ | |
| 446 | + re_compile(&pRE, zRE, 0); | |
| 447 | + url_add_parameter(&sURI, "re", zRE); | |
| 448 | + zREx = mprintf("&re=%T", zRE); | |
| 449 | + } | |
| 431 | 450 | |
| 432 | 451 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 433 | 452 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 434 | 453 | |
| 435 | 454 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -441,52 +460,50 @@ | ||
| 441 | 460 | if( pM ){ |
| 442 | 461 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 443 | 462 | linkTrunk = trunkRid && rid != trunkRid; |
| 444 | 463 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 445 | 464 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 465 | + url_add_parameter(&sURI, "ci", zCI); | |
| 446 | 466 | }else{ |
| 447 | 467 | zCI = 0; |
| 448 | 468 | } |
| 449 | 469 | } |
| 450 | 470 | |
| 451 | 471 | /* Compute the title of the page */ |
| 452 | 472 | blob_zero(&dirname); |
| 453 | 473 | if( zD ){ |
| 454 | - blob_appendf(&dirname, "in directory %h", zD); | |
| 474 | + url_add_parameter(&sURI, "name", zD); | |
| 475 | + blob_append(&dirname, "within directory ", -1); | |
| 476 | + hyperlinked_path(zD, &dirname, zCI, "tree", zREx); | |
| 455 | 477 | if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); |
| 456 | - if( linkTrunk ){ | |
| 457 | - style_submenu_element("Trunk", "Trunk", "%R/tree?name=%t&ci=trunk", | |
| 458 | - zD); | |
| 459 | - } | |
| 460 | - if ( linkTip ){ | |
| 461 | - style_submenu_element("Tip", "Tip", "%R/tree?name=%t&ci=tip", zD); | |
| 462 | - } | |
| 478 | + zPrefix = mprintf("%T/", zD); | |
| 479 | + style_submenu_element("Top", "Top", "%s", | |
| 480 | + url_render(&sURI, "name", 0, 0, 0)); | |
| 463 | 481 | }else{ |
| 464 | 482 | if( zRE ){ |
| 465 | 483 | blob_appendf(&dirname, "matching \"%s\"", zRE); |
| 466 | - }else{ | |
| 467 | - blob_append(&dirname, "in the top-level directory", -1); | |
| 468 | - } | |
| 469 | - if( linkTrunk ){ | |
| 470 | - style_submenu_element("Trunk", "Trunk", "%R/tree?ci=trunk"); | |
| 471 | - } | |
| 472 | - if ( linkTip ){ | |
| 473 | - style_submenu_element("Tip", "Tip", "%R/tree?ci=tip"); | |
| 474 | - } | |
| 475 | - } | |
| 484 | + } | |
| 485 | + zPrefix = ""; | |
| 486 | + } | |
| 487 | + if( linkTrunk ){ | |
| 488 | + style_submenu_element("Trunk", "Trunk", "%s", | |
| 489 | + url_render(&sURI, "ci", "trunk", 0, 0)); | |
| 490 | + } | |
| 491 | + if ( linkTip ){ | |
| 492 | + style_submenu_element("Tip", "Tip", "%s", | |
| 493 | + url_render(&sURI, "ci", "tip", 0, 0)); | |
| 494 | + } | |
| 495 | + style_submenu_element("All", "All", "%s", | |
| 496 | + url_render(&sURI, "ci", 0, 0, 0)); | |
| 497 | + style_submenu_element("Flat-View", "Flat-View", "%s", | |
| 498 | + url_render(&sURI, "type", "flat", 0, 0)); | |
| 476 | 499 | if( zCI ){ |
| 477 | 500 | char zShort[20]; |
| 478 | 501 | memcpy(zShort, zUuid, 10); |
| 479 | 502 | zShort[10] = 0; |
| 480 | 503 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 481 | 504 | @ %s(blob_str(&dirname))</h2> |
| 482 | - if( zD ){ | |
| 483 | - style_submenu_element("Top", "Top", "%R/tree?ci=%S", zUuid); | |
| 484 | - style_submenu_element("All", "All", "%R/tree?name=%t", zD); | |
| 485 | - }else{ | |
| 486 | - style_submenu_element("All", "All", "%R/tree"); | |
| 487 | - } | |
| 488 | 505 | }else{ |
| 489 | 506 | @ <h2>The union of all files from all check-ins |
| 490 | 507 | @ %s(blob_str(&dirname))</h2> |
| 491 | 508 | } |
| 492 | 509 | |
| @@ -552,17 +569,20 @@ | ||
| 552 | 569 | cgi_append_content("└── ", 25); |
| 553 | 570 | }else{ |
| 554 | 571 | cgi_append_content("├── ", 25); |
| 555 | 572 | } |
| 556 | 573 | if( p->isDir ){ |
| 557 | - @ %h(p->zName) | |
| 574 | + char *zName = mprintf("%s%T", zPrefix, p->zFullName); | |
| 575 | + char *zLink = href("%s", url_render(&sURI, "name", zName, 0, 0)); | |
| 576 | + fossil_free(zName); | |
| 577 | + @ %z(zLink)%h(p->zName)</a> | |
| 558 | 578 | }else{ |
| 559 | 579 | char *zLink; |
| 560 | 580 | if( zCI ){ |
| 561 | 581 | zLink = href("%R/artifact/%s",p->zUuid); |
| 562 | 582 | }else{ |
| 563 | - zLink = href("%R/finfo?name=%T",p->zFullName); | |
| 583 | + zLink = href("%R/finfo?name=%s%T",zPrefix,p->zFullName); | |
| 564 | 584 | } |
| 565 | 585 | @ %z(zLink)%h(p->zName)</a> |
| 566 | 586 | } |
| 567 | 587 | } |
| 568 | 588 | @ </pre> |
| 569 | 589 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -71,23 +71,29 @@ | |
| 71 | ** There is no hyperlink on the file element of the path. |
| 72 | ** |
| 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | ** have already been initialized. |
| 75 | */ |
| 76 | void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ |
| 77 | int i, j; |
| 78 | char *zSep = ""; |
| 79 | |
| 80 | for(i=0; zPath[i]; i=j){ |
| 81 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 82 | if( zPath[j] && g.perm.Hyperlink ){ |
| 83 | if( zCI ){ |
| 84 | char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); |
| 85 | blob_appendf(pOut, "%s%z%#h</a>", |
| 86 | zSep, zLink, j-i, &zPath[i]); |
| 87 | }else{ |
| 88 | char *zLink = href("%R/dir?name=%#T", j, zPath); |
| 89 | blob_appendf(pOut, "%s%z%#h</a>", |
| 90 | zSep, zLink, j-i, &zPath[i]); |
| 91 | } |
| 92 | }else{ |
| 93 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -118,18 +124,22 @@ | |
| 118 | int rid = 0; |
| 119 | char *zUuid = 0; |
| 120 | Blob dirname; |
| 121 | Manifest *pM = 0; |
| 122 | const char *zSubdirLink; |
| 123 | int linkTrunk = 1, linkTip = 1; |
| 124 | |
| 125 | login_check_credentials(); |
| 126 | if( !g.perm.Read ){ login_needed(); return; } |
| 127 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 128 | style_header("File List"); |
| 129 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 130 | pathelementFunc, 0, 0); |
| 131 | |
| 132 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 133 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 134 | |
| 135 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | |
| 141 | if( pM ){ |
| 142 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 143 | linkTrunk = trunkRid && rid != trunkRid; |
| 144 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 145 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 146 | }else{ |
| 147 | zCI = 0; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | /* Compute the title of the page */ |
| 152 | blob_zero(&dirname); |
| 153 | if( zD ){ |
| 154 | blob_append(&dirname, "in directory ", -1); |
| 155 | hyperlinked_path(zD, &dirname, zCI); |
| 156 | zPrefix = mprintf("%s/", zD); |
| 157 | if( linkTrunk ){ |
| 158 | style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", |
| 159 | zD); |
| 160 | } |
| 161 | if( linkTip ){ |
| 162 | style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); |
| 163 | } |
| 164 | }else{ |
| 165 | blob_append(&dirname, "in the top-level directory", -1); |
| 166 | zPrefix = ""; |
| 167 | if( linkTrunk ){ |
| 168 | style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); |
| 169 | } |
| 170 | if( linkTip ){ |
| 171 | style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); |
| 172 | } |
| 173 | } |
| 174 | if( zCI ){ |
| 175 | char zShort[20]; |
| 176 | memcpy(zShort, zUuid, 10); |
| 177 | zShort[10] = 0; |
| 178 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 179 | @ %s(blob_str(&dirname))</h2> |
| 180 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 181 | if( zD ){ |
| 182 | style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); |
| 183 | style_submenu_element("All", "All", "%R/dir?name=%t", zD); |
| 184 | }else{ |
| 185 | style_submenu_element("All", "All", "%R/dir"); |
| 186 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 187 | zUuid); |
| 188 | } |
| 189 | }else{ |
| 190 | @ <h2>The union of all files from all check-ins |
| 191 | @ %s(blob_str(&dirname))</h2> |
| 192 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 193 | } |
| 194 | |
| 195 | /* Compute the temporary table "localfiles" containing the names |
| 196 | ** of all files and subdirectories in the zD[] directory. |
| 197 | ** |
| 198 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -409,27 +418,37 @@ | |
| 409 | const char *zCI = P("ci"); |
| 410 | int rid = 0; |
| 411 | char *zUuid = 0; |
| 412 | Blob dirname; |
| 413 | Manifest *pM = 0; |
| 414 | int linkTrunk = 1, linkTip = 1; |
| 415 | const char *zRE; |
| 416 | ReCompiled *pRE = 0; |
| 417 | FileTreeNode *p; |
| 418 | FileTree sTree; |
| 419 | |
| 420 | memset(&sTree, 0, sizeof(sTree)); |
| 421 | login_check_credentials(); |
| 422 | if( !g.perm.Read ){ login_needed(); return; } |
| 423 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 424 | style_header("File List"); |
| 425 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 426 | pathelementFunc, 0, 0); |
| 427 | |
| 428 | /* If a regular expression is specified, compile it */ |
| 429 | zRE = P("re"); |
| 430 | if( zRE ) re_compile(&pRE, zRE, 0); |
| 431 | |
| 432 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 433 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 434 | |
| 435 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -441,52 +460,50 @@ | |
| 441 | if( pM ){ |
| 442 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 443 | linkTrunk = trunkRid && rid != trunkRid; |
| 444 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 445 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 446 | }else{ |
| 447 | zCI = 0; |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | /* Compute the title of the page */ |
| 452 | blob_zero(&dirname); |
| 453 | if( zD ){ |
| 454 | blob_appendf(&dirname, "in directory %h", zD); |
| 455 | if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); |
| 456 | if( linkTrunk ){ |
| 457 | style_submenu_element("Trunk", "Trunk", "%R/tree?name=%t&ci=trunk", |
| 458 | zD); |
| 459 | } |
| 460 | if ( linkTip ){ |
| 461 | style_submenu_element("Tip", "Tip", "%R/tree?name=%t&ci=tip", zD); |
| 462 | } |
| 463 | }else{ |
| 464 | if( zRE ){ |
| 465 | blob_appendf(&dirname, "matching \"%s\"", zRE); |
| 466 | }else{ |
| 467 | blob_append(&dirname, "in the top-level directory", -1); |
| 468 | } |
| 469 | if( linkTrunk ){ |
| 470 | style_submenu_element("Trunk", "Trunk", "%R/tree?ci=trunk"); |
| 471 | } |
| 472 | if ( linkTip ){ |
| 473 | style_submenu_element("Tip", "Tip", "%R/tree?ci=tip"); |
| 474 | } |
| 475 | } |
| 476 | if( zCI ){ |
| 477 | char zShort[20]; |
| 478 | memcpy(zShort, zUuid, 10); |
| 479 | zShort[10] = 0; |
| 480 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 481 | @ %s(blob_str(&dirname))</h2> |
| 482 | if( zD ){ |
| 483 | style_submenu_element("Top", "Top", "%R/tree?ci=%S", zUuid); |
| 484 | style_submenu_element("All", "All", "%R/tree?name=%t", zD); |
| 485 | }else{ |
| 486 | style_submenu_element("All", "All", "%R/tree"); |
| 487 | } |
| 488 | }else{ |
| 489 | @ <h2>The union of all files from all check-ins |
| 490 | @ %s(blob_str(&dirname))</h2> |
| 491 | } |
| 492 | |
| @@ -552,17 +569,20 @@ | |
| 552 | cgi_append_content("└── ", 25); |
| 553 | }else{ |
| 554 | cgi_append_content("├── ", 25); |
| 555 | } |
| 556 | if( p->isDir ){ |
| 557 | @ %h(p->zName) |
| 558 | }else{ |
| 559 | char *zLink; |
| 560 | if( zCI ){ |
| 561 | zLink = href("%R/artifact/%s",p->zUuid); |
| 562 | }else{ |
| 563 | zLink = href("%R/finfo?name=%T",p->zFullName); |
| 564 | } |
| 565 | @ %z(zLink)%h(p->zName)</a> |
| 566 | } |
| 567 | } |
| 568 | @ </pre> |
| 569 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -71,23 +71,29 @@ | |
| 71 | ** There is no hyperlink on the file element of the path. |
| 72 | ** |
| 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | ** have already been initialized. |
| 75 | */ |
| 76 | void hyperlinked_path( |
| 77 | const char *zPath, /* Path to render */ |
| 78 | Blob *pOut, /* Write into this blob */ |
| 79 | const char *zCI, /* check-in name, or NULL */ |
| 80 | const char *zURI, /* "dir" or "tree" */ |
| 81 | const char *zREx /* Extra query parameters */ |
| 82 | ){ |
| 83 | int i, j; |
| 84 | char *zSep = ""; |
| 85 | |
| 86 | for(i=0; zPath[i]; i=j){ |
| 87 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 88 | if( zPath[j] && g.perm.Hyperlink ){ |
| 89 | if( zCI ){ |
| 90 | char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx); |
| 91 | blob_appendf(pOut, "%s%z%#h</a>", |
| 92 | zSep, zLink, j-i, &zPath[i]); |
| 93 | }else{ |
| 94 | char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); |
| 95 | blob_appendf(pOut, "%s%z%#h</a>", |
| 96 | zSep, zLink, j-i, &zPath[i]); |
| 97 | } |
| 98 | }else{ |
| 99 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -118,18 +124,22 @@ | |
| 124 | int rid = 0; |
| 125 | char *zUuid = 0; |
| 126 | Blob dirname; |
| 127 | Manifest *pM = 0; |
| 128 | const char *zSubdirLink; |
| 129 | int linkTrunk = 1; |
| 130 | int linkTip = 1; |
| 131 | HQuery sURI; |
| 132 | |
| 133 | if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; } |
| 134 | login_check_credentials(); |
| 135 | if( !g.perm.Read ){ login_needed(); return; } |
| 136 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 137 | style_header("File List"); |
| 138 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 139 | pathelementFunc, 0, 0); |
| 140 | url_initialize(&sURI, "dir"); |
| 141 | |
| 142 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 143 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 144 | |
| 145 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | |
| 151 | if( pM ){ |
| 152 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 153 | linkTrunk = trunkRid && rid != trunkRid; |
| 154 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 155 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 156 | url_add_parameter(&sURI, "ci", zCI); |
| 157 | }else{ |
| 158 | zCI = 0; |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | /* Compute the title of the page */ |
| 163 | blob_zero(&dirname); |
| 164 | if( zD ){ |
| 165 | url_add_parameter(&sURI, "name", zD); |
| 166 | blob_append(&dirname, "in directory ", -1); |
| 167 | hyperlinked_path(zD, &dirname, zCI, "dir", ""); |
| 168 | zPrefix = mprintf("%s/", zD); |
| 169 | style_submenu_element("Top", "Top", "%s", |
| 170 | url_render(&sURI, "name", 0, 0, 0)); |
| 171 | }else{ |
| 172 | blob_append(&dirname, "in the top-level directory", -1); |
| 173 | zPrefix = ""; |
| 174 | } |
| 175 | if( linkTrunk ){ |
| 176 | style_submenu_element("Trunk", "Trunk", "%s", |
| 177 | url_render(&sURI, "ci", "trunk", 0, 0)); |
| 178 | } |
| 179 | if( linkTip ){ |
| 180 | style_submenu_element("Tip", "Tip", "%s", |
| 181 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 182 | } |
| 183 | if( zCI ){ |
| 184 | char zShort[20]; |
| 185 | memcpy(zShort, zUuid, 10); |
| 186 | zShort[10] = 0; |
| 187 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 188 | @ %s(blob_str(&dirname))</h2> |
| 189 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 190 | if( nD==0 ){ |
| 191 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 192 | zUuid); |
| 193 | } |
| 194 | }else{ |
| 195 | @ <h2>The union of all files from all check-ins |
| 196 | @ %s(blob_str(&dirname))</h2> |
| 197 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 198 | } |
| 199 | style_submenu_element("All", "All", "%s", |
| 200 | url_render(&sURI, "ci", 0, 0, 0)); |
| 201 | style_submenu_element("Tree-View", "Tree-View", "%s", |
| 202 | url_render(&sURI, "type", "tree", 0, 0)); |
| 203 | |
| 204 | /* Compute the temporary table "localfiles" containing the names |
| 205 | ** of all files and subdirectories in the zD[] directory. |
| 206 | ** |
| 207 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -409,27 +418,37 @@ | |
| 418 | const char *zCI = P("ci"); |
| 419 | int rid = 0; |
| 420 | char *zUuid = 0; |
| 421 | Blob dirname; |
| 422 | Manifest *pM = 0; |
| 423 | int linkTrunk = 1; /* include link to "trunk" */ |
| 424 | int linkTip = 1; /* include link to "tip" */ |
| 425 | const char *zRE; /* the value for the re=REGEXP query parameter */ |
| 426 | char *zPrefix; /* Prefix on all filenames */ |
| 427 | char *zREx = ""; /* Extra parameters for path hyperlinks */ |
| 428 | ReCompiled *pRE = 0; /* Compiled regular expression */ |
| 429 | FileTreeNode *p; /* One line of the tree */ |
| 430 | FileTree sTree; /* The complete tree of files */ |
| 431 | HQuery sURI; /* Hyperlink */ |
| 432 | |
| 433 | if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } |
| 434 | memset(&sTree, 0, sizeof(sTree)); |
| 435 | login_check_credentials(); |
| 436 | if( !g.perm.Read ){ login_needed(); return; } |
| 437 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 438 | style_header("File List"); |
| 439 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 440 | pathelementFunc, 0, 0); |
| 441 | url_initialize(&sURI, "tree"); |
| 442 | |
| 443 | /* If a regular expression is specified, compile it */ |
| 444 | zRE = P("re"); |
| 445 | if( zRE ){ |
| 446 | re_compile(&pRE, zRE, 0); |
| 447 | url_add_parameter(&sURI, "re", zRE); |
| 448 | zREx = mprintf("&re=%T", zRE); |
| 449 | } |
| 450 | |
| 451 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 452 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 453 | |
| 454 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -441,52 +460,50 @@ | |
| 460 | if( pM ){ |
| 461 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 462 | linkTrunk = trunkRid && rid != trunkRid; |
| 463 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 464 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 465 | url_add_parameter(&sURI, "ci", zCI); |
| 466 | }else{ |
| 467 | zCI = 0; |
| 468 | } |
| 469 | } |
| 470 | |
| 471 | /* Compute the title of the page */ |
| 472 | blob_zero(&dirname); |
| 473 | if( zD ){ |
| 474 | url_add_parameter(&sURI, "name", zD); |
| 475 | blob_append(&dirname, "within directory ", -1); |
| 476 | hyperlinked_path(zD, &dirname, zCI, "tree", zREx); |
| 477 | if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); |
| 478 | zPrefix = mprintf("%T/", zD); |
| 479 | style_submenu_element("Top", "Top", "%s", |
| 480 | url_render(&sURI, "name", 0, 0, 0)); |
| 481 | }else{ |
| 482 | if( zRE ){ |
| 483 | blob_appendf(&dirname, "matching \"%s\"", zRE); |
| 484 | } |
| 485 | zPrefix = ""; |
| 486 | } |
| 487 | if( linkTrunk ){ |
| 488 | style_submenu_element("Trunk", "Trunk", "%s", |
| 489 | url_render(&sURI, "ci", "trunk", 0, 0)); |
| 490 | } |
| 491 | if ( linkTip ){ |
| 492 | style_submenu_element("Tip", "Tip", "%s", |
| 493 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 494 | } |
| 495 | style_submenu_element("All", "All", "%s", |
| 496 | url_render(&sURI, "ci", 0, 0, 0)); |
| 497 | style_submenu_element("Flat-View", "Flat-View", "%s", |
| 498 | url_render(&sURI, "type", "flat", 0, 0)); |
| 499 | if( zCI ){ |
| 500 | char zShort[20]; |
| 501 | memcpy(zShort, zUuid, 10); |
| 502 | zShort[10] = 0; |
| 503 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 504 | @ %s(blob_str(&dirname))</h2> |
| 505 | }else{ |
| 506 | @ <h2>The union of all files from all check-ins |
| 507 | @ %s(blob_str(&dirname))</h2> |
| 508 | } |
| 509 | |
| @@ -552,17 +569,20 @@ | |
| 569 | cgi_append_content("└── ", 25); |
| 570 | }else{ |
| 571 | cgi_append_content("├── ", 25); |
| 572 | } |
| 573 | if( p->isDir ){ |
| 574 | char *zName = mprintf("%s%T", zPrefix, p->zFullName); |
| 575 | char *zLink = href("%s", url_render(&sURI, "name", zName, 0, 0)); |
| 576 | fossil_free(zName); |
| 577 | @ %z(zLink)%h(p->zName)</a> |
| 578 | }else{ |
| 579 | char *zLink; |
| 580 | if( zCI ){ |
| 581 | zLink = href("%R/artifact/%s",p->zUuid); |
| 582 | }else{ |
| 583 | zLink = href("%R/finfo?name=%s%T",zPrefix,p->zFullName); |
| 584 | } |
| 585 | @ %z(zLink)%h(p->zName)</a> |
| 586 | } |
| 587 | } |
| 588 | @ </pre> |
| 589 |
+2
-2
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -375,16 +375,16 @@ | ||
| 375 | 375 | blob_zero(&title); |
| 376 | 376 | if( baseCheckin ){ |
| 377 | 377 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 378 | 378 | char *zLink = href("%R/info/%S", zUuid); |
| 379 | 379 | blob_appendf(&title, "Ancestors of file "); |
| 380 | - hyperlinked_path(zFilename, &title, zUuid); | |
| 380 | + hyperlinked_path(zFilename, &title, zUuid, "dir", ""); | |
| 381 | 381 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 382 | 382 | fossil_free(zUuid); |
| 383 | 383 | }else{ |
| 384 | 384 | blob_appendf(&title, "History of files named "); |
| 385 | - hyperlinked_path(zFilename, &title, 0); | |
| 385 | + hyperlinked_path(zFilename, &title, 0, "dir", ""); | |
| 386 | 386 | } |
| 387 | 387 | @ <h2>%b(&title)</h2> |
| 388 | 388 | blob_reset(&title); |
| 389 | 389 | pGraph = graph_init(); |
| 390 | 390 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 391 | 391 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -375,16 +375,16 @@ | |
| 375 | blob_zero(&title); |
| 376 | if( baseCheckin ){ |
| 377 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 378 | char *zLink = href("%R/info/%S", zUuid); |
| 379 | blob_appendf(&title, "Ancestors of file "); |
| 380 | hyperlinked_path(zFilename, &title, zUuid); |
| 381 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 382 | fossil_free(zUuid); |
| 383 | }else{ |
| 384 | blob_appendf(&title, "History of files named "); |
| 385 | hyperlinked_path(zFilename, &title, 0); |
| 386 | } |
| 387 | @ <h2>%b(&title)</h2> |
| 388 | blob_reset(&title); |
| 389 | pGraph = graph_init(); |
| 390 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 391 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -375,16 +375,16 @@ | |
| 375 | blob_zero(&title); |
| 376 | if( baseCheckin ){ |
| 377 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 378 | char *zLink = href("%R/info/%S", zUuid); |
| 379 | blob_appendf(&title, "Ancestors of file "); |
| 380 | hyperlinked_path(zFilename, &title, zUuid, "dir", ""); |
| 381 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 382 | fossil_free(zUuid); |
| 383 | }else{ |
| 384 | blob_appendf(&title, "History of files named "); |
| 385 | hyperlinked_path(zFilename, &title, 0, "dir", ""); |
| 386 | } |
| 387 | @ <h2>%b(&title)</h2> |
| 388 | blob_reset(&title); |
| 389 | pGraph = graph_init(); |
| 390 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 391 |