@@ -99,6 +99,40 @@ function appJSONLoadedHandler() {
9999 } ) ;
100100}
101101
102+ /**
103+ * Extract an app name from a /apps/appname path
104+ * - assumes app names cannot contain periods
105+ * - assumes apps cannot be named "apps"
106+ * - assumes we're in or including the "apps" folder in the href
107+ * Returns the app name string or null if not an app folder.
108+ */
109+ function extractAppNameFromHref ( href ) {
110+ if ( ! href ) return null ;
111+
112+ try {
113+ const u = new URL ( href , window . location . href ) ;
114+ href = u . pathname ;
115+ } catch ( e ) {
116+ // ignore - just use href as-is
117+ }
118+ // very unlikely, but get rid of query/hash
119+ href = href . split ( '?' ) [ 0 ] . split ( '#' ) [ 0 ] . trim ( ) ;
120+ // remove leading/trailing slashes
121+ href = href . replace ( / ^ \/ + | \/ + $ / g, '' ) ;
122+ if ( ! href ) return null ; // was just /, throw it out
123+
124+ const parts = href . split ( '/' ) . filter ( Boolean ) ;
125+ if ( parts . length === 0 ) return null ;
126+ // allow './apps/appname' or './appname' by dropping leading '.' segments
127+ while ( parts . length && parts [ 0 ] === '.' ) parts . shift ( ) ;
128+ if ( parts . length === 0 ) return null ; // skip if it was current dir only
129+ if ( parts [ 0 ] === '..' ) return null ; // skip parent redirect
130+ if ( parts [ 0 ] . toLowerCase ( ) === 'apps' ) parts . shift ( ) ; // skip over apps folder
131+ if ( parts . length === 0 ) return null ;
132+ if ( parts [ 0 ] . includes ( '.' ) ) return null ;
133+ return parts [ 0 ] ;
134+ }
135+
102136httpGet ( Const . APPS_JSON_FILE ) . then ( apps => {
103137 if ( apps . startsWith ( "---" ) ) {
104138 showToast ( Const . APPS_JSON_FILE + " still contains Jekyll markup" , "warning" ) ;
@@ -127,8 +161,12 @@ httpGet(Const.APPS_JSON_FILE).then(apps=>{
127161 let promises = [ ] ;
128162 htmlToArray ( xmlDoc . querySelectorAll ( "a" ) ) . forEach ( a => {
129163 let href = a . getAttribute ( "href" ) ;
130- if ( ! href || href . startsWith ( "/" ) || href . startsWith ( "_" ) || ! href . endsWith ( "/" ) ) return ;
131- let metadataURL = appsURL + "/" + href + "metadata.json" ;
164+ const appName = extractAppNameFromHref ( href ) ;
165+ // Skip anything that doesn't look like an app or is an _example_app
166+ if ( ! appName || appName . startsWith ( "_" ) ) {
167+ return ;
168+ }
169+ let metadataURL = appsURL + appName + "/metadata.json" ;
132170 console . log ( " - Loading " + metadataURL ) ;
133171 promises . push ( httpGet ( metadataURL ) . then ( metadataText => {
134172 try {
0 commit comments