Fossil SCM

Propose tree-view enhancement.

joel 2014-01-02 12:47 UTC trunk
Commit 377a4f2d534f733f3bbd71e36ccd6309cf2c8981
2 files changed +33 -39 +30
+33 -39
--- src/browse.c
+++ src/browse.c
@@ -386,24 +386,10 @@
386386
pNew->isLast = 1;
387387
while( zPath[i]=='/' ){ i++; }
388388
pParent = pNew;
389389
}
390390
}
391
-
392
-/*
393
-** Render parent lines for pNode
394
-*/
395
-static void tree_indentation(FileTreeNode *p){
396
- if( p==0 ) return;
397
- tree_indentation(p->pParent);
398
- if( p->isLast ){
399
- cgi_append_content(" ", 4);
400
- }else{
401
- cgi_append_content("│ ", 11);
402
- }
403
-}
404
-
405391
406392
/*
407393
** WEBPAGE: tree
408394
**
409395
** Query parameters:
@@ -422,16 +408,17 @@
422408
Manifest *pM = 0;
423409
int nFile = 0; /* Number of files */
424410
int linkTrunk = 1; /* include link to "trunk" */
425411
int linkTip = 1; /* include link to "tip" */
426412
const char *zRE; /* the value for the re=REGEXP query parameter */
427
- char *zPrefix; /* Prefix on all filenames */
428413
char *zREx = ""; /* Extra parameters for path hyperlinks */
429414
ReCompiled *pRE = 0; /* Compiled regular expression */
430415
FileTreeNode *p; /* One line of the tree */
431416
FileTree sTree; /* The complete tree of files */
432417
HQuery sURI; /* Hyperlink */
418
+ int iDepth = 0; /* <ul> depth */
419
+ char *zProjectName = db_get("project-name", 0);
433420
434421
if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
435422
memset(&sTree, 0, sizeof(sTree));
436423
login_check_credentials();
437424
if( !g.perm.Read ){ login_needed(); return; }
@@ -474,18 +461,16 @@
474461
if( zD ){
475462
url_add_parameter(&sURI, "name", zD);
476463
blob_append(&dirname, "within directory ", -1);
477464
hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
478465
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
479
- zPrefix = mprintf("%T/", zD);
480466
style_submenu_element("Top-Level", "Top-Level", "%s",
481467
url_render(&sURI, "name", 0, 0, 0));
482468
}else{
483469
if( zRE ){
484470
blob_appendf(&dirname, "matching \"%s\"", zRE);
485471
}
486
- zPrefix = "";
487472
}
488473
if( zCI ){
489474
style_submenu_element("All", "All", "%s",
490475
url_render(&sURI, "ci", 0, 0, 0));
491476
}
@@ -519,11 +504,11 @@
519504
|| pFile->zName[nD-1]!='/')
520505
){
521506
continue;
522507
}
523508
if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
524
- db_bind_text(&ins, ":f", &pFile->zName[nD]);
509
+ db_bind_text(&ins, ":f", pFile->zName);
525510
db_bind_text(&ins, ":u", pFile->zUuid);
526511
db_step(&ins);
527512
db_reset(&ins);
528513
}
529514
db_finalize(&ins);
@@ -540,11 +525,11 @@
540525
const char *z = db_column_text(&q, 0);
541526
if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
542527
continue;
543528
}
544529
if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
545
- tree_add_node(&sTree, z+nD, 0);
530
+ tree_add_node(&sTree, z, 0);
546531
nFile++;
547532
}
548533
db_finalize(&q);
549534
}
550535
@@ -560,39 +545,48 @@
560545
561546
562547
/* Generate a multi-column table listing the contents of zD[]
563548
** directory.
564549
*/
565
- @ <pre>
566
- if( nD ){
567
- cgi_printf("%.*h\n", nD, zD);
568
- }else{
569
- @ .
570
- }
571
- for(p=sTree.pFirst; p; p=p->pNext){
572
- tree_indentation(p->pParent);
573
- if( p->isLast ){
574
- cgi_append_content("&#x2514;&#x2500;&#x2500; ", 25);
575
- }else{
576
- cgi_append_content("&#x251c;&#x2500;&#x2500; ", 25);
577
- }
550
+ @ <ul class="filetree root">
551
+ @ <li class="dir">
552
+ if( nD ){
553
+ char *zLink = href("%s", url_render(&sURI, "name", 0, 0, 0));
554
+ @ %z(zLink)%h(zProjectName)</a>
555
+ }else{
556
+ @ <a>%h(zProjectName)</a>
557
+ }
558
+ @ <ul class="filetree">
559
+ iDepth = 2;
560
+ for(p=sTree.pFirst; p; p=p->pNext){
578561
if( p->isDir ){
579
- char *zName = mprintf("%s%T", zPrefix, p->zFullName);
580
- char *zLink = href("%s", url_render(&sURI, "name", zName, 0, 0));
581
- fossil_free(zName);
582
- @ %z(zLink)%h(p->zName)</a>
562
+ @ <li class="dir">
563
+ if( fossil_strcmp(p->zFullName, zD)==0 ){
564
+ @ <a>%h(p->zName)</a>
565
+ }else{
566
+ char *zLink = href("%s", url_render(&sURI, "name", p->zFullName, 0, 0));
567
+ @ %z(zLink)%h(p->zName)</a>
568
+ }
569
+ @ <ul class="filetree">
570
+ iDepth++;
583571
}else{
584572
char *zLink;
585573
if( zCI ){
586574
zLink = href("%R/artifact/%s",p->zUuid);
587575
}else{
588
- zLink = href("%R/finfo?name=%s%T",zPrefix,p->zFullName);
576
+ zLink = href("%R/finfo?name=%T",p->zFullName);
589577
}
590
- @ %z(zLink)%h(p->zName)</a>
578
+ @ <li class="file">%z(zLink)%h(p->zName)</a>
579
+ }
580
+ if( p->isLast && !p->isDir ){
581
+ @ </ul>
582
+ iDepth--;
591583
}
592584
}
593
- @ </pre>
585
+ while( iDepth-- > 0 ) {
586
+ @ </ul>
587
+ }
594588
style_footer();
595589
596590
/* We could free memory used by sTree here if we needed to. But
597591
** the process is about to exit, so doing so would not really accomplish
598592
** anything useful. */
599593
--- src/browse.c
+++ src/browse.c
@@ -386,24 +386,10 @@
386 pNew->isLast = 1;
387 while( zPath[i]=='/' ){ i++; }
388 pParent = pNew;
389 }
390 }
391
392 /*
393 ** Render parent lines for pNode
394 */
395 static void tree_indentation(FileTreeNode *p){
396 if( p==0 ) return;
397 tree_indentation(p->pParent);
398 if( p->isLast ){
399 cgi_append_content(" ", 4);
400 }else{
401 cgi_append_content("&#x2502; ", 11);
402 }
403 }
404
405
406 /*
407 ** WEBPAGE: tree
408 **
409 ** Query parameters:
@@ -422,16 +408,17 @@
422 Manifest *pM = 0;
423 int nFile = 0; /* Number of files */
424 int linkTrunk = 1; /* include link to "trunk" */
425 int linkTip = 1; /* include link to "tip" */
426 const char *zRE; /* the value for the re=REGEXP query parameter */
427 char *zPrefix; /* Prefix on all filenames */
428 char *zREx = ""; /* Extra parameters for path hyperlinks */
429 ReCompiled *pRE = 0; /* Compiled regular expression */
430 FileTreeNode *p; /* One line of the tree */
431 FileTree sTree; /* The complete tree of files */
432 HQuery sURI; /* Hyperlink */
 
 
433
434 if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
435 memset(&sTree, 0, sizeof(sTree));
436 login_check_credentials();
437 if( !g.perm.Read ){ login_needed(); return; }
@@ -474,18 +461,16 @@
474 if( zD ){
475 url_add_parameter(&sURI, "name", zD);
476 blob_append(&dirname, "within directory ", -1);
477 hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
478 if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
479 zPrefix = mprintf("%T/", zD);
480 style_submenu_element("Top-Level", "Top-Level", "%s",
481 url_render(&sURI, "name", 0, 0, 0));
482 }else{
483 if( zRE ){
484 blob_appendf(&dirname, "matching \"%s\"", zRE);
485 }
486 zPrefix = "";
487 }
488 if( zCI ){
489 style_submenu_element("All", "All", "%s",
490 url_render(&sURI, "ci", 0, 0, 0));
491 }
@@ -519,11 +504,11 @@
519 || pFile->zName[nD-1]!='/')
520 ){
521 continue;
522 }
523 if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
524 db_bind_text(&ins, ":f", &pFile->zName[nD]);
525 db_bind_text(&ins, ":u", pFile->zUuid);
526 db_step(&ins);
527 db_reset(&ins);
528 }
529 db_finalize(&ins);
@@ -540,11 +525,11 @@
540 const char *z = db_column_text(&q, 0);
541 if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
542 continue;
543 }
544 if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
545 tree_add_node(&sTree, z+nD, 0);
546 nFile++;
547 }
548 db_finalize(&q);
549 }
550
@@ -560,39 +545,48 @@
560
561
562 /* Generate a multi-column table listing the contents of zD[]
563 ** directory.
564 */
565 @ <pre>
566 if( nD ){
567 cgi_printf("%.*h\n", nD, zD);
568 }else{
569 @ .
570 }
571 for(p=sTree.pFirst; p; p=p->pNext){
572 tree_indentation(p->pParent);
573 if( p->isLast ){
574 cgi_append_content("&#x2514;&#x2500;&#x2500; ", 25);
575 }else{
576 cgi_append_content("&#x251c;&#x2500;&#x2500; ", 25);
577 }
578 if( p->isDir ){
579 char *zName = mprintf("%s%T", zPrefix, p->zFullName);
580 char *zLink = href("%s", url_render(&sURI, "name", zName, 0, 0));
581 fossil_free(zName);
582 @ %z(zLink)%h(p->zName)</a>
 
 
 
 
 
583 }else{
584 char *zLink;
585 if( zCI ){
586 zLink = href("%R/artifact/%s",p->zUuid);
587 }else{
588 zLink = href("%R/finfo?name=%s%T",zPrefix,p->zFullName);
589 }
590 @ %z(zLink)%h(p->zName)</a>
 
 
 
 
591 }
592 }
593 @ </pre>
 
 
594 style_footer();
595
596 /* We could free memory used by sTree here if we needed to. But
597 ** the process is about to exit, so doing so would not really accomplish
598 ** anything useful. */
599
--- src/browse.c
+++ src/browse.c
@@ -386,24 +386,10 @@
386 pNew->isLast = 1;
387 while( zPath[i]=='/' ){ i++; }
388 pParent = pNew;
389 }
390 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
392 /*
393 ** WEBPAGE: tree
394 **
395 ** Query parameters:
@@ -422,16 +408,17 @@
408 Manifest *pM = 0;
409 int nFile = 0; /* Number of files */
410 int linkTrunk = 1; /* include link to "trunk" */
411 int linkTip = 1; /* include link to "tip" */
412 const char *zRE; /* the value for the re=REGEXP query parameter */
 
