@@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', () => {
4242 repo : '' ,
4343 path : '' ,
4444 selectedFileItemElement : null ,
45- previewedFile : null ,
45+ previewFile : null ,
4646 } ;
4747
4848
@@ -55,7 +55,7 @@ document.addEventListener('DOMContentLoaded', () => {
5555 return ;
5656 }
5757 setupEventListeners ( ) ;
58- handleInitialUrl ( ) ;
58+ handleUrlAndLoad ( ) ;
5959 }
6060
6161 // Set up all event listeners
@@ -68,83 +68,7 @@ document.addEventListener('DOMContentLoaded', () => {
6868 DOM . ownerInput . addEventListener ( 'keypress' , handleInputKeyPress ) ;
6969 DOM . upDirectoryBtn . addEventListener ( 'click' , navigateUp ) ;
7070 DOM . closePreviewBtn . addEventListener ( 'click' , closeFilePreview ) ;
71- window . addEventListener ( 'popstate' , handleInitialUrl ) ; // New: Handle browser back/forward buttons
72- }
73-
74-
75- //==============================================================================
76- // URL HANDLING
77- //==============================================================================
78- // Parses the URL on load and populates the file explorer state
79- async function handleInitialUrl ( ) {
80- const redirectUrl = sessionStorage . getItem ( 'redirect' ) ;
81- if ( redirectUrl ) {
82- sessionStorage . removeItem ( 'redirect' ) ;
83- history . replaceState ( null , '' , redirectUrl ) ;
84- }
85-
86- // Proceed with the path from the URL bar
87- const path = window . location . pathname ;
88- const params = new URLSearchParams ( window . location . search ) ;
89- const previewFile = params . get ( 'preview' ) ;
90-
91- // This regex needs to account for potential repository names in the path on GitHub Pages
92- const pathSegments = path . split ( '/' ) . filter ( Boolean ) ;
93- const feIndex = pathSegments . indexOf ( 'fe' ) ;
94-
95- if ( feIndex > - 1 && pathSegments . length >= feIndex + 3 ) {
96- const owner = pathSegments [ feIndex + 1 ] ;
97- const repo = pathSegments [ feIndex + 2 ] ;
98- const filePath = pathSegments . slice ( feIndex + 3 ) . join ( '/' ) ;
99-
100- DOM . ownerInput . value = owner ;
101- DOM . repoInput . value = repo ;
102- state . owner = owner ;
103- state . repo = repo ;
104-
105- // Open the explorer automatically if a repo is specified in the URL
106- openExplorer ( ) ;
107-
108- await fetchAndDisplayContents ( filePath || '' , false ) ;
109-
110- if ( previewFile ) {
111- // Find the file in the current listing and open its preview
112- const fullItemPath = ( filePath ? filePath + '/' : '' ) + previewFile ;
113- const fileItemElement = DOM . fileListingContainer . querySelector ( `[data-path="${ fullItemPath } "]` ) ;
114- if ( fileItemElement ) {
115- const item = {
116- path : fullItemPath ,
117- name : previewFile ,
118- type : 'file' ,
119- } ;
120- handleListItemClick ( item ) ;
121- }
122- }
123- } else {
124- updateStatus ( 'Enter GitHub Owner and Repository to begin.' ) ;
125- }
126- }
127-
128- // Updates the browser's URL to reflect the current state
129- function updateUrl ( ) {
130- if ( ! state . owner || ! state . repo ) return ;
131-
132- let newPath = `/fe/${ state . owner } /${ state . repo } ` ;
133- if ( state . path ) {
134- newPath += `/${ state . path } ` ;
135- }
136-
137- const params = new URLSearchParams ( ) ;
138- if ( state . previewedFile ) {
139- params . set ( 'preview' , state . previewedFile . name ) ;
140- }
141-
142- const queryString = params . toString ( ) ;
143- const finalUrl = queryString ? `${ newPath } ?${ queryString } ` : newPath ;
144-
145- if ( window . location . pathname !== newPath || window . location . search !== ( queryString ? `?${ queryString } ` : '' ) ) {
146- history . pushState ( { path : state . path } , '' , finalUrl ) ;
147- }
71+ window . addEventListener ( 'popstate' , handlePopState ) ;
14872 }
14973
15074
@@ -222,6 +146,89 @@ document.addEventListener('DOMContentLoaded', () => {
222146 }
223147
224148
149+ //==============================================================================
150+ // URL HANDLING
151+ //==============================================================================
152+ // Updates the browser's URL to reflect the current state of the file explorer.
153+ function updateUrl ( replaceState = false ) {
154+ if ( ! state . owner || ! state . repo ) return ;
155+ const basePath = window . location . pathname . substring ( 0 , window . location . pathname . indexOf ( '/fe/' ) ) ;
156+ let newPath = `${ basePath } /fe/${ state . owner } /${ state . repo } ` ;
157+ if ( state . path ) {
158+ newPath += `/${ state . path } ` ;
159+ }
160+
161+ const params = new URLSearchParams ( window . location . search ) ;
162+ if ( state . previewFile ) {
163+ params . set ( 'preview' , state . previewFile ) ;
164+ } else {
165+ params . delete ( 'preview' ) ;
166+ }
167+
168+ const queryString = params . toString ( ) ;
169+ if ( queryString ) {
170+ newPath += `?${ queryString } ` ;
171+ }
172+
173+ const currentUrl = window . location . pathname + window . location . search ;
174+ if ( currentUrl !== newPath ) {
175+ const method = replaceState ? 'replaceState' : 'pushState' ;
176+ // Use an empty string for the title
177+ history [ method ] ( { } , '' , newPath ) ;
178+ }
179+ }
180+
181+ // Parses the URL on page load to initialize the explorer state.
182+ function handleUrlAndLoad ( ) {
183+ // Handle the redirect from the 404.html page.
184+ const initialParams = new URLSearchParams ( window . location . search ) ;
185+ const redirectPath = initialParams . get ( 'redirect' ) ;
186+
187+ if ( redirectPath ) {
188+ // Contain the path the user originally tried to access.
189+ history . replaceState ( null , '' , '/' + redirectPath ) ;
190+ }
191+
192+ const path = window . location . pathname ;
193+ const params = new URLSearchParams ( window . location . search ) ;
194+ const previewFile = params . get ( 'preview' ) ;
195+
196+ const segments = path . split ( '/' ) ;
197+ // Find the 'fe' segment
198+ const feIndex = segments . findIndex ( s => s . toLowerCase ( ) === 'fe' ) ;
199+
200+ if ( feIndex > - 1 && segments . length >= feIndex + 3 ) {
201+ const owner = segments [ feIndex + 1 ] ;
202+ const repo = segments [ feIndex + 2 ] ;
203+ const filePath = segments . slice ( feIndex + 3 ) . join ( '/' ) ;
204+
205+ openExplorer ( ) ;
206+ DOM . ownerInput . value = owner ;
207+ DOM . repoInput . value = repo ;
208+ state . owner = owner ;
209+ state . repo = repo ;
210+
211+ const onContentLoaded = ( items ) => {
212+ if ( previewFile ) {
213+ const fileToPreview = items . find ( item => item . name === previewFile && item . type === 'file' ) ;
214+ if ( fileToPreview ) {
215+ handleListItemClick ( fileToPreview ) ;
216+ }
217+ }
218+ } ;
219+ fetchAndDisplayContents ( filePath , onContentLoaded ) ;
220+ } else {
221+ updateStatus ( 'Enter GitHub Owner and Repository to begin.' ) ;
222+ }
223+ }
224+
225+ // Handles browser back/forward navigation.
226+ function handlePopState ( ) {
227+ closeFilePreview ( ) ;
228+ handleUrlAndLoad ( ) ;
229+ }
230+
231+
225232 //==============================================================================
226233 // REPOSITORY LOADING & DATA FETCHING
227234 //==============================================================================
@@ -235,25 +242,24 @@ document.addEventListener('DOMContentLoaded', () => {
235242 }
236243 setPlaceholder ( DOM . fileListingContainer , 'Loading content...' ) ;
237244 DOM . breadcrumbs . innerHTML = '' ;
238- closeFilePreview ( false ) ; // Updated: Don't update URL yet
245+ closeFilePreview ( ) ;
239246 fetchAndDisplayContents ( '' ) ;
240247 }
241248
242249 // Fetch and display contents for a given path
243- async function fetchAndDisplayContents ( path , shouldUpdateUrl = true ) {
250+ async function fetchAndDisplayContents ( path , onLoadCallback ) {
244251 state . path = path ;
245- state . previewedFile = null ;
246- if ( shouldUpdateUrl ) {
247- updateUrl ( ) ;
248- }
249-
252+ updateUrl ( ) ;
250253 setPlaceholder ( DOM . fileListingContainer , 'Loading items...' ) ;
251254 updateBreadcrumbs ( path ) ;
252255 DOM . upDirectoryBtn . style . display = path ? 'flex' : 'none' ;
253256
254257 try {
255258 const contents = await fetchGitHubContentsWithCache ( path ) ;
256259 renderItems ( contents || [ ] ) ;
260+ if ( onLoadCallback ) {
261+ onLoadCallback ( contents || [ ] ) ;
262+ }
257263 } catch ( error ) {
258264 console . error ( '[REPO EXPLORER] GitHub API Fetch error:' , error ) ;
259265 setPlaceholder ( DOM . fileListingContainer , `Error: ${ error . message } ` , true ) ;
@@ -425,16 +431,16 @@ document.addEventListener('DOMContentLoaded', () => {
425431
426432 // Display file preview for a given file item
427433 async function displayFilePreview ( fileItem ) {
428- state . previewedFile = fileItem ;
429- updateUrl ( ) ;
430-
431434 DOM . previewFileName . textContent = fileItem . name ;
432435 setPlaceholder ( DOM . previewContent , 'Loading preview...' ) ;
433436 DOM . previewActions . innerHTML = '' ;
434437 DOM . filePreviewContainer . style . display = 'flex' ;
435438 DOM . filePreviewContainer . classList . add ( 'active' ) ;
436439 DOM . fileListingContainer . classList . add ( 'preview-open' ) ;
437440
441+ state . previewFile = fileItem . name ;
442+ updateUrl ( true ) ;
443+
438444 const jsDelivrUrl = `${ JSDELIVR_CDN_BASE } /${ state . owner } /${ state . repo } /${ fileItem . path } ` ;
439445 const extension = fileItem . name . split ( '.' ) . pop ( ) . toLowerCase ( ) ;
440446
@@ -521,26 +527,23 @@ document.addEventListener('DOMContentLoaded', () => {
521527 }
522528
523529 // Close the file preview panel
524- function closeFilePreview ( shouldUpdateUrl = true ) {
530+ function closeFilePreview ( ) {
531+ if ( ! DOM . filePreviewContainer . classList . contains ( 'active' ) ) return ;
532+
525533 DOM . filePreviewContainer . classList . remove ( 'active' ) ;
526534 DOM . fileListingContainer . classList . remove ( 'preview-open' ) ;
527535 DOM . filePreviewContainer . style . display = 'none' ;
528536 DOM . previewContent . innerHTML = '' ;
529537 DOM . previewActions . innerHTML = '' ;
530538 DOM . previewFileName . textContent = '' ;
539+
540+ state . previewFile = null ;
541+ updateUrl ( true ) ;
531542
532543 if ( state . selectedFileItemElement ) {
533544 state . selectedFileItemElement . classList . remove ( 'selected' ) ;
534545 state . selectedFileItemElement = null ;
535546 }
536-
537- // Clear preview state and update URL
538- if ( state . previewedFile ) {
539- state . previewedFile = null ;
540- if ( shouldUpdateUrl ) {
541- updateUrl ( ) ;
542- }
543- }
544547 }
545548
546549 // Navigate up one directory level
0 commit comments