Fossil

Check-in [377a4f2d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Propose tree-view enhancement.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | csstree
Files: files | file ages | folders
SHA1: 377a4f2d534f733f3bbd71e36ccd6309cf2c8981
User & Date: joel 2014-01-02 12:47:40
Context
2014-01-02
18:50
Fix incorrect insertion of closing UL tags. check-in: 417d1808 user: joel tags: csstree
12:47
Propose tree-view enhancement. check-in: 377a4f2d user: joel tags: csstree
12:36
Add portion of MANIFEST_UUID to TH1 URL variables. check-in: daa43661 user: joel tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/browse.c.

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
420
421
422
423
424
425
426
427
428
429
430
431
432


433
434
435
436
437
438
439
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
...
558
559
560
561
562
563
564
565

566
567


568
569

570


571
572
573
574



575
576
577
578
579
580
581
582



583
584
585
586
587
588
589
590
591



592


593

594
595
596
597
598
599
600
    pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
    pNew->isDir = zPath[i]=='/';
    pNew->isLast = 1;
    while( zPath[i]=='/' ){ i++; }
    pParent = pNew;
  }
}

/*
** Render parent lines for pNode
*/
static void tree_indentation(FileTreeNode *p){
  if( p==0 ) return;
  tree_indentation(p->pParent);
  if( p->isLast ){
    cgi_append_content("    ", 4);
  }else{
    cgi_append_content("│   ", 11);
  }
}


/*
** WEBPAGE: tree
**
** Query parameters:
**
**    name=PATH        Directory to display.  Optional
................................................................................
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
  int nFile = 0;           /* Number of files */
  int linkTrunk = 1;       /* include link to "trunk" */
  int linkTip = 1;         /* include link to "tip" */
  const char *zRE;         /* the value for the re=REGEXP query parameter */
  char *zPrefix;           /* Prefix on all filenames */
  char *zREx = "";         /* Extra parameters for path hyperlinks */
  ReCompiled *pRE = 0;     /* Compiled regular expression */
  FileTreeNode *p;         /* One line of the tree */
  FileTree sTree;          /* The complete tree of files */
  HQuery sURI;             /* Hyperlink */



  if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
  memset(&sTree, 0, sizeof(sTree));
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");
................................................................................
  /* Compute the title of the page */
  blob_zero(&dirname);
  if( zD ){
    url_add_parameter(&sURI, "name", zD);
    blob_append(&dirname, "within directory ", -1);
    hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
    if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
    zPrefix = mprintf("%T/", zD);
    style_submenu_element("Top-Level", "Top-Level", "%s",
                          url_render(&sURI, "name", 0, 0, 0));
  }else{
    if( zRE ){
      blob_appendf(&dirname, "matching \"%s\"", zRE);
    }
    zPrefix = "";
  }
  if( zCI ){
    style_submenu_element("All", "All", "%s",
                          url_render(&sURI, "ci", 0, 0, 0));
  }
  if( linkTrunk ){
    style_submenu_element("Trunk", "Trunk", "%s",
................................................................................
      if( nD>0
       && (fossil_strncmp(pFile->zName, zD, nD-1)!=0
           || pFile->zName[nD-1]!='/')
      ){
        continue;
      }
      if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
      db_bind_text(&ins, ":f", &pFile->zName[nD]);
      db_bind_text(&ins, ":u", pFile->zUuid);
      db_step(&ins);
      db_reset(&ins);
    }
    db_finalize(&ins);
    db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
    while( db_step(&q)==SQLITE_ROW ){
................................................................................
    db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase");
    while( db_step(&q)==SQLITE_ROW ){
      const char *z = db_column_text(&q, 0);
      if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
        continue;
      }
      if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
      tree_add_node(&sTree, z+nD, 0);
      nFile++;
    }
    db_finalize(&q);
  }

  if( zCI ){
    @ <h2>%d(nFile) files of
................................................................................
    @ %s(blob_str(&dirname))</h2>
  }


  /* Generate a multi-column table listing the contents of zD[]
  ** directory.
  */
  @ <pre>

  if( nD ){
    cgi_printf("%.*h\n", nD, zD);


  }else{
    @ .

  }


  for(p=sTree.pFirst; p; p=p->pNext){
    tree_indentation(p->pParent);
    if( p->isLast ){
      cgi_append_content("&#x2514;&#x2500;&#x2500; ", 25);



    }else{
      cgi_append_content("&#x251c;&#x2500;&#x2500; ", 25);
    }
    if( p->isDir ){
      char *zName = mprintf("%s%T", zPrefix, p->zFullName);
      char *zLink = href("%s", url_render(&sURI, "name", zName, 0, 0));
      fossil_free(zName);
      @ %z(zLink)%h(p->zName)</a>



    }else{
      char *zLink;
      if( zCI ){
        zLink = href("%R/artifact/%s",p->zUuid);
      }else{
        zLink = href("%R/finfo?name=%s%T",zPrefix,p->zFullName);
      }
      @ %z(zLink)%h(p->zName)</a>
    }



  }


  @ </pre>

  style_footer();

  /* We could free memory used by sTree here if we needed to.  But
  ** the process is about to exit, so doing so would not really accomplish
  ** anything useful. */
}








