4242margin-bottom : 20px ;
4343}
4444
45- input [ type = "text" ] {
45+ . input-wrapper {
4646flex : 1 ;
47+ position : relative;
48+ }
49+
50+ .autocomplete-dropdown {
51+ position : absolute;
52+ top : 100% ;
53+ left : 0 ;
54+ right : 0 ;
55+ background : white;
56+ border : 2px solid # 0066cc ;
57+ border-top : none;
58+ border-radius : 0 0 8px 8px ;
59+ max-height : 300px ;
60+ overflow-y : auto;
61+ z-index : 100 ;
62+ display : none;
63+ box-shadow : 0 4px 12px rgba (0 , 0 , 0 , 0.15 );
64+ }
65+
66+ .autocomplete-dropdown .visible {
67+ display : block;
68+ }
69+
70+ .autocomplete-item {
71+ padding : 10px 16px ;
72+ cursor : pointer;
73+ border-bottom : 1px solid # eee ;
74+ font-size : 14px ;
75+ color : # 333 ;
76+ }
77+
78+ .autocomplete-item : last-child {
79+ border-bottom : none;
80+ }
81+
82+ .autocomplete-item : hover ,
83+ .autocomplete-item .selected {
84+ background : # f0f7ff ;
85+ }
86+
87+ .autocomplete-item .page-ns {
88+ color : # 666 ;
89+ font-size : 12px ;
90+ margin-left : 8px ;
91+ }
92+
93+ @media (max-width : 500px ) {
94+ .input-group {
95+ flex-direction : column;
96+ }
97+
98+ button {
99+ width : 100% ;
100+ }
101+ }
102+
103+ input [type = "text" ] {
104+ width : 100% ;
47105padding : 12px 16px ;
48106font-size : 16px ;
49107font-family : Helvetica, Arial, sans-serif;
170228< body >
171229 < div class ="container ">
172230 < h1 > Wikipedia wikitext fetcherh1 >
173- < p class ="subtitle "> Paste a Wikipedia URL to fetch its raw wikitext sourcep >
231+ < p class ="subtitle "> Search for a Wikipedia article or paste a URL to fetch its raw wikitext sourcep >
174232
175233< div class ="input-group ">
176- < input type ="text " id ="urlInput " placeholder ="https://en.wikipedia.org/wiki/Albert_Einstein ">
234+ < div class ="input-wrapper ">
235+ < input type ="text " id ="urlInput " placeholder ="Search Wikipedia or paste a URL... " autocomplete ="off ">
236+ < div class ="autocomplete-dropdown " id ="autocompleteDropdown "> div >
237+ div >
177238 < button id ="fetchBtn "> Fetch wikitextbutton >
178239div >
179240
@@ -204,6 +265,123 @@
Wikipedia wikitext fetcher 204265const pageTitle = document . getElementById ( 'pageTitle' ) ;
205266const wikitextOutput = document . getElementById ( 'wikitextOutput' ) ;
206267const copyBtn = document . getElementById ( 'copyBtn' ) ;
268+ const autocompleteDropdown = document . getElementById ( 'autocompleteDropdown' ) ;
269+
270+ let debounceTimer = null ;
271+ let selectedIndex = - 1 ;
272+ let currentSuggestions = [ ] ;
273+
274+ function isUrl ( text ) {
275+ return text . startsWith ( 'http://' ) || text . startsWith ( 'https://' ) || text . includes ( 'wikipedia.org' ) ;
276+ }
277+
278+ async function fetchSuggestions ( query ) {
279+ if ( ! query || query . length < 2 || isUrl ( query ) ) {
280+ hideAutocomplete ( ) ;
281+ return ;
282+ }
283+
284+ try {
285+ const apiUrl = `https://en.wikipedia.org/w/api.php?action=query&list=prefixsearch&pssearch=${ encodeURIComponent ( query ) } &pslimit=10&format=json&origin=*` ;
286+ const response = await fetch ( apiUrl ) ;
287+ const data = await response . json ( ) ;
288+
289+ if ( data . query && data . query . prefixsearch ) {
290+ currentSuggestions = data . query . prefixsearch ;
291+ showSuggestions ( currentSuggestions ) ;
292+ } else {
293+ hideAutocomplete ( ) ;
294+ }
295+ } catch ( err ) {
296+ hideAutocomplete ( ) ;
297+ }
298+ }
299+
300+ function showSuggestions ( suggestions ) {
301+ if ( suggestions . length === 0 ) {
302+ hideAutocomplete ( ) ;
303+ return ;
304+ }
305+
306+ selectedIndex = - 1 ;
307+ autocompleteDropdown . innerHTML = suggestions . map ( ( item , index ) =>
308+ 309+ ) . join ( '' ) ;
310+ autocompleteDropdown . classList . add ( 'visible' ) ;
311+ }
312+
313+ function hideAutocomplete ( ) {
314+ autocompleteDropdown . classList . remove ( 'visible' ) ;
315+ autocompleteDropdown . innerHTML = '' ;
316+ selectedIndex = - 1 ;
317+ currentSuggestions = [ ] ;
318+ }
319+
320+ function selectSuggestion ( title ) {
321+ const wikiUrl = `https://en.wikipedia.org/wiki/${ encodeURIComponent ( title . replace ( / / g, '_' ) ) } ` ;
322+ urlInput . value = wikiUrl ;
323+ hideAutocomplete ( ) ;
324+ fetchWikitext ( ) ;
325+ }
326+
327+ function updateSelection ( ) {
328+ const items = autocompleteDropdown . querySelectorAll ( '.autocomplete-item' ) ;
329+ items . forEach ( ( item , index ) => {
330+ item . classList . toggle ( 'selected' , index === selectedIndex ) ;
331+ } ) ;
332+ if ( selectedIndex >= 0 && items [ selectedIndex ] ) {
333+ items [ selectedIndex ] . scrollIntoView ( { block : 'nearest' } ) ;
334+ }
335+ }
336+
337+ urlInput . addEventListener ( 'input' , ( ) => {
338+ clearTimeout ( debounceTimer ) ;
339+ const query = urlInput . value . trim ( ) ;
340+
341+ debounceTimer = setTimeout ( ( ) => {
342+ fetchSuggestions ( query ) ;
343+ } , 200 ) ;
344+ } ) ;
345+
346+ urlInput . addEventListener ( 'keydown' , ( e ) => {
347+ const items = autocompleteDropdown . querySelectorAll ( '.autocomplete-item' ) ;
348+
349+ if ( ! autocompleteDropdown . classList . contains ( 'visible' ) ) {
350+ return ;
351+ }
352+
353+ if ( e . key === 'ArrowDown' ) {
354+ e . preventDefault ( ) ;
355+ selectedIndex = Math . min ( selectedIndex + 1 , items . length - 1 ) ;
356+ updateSelection ( ) ;
357+ } else if ( e . key === 'ArrowUp' ) {
358+ e . preventDefault ( ) ;
359+ selectedIndex = Math . max ( selectedIndex - 1 , - 1 ) ;
360+ updateSelection ( ) ;
361+ } else if ( e . key === 'Enter' && selectedIndex >= 0 ) {
362+ e . preventDefault ( ) ;
363+ const title = currentSuggestions [ selectedIndex ] ?. title ;
364+ if ( title ) {
365+ selectSuggestion ( title ) ;
366+ }
367+ } else if ( e . key === 'Escape' ) {
368+ hideAutocomplete ( ) ;
369+ }
370+ } ) ;
371+
372+ autocompleteDropdown . addEventListener ( 'click' , ( e ) => {
373+ const item = e . target . closest ( '.autocomplete-item' ) ;
374+ if ( item ) {
375+ const title = item . dataset . title ;
376+ selectSuggestion ( title ) ;
377+ }
378+ } ) ;
379+
380+ document . addEventListener ( 'click' , ( e ) => {
381+ if ( ! e . target . closest ( '.input-wrapper' ) ) {
382+ hideAutocomplete ( ) ;
383+ }
384+ } ) ;
207385
208386function extractPageName ( url ) {
209387 try {
0 commit comments