PageSourceSearch

https://www.paleophilatelie.eu/scripts/component-loader.js

js paleophilatelie.eu collected 2026-10-02 12:28:07 UTC 47,866 bytes, 779 lines download raw bytes

1/**
2 * Component Loader — CRITICAL FILE
3 *
4 * This is the SINGLE SOURCE OF TRUTH for the site header and footer HTML.
5 * The files components/header/header.html and components/footer/footer.html
6 * are reference copies ONLY — this file contains the live HTML that gets
7 * injected at runtime into every page.
8 *
9 * What this file does:
10 * 1. Injects header HTML into #header-placeholder
11 * 2. Injects footer HTML into #footer-placeholder
12 * 3. Replaces {{BASE}} placeholders with correct relative paths
13 * 4. Builds breadcrumb navigation from data-breadcrumb attribute
14 * 5. Loads Google Translate widget
15 * 6. Manages login button visibility (homepage only)
16 * 7. Shows correct footer badges (homepage vs other pages)
17 * 8. Provides NAV_HIGHLIGHT_RULES for active nav link highlighting
18 * 9. Dispatches 'componentsLoaded' event when done
19 *
20 * To modify header/footer: Edit the headerHTML/footerHTML template strings below.
21 * To add breadcrumbs to a page: Add data-breadcrumb="Label::URL|..." to #header-placeholder.
22 */
23
24(function() {
25    'use strict';
26
27    // Header HTML template
28    const headerHTML = `
29<!-- Header Component - Smithsonian Magazine Style (Black/White/Yellow) -->
30<header class="site-header" id="site-header" role="banner">
31    <!-- Slogan Strip -->
32    <div class="header-slogan">
33        <div class="container">
34            <span class="header-slogan__text">Paleophilatelie <span class="header-slogan__separator">&ndash;</span> the place where Paleontology and Paleoanthropology meet Philately</span>
35        </div>
36    </div>
37    <!-- Top Black Bar with Logo and Navigation -->
38    <div class="header-top">
39        <div class="container">
40            <div class="header-top__content">
41                <!-- Logo -->
42                <a href="{{BASE}}index.html" class="site-logo" aria-label="Paleophilatelie Home">
43                    <img src="{{BASE}}images/others/paleophilatelie-logo.png" alt="Paleophilatelie Logo" class="site-logo__image" width="70" height="88">
44                    <span class="site-logo__text">Paleophilatelie</span>
45                </a>
46
47                <!-- Main Navigation -->
48                <nav class="main-nav" id="main-nav" role="navigation" aria-label="Main navigation">
49                    <!-- Mobile Close Button -->
50                    <button class="main-nav__close" id="nav-close" aria-label="Close menu">
51                        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
52                            <path d="M18 6L6 18M6 6l12 12"/>
53                        </svg>
54                    </button>
55                    <ul class="nav-list">
56                <!-- Home -->
57                <li class="nav-item">
58                    <a href="{{BASE}}index.html" class="nav-link">Home</a>
59                </li>
60
61                <!-- Catalogue with Dropdown -->
62                <li class="nav-item has-dropdown">
63                    <a href="{{BASE}}phil_catalogue_main.html" class="nav-link">Catalogue</a>
64                    <ul class="nav-dropdown">
65                        <li><a href="{{BASE}}country/index.html" class="nav-dropdown__link">Country</a></li>
66                        <li><a href="{{BASE}}year/index.html" class="nav-dropdown__link">Date of Issue</a></li>
67
68                        <li class="has-subdropdown">
69                        <a href="{{BASE}}description/index.html" class="nav-dropdown__link">Descriptions</a>
70                              <ul class="nav-subdropdown">
71                                <li><a href="{{BASE}}description/stamps/index.html"               class="nav-subdropdown__link">Official Stamps – Primary Topics</a></li>
72                                <li><a href="{{BASE}}description/stamps/personalized/index.html"  class="nav-subdropdown__link">Personalized Stamps – Primary Topics</a></li>
73                                <li><a href="{{BASE}}description/stamps/others/index.html"        class="nav-subdropdown__link">Official Stamps – Associated Topics</a></li>
74                                <li><a href="{{BASE}}description/pm/index.html"                   class="nav-subdropdown__link">Postmarks – Primary Topics</a></li>
75                                <li><a href="{{BASE}}description/ps/others/index.html"            class="nav-subdropdown__link">Postal Stationery – Associated Topics</a></li>
76                                <li><a href="{{BASE}}description/covers/index.html"               class="nav-subdropdown__link">Commemorative Covers – Primary Topics</a></li>
77                            </ul>
78                        </li>
79
80						
81					<li class="has-subdropdown">
82                        <a href="{{BASE}}check_list.html" class="nav-dropdown__link">Check List</a>
83                              <ul class="nav-subdropdown">
84                                <li><a href="{{BASE}}images/checklist_stamps.html" class="nav-subdropdown__link">Stamps</a></li>
85                                <li><a href="{{BASE}}images/checklist_pm.html" class="nav-subdropdown__link">Postmarks</a></li>
86                            </ul>
87                        </li>
88
89                        <li><a href="{{BASE}}legend.html" class="nav-dropdown__link">Legend</a></li>
90                        <li><a href="{{BASE}}phil_glossary.html" class="nav-dropdown__link">Glossary</a></li>
91                    </ul>
92                </li>
93
94                <!-- Gallery with Dropdown -->
95                <li class="nav-item has-dropdown">
96                    <a href="{{BASE}}images/index.html" class="nav-link">Gallery</a>					
97                    <ul class="nav-dropdown">
98					
99                     <li class="has-subdropdown">
100                        <a href="{{BASE}}images/stamps_gallery.html" class="nav-dropdown__link">Postage Stamps</a>
101                              <ul class="nav-subdropdown">
102                                <li><a href="{{BASE}}images/stamps.html"             class="nav-subdropdown__link">Primary Topics</a></li>
103                                <li><a href="{{BASE}}images/stamps_others.html"      class="nav-subdropdown__link">Associated Topics</a></li>
104                                <li><a href="{{BASE}}images/stamps_used.html"        class="nav-subdropdown__link">Circulated examples – Primary Topics</a></li>
105                                <li><a href="{{BASE}}images/stamps_others_used.html" class="nav-subdropdown__link">Circulated examples – Associated Topics</a></li>
106                            </ul>
107                        </li>
108
109                     <li class="has-subdropdown">					
110                        <a href="{{BASE}}images/fdc_gallery.html" class="nav-dropdown__link">First Day Covers</a>
111                              <ul class="nav-subdropdown">
112                                <li><a href="{{BASE}}images/fdc.html"             class="nav-subdropdown__link">Primary Topics</a></li>
113                                <li><a href="{{BASE}}images/fdc_others.html"      class="nav-subdropdown__link">Associated Topics</a></li>
114                                <li><a href="{{BASE}}images/fdc_used.html"        class="nav-subdropdown__link">Circulated examples – Primary Topics</a></li>
115                                <li><a href="{{BASE}}images/fdc_others_used.html" class="nav-subdropdown__link">Circulated examples – Associated Topics</a></li>
116                            </ul>
117                        </li>
118
119
120						<li class="has-subdropdown">					
121                        <a href="{{BASE}}images/pm_gallery.html" class="nav-dropdown__link">Postmarks</a>
122                              <ul class="nav-subdropdown">
123                                <li><a href="{{BASE}}images/pm.html"             class="nav-subdropdown__link">Primary Topics</a></li>
124                                <li><a href="{{BASE}}images/pm_others.html"      class="nav-subdropdown__link">Associated Topics</a></li>
125                                <li><a href="{{BASE}}images/pm_used.html"        class="nav-subdropdown__link">Circulated examples – Primary Topics</a></li>
126                                <li><a href="{{BASE}}images/pm_others_used.html" class="nav-subdropdown__link">Circulated examples – Associated Topics</a></li>
127                            </ul>
128                        </li>
129
130
131
132						<li class="has-subdropdown">					
133	                        <a href="{{BASE}}images/ps_gallery.html" class="nav-dropdown__link">Postal Stationeries</a>
134
135                              <ul class="nav-subdropdown">
136                                <li><a href="{{BASE}}images/ps.html"             class="nav-subdropdown__link">Primary Topics</a></li>
137                                <li><a href="{{BASE}}images/ps_others.html"      class="nav-subdropdown__link">Associated Topics</a></li>
138                                <li><a href="{{BASE}}images/ps_used.html"        class="nav-subdropdown__link">Circulated examples – Primary Topics</a></li>
139                                <li><a href="{{BASE}}images/ps_others_used.html" class="nav-subdropdown__link">Circulated examples – Associated Topics</a></li>
140                            </ul>
141                        </li>
142
143
144                        <li><a href="{{BASE}}exhibitions/index.html" class="nav-dropdown__link">Exhibits</a></li>
145                    </ul>
146                </li>
147
148                <!-- Topics with Dropdown -->
149                <li class="nav-item has-dropdown">
150                    <a href="{{BASE}}topics/index.html" class="nav-link">Topics</a>
151                    <ul class="nav-dropdown">
152                        <li class="has-subdropdown">
153                            <a href="{{BASE}}topics/paleo/index.html" class="nav-dropdown__link">Paleontology</a>
154                            <ul class="nav-subdropdown">
155                                <li><a href="{{BASE}}topics/paleo/paleontologist.html" class="nav-subdropdown__link">Paleontologists</a></li>
156                                <li><a href="{{BASE}}topics/paleo/contributors.html" class="nav-subdropdown__link">Contributors</a></li>
157                                <li><a href="{{BASE}}topics/paleo/museums.html" class="nav-subdropdown__link">Museums</a></li>
158                                <li><a href="{{BASE}}topics/paleo/sites.html" class="nav-subdropdown__link">Fossil Sites</a></li>
159                                <li><a href="{{BASE}}topics/paleo/vertebrate/index.html" class="nav-subdropdown__link">Vertebrate</a></li>
160                            </ul>
161                        </li>
162                        <li class="has-subdropdown">
163                            <a href="{{BASE}}topics/anthro/index.html" class="nav-dropdown__link">Paleoanthropology</a>
164                            <ul class="nav-subdropdown">
165                                <li><a href="{{BASE}}topics/anthro/antropologist.html" class="nav-subdropdown__link">Paleoanthropologists</a></li>
166                                <li><a href="{{BASE}}topics/anthro/contributors.html" class="nav-subdropdown__link">Contributors</a></li>
167                                <li><a href="{{BASE}}topics/anthro/museums.html" class="nav-subdropdown__link">Museums</a></li>
168                                <li><a href="{{BASE}}topics/anthro/sites.html" class="nav-subdropdown__link">Fossil Sites</a></li>
169                            </ul>
170                        </li>
171                    </ul>
172                </li>
173
174
175
176                <li class="nav-item has-dropdown">
177                    <a href="{{BASE}}articles/index.html" class="nav-link">Resources</a>
178                    <ul class="nav-dropdown">
179                        <li><a href="{{BASE}}articles/index.html" class="nav-dropdown__link">Articles</a></li>
180						<li><a href="{{BASE}}description/letters/index.html" class="nav-dropdown__link">Letters</a></li>
181
182                        <li><a href="{{BASE}}media/books.html" class="nav-dropdown__link">Books</a></li>
183                        <li><a href="{{BASE}}media/paleoart.html" class="nav-dropdown__link">Paleoart</a></li>
184                        <li><a href="{{BASE}}media/videos.html" class="nav-dropdown__link">Videos</a></li>
185                        <li class="has-subdropdown">
186                            <a href="{{BASE}}links.html" class="nav-dropdown__link">Links</a>
187                            <ul class="nav-subdropdown">
188                                <li><a href="{{BASE}}links_paleo.html"            class="nav-dropdown__link">Paleontology</a></li>
189                                <li><a href="{{BASE}}links.html"                  class="nav-dropdown__link">Philately</a></li>
190                                <li><a href="{{BASE}}links_postal_resources.html" class="nav-dropdown__link">Postal Resources</a></li>
191                                <li><a href="{{BASE}}links_forums.html"           class="nav-dropdown__link">Forums</a></li>
192                            </ul>
193                        </li>
194                     </ul>
195                </li>
196
197
198                <!-- About with Dropdown -->
199                <li class="nav-item has-dropdown">
200                    <a href="{{BASE}}about_website.html" class="nav-link">About</a>
201                    <ul class="nav-dropdown">
202                        <li><a href="{{BASE}}about.html" class="nav-dropdown__link">About Author</a></li>
203                        <li><a href="{{BASE}}about_website.html" class="nav-dropdown__link">About Website</a></li>
204                        <li><a href="{{BASE}}awards.html" class="nav-dropdown__link">Website's Awards</a></li>
205                        <li><a href="{{BASE}}news.html" class="nav-dropdown__link">Website's News</a></li>
206                        <li><a href="{{BASE}}about_how-to-help.html" class="nav-dropdown__link">How to Help</a></li>
207                        <li><a href="{{BASE}}contact.html" class="nav-dropdown__link">Contact</a></li>
208                        <li><a href="{{BASE}}sitemap.html" class="nav-dropdown__link">Sitemap</a></li>
209                    </ul>
210                </li>
211
212                <!-- MK Private Area with Dropdown (only shown inside /mk/) -->
213                <li class="nav-item has-dropdown nav-item--mk">
214                    <a href="{{BASE}}mk/index.html" class="nav-link">Private</a>
215                    <ul class="nav-dropdown">
216                        <li><a href="{{BASE}}mk/dealers.html" class="nav-dropdown__link">Dealers</a></li>
217                        <li><a href="{{BASE}}mk/keywords_persons.html" class="nav-dropdown__link">Keywords</a></li>
218                        <li><a href="{{BASE}}mk/wishlist.html" class="nav-dropdown__link">Wishlist</a></li>
219                        <li><a href="{{BASE}}mk/my_links.html" class="nav-dropdown__link">My Links</a></li>
220                        <li><a href="{{BASE}}mk/publications.html" class="nav-dropdown__link">Publications</a></li>
221                    </ul>
222                </li>
223
224                <!-- Login (homepage only) -->
225                <li class="nav-item nav-item--login">
226                    <a href="{{BASE}}mk/index.html" class="nav-link">Login</a>
227                </li>
228            </ul>
229        </nav>
230
231                <!-- Mobile Menu Toggle -->
232                <button class="menu-toggle" id="menu-toggle" aria-label="Toggle navigation menu" aria-expanded="false">
233                    <span class="menu-toggle__bar"></span>
234                    <span class="menu-toggle__bar"></span>
235                    <span class="menu-toggle__bar"></span>
236                </button>
237            </div>
238        </div>
239    </div>
240
241    <!-- Second Bar: Google Translate and FreeFind Search -->
242    <div class="header-toolbar">
243        <div class="container">
244            <div class="header-toolbar__content">
245                <!-- Left column: Translate -->
246                <div class="header-toolbar__left">
247                    <div id="google_translate_element"></div>
248                </div>
249
250                <!-- Right column: Search Form -->
251                <div class="header-search-wrapper">
252                    <form action="https://search.freefind.com/find.html" method="get" accept-charset="UTF-8" class="header-search-form">
253                        <input type="hidden" name="si" value="14323397">
254                        <input type="hidden" name="pid" value="r">
255                        <input type="text" name="query" class="header-search-input" placeholder="Search stamps, countries, years..." aria-label="Search" autocomplete="off">
256                        <button type="submit" class="header-search-button" aria-label="Search">
257                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
258                                <circle cx="11" cy="11" r="8"></circle>
259                                <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
260                            </svg>
261                        </button>
262                    </form>
263                    <div class="header-search-links">
264                        <a href="https://www.freefind.com/searchtipspop.html" target="_blank" rel="noopener noreferrer" class="header-search-links__item">search tips</a>
265                        <span class="header-search-credit"><a href="https://www.freefind.com" target="_blank" rel="noopener noreferrer">search engine</a> by <a href="https://www.freefind.com" target="_blank" rel="noopener noreferrer">freefind</a></span>
266                        <a href="https://search.freefind.com/find.html?si=14323397&amp;pid=a" class="header-search-links__item">advanced search</a>
267                    </div>
268                </div>
269
270                <!-- Sticky Toggle -->
271                <label class="toolbar-sticky-toggle" title="Pin toolbar to top">
272                    <input type="checkbox" id="toolbar-sticky-checkbox">
273                    <span class="toolbar-sticky-toggle__pin">
274                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
275                            <path d="M16 3a1 1 0 0 1 .117 1.993L16 5h-.39l-1.45 4.36A3.5 3.5 0 0 1 16 12.5V14h-3v7l-1 1-1-1v-7H8v-1.5a3.5 3.5 0 0 1 1.84-3.14L8.39 5H8a1 1 0 0 1-.117-1.993L8 3h8z"/>
276                        </svg>
277                    </span>
278                </label>
279            </div>
280            <div id="header-breadcrumb-slot"></div>
281        </div>
282    </div>
283
284    <!-- Search Overlay -->
285    <div class="search-overlay" id="search-overlay">
286        <div class="search-overlay-content">
287            <form action="https://search.freefind.com/find.html" method="get" accept-charset="UTF-8">
288                <input type="hidden" name="si" value="14323397">
289                <input type="hidden" name="pid" value="r">
290                <input type="text" name="query" class="search-overlay-input" placeholder="Search stamps, countries, years..." aria-label="Search" autocomplete="off">
291            </form>
292        </div>
293        <button class="search-overlay-close" id="search-close" aria-label="Close search">&times;</button>
294    </div>
295</header>
296`;
297
298    // Footer HTML template
299    const footerHTML = `
300<!-- Site Footer Component -->
301<footer class="site-footer" id="site-footer">
302    <!-- Main Footer -->
303    <div class="footer-main">
304        <div class="container">
305            <div class="footer-grid">
306                <!-- About Column -->
307                <div class="footer-col footer-col--about">
308                    <a href="{{BASE}}index.html" class="footer-logo">
309                        <img src="{{BASE}}images/others/paleophilatelie-logo.png" alt="Paleophilatelie" class="footer-logo__image" width="70" height="88">
310                        <span class="footer-logo__text">Paleophilatelie<span class="footer-logo__tld">.eu</span></span>
311                    </a>
312                    <p class="footer-about">
313                        The place where Paleontology and Paleoanthropology meets Philately.
314                        Explore the world's most comprehensive collection of prehistoric life on stamps.
315                    </p>
316                    <div class="footer-social">
317                        <a href="mailto:[email protected]" class="footer-social__link" aria-label="Email">
318                            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
319                                <path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
320                            </svg>
321                        </a>
322                        <a href="https://x.com/PaleoPhilatelis" class="footer-social__link" aria-label="Follow us on X" target="_blank" rel="noopener noreferrer">
323                            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
324                                <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
325                            </svg>
326                        </a>
327                    </div>
328                    <div class="footer-badges footer-badges--other">
329                        <a href="{{BASE}}images/others/qrcode_www.paleophilatelie.eu.png">
330                            <img src="{{BASE}}images/others/qrcode_www.paleophilatelie.eu.png"
331                                 alt="QR code of PaleoPhilatelie.eu website"
332                                 class="footer-badges__img"
333                                 loading="lazy">
334                        </a>
335                        <a href="{{BASE}}images/others/logo_qr_code_fb.png"  rel="noopener noreferrer">
336                            <img src="{{BASE}}images/others/logo_qr_code_fb.png"
337                                 alt="QR code of Paleophilately Facebook group"
338                                 class="footer-badges__img"
339                                 loading="lazy">
340                        </a>
341                    </div>
342                    <div class="footer-badges footer-badges--facebook">
343                        <a href="https://www.facebook.com/groups/889825297731726/" target="_blank" rel="noopener noreferrer">
344                            <img src="{{BASE}}images/others/facebook.jpg"
345                                 alt="PaleoPhilatelie.eu on Facebook - Welcome to join !"
346                                 title="PaleoPhilatelie.eu on Facebook - Welcome to join !"
347                                 class="footer-badges__img footer-badges__img--facebook"
348                                 loading="lazy">
349                        </a>
350                    </div>
351                   <!-- 
352                    <div class="footer-badges footer-badges--homepage">
353                        <a href="https://www.pwmo.org/" target="_blank" rel="noopener noreferrer">
354                            <img src="{{BASE}}images/others/pwo-logo.gif" 
355                                 alt="Philatelic Webmasters Organization"
356                                 class="footer-badges__img_pwo"
357                                 loading="lazy">
358                        </a>                        
359                    </div>
360                    -->
361                </div>
362
363                <!-- Catalogue Column -->
364                <div class="footer-col">
365                    <h3 class="footer-col__title">Catalogue</h3>
366                    <ul class="footer-links">
367                        <li><a href="{{BASE}}country/index.html">Country</a></li>
368                        <li><a href="{{BASE}}year/index.html">Year</a></li>
369                        <li><a href="{{BASE}}images/checklist_stamps.html">Checklist</a></li>
370                        <li><a href="{{BASE}}description/index.html">Descriptions</a></li>
371
372                    <!-- 
373                    </ul>
374                    <h4 class="footer-col__subtitle"><a href="{{BASE}}description/index.html">Descriptions</a></h4>
375                        <ul class="footer-links footer-links--nested">
376                            <li><a href="{{BASE}}description/stamps/index.html" >Official Stamps – Primary Topics</a></li>
377                            <li><a href="{{BASE}}description/stamps/personalized/index.html" >Personalized Stamps – Primary Topics</a></li>
378                            <li><a href="{{BASE}}description/stamps/others/index.html" >Official Stamps – Associated Topics:</a></li>
379                            <li><a href="{{BASE}}description/pm/index.html" >Postmarks – Primary Topics</a></li>
380                            <li><a href="{{BASE}}description/ps/others/index.html" >Postal Stationery – Associated Topics</a></li>
381                            <li><a href="{{BASE}}description/covers/index.html" >Commemorative Covers – Primary Topics</a></li>
382                        </ul>
383                     <ul class="footer-links">
384                    --> 
385                    
386                        <li><a href="{{BASE}}legend.html">Legend</a></li>
387                        <li><a href="{{BASE}}phil_glossary.html">Glossary</a></li>
388                    </ul>
389                </div>
390
391                <!-- Gallery Column -->
392                <div class="footer-col">
393                    <h3 class="footer-col__title">Gallery</h3>
394                    <ul class="footer-links">
395                        <li><a href="{{BASE}}images/stamps_gallery.html">Stamps</a></li>
396                        <li><a href="{{BASE}}images/ps.html">Postal Stationeries</a></li>
397                        <li><a href="{{BASE}}images/fdc.html">FDC</a></li>
398                        <li><a href="{{BASE}}images/pm.html">Postmarks</a></li>
399                        <li><a href="{{BASE}}exhibitions/index.html">Exhibits</a></li>
400                    </ul>
401                </div>
402
403                <!-- Topics Column -->
404                <div class="footer-col">
405                    <h3 class="footer-col__title">Topics</h3>
406                    <h4 class="footer-col__subtitle"><a href="{{BASE}}topics/paleo/index.html">Paleontology</a></h4>
407                    <ul class="footer-links footer-links--nested">
408                        <li><a href="{{BASE}}topics/paleo/paleontologist.html">Paleontologists</a></li>
409                        <li><a href="{{BASE}}topics/paleo/contributors.html">Contributors</a></li>
410                        <li><a href="{{BASE}}topics/paleo/museums.html">Museums</a></li>
411                        <li><a href="{{BASE}}topics/paleo/sites.html">Fossil Sites</a></li>
412                        <li><a href="{{BASE}}topics/paleo/vertebrate/index.html">Vertebrate</a></li>
413                    </ul>
414                    <h4 class="footer-col__subtitle"><a href="{{BASE}}topics/anthro/index.html">Paleoanthropology</a></h4>
415                    <ul class="footer-links footer-links--nested">
416                        <li><a href="{{BASE}}topics/anthro/antropologist.html">Paleoanthropologists</a></li>
417                        <li><a href="{{BASE}}topics/anthro/contributors.html">Contributors</a></li>
418                        <li><a href="{{BASE}}topics/anthro/museums.html">Museums</a></li>
419                        <li><a href="{{BASE}}topics/anthro/sites.html">Fossil Sites</a></li>
420                    </ul>
421                </div>
422
423                <!-- Resources Column -->
424                <div class="footer-col">
425                    <h3 class="footer-col__title">Resources</h3>
426                    <ul class="footer-links">
427                        <li><a href="{{BASE}}articles/index.html">Articles</a></li>
428                        <li><a href="{{BASE}}media/books.html">Books</a></li>
429                        <li><a href="{{BASE}}media/paleoart.html">Paleoart</a></li>
430                        <li><a href="{{BASE}}media/videos.html">Videos</a></li>
431                    </u>
432
433                    <h4 class="footer-col__subtitle"><a href="{{BASE}}links.html">Links</a></h4>
434                    <ul class="footer-links footer-links--nested">
435                        <li><a href="{{BASE}}links_paleo.html">Paleontology</a></li>
436                        <li><a href="{{BASE}}links.html">Philately</a></li>
437                        <li><a href="{{BASE}}links_postal_resources.html">Postal Resources</a></li>
438                        <li><a href="{{BASE}}links_forums.html">Forums</a></li>
439                    </ul>
440                </div>
441
442                <!-- About Column -->
443                <div class="footer-col">
444                    <h3 class="footer-col__title">About</h3>
445                    <ul class="footer-links">
446                        <li><a href="{{BASE}}about_website.html">Website</a></li>
447                        <li><a href="{{BASE}}about.html">Author</a></li>
448                        <li><a href="{{BASE}}awards.html">Awards</a></li>
449                        <li><a href="{{BASE}}news.html">News</a></li>
450                        <li><a href="{{BASE}}about_how-to-help.html">How to Help</a></li>
451                        <li><a href="{{BASE}}contact.html">Contact</a></li>
452                        <li><a href="{{BASE}}sitemap.html">Sitemap</a></li>
453                    </ul>
454                </div>
455            </div>
456        </div>
457    </div>
458
459    <!-- Footer Bottom -->
460    <div class="footer-bottom">
461        <div class="container">
462            <div class="footer-bottom__content">
463                <p class="footer-copyright">
464                    &copy; 2010&ndash;<span id="currentYear"></span> Paleophilatelie. All rights reserved. Contact for any issue: <a href="mailto:[email protected]">[email protected]</a>
465                </p>
466                <div class="footer-bottom__links">
467                    <a href="{{BASE}}sitemap.html">Sitemap</a>
468                    <span class="footer-bottom__divider">|</span>
469                    <a href="{{BASE}}legend.html">Legend</a>
470                    <span class="footer-bottom__divider">|</span>
471                    <a href="{{BASE}}phil_glossary.html">Glossary</a>
472                </div>
473            </div>
474            <p class="footer-developer">
475                Designed &amp; Developed by <a href="https://softechinfra.com" target="_blank" rel="noopener noreferrer">SoftechInfra</a>
476            </p>
477        </div>
478    </div>
479
480    <!-- Back to Top Button -->
481    <button class="back-to-top" id="back-to-top" aria-label="Back to top">
482        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
483            <path d="M18 15l-6-6-6 6"/>
484        </svg>
485    </button>
486</footer>
487`;
488
489    // ===== Centralized Navigation Highlighting Config =====
490    // Each rule maps a page (by exact path or prefix) to the nav hrefs that should be highlighted.
491    // nav array: [top-level href, dropdown href, subdropdown href] — only include what applies.
492    // Exact paths are checked before prefixes (order matters within each type).
493    window.NAV_HIGHLIGHT_RULES = [
494        // HOME
495        { path: "index.html", nav: ["index.html"] },
496
497        // CATALOGUE (top-level href: phil_catalogue_main.html)
498        { path: "phil_catalogue_main.html",   nav: ["phil_catalogue_main.html"] },
499        { path: "phil_catalogue_framed.html", nav: ["phil_catalogue_main.html"] },
500        { path: "phil_catalogue_trends.html", nav: ["phil_catalogue_main.html", "phil_catalogue_trends.html"] },
501        
502		{ path: "checklist.html",               nav: ["phil_catalogue_main.html", "check_list.html"] },
503        { path: "images/checklist_stamps.html", nav: ["phil_catalogue_main.html", "check_list.html", "images/checklist_stamps.html"] },
504        { path: "images/checklist_pm.html",     nav: ["phil_catalogue_main.html", "check_list.html", "images/checklist_pm.html"] },
505        
506		{ path: "legend.html", nav: ["phil_catalogue_main.html", "legend.html"] },
507        { path: "phil_glossary.html", nav: ["phil_catalogue_main.html", "phil_glossary.html"] },
508        { prefix: "country/", nav: ["phil_catalogue_main.html", "country/index.html"] },
509        { prefix: "year/", nav: ["phil_catalogue_main.html", "year/index.html"] },
510		
511        { path:   "description/index.html",           nav: ["phil_catalogue_main.html", "description/index.html"] },
512        { prefix: "description/stamps/personalized/", nav: ["phil_catalogue_main.html", "description/index.html", "description/stamps/personalized/index.html"] },
513        { prefix: "description/stamps/others/",       nav: ["phil_catalogue_main.html", "description/index.html", "description/stamps/others/index.html"] },
514        { prefix: "description/stamps/",              nav: ["phil_catalogue_main.html", "description/index.html", "description/stamps/index.html"] },
515        { prefix: "description/pm/",                  nav: ["phil_catalogue_main.html", "description/index.html", "description/pm/index.html"] },
516        { prefix: "description/ps/",                  nav: ["phil_catalogue_main.html", "description/index.html", "description/ps/others/index.html"] },
517        { prefix: "description/covers/",              nav: ["phil_catalogue_main.html", "description/index.html", "description/covers/index.html"] },
518
519        // GALLERY (top-level href: images/index.html)
520        { path: "images/index.html", nav: ["images/index.html"] },
521		
522       //   { path: "images/stamps_gallery.html", nav: ["images/stamps_gallery.html"] },
523			{ prefix: "images/stamps_gallery.html",               nav: ["images/index.html", "images/stamps_gallery.html"] },
524	   
525			{ prefix: "images/stamps.html",               nav: ["images/index.html", "images/stamps_gallery.html", "images/stamps.html"] },
526			{ prefix: "images/stamps_used.html",          nav: ["images/index.html", "images/stamps_gallery.html", "images/stamps_used.html"] },
527			{ prefix: "images/stamps_others.html",        nav: ["images/index.html", "images/stamps_gallery.html", "images/stamps_others.html"] },
528			{ prefix: "images/stamps_others_used.html",   nav: ["images/index.html", "images/stamps_gallery.html", "images/stamps_others_used.html"] },
529			
530			{ prefix: "images/ps.html",             nav: ["images/index.html",  "images/ps_gallery.html", "images/ps.html"] },
531			{ prefix: "images/ps_used.html",        nav: ["images/index.html",  "images/ps_gallery.html", "images/ps_used.html"] },
532			{ prefix: "images/ps_others.html",      nav: ["images/index.html",  "images/ps_gallery.html", "images/ps_others.html"] },
533			{ prefix: "images/ps_others_used.html", nav: ["images/index.html",  "images/ps_gallery.html", "images/ps_others_used.html"] },
534
535			{ prefix: "images/fdc_gallery.html",               nav: ["images/index.html", "images/fdc_gallery.html"] },
536				{ prefix: "images/fdc.html",             nav: ["images/index.html", "images/fdc_gallery.html", "images/fdc.html"] },
537				{ prefix: "images/fdc_used.html",        nav: ["images/index.html", "images/fdc_gallery.html", "images/fdc_used.html"] },
538				{ prefix: "images/fdc_others.html",      nav: ["images/index.html", "images/fdc_gallery.html", "images/fdc_others.html"] },
539				{ prefix: "images/fdc_others_used.html", nav: ["images/index.html", "images/fdc_gallery.html", "images/fdc_others_used.html"] },
540			
541			
542			{ prefix: "images/pm.html",              nav: ["images/index.html", "images/pm_gallery.html", "images/pm.html"] },
543			{ prefix: "images/pm_used.html",         nav: ["images/index.html", "images/pm_gallery.html", "images/pm_used.html"] },
544			{ prefix: "images/pm_others.html",       nav: ["images/index.html", "images/pm_gallery.html", "images/pm_others.html"] },
545			{ prefix: "images/pm_others_used.html",  nav: ["images/index.html", "images/pm_gallery.html", "images/pm_others_used.html"] },
546			
547			{ prefix: "exhibitions/", nav: ["images/index.html", "exhibitions/index.html"] },
548
549        // TOPICS > PALEONTOLOGY
550        { path: "topics/index.html",                nav: ["topics/index.html"] },
551        { path: "topics/paleo/index.html",          nav: ["topics/index.html", "topics/paleo/index.html"] },
552        { path: "topics/paleo/paleontologist.html", nav: ["topics/index.html", "topics/paleo/index.html", "topics/paleo/paleontologist.html"] },
553        { path: "topics/paleo/contributors.html",   nav: ["topics/index.html", "topics/paleo/index.html", "topics/paleo/contributors.html"] },
554        { path: "topics/paleo/museums.html",        nav: ["topics/index.html", "topics/paleo/index.html", "topics/paleo/museums.html"] },
555        { path: "topics/paleo/sites.html",          nav: ["topics/index.html", "topics/paleo/index.html", "topics/paleo/sites.html"] },
556        { prefix: "topics/paleo/vertebrate/",       nav: ["topics/index.html", "topics/paleo/index.html", "topics/paleo/vertebrate/index.html"] },
557        { prefix: "topics/paleo/",                  nav: ["topics/index.html", "topics/paleo/index.html"] },
558
559        // TOPICS > PALEOANTHROPOLOGY
560        { path: "topics/anthro/index.html", nav: ["topics/index.html", "topics/anthro/index.html"] },
561        { path: "topics/anthro/antropologist.html", nav: ["topics/index.html", "topics/anthro/index.html", "topics/anthro/antropologist.html"] },
562        { path: "topics/anthro/contributors.html", nav: ["topics/index.html", "topics/anthro/index.html", "topics/anthro/contributors.html"] },
563        { path: "topics/anthro/museums.html", nav: ["topics/index.html", "topics/anthro/index.html", "topics/anthro/museums.html"] },
564        { path: "topics/anthro/sites.html", nav: ["topics/index.html", "topics/anthro/index.html", "topics/anthro/sites.html"] },
565        { prefix: "topics/anthro/", nav: ["topics/index.html", "topics/anthro/index.html"] },
566
567        // RESOURCES (top-level href: articles/index.html)
568        { prefix: "articles/", nav: ["articles/index.html"] },
569        { path: "links_paleo.html", nav: ["articles/index.html", "links_paleo.html"] },
570		
571		{ prefix: "description/letters/", nav: ["articles/index.html", "description/letters/index.html"] },
572
573        { path: "links.html", nav: ["articles/index.html", "links.html"] },
574        { path: "links_postal_resources.html", nav: ["articles/index.html", "links_postal_resources.html"] },
575        { path: "links_forums.html", nav: ["articles/index.html", "links_forums.html"] },
576        { path: "media/books.html", nav: ["articles/index.html", "media/books.html"] },
577        { path: "media/paleoart.html", nav: ["articles/index.html", "media/paleoart.html"] },
578        { path: "media/videos.html", nav: ["articles/index.html", "media/videos.html"] },
579        { prefix: "media/", nav: ["articles/index.html"] },
580
581        // ABOUT (top-level href: about_website.html)
582        { path: "about_website.html", nav: ["about_website.html"] },
583        { path: "about.html", nav: ["about_website.html", "about.html"] },
584        { path: "news.html", nav: ["about_website.html", "news.html"] },
585        { path: "news_archive.html", nav: ["about_website.html", "news.html"] },
586        { path: "awards.html", nav: ["about_website.html", "awards.html"] },
587        { path: "contact.html", nav: ["contact.html"] },
588        { path: "sitemap.html", nav: ["sitemap.html"] },
589        { path: "paleophilatelie_site_map.html", nav: ["sitemap.html"] },
590        { path: "about_how-to-help.html", nav: ["about_website.html", "about_how-to-help.html"] },
591
592        // LOGIN
593        { prefix: "mk/", nav: ["mk/index.html"] },
594    ];
595
596    // Get the site-root-relative path of the current page (e.g.
597    // "country/afghanistan.html"). The folder depth is taken from getBasePath()
598    // (the number of "../" steps back to the site root), so the last N URL
599    // segments give the path relative to root. Works on a server and on a local
600    // file:// copy, and needs no list of folder names.
601    window.getSiteRelativePath = function() {
602        var depth = (getBasePath().match(/\.\.\//g) || []).length;
603        var pathname = window.location.pathname.replace(/\\/g, '/');
604        var segs = pathname.split('/').filter(Boolean);
605        return segs.slice(segs.length - (depth + 1)).join('/') || 'index.html';
606    };
607
608    // Find the matching highlight rule for the current page
609    window.getNavHighlightRule = function() {
610        var pagePath = window.getSiteRelativePath().toLowerCase();
611        var rules = window.NAV_HIGHLIGHT_RULES;
612        // Exact path matches first
613        for (var i = 0; i < rules.length; i++) {
614            if (rules[i].path && pagePath === rules[i].path.toLowerCase()) {
615                return rules[i];
616            }
617        }
618        // Prefix matches second
619        for (var i = 0; i < rules.length; i++) {
620            if (rules[i].prefix && pagePath.indexOf(rules[i].prefix.toLowerCase()) === 0) {
621                return rules[i];
622            }
623        }
624        return null;
625    };
626
627    // Determine the base path for {{BASE}} links.
628    // Derive it from THIS script's own <script src="..."> value. Every page
629    // already references the loader with the correct relative depth
630    // (e.g. "scripts/...", "../scripts/...", "../../scripts/..."), so whatever
631    // comes before "scripts/component-loader.js" is exactly the relative path
632    // back to the site root. This means:
633    //   • Works on a live web server AND on a local file:// copy (relative links).
634    //   • Needs NO hardcoded list of folder names — new subdirectories, at any
635    //     depth, work automatically.
636    function getBasePath() {
637        var scripts = document.getElementsByTagName('script');
638        for (var i = 0; i < scripts.length; i++) {
639            var src = scripts[i].getAttribute('src') || '';
640            var m = src.match(/^(.*?)scripts\/component-loader\.js(?:[?#].*)?$/);
641            if (m) {
642                return m[1]; // '', '../', '../../', etc.
643            }
644        }
645        return '';
646    }
647
648    // Replace base path placeholders in HTML
649    function applyBasePath(html, basePath) {
650        return html.replace(/\{\{BASE\}\}/g, basePath);
651    }
652
653    // Load header component
654    function loadHeader(basePath) {
655        const element = document.getElementById('header-placeholder');
656        if (!element) return;
657
658        element.innerHTML = applyBasePath(headerHTML, basePath);
659
660        // Show login button only on the root homepage
661        const pageName = window.location.pathname.replace(/\\/g, '/').split('/').pop();
662        // Root homepage = an index page with no subfolder in its site-relative path
663        const siteRel = window.getSiteRelativePath();
664        const isHomepage = (pageName === 'index.html' || pageName === 'index.htm' || pageName === '') && siteRel.indexOf('/') === -1;
665        const loginItem = element.querySelector('.nav-item--login');
666        if (loginItem && !isHomepage) {
667            loginItem.style.display = 'none';
668        }
669
670        // Show the MK private-area menu only inside the /mk/ section
671        const isMkArea = siteRel.toLowerCase().indexOf('mk/') === 0;
672        const mkItem = element.querySelector('.nav-item--mk');
673        if (mkItem && !isMkArea) {
674            mkItem.style.display = 'none';
675        }
676
677        // Build breadcrumb from data attribute
678        var breadcrumbData = element.getAttribute('data-breadcrumb');
679        var slot = element.querySelector('#header-breadcrumb-slot');
680        if (breadcrumbData && slot) {
681            var items = breadcrumbData.split('|');
682            // Filter out any existing "Sitemap" entry — we auto-prepend it
683            items = items.filter(function(item) {
684                return item.split('::')[0].trim().toLowerCase() !== 'sitemap';
685            });
686            var lis = items.map(function(item) {
687                var parts = item.split('::');
688                var label = parts[0];
689                var url = parts[1];
690                if (url) {
691                    return '<li class="breadcrumb__item"><a href="' + url + '" class="breadcrumb__link">' + label + '</a></li>';
692                }
693                return '<li class="breadcrumb__item"><span class="breadcrumb__current">' + label + '</span></li>';
694            }).join('');
695            var sitemapLink = '<a href="' + basePath + 'sitemap.html" class="breadcrumb__sitemap-link">Sitemap</a>:\u00a0 ';
696            slot.innerHTML = '<nav class="breadcrumb" aria-label="Breadcrumb">' + sitemapLink + '<ol class="breadcrumb__list">' + lis + '</ol></nav>';
697        }
698    }
699
700    // Load footer component
701    function loadFooter(basePath) {
702        const element = document.getElementById('footer-placeholder');
703        if (!element) return;
704
705        element.innerHTML = applyBasePath(footerHTML, basePath);
706
707        // Detect homepage and show the appropriate footer badges
708        const path = window.location.pathname;
709        const isHomepage = path === '/' || path.endsWith('/index.html') || path.endsWith('/index.htm') || path === '';
710        const homepageBadges = element.querySelector('.footer-badges--homepage');
711        const otherBadges = element.querySelector('.footer-badges--other');
712
713        if (homepageBadges && otherBadges) {
714            if (isHomepage) {
715                otherBadges.style.display = 'none';
716            } else {
717                homepageBadges.style.display = 'none';
718            }
719        }
720    }
721
722    // Load Google Translate script
723    function loadGoogleTranslate() {
724        // Define the callback function globally
725        window.googleTranslateElementInit = function() {
726            new google.translate.TranslateElement({
727                pageLanguage: 'en',
728                layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL
729            }, 'google_translate_element');
730        };
731
732        // Load the script (use https explicitly for file:// protocol compatibility)
733        const script = document.createElement('script');
734        script.src = 'https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit';
735        script.async = true;
736        document.body.appendChild(script);
737    }
738
739    // Main initialization
740    function init() {
741        // Suppress Chrome's built-in translate bar (site has its own translate widget)
742        if (!document.querySelector('meta[name="google"][content="notranslate"]')) {
743            const meta = document.createElement('meta');
744            meta.name = 'google';
745            meta.content = 'notranslate';
746            document.head.appendChild(meta);
747        }
748
749        // Skip header/footer when loaded inside an iframe (e.g. 3-panel navigator)
750        const isInIframe = window !== window.top;
751
752        const basePath = getBasePath();
753
754        // Load components (skip if inside iframe to avoid double header/footer)
755        if (!isInIframe) {
756            loadHeader(basePath);
757            loadFooter(basePath);
758
759            // Load Google Translate after header is loaded
760            loadGoogleTranslate();
761
762            // Update copyright year
763            const yearSpan = document.getElementById('currentYear');
764            if (yearSpan) {
765                yearSpan.textContent = new Date().getFullYear();
766            }
767        }
768
769        // Dispatch event to notify other scripts that components are loaded
770        document.dispatchEvent(new CustomEvent('componentsLoaded'));
771    }
772
773    // Run when DOM is ready
774    if (document.readyState === 'loading') {
775        document.addEventListener('DOMContentLoaded', init);
776    } else {
777        init();
778    }
779})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.