<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<





>
>







 







<






<







 







|







 







|







 







|
>

<
>
>

<
>

>
>

<
|
<
>
>
>
|
<
<
<
<
|
<
|
>
>
>





|

|

>
>
>
|
>
>
|
>







384
385
386
387
388
389
390














391
392
393
394
395
396
397
...
406
407
408
409
410
411
412

413
414
415
416
417
418
419
420
421
422
423
424
425
426
...
459
460
461
462
463
464
465

466
467
468
469
470
471

472
473
474
475
476
477
478
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
543
544
545
546
547
548
549
550
551
552

553
554
555

556
557
558
559
560

561

562
563
564
565




566

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
    pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
    pNew->isDir = zPath[i]=='/';
    pNew->isLast = 1;
    while( zPath[i]=='/' ){ i++; }
    pParent = pNew;
  }
}















/*
** WEBPAGE: tree
**
** Query parameters:
**
**    name=PATH        Directory to display.  Optional
................................................................................
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
  int nFile = 0;           /* Number of files */
  int linkTrunk = 1;       /* include link to "trunk" */
  int linkTip = 1;         /* include link to "tip" */
  const char *zRE;         /* the value for the re=REGEXP query parameter */

  char *zREx = "";         /* Extra parameters for path hyperlinks */
  ReCompiled *pRE = 0;     /* Compiled regular expression */
  FileTreeNode *p;         /* One line of the tree */
  FileTree sTree;          /* The complete tree of files */
  HQuery sURI;             /* Hyperlink */
  int iDepth = 0;          /* <ul> depth */
  char *zProjectName = db_get("project-name", 0);

  if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
  memset(&sTree, 0, sizeof(sTree));
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");
................................................................................
  /* Compute the title of the page */
  blob_zero(&dirname);
  if( zD ){
    url_add_parameter(&sURI, "name", zD);
    blob_append(&dirname, "within directory ", -1);
    hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
    if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);

    style_submenu_element("Top-Level", "Top-Level", "%s",
                          url_render(&sURI, "name", 0, 0, 0));
  }else{
    if( zRE ){
      blob_appendf(&dirname, "matching \"%s\"", zRE);
    }

  }
  if( zCI ){
    style_submenu_element("All", "All", "%s",
                          url_render(&sURI, "ci", 0, 0, 0));
  }
  if( linkTrunk ){
    style_submenu_element("Trunk", "Trunk", "%s",
................................................................................
      if( nD>0
       && (fossil_strncmp(pFile->zName, zD, nD-1)!=0
           || pFile->zName[nD-1]!='/')
      ){
        continue;
      }
      if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
      db_bind_text(&ins, ":f", pFile->zName);
      db_bind_text(&ins, ":u", pFile->zUuid);
      db_step(&ins);
      db_reset(&ins);
    }
    db_finalize(&ins);
    db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
    while( db_step(&q)==SQLITE_ROW ){
................................................................................
    db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase");
    while( db_step(&q)==SQLITE_ROW ){
      const char *z = db_column_text(&q, 0);
      if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
        continue;
      }
      if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
      tree_add_node(&sTree, z, 0);
      nFile++;
    }
    db_finalize(&q);
  }

  if( zCI ){
    @ <h2>%d(nFile) files of
................................................................................
    @ %s(blob_str(&dirname))</h2>
  }


  /* Generate a multi-column table listing the contents of zD[]
  ** directory.
  */
  @ <ul class="filetree root">
  @ <li class="dir">
  if( nD ){

    char *zLink = href("%s", url_render(&sURI, "name", 0, 0, 0));
    @ %z(zLink)%h(zProjectName)</a>
  }else{

    @ <a>%h(zProjectName)</a>
  }
  @ <ul class="filetree">
  iDepth = 2;
  for(p=sTree.pFirst; p; p=p->pNext){

    if( p->isDir ){

      @ <li class="dir">
      if( fossil_strcmp(p->zFullName, zD)==0 ){
        @ <a>%h(p->zName)</a>
      }else{




        char *zLink = href("%s", url_render(&sURI, "name", p->zFullName, 0, 0));

        @ %z(zLink)%h(p->zName)</a>
      }
      @ <ul class="filetree">
      iDepth++;
    }else{
      char *zLink;
      if( zCI ){
        zLink = href("%R/artifact/%s",p->zUuid);
      }else{
        zLink = href("%R/finfo?name=%T",p->zFullName);
      }
      @ <li class="file">%z(zLink)%h(p->zName)</a>
    }
    if( p->isLast && !p->isDir ){
      @ </ul>
      iDepth--;
    }
  }
  while( iDepth-- > 0 ) {
    @ </ul>
  }
  style_footer();

  /* We could free memory used by sTree here if we needed to.  But
  ** the process is about to exit, so doing so would not really accomplish
  ** anything useful. */
}

