1+ const themeFlyoutDisplay = "hidden" ;
2+ const themeVersionSelector = true ;
3+ const themeLanguageSelector = true ;
4+
5+ if ( themeFlyoutDisplay === "attached" ) {
6+ function renderLanguages ( config ) {
7+ if ( ! config . projects . translations . length ) {
8+ return "" ;
9+ }
10+
11+ // Insert the current language to the options on the selector
12+ let languages = config . projects . translations . concat ( config . projects . current ) ;
13+ languages = languages . sort ( ( a , b ) => a . language . name . localeCompare ( b . language . name ) ) ;
14+
15+ const languagesHTML = `
16+ <dl>
17+ <dt>Languages</dt>
18+ ${ languages
19+ . map (
20+ ( translation ) => `
21+ <dd ${ translation . slug == config . projects . current . slug ? 'class="rtd-current-item"' : "" } >
22+ <a href="${ translation . urls . documentation } ">${ translation . language . code } </a>
23+ </dd>
24+ ` ,
25+ )
26+ . join ( "\n" ) }
27+ </dl>
28+ ` ;
29+ return languagesHTML ;
30+ }
31+
32+ function renderVersions ( config ) {
33+ if ( ! config . versions . active . length ) {
34+ return "" ;
35+ }
36+ const versionsHTML = `
37+ <dl>
38+ <dt>Versions</dt>
39+ ${ config . versions . active
40+ . map (
41+ ( version ) => `
42+ <dd ${ version . slug === config . versions . current . slug ? 'class="rtd-current-item"' : "" } >
43+ <a href="${ version . urls . documentation } ">${ version . slug } </a>
44+ </dd>
45+ ` ,
46+ )
47+ . join ( "\n" ) }
48+ </dl>
49+ ` ;
50+ return versionsHTML ;
51+ }
52+
53+ function renderDownloads ( config ) {
54+ if ( ! Object . keys ( config . versions . current . downloads ) . length ) {
55+ return "" ;
56+ }
57+ const downloadsNameDisplay = {
58+ pdf : "PDF" ,
59+ epub : "Epub" ,
60+ htmlzip : "HTML" ,
61+ } ;
62+
63+ const downloadsHTML = `
64+ <dl>
65+ <dt>Downloads</dt>
66+ ${ Object . entries ( config . versions . current . downloads )
67+ . map (
68+ ( [ name , url ] ) => `
69+ <dd>
70+ <a href="${ url } ">${ downloadsNameDisplay [ name ] } </a>
71+ </dd>
72+ ` ,
73+ )
74+ . join ( "\n" ) }
75+ </dl>
76+ ` ;
77+ return downloadsHTML ;
78+ }
79+
80+ document . addEventListener ( "readthedocs-addons-data-ready" , function ( event ) {
81+ const config = event . detail . data ( ) ;
82+
83+ const flyout = `
84+ <div class="rst-versions" data-toggle="rst-versions" role="note">
85+ <span class="rst-current-version" data-toggle="rst-current-version">
86+ <span class="fa fa-book"> Read the Docs</span>
87+ v: ${ config . versions . current . slug }
88+ <span class="fa fa-caret-down"></span>
89+ </span>
90+ <div class="rst-other-versions">
91+ <div class="injected">
92+ ${ renderLanguages ( config ) }
93+ ${ renderVersions ( config ) }
94+ ${ renderDownloads ( config ) }
95+ <dl>
96+ <dt>On Read the Docs</dt>
97+ <dd>
98+ <a href="${ config . projects . current . urls . home } ">Project Home</a>
99+ </dd>
100+ <dd>
101+ <a href="${ config . projects . current . urls . builds } ">Builds</a>
102+ </dd>
103+ <dd>
104+ <a href="${ config . projects . current . urls . downloads } ">Downloads</a>
105+ </dd>
106+ </dl>
107+ <dl>
108+ <dt>Search</dt>
109+ <dd>
110+ <form id="flyout-search-form">
111+ <input
112+ class="wy-form"
113+ type="text"
114+ name="q"
115+ aria-label="Search docs"
116+ placeholder="Search docs"
117+ />
118+ </form>
119+ </dd>
120+ </dl>
121+ <hr />
122+ <small>
123+ <span>Hosted by <a href="https://about.readthedocs.org/?utm_source=&utm_content=flyout">Read the Docs</a></span>
124+ </small>
125+ </div>
126+ </div>
127+ ` ;
128+
129+ // Inject the generated flyout into the body HTML element.
130+ document . body . insertAdjacentHTML ( "beforeend" , flyout ) ;
131+
132+ // Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout.
133+ document
134+ . querySelector ( "#flyout-search-form" )
135+ . addEventListener ( "focusin" , ( ) => {
136+ const event = new CustomEvent ( "readthedocs-search-show" ) ;
137+ document . dispatchEvent ( event ) ;
138+ } ) ;
139+ } )
140+ }
141+
142+ if ( themeLanguageSelector || themeVersionSelector ) {
143+ function onSelectorSwitch ( event ) {
144+ const option = event . target . selectedIndex ;
145+ const item = event . target . options [ option ] ;
146+ window . location . href = item . dataset . url ;
147+ }
148+
149+ document . addEventListener ( "readthedocs-addons-data-ready" , function ( event ) {
150+ const config = event . detail . data ( ) ;
151+
152+ const versionSwitch = document . querySelector (
153+ "div.switch-menus > div.version-switch" ,
154+ ) ;
155+ if ( themeVersionSelector ) {
156+ let versions = config . versions . active ;
157+ if ( config . versions . current . hidden || config . versions . current . type === "external" ) {
158+ versions . unshift ( config . versions . current ) ;
159+ }
160+ const versionSelect = `
161+ <select>
162+ ${ versions
163+ . map (
164+ ( version ) => `
165+ <option
166+ value="${ version . slug } "
167+ ${ config . versions . current . slug === version . slug ? 'selected="selected"' : "" }
168+ data-url="${ version . urls . documentation } ">
169+ ${ version . slug }
170+ </option>` ,
171+ )
172+ . join ( "\n" ) }
173+ </select>
174+ ` ;
175+
176+ versionSwitch . innerHTML = versionSelect ;
177+ versionSwitch . firstElementChild . addEventListener ( "change" , onSelectorSwitch ) ;
178+ }
179+
180+ const languageSwitch = document . querySelector (
181+ "div.switch-menus > div.language-switch" ,
182+ ) ;
183+
184+ if ( themeLanguageSelector ) {
185+ if ( config . projects . translations . length ) {
186+ // Add the current language to the options on the selector
187+ let languages = config . projects . translations . concat (
188+ config . projects . current ,
189+ ) ;
190+ languages = languages . sort ( ( a , b ) =>
191+ a . language . name . localeCompare ( b . language . name ) ,
192+ ) ;
193+
194+ const languageSelect = `
195+ <select>
196+ ${ languages
197+ . map (
198+ ( language ) => `
199+ <option
200+ value="${ language . language . code } "
201+ ${ config . projects . current . slug === language . slug ? 'selected="selected"' : "" }
202+ data-url="${ language . urls . documentation } ">
203+ ${ language . language . name }
204+ </option>` ,
205+ )
206+ . join ( "\n" ) }
207+ </select>
208+ ` ;
209+
210+ languageSwitch . innerHTML = languageSelect ;
211+ languageSwitch . firstElementChild . addEventListener ( "change" , onSelectorSwitch ) ;
212+ }
213+ else {
214+ languageSwitch . remove ( ) ;
215+ }
216+ }
217+ } ) ;
218+ }
219+
220+ document . addEventListener ( "readthedocs-addons-data-ready" , function ( event ) {
221+ // Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav.
222+ document
223+ . querySelector ( "[role='search'] input" )
224+ . addEventListener ( "focusin" , ( ) => {
225+ const event = new CustomEvent ( "readthedocs-search-show" ) ;
226+ document . dispatchEvent ( event ) ;
227+ } ) ;
228+ } ) ;
0 commit comments