Fossil SCM
Make tree-view expansions and contractions persist on a "Back" in Chrome and IE. (Works without the extra javascript on Firefox and Safari.)
Commit
ab00f2b007d5229da6868718bad9ce126bb34506
Parent
5e368e911dcc48f…
1 file changed
+42
-14
+42
-14
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -418,10 +418,11 @@ | ||
| 418 | 418 | FileTreeNode *p; /* One line of the tree */ |
| 419 | 419 | FileTree sTree; /* The complete tree of files */ |
| 420 | 420 | HQuery sURI; /* Hyperlink */ |
| 421 | 421 | int startExpanded; /* True to start out with the tree expanded */ |
| 422 | 422 | int showDirOnly; /* Show directories only. Omit files */ |
| 423 | + int nDir = 0; /* Number of directories. Used for ID attributes */ | |
| 423 | 424 | char *zProjectName = db_get("project-name", 0); |
| 424 | 425 | |
| 425 | 426 | if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } |
| 426 | 427 | memset(&sTree, 0, sizeof(sTree)); |
| 427 | 428 | login_check_credentials(); |
| @@ -602,23 +603,24 @@ | ||
| 602 | 603 | }else{ |
| 603 | 604 | @ <li class="dir subdir"> |
| 604 | 605 | } |
| 605 | 606 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 606 | 607 | @ <ul> |
| 607 | - for(p=sTree.pFirst; p; p=p->pNext){ | |
| 608 | + for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ | |
| 608 | 609 | if( p->isDir ){ |
| 609 | 610 | if( p->nFullName==nD-1 ){ |
| 610 | 611 | @ <li class="dir subdir"> |
| 611 | 612 | }else{ |
| 612 | 613 | @ <li class="dir"> |
| 613 | 614 | } |
| 614 | 615 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 615 | 616 | if( startExpanded || p->nFullName<=nD ){ |
| 616 | - @ <ul> | |
| 617 | + @ <ul id="dir%d(nDir)"> | |
| 617 | 618 | }else{ |
| 618 | - @ <ul style='display:none;'> | |
| 619 | + @ <ul id="dir%d(nDir)" style='display:none;'> | |
| 619 | 620 | } |
| 621 | + nDir++; | |
| 620 | 622 | }else if( !showDirOnly ){ |
| 621 | 623 | char *zLink; |
| 622 | 624 | if( zCI ){ |
| 623 | 625 | zLink = href("%R/artifact/%S",p->zUuid); |
| 624 | 626 | }else{ |
| @@ -634,31 +636,57 @@ | ||
| 634 | 636 | } |
| 635 | 637 | } |
| 636 | 638 | @ </ul> |
| 637 | 639 | @ </ul></div> |
| 638 | 640 | @ <script>(function(){ |
| 639 | - @ function style(elem, prop){ | |
| 640 | - @ return window.getComputedStyle(elem).getPropertyValue(prop); | |
| 641 | + @ function isExpanded(ul){ | |
| 642 | + @ var display = window.getComputedStyle(ul).getPropertyValue('display'); | |
| 643 | + @ return display!='none'; | |
| 644 | + @ } | |
| 645 | + @ | |
| 646 | + @ function toggleDir(ul, useInitValue){ | |
| 647 | + @ if( !useInitValue ){ | |
| 648 | + @ expandMap[ul.id] = !isExpanded(ul); | |
| 649 | + @ history.replaceState(expandMap, ''); | |
| 650 | + @ } | |
| 651 | + @ ul.style.display = expandMap[ul.id] ? 'block' : 'none'; | |
| 641 | 652 | @ } |
| 642 | 653 | @ |
| 643 | - @ function toggleAll(tree){ | |
| 654 | + @ function toggleAll(tree, useInitValue){ | |
| 644 | 655 | @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); |
| 645 | - @ var display = 'block'; /* Default action: make all sublists visible */ | |
| 646 | - @ for( var i=0; lists[i]; i++ ){ | |
| 647 | - @ if( style(lists[i], 'display')!='none'){ | |
| 648 | - @ display = 'none'; /* Any already visible - make them all hidden */ | |
| 649 | - @ break; | |
| 656 | + @ if( !useInitValue ){ | |
| 657 | + @ var expand = true; /* Default action: make all sublists visible */ | |
| 658 | + @ for( var i=0; lists[i]; i++ ){ | |
| 659 | + @ if( isExpanded(lists[i]) ){ | |
| 660 | + @ expand = false; /* Any already visible - make them all hidden */ | |
| 661 | + @ break; | |
| 662 | + @ } | |
| 650 | 663 | @ } |
| 664 | + @ expandMap = {'*': expand}; | |
| 665 | + @ history.replaceState(expandMap, ''); | |
| 651 | 666 | @ } |
| 667 | + @ var display = expandMap['*'] ? 'block' : 'none'; | |
| 652 | 668 | @ for( var i=0; lists[i]; i++ ){ |
| 653 | 669 | @ lists[i].style.display = display; |
| 654 | 670 | @ } |
| 655 | 671 | @ } |
| 656 | - @ | |
| 672 | + @ | |
| 673 | + @ function checkState(){ | |
| 674 | + @ expandMap = history.state || {}; | |
| 675 | + @ if( expandMap['*'] ) toggleAll(outer_ul, true); | |
| 676 | + @ for( var id in expandMap ){ | |
| 677 | + @ if( id!=='*' ) toggleDir(gebi(id), true); | |
| 678 | + @ } | |
| 679 | + @ } | |
| 680 | + @ | |
| 681 | + @ /* No-op shim for IE9 */ | |
| 682 | + @ if( !history.replaceState ) history.replaceState = function(){}; | |
| 657 | 683 | @ var outer_ul = document.querySelector('.filetree > ul'); |
| 658 | 684 | @ var subdir = outer_ul.querySelector('.subdir'); |
| 659 | - @ outer_ul.onclick = function( e ){ | |
| 685 | + @ var expandMap = {}; | |
| 686 | + @ checkState(); | |
| 687 | + @ outer_ul.onclick = function(e){ | |
| 660 | 688 | @ var a = e.target; |
| 661 | 689 | @ if( a.nodeName!='A' ) return true; |
| 662 | 690 | @ if( a.parentNode==subdir ){ |
| 663 | 691 | @ toggleAll(outer_ul); |
| 664 | 692 | @ return false; |
| @@ -665,11 +693,11 @@ | ||
| 665 | 693 | @ } |
| 666 | 694 | @ if( !subdir.contains(a) ) return true; |
| 667 | 695 | @ var ul = a.nextSibling; |
| 668 | 696 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 669 | 697 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 670 | - @ ul.style.display = style(ul, 'display')=='none' ? 'block' : 'none'; | |
| 698 | + @ toggleDir(ul); | |
| 671 | 699 | @ return false; |
| 672 | 700 | @ } |
| 673 | 701 | @ }())</script> |
| 674 | 702 | style_footer(); |
| 675 | 703 | |
| 676 | 704 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -418,10 +418,11 @@ | |
| 418 | FileTreeNode *p; /* One line of the tree */ |
| 419 | FileTree sTree; /* The complete tree of files */ |
| 420 | HQuery sURI; /* Hyperlink */ |
| 421 | int startExpanded; /* True to start out with the tree expanded */ |
| 422 | int showDirOnly; /* Show directories only. Omit files */ |
| 423 | char *zProjectName = db_get("project-name", 0); |
| 424 | |
| 425 | if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } |
| 426 | memset(&sTree, 0, sizeof(sTree)); |
| 427 | login_check_credentials(); |
| @@ -602,23 +603,24 @@ | |
| 602 | }else{ |
| 603 | @ <li class="dir subdir"> |
| 604 | } |
| 605 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 606 | @ <ul> |
| 607 | for(p=sTree.pFirst; p; p=p->pNext){ |
| 608 | if( p->isDir ){ |
| 609 | if( p->nFullName==nD-1 ){ |
| 610 | @ <li class="dir subdir"> |
| 611 | }else{ |
| 612 | @ <li class="dir"> |
| 613 | } |
| 614 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 615 | if( startExpanded || p->nFullName<=nD ){ |
| 616 | @ <ul> |
| 617 | }else{ |
| 618 | @ <ul style='display:none;'> |
| 619 | } |
| 620 | }else if( !showDirOnly ){ |
| 621 | char *zLink; |
| 622 | if( zCI ){ |
| 623 | zLink = href("%R/artifact/%S",p->zUuid); |
| 624 | }else{ |
| @@ -634,31 +636,57 @@ | |
| 634 | } |
| 635 | } |
| 636 | @ </ul> |
| 637 | @ </ul></div> |
| 638 | @ <script>(function(){ |
| 639 | @ function style(elem, prop){ |
| 640 | @ return window.getComputedStyle(elem).getPropertyValue(prop); |
| 641 | @ } |
| 642 | @ |
| 643 | @ function toggleAll(tree){ |
| 644 | @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); |
| 645 | @ var display = 'block'; /* Default action: make all sublists visible */ |
| 646 | @ for( var i=0; lists[i]; i++ ){ |
| 647 | @ if( style(lists[i], 'display')!='none'){ |
| 648 | @ display = 'none'; /* Any already visible - make them all hidden */ |
| 649 | @ break; |
| 650 | @ } |
| 651 | @ } |
| 652 | @ for( var i=0; lists[i]; i++ ){ |
| 653 | @ lists[i].style.display = display; |
| 654 | @ } |
| 655 | @ } |
| 656 | @ |
| 657 | @ var outer_ul = document.querySelector('.filetree > ul'); |
| 658 | @ var subdir = outer_ul.querySelector('.subdir'); |
| 659 | @ outer_ul.onclick = function( e ){ |
| 660 | @ var a = e.target; |
| 661 | @ if( a.nodeName!='A' ) return true; |
| 662 | @ if( a.parentNode==subdir ){ |
| 663 | @ toggleAll(outer_ul); |
| 664 | @ return false; |
| @@ -665,11 +693,11 @@ | |
| 665 | @ } |
| 666 | @ if( !subdir.contains(a) ) return true; |
| 667 | @ var ul = a.nextSibling; |
| 668 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 669 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 670 | @ ul.style.display = style(ul, 'display')=='none' ? 'block' : 'none'; |
| 671 | @ return false; |
| 672 | @ } |
| 673 | @ }())</script> |
| 674 | style_footer(); |
| 675 | |
| 676 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -418,10 +418,11 @@ | |
| 418 | FileTreeNode *p; /* One line of the tree */ |
| 419 | FileTree sTree; /* The complete tree of files */ |
| 420 | HQuery sURI; /* Hyperlink */ |
| 421 | int startExpanded; /* True to start out with the tree expanded */ |
| 422 | int showDirOnly; /* Show directories only. Omit files */ |
| 423 | int nDir = 0; /* Number of directories. Used for ID attributes */ |
| 424 | char *zProjectName = db_get("project-name", 0); |
| 425 | |
| 426 | if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } |
| 427 | memset(&sTree, 0, sizeof(sTree)); |
| 428 | login_check_credentials(); |
| @@ -602,23 +603,24 @@ | |
| 603 | }else{ |
| 604 | @ <li class="dir subdir"> |
| 605 | } |
| 606 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 607 | @ <ul> |
| 608 | for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ |
| 609 | if( p->isDir ){ |
| 610 | if( p->nFullName==nD-1 ){ |
| 611 | @ <li class="dir subdir"> |
| 612 | }else{ |
| 613 | @ <li class="dir"> |
| 614 | } |
| 615 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 616 | if( startExpanded || p->nFullName<=nD ){ |
| 617 | @ <ul id="dir%d(nDir)"> |
| 618 | }else{ |
| 619 | @ <ul id="dir%d(nDir)" style='display:none;'> |
| 620 | } |
| 621 | nDir++; |
| 622 | }else if( !showDirOnly ){ |
| 623 | char *zLink; |
| 624 | if( zCI ){ |
| 625 | zLink = href("%R/artifact/%S",p->zUuid); |
| 626 | }else{ |
| @@ -634,31 +636,57 @@ | |
| 636 | } |
| 637 | } |
| 638 | @ </ul> |
| 639 | @ </ul></div> |
| 640 | @ <script>(function(){ |
| 641 | @ function isExpanded(ul){ |
| 642 | @ var display = window.getComputedStyle(ul).getPropertyValue('display'); |
| 643 | @ return display!='none'; |
| 644 | @ } |
| 645 | @ |
| 646 | @ function toggleDir(ul, useInitValue){ |
| 647 | @ if( !useInitValue ){ |
| 648 | @ expandMap[ul.id] = !isExpanded(ul); |
| 649 | @ history.replaceState(expandMap, ''); |
| 650 | @ } |
| 651 | @ ul.style.display = expandMap[ul.id] ? 'block' : 'none'; |
| 652 | @ } |
| 653 | @ |
| 654 | @ function toggleAll(tree, useInitValue){ |
| 655 | @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); |
| 656 | @ if( !useInitValue ){ |
| 657 | @ var expand = true; /* Default action: make all sublists visible */ |
| 658 | @ for( var i=0; lists[i]; i++ ){ |
| 659 | @ if( isExpanded(lists[i]) ){ |
| 660 | @ expand = false; /* Any already visible - make them all hidden */ |
| 661 | @ break; |
| 662 | @ } |
| 663 | @ } |
| 664 | @ expandMap = {'*': expand}; |
| 665 | @ history.replaceState(expandMap, ''); |
| 666 | @ } |
| 667 | @ var display = expandMap['*'] ? 'block' : 'none'; |
| 668 | @ for( var i=0; lists[i]; i++ ){ |
| 669 | @ lists[i].style.display = display; |
| 670 | @ } |
| 671 | @ } |
| 672 | @ |
| 673 | @ function checkState(){ |
| 674 | @ expandMap = history.state || {}; |
| 675 | @ if( expandMap['*'] ) toggleAll(outer_ul, true); |
| 676 | @ for( var id in expandMap ){ |
| 677 | @ if( id!=='*' ) toggleDir(gebi(id), true); |
| 678 | @ } |
| 679 | @ } |
| 680 | @ |
| 681 | @ /* No-op shim for IE9 */ |
| 682 | @ if( !history.replaceState ) history.replaceState = function(){}; |
| 683 | @ var outer_ul = document.querySelector('.filetree > ul'); |
| 684 | @ var subdir = outer_ul.querySelector('.subdir'); |
| 685 | @ var expandMap = {}; |
| 686 | @ checkState(); |
| 687 | @ outer_ul.onclick = function(e){ |
| 688 | @ var a = e.target; |
| 689 | @ if( a.nodeName!='A' ) return true; |
| 690 | @ if( a.parentNode==subdir ){ |
| 691 | @ toggleAll(outer_ul); |
| 692 | @ return false; |
| @@ -665,11 +693,11 @@ | |
| 693 | @ } |
| 694 | @ if( !subdir.contains(a) ) return true; |
| 695 | @ var ul = a.nextSibling; |
| 696 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 697 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 698 | @ toggleDir(ul); |
| 699 | @ return false; |
| 700 | @ } |
| 701 | @ }())</script> |
| 702 | style_footer(); |
| 703 | |
| 704 |