Changes to src/style.c.

769
770
771
772
773
774
775






























776
777
778
779
780
781
782
  },
  { "ul.browser",
    "format for the list in the file browser",
    @   margin-left: 0.5em;
    @   padding-left: 0.5em;
    @   white-space: nowrap;
  },






























  { "table.login_out",
    "table format for login/out label/input table",
    @   text-align: left;
    @   margin-right: 10px;
    @   margin-left: 10px;
    @   margin-top: 10px;
  },







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
  },
  { "ul.browser",
    "format for the list in the file browser",
    @   margin-left: 0.5em;
    @   padding-left: 0.5em;
    @   white-space: nowrap;
  },
  { ".filetree",
    "file tree",
    @   padding-left: 0;
    @   list-style: none;
  },
  {
    ".filetree li",
    "file tree list items",
    @   margin: .2em 0;
  },
  { ".filetree ul",
    "file tree subdirectory lists",
    @   margin-left: 7px;
    @   padding-left: 12px;
    @   border-left: 2px dotted #aaa;
  },
  {
    ".filetree a:before",
    "file tree link icons",
    @   margin-right: 5px;
    @   vertical-align: middle;
  },
  { ".filetree .dir > a:before",
    "file tree directory link icons",
    @   content: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
  },
  { ".filetree .file > a:before",
    "file tree file link icons",
    @   content: url(data:image/gif;base64,R0lGODlhDQAQAJEAAP\/\/\/yIiIv\/\/\/wAAACH5BAEHAAIALAAAAAANABAAAAIhjI+iyLYBYmTCyAnZBc3eDm0SIo5HiXklibLr2cIvSNMFADs=);
  },
  { "table.login_out",
    "table format for login/out label/input table",
    @   text-align: left;
    @   margin-right: 10px;
    @   margin-left: 10px;
    @   margin-top: 10px;
  },