Jump to content

MediaWiki:Minerva.js: Difference between revisions

From Vanipedia
Kashya (talk | contribs)
No edit summary
Kashya (talk | contribs)
No edit summary
Line 1: Line 1:
/* Mobile and Desktop VaniSearch Popup Launcher */
/* Mobile and Desktop VaniSearch Popup Handler */
(function() {
(function() {
     function triggerVaniSearchPopup(queryText) {
     function openVaniPopupFromInput(inputEl) {
         // 1. If the VaniSearch extension provides a global popup function on the page, call it
        if (!inputEl) return;
        inputEl.focus();
 
         // 1. If the extension exposes a direct JS function, call it
         if (typeof window.openVaniSearch === 'function') {
         if (typeof window.openVaniSearch === 'function') {
             window.openVaniSearch(queryText);
             window.openVaniSearch(inputEl.value.trim());
             return;
             return;
         }
         }
         if (typeof window.VaniSearch === 'object' && typeof window.VaniSearch.open === 'function') {
         if (typeof window.VaniSearch === 'object' && typeof window.VaniSearch.open === 'function') {
             window.VaniSearch.open(queryText);
             window.VaniSearch.open(inputEl.value.trim());
            return;
        }
 
        // 2. If there is a hidden popup/modal element already in the DOM, open it and fill the input
        var modal = document.querySelector('#vani-search-modal, #vanisearch-popup, .vani-search-modal, .vanisearch-overlay');
        if (modal) {
            modal.style.display = 'flex';
            modal.classList.add('is-open', 'active', 'visible');
            var modalInput = modal.querySelector('input[type="text"], input[type="search"]');
            if (modalInput) {
                modalInput.value = queryText || '';
                modalInput.focus();
            }
             return;
             return;
         }
         }


         // 3. Otherwise, open the Special:VaniSearch extension page first (without forcing immediate results)
         // 2. Otherwise, fire the synthetic Enter events that the extension listens for
         // Stores the typed word in sessionStorage so Special:VaniSearch can pre-fill its input box
         ['keydown', 'keypress', 'keyup'].forEach(function(evtType) {
        if (queryText) {
             var ev = new KeyboardEvent(evtType, {
            try { sessionStorage.setItem('vani_pending_query', queryText); } catch (e) {}
                 key: 'Enter',
        }
                 code: 'Enter',
        window.location.href = '/wiki/Special:VaniSearch';
                keyCode: 13,
    }
                which: 13,
 
                bubbles: true,
    // If we just landed on Special:VaniSearch, pre-fill the extension's input box with the word the user typed
                cancelable: true
    if (window.location.pathname.indexOf('Special:VaniSearch') !== -1) {
            });
        window.addEventListener('DOMContentLoaded', function() {
             inputEl.dispatchEvent(ev);
             try {
                 var pending = sessionStorage.getItem('vani_pending_query');
                 if (pending) {
                    sessionStorage.removeItem('vani_pending_query');
                    setTimeout(function() {
                        var extInput = document.querySelector('#content input[type="text"], #content input[type="search"], .vanisearch-input');
                        if (extInput) {
                            extInput.value = pending;
                            extInput.focus();
                            extInput.dispatchEvent(new Event('input', { bubbles: true }));
                        }
                    }, 150);
                }
             } catch (e) {}
         });
         });
     }
     }
Line 64: Line 40:


             var f = minervaHeader.querySelector('.minerva-search-form');
             var f = minervaHeader.querySelector('.minerva-search-form');
             if (f && !document.getElementById('vani-mobile-search-input')) {
             if (f && !minervaHeader.querySelector('.vani-mobile-search-wrap')) {
                 var d = document.createElement('div');
                 var d = document.createElement('div');
                 d.className = 'vani-mobile-search-wrap';
                 d.className = 'vani-mobile-search-wrap';
Line 70: Line 46:


                 var inp = document.createElement('input');
                 var inp = document.createElement('input');
                 inp.type = 'text';
                 inp.type = 'search';
                 inp.id = 'vani-mobile-search-input';
                // Use standard #searchInput ID so the VaniSearch extension's popup script binds to it on mobile too
                 inp.id = 'searchInput';
                 inp.name = 'search';
                 inp.name = 'search';
                inp.className = 'vani-clean-search-input mw-searchInput';
                 inp.placeholder = 'Search Vanipedia';
                 inp.placeholder = 'Search Vanipedia';
                 inp.autocomplete = 'off';
                 inp.autocomplete = 'off';
                 inp.style.cssText = 'width:100% !important; height:32px !important; background:#1f3e45 !important; color:#ffffff !important; -webkit-text-fill-color:#ffffff !important; border:1.5px solid #f5d77f !important; border-radius:16px !important; padding:2px 32px 2px 12px !important; font-size:15px !important; outline:none !important; box-sizing:border-box !important; pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important;';
                 inp.style.cssText = 'width:100% !important; height:32px !important; background:#1f3e45 !important; background-image:none !important; color:#ffffff !important; -webkit-text-fill-color:#ffffff !important; border:1.5px solid #f5d77f !important; border-radius:16px !important; padding:2px 32px 2px 12px !important; font-size:15px !important; outline:none !important; box-sizing:border-box !important; pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important;';


                 var btn = document.createElement('button');
                 var btn = document.createElement('button');
                 btn.type = 'button';
                 btn.type = 'button';
                btn.className = 'vani-inline-go';
                 btn.innerHTML = '🔍';
                 btn.innerHTML = '🔍';
                 btn.style.cssText = 'position:absolute !important; right:8px !important; top:50% !important; transform:translateY(-50%) !important; background:none !important; border:none !important; font-size:15px !important; cursor:pointer !important; padding:0 !important; line-height:1 !important; z-index:10 !important; pointer-events:auto !important;';
                 btn.style.cssText = 'position:absolute !important; right:8px !important; top:50% !important; transform:translateY(-50%) !important; background:none !important; border:none !important; font-size:15px !important; cursor:pointer !important; padding:0 !important; line-height:1 !important; z-index:10 !important; pointer-events:auto !important;';


                 var go = function(e) {
                 // Block Minerva from hijacking focus/clicks, but let Enter bubble to the VaniSearch extension
                     if (e) { e.preventDefault(); e.stopPropagation(); }
                ['click', 'focus', 'focusin', 'touchstart', 'input'].forEach(function(evtType) {
                     triggerVaniSearchPopup(inp.value.trim());
                     inp.addEventListener(evtType, function(e) {
                 };
                        e.stopPropagation();
                     }, false);
                 });


                 btn.addEventListener('click', go, true);
                 btn.addEventListener('click', function(e) {
                inp.addEventListener('keydown', function(e) {
                    e.preventDefault();
                     e.stopPropagation();
                     e.stopPropagation();
                     if (e.key === 'Enter' || e.keyCode === 13) go(e);
                     openVaniPopupFromInput(inp);
                 }, true);
                 }, true);


Line 99: Line 80:
         }
         }


         // 2. Desktop (Vector header): Add right-side 🔍 icon without blocking extension's native Enter listener
         // 2. Desktop (Vector header): Prevent native form submit from navigating away after popup opens
         var desktopForm = document.querySelector('#p-search form, form#searchform');
         var desktopForm = document.querySelector('#p-search form, form#searchform');
         if (desktopForm && !desktopForm.classList.contains('minerva-search-form') && !desktopForm.dataset.vaniBound) {
         if (desktopForm && !desktopForm.classList.contains('minerva-search-form') && !desktopForm.dataset.vaniBound) {
             desktopForm.dataset.vaniBound = 'true';
             desktopForm.dataset.vaniBound = 'true';
            // Stop the form from navigating away to a results page when Enter is pressed
            desktopForm.addEventListener('submit', function(e) {
                e.preventDefault();
                e.stopPropagation();
                return false;
            }, true);


             var dInput = desktopForm.querySelector('input[type="search"], input[name="search"], #searchInput');
             var dInput = desktopForm.querySelector('input[type="search"], input[name="search"], #searchInput');
             if (dInput) {
             if (dInput) {
                 dInput.setAttribute('autocomplete', 'off');
                 dInput.setAttribute('autocomplete', 'off');
                // Prevent browser default form submit on Enter while allowing the event to reach the extension popup listener
                dInput.addEventListener('keydown', function(e) {
                    if (e.key === 'Enter' || e.keyCode === 13) {
                        e.preventDefault();
                    }
                }, false);
                 var wrap = dInput.parentElement;
                 var wrap = dInput.parentElement;
                 if (wrap && !wrap.querySelector('.vani-inline-go')) {
                 if (wrap && !wrap.querySelector('.vani-inline-go')) {
Line 117: Line 113:
                     dBtn.addEventListener('click', function(e) {
                     dBtn.addEventListener('click', function(e) {
                         e.preventDefault();
                         e.preventDefault();
                         // Dispatch an Enter keypress on the desktop input so the extension's native popup listener fires
                         e.stopPropagation();
                        var enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true, cancelable: true });
                         openVaniPopupFromInput(dInput);
                         dInput.dispatchEvent(enterEvent);
                     });
                     });
                     wrap.appendChild(dBtn);
                     wrap.appendChild(dBtn);

Revision as of 02:42, 13 November 2026

/* Mobile and Desktop VaniSearch Popup Handler */
(function() {
    function openVaniPopupFromInput(inputEl) {
        if (!inputEl) return;
        inputEl.focus();

        // 1. If the extension exposes a direct JS function, call it
        if (typeof window.openVaniSearch === 'function') {
            window.openVaniSearch(inputEl.value.trim());
            return;
        }
        if (typeof window.VaniSearch === 'object' && typeof window.VaniSearch.open === 'function') {
            window.VaniSearch.open(inputEl.value.trim());
            return;
        }

        // 2. Otherwise, fire the synthetic Enter events that the extension listens for
        ['keydown', 'keypress', 'keyup'].forEach(function(evtType) {
            var ev = new KeyboardEvent(evtType, {
                key: 'Enter',
                code: 'Enter',
                keyCode: 13,
                which: 13,
                bubbles: true,
                cancelable: true
            });
            inputEl.dispatchEvent(ev);
        });
    }

    function installVaniSearch() {
        // 1. Mobile (Minerva header)
        var minervaHeader = document.querySelector('.minerva-header');
        if (minervaHeader) {
            document.documentElement.classList.remove('overlay-enabled');
            document.body.classList.remove('search-enabled', 'overlay-enabled');

            var b = minervaHeader.querySelector('.branding-box');
            if (b) b.style.setProperty('display', 'none', 'important');

            var f = minervaHeader.querySelector('.minerva-search-form');
            if (f && !minervaHeader.querySelector('.vani-mobile-search-wrap')) {
                var d = document.createElement('div');
                d.className = 'vani-mobile-search-wrap';
                d.style.cssText = 'flex:1 1 auto !important; display:flex !important; align-items:center !important; position:relative !important; margin:0 10px !important; z-index:999999 !important; pointer-events:auto !important;';

                var inp = document.createElement('input');
                inp.type = 'search';
                // Use standard #searchInput ID so the VaniSearch extension's popup script binds to it on mobile too
                inp.id = 'searchInput';
                inp.name = 'search';
                inp.className = 'vani-clean-search-input mw-searchInput';
                inp.placeholder = 'Search Vanipedia';
                inp.autocomplete = 'off';
                inp.style.cssText = 'width:100% !important; height:32px !important; background:#1f3e45 !important; background-image:none !important; color:#ffffff !important; -webkit-text-fill-color:#ffffff !important; border:1.5px solid #f5d77f !important; border-radius:16px !important; padding:2px 32px 2px 12px !important; font-size:15px !important; outline:none !important; box-sizing:border-box !important; pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important;';

                var btn = document.createElement('button');
                btn.type = 'button';
                btn.className = 'vani-inline-go';
                btn.innerHTML = '🔍';
                btn.style.cssText = 'position:absolute !important; right:8px !important; top:50% !important; transform:translateY(-50%) !important; background:none !important; border:none !important; font-size:15px !important; cursor:pointer !important; padding:0 !important; line-height:1 !important; z-index:10 !important; pointer-events:auto !important;';

                // Block Minerva from hijacking focus/clicks, but let Enter bubble to the VaniSearch extension
                ['click', 'focus', 'focusin', 'touchstart', 'input'].forEach(function(evtType) {
                    inp.addEventListener(evtType, function(e) {
                        e.stopPropagation();
                    }, false);
                });

                btn.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    openVaniPopupFromInput(inp);
                }, true);

                d.appendChild(inp);
                d.appendChild(btn);
                f.replaceWith(d);
            }
        }

        // 2. Desktop (Vector header): Prevent native form submit from navigating away after popup opens
        var desktopForm = document.querySelector('#p-search form, form#searchform');
        if (desktopForm && !desktopForm.classList.contains('minerva-search-form') && !desktopForm.dataset.vaniBound) {
            desktopForm.dataset.vaniBound = 'true';

            // Stop the form from navigating away to a results page when Enter is pressed
            desktopForm.addEventListener('submit', function(e) {
                e.preventDefault();
                e.stopPropagation();
                return false;
            }, true);

            var dInput = desktopForm.querySelector('input[type="search"], input[name="search"], #searchInput');
            if (dInput) {
                dInput.setAttribute('autocomplete', 'off');

                // Prevent browser default form submit on Enter while allowing the event to reach the extension popup listener
                dInput.addEventListener('keydown', function(e) {
                    if (e.key === 'Enter' || e.keyCode === 13) {
                        e.preventDefault();
                    }
                }, false);

                var wrap = dInput.parentElement;
                if (wrap && !wrap.querySelector('.vani-inline-go')) {
                    wrap.style.position = 'relative';
                    var dBtn = document.createElement('button');
                    dBtn.type = 'button';
                    dBtn.className = 'vani-inline-go';
                    dBtn.innerHTML = '🔍';
                    dBtn.style.cssText = 'position:absolute !important; right:8px !important; top:50% !important; transform:translateY(-50%) !important; background:none !important; border:none !important; font-size:15px !important; cursor:pointer !important; padding:0 !important; line-height:1 !important; z-index:20 !important;';
                    dBtn.addEventListener('click', function(e) {
                        e.preventDefault();
                        e.stopPropagation();
                        openVaniPopupFromInput(dInput);
                    });
                    wrap.appendChild(dBtn);
                }
            }
        }
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', installVaniSearch);
    } else {
        installVaniSearch();
    }
    setTimeout(installVaniSearch, 250);
    setTimeout(installVaniSearch, 800);
})();