@@ -5,65 +5,46 @@ anchors.options.placement = 'left';
55anchors . add ( 'h3' ) ;
66
77// Filter UI
8- var tocElements = document . getElementById ( 'toc' )
9- . getElementsByTagName ( 'li' ) ;
10-
11- document . getElementById ( 'filter-input' )
12- . addEventListener ( 'keyup' , function ( e ) {
13-
14- var i , element , children ;
15-
16- // enter key
17- if ( e . keyCode === 13 ) {
18- // go to the first displayed item in the toc
19- for ( i = 0 ; i < tocElements . length ; i ++ ) {
20- element = tocElements [ i ] ;
21- if ( ! element . classList . contains ( 'display-none' ) ) {
22- location . replace ( element . firstChild . href ) ;
23- return e . preventDefault ( ) ;
24- }
25- }
26- }
27-
28- var match = function ( ) {
29- return true ;
30- } ;
31-
32- var value = this . value . toLowerCase ( ) ;
8+ var tocElements = document . getElementById ( 'toc' ) . getElementsByTagName ( 'li' ) ;
339
34- if ( ! value . match ( / ^ \s * $ / ) ) {
35- match = function ( element ) {
36- return element . firstChild . innerHTML . toLowerCase ( ) . indexOf ( value ) !== - 1 ;
37- } ;
38- }
10+ document . getElementById ( 'filter-input' ) . addEventListener ( 'keyup' , function ( e ) {
11+ var i , element , children ;
3912
13+ // enter key
14+ if ( e . keyCode === 13 ) {
15+ // go to the first displayed item in the toc
4016 for ( i = 0 ; i < tocElements . length ; i ++ ) {
4117 element = tocElements [ i ] ;
42- children = Array . from ( element . getElementsByTagName ( 'li' ) ) ;
43- if ( match ( element ) || children . some ( match ) ) {
44- element . classList . remove ( 'display-none' ) ;
45- } else {
46- element . classList . add ( 'display-none' ) ;
18+ if ( ! element . classList . contains ( 'display-none' ) ) {
19+ location . replace ( element . firstChild . href ) ;
20+ return e . preventDefault ( ) ;
4721 }
4822 }
49- } ) ;
23+ }
5024
51- var toggles = document . getElementsByClassName ( 'toggle-step-sibling' ) ;
52- for ( var i = 0 ; i < toggles . length ; i ++ ) {
53- toggles [ i ] . addEventListener ( 'click' , toggleStepSibling ) ;
54- }
25+ var match = function ( ) {
26+ return true ;
27+ } ;
5528
56- function toggleStepSibling ( ) {
57- var stepSibling = this . parentNode . parentNode . parentNode . getElementsByClassName ( 'toggle-target' ) [ 0 ] ;
58- var klass = 'display-none' ;
59- if ( stepSibling . classList . contains ( klass ) ) {
60- stepSibling . classList . remove ( klass ) ;
61- stepSibling . innerHTML = '▾' ;
62- } else {
63- stepSibling . classList . add ( klass ) ;
64- stepSibling . innerHTML = '▸' ;
29+ var value = this . value . toLowerCase ( ) ;
30+
31+ if ( ! value . match ( / ^ \s * $ / ) ) {
32+ match = function ( element ) {
33+ var html = element . firstChild . innerHTML ;
34+ return html && html . toLowerCase ( ) . indexOf ( value ) !== - 1 ;
35+ } ;
6536 }
66- }
37+
38+ for ( i = 0 ; i < tocElements . length ; i ++ ) {
39+ element = tocElements [ i ] ;
40+ children = Array . from ( element . getElementsByTagName ( 'li' ) ) ;
41+ if ( match ( element ) || children . some ( match ) ) {
42+ element . classList . remove ( 'display-none' ) ;
43+ } else {
44+ element . classList . add ( 'display-none' ) ;
45+ }
46+ }
47+ } ) ;
6748
6849var items = document . getElementsByClassName ( 'toggle-sibling' ) ;
6950for ( var j = 0 ; j < items . length ; j ++ ) {
@@ -84,19 +65,36 @@ function toggleSibling() {
8465}
8566
8667function showHashTarget ( targetId ) {
87- var hashTarget = document . getElementById ( targetId ) ;
88- // new target is hidden
89- if ( hashTarget && hashTarget . offsetHeight === 0 &&
90- hashTarget . parentNode . parentNode . classList . contains ( 'display-none' ) ) {
91- hashTarget . parentNode . parentNode . classList . remove ( 'display-none' ) ;
68+ if ( targetId ) {
69+ var hashTarget = document . getElementById ( targetId ) ;
70+ // new target is hidden
71+ if (
72+ hashTarget &&
73+ hashTarget . offsetHeight === 0 &&
74+ hashTarget . parentNode . parentNode . classList . contains ( 'display-none' )
75+ ) {
76+ hashTarget . parentNode . parentNode . classList . remove ( 'display-none' ) ;
77+ }
78+ }
79+ }
80+
81+ function scrollIntoView ( targetId ) {
82+ // Only scroll to element if we don't have a stored scroll position.
83+ if ( targetId && ! history . state ) {
84+ var hashTarget = document . getElementById ( targetId ) ;
85+ if ( hashTarget ) {
86+ hashTarget . scrollIntoView ( ) ;
87+ }
9288 }
9389}
9490
95- window . addEventListener ( 'hashchange' , function ( ) {
91+ function gotoCurrentTarget ( ) {
9692 showHashTarget ( location . hash . substring ( 1 ) ) ;
97- } ) ;
93+ scrollIntoView ( location . hash . substring ( 1 ) ) ;
94+ }
9895
99- showHashTarget ( location . hash . substring ( 1 ) ) ;
96+ window . addEventListener ( 'hashchange' , gotoCurrentTarget ) ;
97+ gotoCurrentTarget ( ) ;
10098
10199var toclinks = document . getElementsByClassName ( 'pre-open' ) ;
102100for ( var k = 0 ; k < toclinks . length ; k ++ ) {
@@ -106,3 +104,74 @@ for (var k = 0; k < toclinks.length; k++) {
106104function preOpen ( ) {
107105 showHashTarget ( this . hash . substring ( 1 ) ) ;
108106}
107+
108+ var split_left = document . querySelector ( '#split-left' ) ;
109+ var split_right = document . querySelector ( '#split-right' ) ;
110+ var split_parent = split_left . parentNode ;
111+ var cw_with_sb = split_left . clientWidth ;
112+ split_left . style . overflow = 'hidden' ;
113+ var cw_without_sb = split_left . clientWidth ;
114+ split_left . style . overflow = '' ;
115+
116+ // Need to add:
117+ // - Half of gutterSize (i.e. 10) because gutter will take that much from each.
118+ // - Scrollbar width (cw_with_sb - cw_without_sb), if it takes up existing
119+ // space (Firefox) rather than adding the scrollbar to the side (Chrome)
120+ var percent_left =
121+ ( split_left . getBoundingClientRect ( ) . width + 10 + cw_without_sb - cw_with_sb ) /
122+ split_parent . getBoundingClientRect ( ) . width *
123+ 100 ;
124+
125+ Split ( [ '#split-left' , '#split-right' ] , {
126+ elementStyle : function ( dimension , size , gutterSize ) {
127+ return {
128+ 'flex-basis' : 'calc(' + size + '% - ' + gutterSize + 'px)'
129+ } ;
130+ } ,
131+ gutterStyle : function ( dimension , gutterSize ) {
132+ return {
133+ 'flex-basis' : gutterSize + 'px'
134+ } ;
135+ } ,
136+ gutterSize : 20 ,
137+ sizes : [ percent_left , 100 - percent_left ]
138+ } ) ;
139+
140+ // Chrome doesn't remember scroll position properly so do it ourselves.
141+ // Also works on Firefox and Edge.
142+
143+ function updateState ( ) {
144+ history . replaceState (
145+ {
146+ left_top : split_left . scrollTop ,
147+ right_top : split_right . scrollTop
148+ } ,
149+ document . title
150+ ) ;
151+ }
152+
153+ function loadState ( ev ) {
154+ if ( ev ) {
155+ // Edge doesn't replace change history.state on popstate.
156+ history . replaceState ( ev . state , document . title ) ;
157+ }
158+ if ( history . state ) {
159+ split_left . scrollTop = history . state . left_top ;
160+ split_right . scrollTop = history . state . right_top ;
161+ }
162+ }
163+
164+ window . addEventListener ( 'load' , function ( ) {
165+ // Restore after Firefox scrolls to hash.
166+ setTimeout ( function ( ) {
167+ loadState ( ) ;
168+ // Update with initial scroll position.
169+ updateState ( ) ;
170+ // Update scroll positions only after we've loaded because Firefox
171+ // emits an initial scroll event with 0.
172+ split_left . addEventListener ( 'scroll' , updateState ) ;
173+ split_right . addEventListener ( 'scroll' , updateState ) ;
174+ } , 1 ) ;
175+ } ) ;
176+
177+ window . addEventListener ( 'popstate' , loadState ) ;
0 commit comments