413 char *zREx = ""; /* Extra parameters for path hyperlinks */
414 ReCompiled *pRE = 0; /* Compiled regular expression */
415 FileTreeNode *p; /* One line of the tree */
416 FileTree sTree; /* The complete tree of files */
417 HQuery sURI; /* Hyperlink */
418 int iDepth = 0; /* <ul> depth */
419 char *zProjectName = db_get("project-name", 0);
420
421 if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
422 memset(&sTree, 0, sizeof(sTree));
423 login_check_credentials();
424 if( !g.perm.Read ){ login_needed(); return; }
@@ -474,18 +461,16 @@
461 if( zD ){
462 url_add_parameter(&sURI, "name", zD);
463 blob_append(&dirname, "within directory ", -1);
464 hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
465 if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
 
466 style_submenu_element("Top-Level", "Top-Level", "%s",
467 url_render(&sURI, "name", 0, 0, 0));
468 }else{
469 if( zRE ){
470 blob_appendf(&dirname, "matching \"%s\"", zRE);
471 }
 
472 }
473 if( zCI ){
474 style_submenu_element("All", "All", "%s",
475 url_render(&sURI, "ci", 0, 0, 0));
476 }
@@ -519,11 +504,11 @@
504 || pFile->zName[nD-1]!='/')
505 ){
506 continue;
507 }
508 if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
509 db_bind_text(&ins, ":f", pFile->zName);
510 db_bind_text(&ins, ":u", pFile->zUuid);
511 db_step(&ins);
512 db_reset(&ins);
513 }
514 db_finalize(&ins);
@@ -540,11 +525,11 @@
525 const char *z = db_column_text(&q, 0);
526 if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
527 continue;
528 }
529 if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
530 tree_add_node(&sTree, z, 0);
531 nFile++;
532 }
533 db_finalize(&q);
534 }
535
@@ -560,39 +545,48 @@
545
546
547 /* Generate a multi-column table listing the contents of zD[]
548 ** directory.
549 */
550 @ <ul class="filetree root">
551 @ <li class="dir">
552 if( nD ){
553 char *zLink = href("%s", url_render(&sURI, "name", 0, 0, 0));
554 @ %z(zLink)%h(zProjectName)</a>
555 }else{
556 @ <a>%h(zProjectName)</a>
557 }
558 @ <ul class="filetree">
559 iDepth = 2;
560 for(p=sTree.pFirst; p; p=p->pNext){
 
 
561 if( p->isDir ){
562 @ <li class="dir">
563 if( fossil_strcmp(p->zFullName, zD)==0 ){
564 @ <a>%h(p->zName)</a>
565 }else{
566 char *zLink = href("%s", url_render(&sURI, "name", p->zFullName, 0, 0));
567 @ %z(zLink)%h(p->zName)</a>
568 }
569 @ <ul class="filetree">
570 iDepth++;
571 }else{
572 char *zLink;
573 if( zCI ){
574 zLink = href("%R/artifact/%s",p->zUuid);
575 }else{
576 zLink = href("%R/finfo?name=%T",p->zFullName);
577 }
578 @ <li class="file">%z(zLink)%h(p->zName)</a>
579 }
580 if( p->isLast && !p->isDir ){
581 @ </ul>
582 iDepth--;
583 }
584 }
585 while( iDepth-- > 0 ) {
586 @ </ul>
587 }
588 style_footer();
589
590 /* We could free memory used by sTree here if we needed to. But
591 ** the process is about to exit, so doing so would not really accomplish
592 ** anything useful. */
593
+30
--- src/style.c
+++ src/style.c
@@ -771,10 +771,40 @@
771771
"format for the list in the file browser",
772772
@ margin-left: 0.5em;
773773
@ padding-left: 0.5em;
774774
@ white-space: nowrap;
775775
},
776
+ { ".filetree",
777
+ "file tree",
778
+ @ padding-left: 0;
779
+ @ list-style: none;
780
+ },
781
+ {
782
+ ".filetree li",
783
+ "file tree list items",
784
+ @ margin: .2em 0;
785
+ },
786
+ { ".filetree ul",
787
+ "file tree subdirectory lists",
788
+ @ margin-left: 7px;
789
+ @ padding-left: 12px;
790
+ @ border-left: 2px dotted #aaa;
791
+ },
792
+ {
793
+ ".filetree a:before",
794
+ "file tree link icons",
795
+ @ margin-right: 5px;
796
+ @ vertical-align: middle;
797
+ },
798
+ { ".filetree .dir > a:before",
799
+ "file tree directory link icons",
800
+ @ content: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
801
+ },
802
+ { ".filetree .file > a:before",
803
+ "file tree file link icons",
804
+ @ content: url(data:image/gif;base64,R0lGODlhDQAQAJEAAP\/\/\/yIiIv\/\/\/wAAACH5BAEHAAIALAAAAAANABAAAAIhjI+iyLYBYmTCyAnZBc3eDm0SIo5HiXklibLr2cIvSNMFADs=);
805
+ },
776806
{ "table.login_out",
777807
"table format for login/out label/input table",
778808
@ text-align: left;
779809
@ margin-right: 10px;
780810
@ margin-left: 10px;
781811
--- src/style.c
+++ src/style.c
@@ -771,10 +771,40 @@
771 "format for the list in the file browser",
772 @ margin-left: 0.5em;
773 @ padding-left: 0.5em;
774 @ white-space: nowrap;
775 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776 { "table.login_out",
777 "table format for login/out label/input table",
778 @ text-align: left;
779 @ margin-right: 10px;
780 @ margin-left: 10px;
781
--- src/style.c
+++ src/style.c
@@ -771,10 +771,40 @@
771 "format for the list in the file browser",
772 @ margin-left: 0.5em;
773 @ padding-left: 0.5em;
774 @ white-space: nowrap;
775 },
776 { ".filetree",
777 "file tree",
778 @ padding-left: 0;
779 @ list-style: none;
780 },
781 {
782 ".filetree li",
783 "file tree list items",
784 @ margin: .2em 0;
785 },
786 { ".filetree ul",
787 "file tree subdirectory lists",
788 @ margin-left: 7px;
789 @ padding-left: 12px;
790 @ border-left: 2px dotted #aaa;
791 },
792 {
793 ".filetree a:before",
794 "file tree link icons",
795 @ margin-right: 5px;
796 @ vertical-align: middle;
797 },
798 { ".filetree .dir > a:before",
799 "file tree directory link icons",
800 @ content: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
801 },
802 { ".filetree .file > a:before",
803 "file tree file link icons",
804 @ content: url(data:image/gif;base64,R0lGODlhDQAQAJEAAP\/\/\/yIiIv\/\/\/wAAACH5BAEHAAIALAAAAAANABAAAAIhjI+iyLYBYmTCyAnZBc3eDm0SIo5HiXklibLr2cIvSNMFADs=);
805 },
806 { "table.login_out",
807 "table format for login/out label/input table",
808 @ text-align: left;
809 @ margin-right: 10px;
810 @ margin-left: 10px;
811

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button