MediaWiki:Minerva.js: Difference between revisions
Appearance
Created page with "→Minerva Mobile & Desktop VaniSearch Replacement: (function() { function installVaniSearch() { // 1. Mobile (Minerva header) var minervaHeader = document.querySelector('.minerva-header'); if (minervaHeader) { // Remove any invisible Minerva overlay states that block clicking/typing document.documentElement.classList.remove('overlay-enabled'); document.body.classList.remove('search-enabled', 'overlay-enab..." |
No edit summary |
||
| (7 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
/* | /* VaniSearch Popup Launcher - Desktop & Mobile */ | ||
(function() { | (function() { | ||
var lockPopupSubmitUntil = 0; | |||
var | // Override global open_modal() so even if an inline HTML attribute calls it on keydown, | ||
// it cannot focus #mspu_txt_input until after the Enter key is released. | |||
window.open_modal = function() { | |||
var ori = document.getElementById('ori_search') || document.getElementById('searchInput'); | |||
var modal = document.getElementById('mspu_div_wrapper'); | |||
var inpSearch = document.getElementById('mspu_txt_input'); | |||
var submitBtn = document.getElementById('mspu_but_submit'); | |||
if (!modal || !inpSearch) return false; | |||
lockPopupSubmitUntil = Date.now() + 500; | |||
// Temporarily disable the popup's submit button for 500ms so a held Enter key cannot trigger it | |||
if (submitBtn) { | |||
submitBtn.disabled = true; | |||
setTimeout(function() { submitBtn.disabled = false; }, 500); | |||
} | |||
if (typeof window.sync_but_search === 'function') { | |||
try { window.sync_but_search(); } catch (e) {} | |||
} | |||
if (ori) { | |||
inpSearch.value = ori.value; | |||
ori.blur(); | |||
} | |||
modal.style.display = 'block'; | |||
// Delay focusing the popup input until the Enter keystroke is completely finished | |||
setTimeout(function() { | |||
inpSearch.focus(); | |||
}, 250); | |||
return false; | |||
}; | |||
function protectModalForm() { | |||
var modal = document.getElementById('mspu_div_wrapper'); | |||
if (!modal || modal.dataset.vaniHardLocked) return; | |||
modal.dataset.vaniHardLocked = 'true'; | |||
// | // Remove any injected magnifying glass inside the popup that might have a redirect attached | ||
var | var strayBtns = modal.querySelectorAll('.vani-search-trigger-btn'); | ||
strayBtns.forEach(function(b) { b.remove(); }); | |||
var mForm = modal.querySelector('form'); | |||
if (mForm) { | |||
// Completely block form submission if the modal opened less than 500ms ago | |||
mForm.addEventListener('submit', function(e) { | |||
if ( | if (Date.now() < lockPopupSubmitUntil) { | ||
e.preventDefault(); | |||
e.stopPropagation(); | |||
e.stopImmediatePropagation(); | |||
return false; | |||
} | } | ||
}, true); | |||
} | |||
var inpSearch = document.getElementById('mspu_txt_input'); | |||
if (e.key === 'Enter' || e.keyCode === 13) { | if (inpSearch) { | ||
// Strip name="search" while locked or stop Enter propagation during the lock window | |||
['keydown', 'keypress', 'keyup'].forEach(function(evt) { | |||
inpSearch.addEventListener(evt, function(e) { | |||
if (Date.now() < lockPopupSubmitUntil && (e.key === 'Enter' || e.keyCode === 13)) { | |||
e.preventDefault(); | e.preventDefault(); | ||
e.stopPropagation(); | |||
e.stopImmediatePropagation(); | e.stopImmediatePropagation(); | ||
return false; | |||
} | } | ||
}, true); | }, true); | ||
}); | |||
} | |||
} | |||
function buildCleanSearchBox(oldElement, isMobile) { | |||
var wrap = document.createElement('div'); | |||
wrap.className = isMobile ? 'vani-mobile-search-wrap' : 'vani-desktop-search-wrap'; | |||
wrap.style.cssText = isMobile | |||
? 'flex:1 1 auto !important; display:flex !important; align-items:center !important; position:relative !important; margin:0 10px !important; z-index:999999 !important;' | |||
: 'display:flex !important; align-items:center !important; position:relative !important; width:100% !important; max-width:280px !important; z-index:999999 !important;'; | |||
var inp = document.createElement('input'); | |||
inp.type = 'text'; // Must NOT be 'search' so older Common.js selectors ignore it | |||
inp.id = 'ori_search'; | |||
// Intentionally NO inp.name = 'search' so older Common.js input[name="search"] selectors ignore it! | |||
inp.className = 'vani-clean-search-input'; | |||
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;'; | |||
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:20 !important;'; | |||
['click', 'focus', 'focusin', 'touchstart', 'input', 'keypress'].forEach(function(evtType) { | |||
inp.addEventListener(evtType, function(e) { | |||
e.stopPropagation(); | |||
}, true); | |||
}); | |||
// Swallow keydown for Enter so no document/window listener sees it | |||
inp.addEventListener('keydown', function(e) { | |||
e.stopPropagation(); | |||
if (e.key === 'Enter' || e.keyCode === 13) { | |||
e.preventDefault(); | |||
e.stopImmediatePropagation(); | |||
window.open_modal(); | |||
} | |||
}, true); | |||
btn.addEventListener('click', function(e) { | |||
e.preventDefault(); | |||
e.stopPropagation(); | |||
e.stopImmediatePropagation(); | |||
window.open_modal(); | |||
}, true); | |||
wrap.appendChild(inp); | |||
wrap.appendChild(btn); | |||
oldElement.replaceWith(wrap); | |||
} | |||
function setupAllSearchBars() { | |||
protectModalForm(); | |||
// 1. Mobile 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 mForm = minervaHeader.querySelector('form.minerva-search-form, form#searchform'); | |||
if (mForm && !minervaHeader.querySelector('.vani-mobile-search-wrap')) { | |||
buildCleanSearchBox(mForm, true); | |||
} | |||
} | |||
// 2. Desktop Header (matches wherever #searchform, #searchInput, or #ori_search currently sits, outside the modal) | |||
if (!document.querySelector('.vani-desktop-search-wrap') && !minervaHeader) { | |||
var dTarget = document.querySelector('form#searchform, #p-search form, .vector-search-box form'); | |||
if (!dTarget) { | |||
var rawInput = document.querySelector('#ori_search, #searchInput, input[type="search"]'); | |||
if (rawInput && !rawInput.closest('#mspu_div_wrapper') && !rawInput.classList.contains('vani-clean-search-input')) { | |||
dTarget = rawInput.closest('form') || rawInput.parentElement; | |||
} | |||
} | |||
if (dTarget && !dTarget.closest('#mspu_div_wrapper')) { | |||
buildCleanSearchBox(dTarget, false); | |||
} | } | ||
} | } | ||
| Line 93: | Line 161: | ||
if (document.readyState === 'loading') { | if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', | document.addEventListener('DOMContentLoaded', setupAllSearchBars); | ||
} else { | } else { | ||
setupAllSearchBars(); | |||
} | } | ||
setTimeout( | setTimeout(setupAllSearchBars, 200); | ||
setTimeout( | setTimeout(setupAllSearchBars, 700); | ||
})(); | })(); | ||
Latest revision as of 03:16, 13 November 2026
/* VaniSearch Popup Launcher - Desktop & Mobile */
(function() {
var lockPopupSubmitUntil = 0;
// Override global open_modal() so even if an inline HTML attribute calls it on keydown,
// it cannot focus #mspu_txt_input until after the Enter key is released.
window.open_modal = function() {
var ori = document.getElementById('ori_search') || document.getElementById('searchInput');
var modal = document.getElementById('mspu_div_wrapper');
var inpSearch = document.getElementById('mspu_txt_input');
var submitBtn = document.getElementById('mspu_but_submit');
if (!modal || !inpSearch) return false;
lockPopupSubmitUntil = Date.now() + 500;
// Temporarily disable the popup's submit button for 500ms so a held Enter key cannot trigger it
if (submitBtn) {
submitBtn.disabled = true;
setTimeout(function() { submitBtn.disabled = false; }, 500);
}
if (typeof window.sync_but_search === 'function') {
try { window.sync_but_search(); } catch (e) {}
}
if (ori) {
inpSearch.value = ori.value;
ori.blur();
}
modal.style.display = 'block';
// Delay focusing the popup input until the Enter keystroke is completely finished
setTimeout(function() {
inpSearch.focus();
}, 250);
return false;
};
function protectModalForm() {
var modal = document.getElementById('mspu_div_wrapper');
if (!modal || modal.dataset.vaniHardLocked) return;
modal.dataset.vaniHardLocked = 'true';
// Remove any injected magnifying glass inside the popup that might have a redirect attached
var strayBtns = modal.querySelectorAll('.vani-search-trigger-btn');
strayBtns.forEach(function(b) { b.remove(); });
var mForm = modal.querySelector('form');
if (mForm) {
// Completely block form submission if the modal opened less than 500ms ago
mForm.addEventListener('submit', function(e) {
if (Date.now() < lockPopupSubmitUntil) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
}, true);
}
var inpSearch = document.getElementById('mspu_txt_input');
if (inpSearch) {
// Strip name="search" while locked or stop Enter propagation during the lock window
['keydown', 'keypress', 'keyup'].forEach(function(evt) {
inpSearch.addEventListener(evt, function(e) {
if (Date.now() < lockPopupSubmitUntil && (e.key === 'Enter' || e.keyCode === 13)) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
}, true);
});
}
}
function buildCleanSearchBox(oldElement, isMobile) {
var wrap = document.createElement('div');
wrap.className = isMobile ? 'vani-mobile-search-wrap' : 'vani-desktop-search-wrap';
wrap.style.cssText = isMobile
? 'flex:1 1 auto !important; display:flex !important; align-items:center !important; position:relative !important; margin:0 10px !important; z-index:999999 !important;'
: 'display:flex !important; align-items:center !important; position:relative !important; width:100% !important; max-width:280px !important; z-index:999999 !important;';
var inp = document.createElement('input');
inp.type = 'text'; // Must NOT be 'search' so older Common.js selectors ignore it
inp.id = 'ori_search';
// Intentionally NO inp.name = 'search' so older Common.js input[name="search"] selectors ignore it!
inp.className = 'vani-clean-search-input';
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;';
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:20 !important;';
['click', 'focus', 'focusin', 'touchstart', 'input', 'keypress'].forEach(function(evtType) {
inp.addEventListener(evtType, function(e) {
e.stopPropagation();
}, true);
});
// Swallow keydown for Enter so no document/window listener sees it
inp.addEventListener('keydown', function(e) {
e.stopPropagation();
if (e.key === 'Enter' || e.keyCode === 13) {
e.preventDefault();
e.stopImmediatePropagation();
window.open_modal();
}
}, true);
btn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
window.open_modal();
}, true);
wrap.appendChild(inp);
wrap.appendChild(btn);
oldElement.replaceWith(wrap);
}
function setupAllSearchBars() {
protectModalForm();
// 1. Mobile 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 mForm = minervaHeader.querySelector('form.minerva-search-form, form#searchform');
if (mForm && !minervaHeader.querySelector('.vani-mobile-search-wrap')) {
buildCleanSearchBox(mForm, true);
}
}
// 2. Desktop Header (matches wherever #searchform, #searchInput, or #ori_search currently sits, outside the modal)
if (!document.querySelector('.vani-desktop-search-wrap') && !minervaHeader) {
var dTarget = document.querySelector('form#searchform, #p-search form, .vector-search-box form');
if (!dTarget) {
var rawInput = document.querySelector('#ori_search, #searchInput, input[type="search"]');
if (rawInput && !rawInput.closest('#mspu_div_wrapper') && !rawInput.classList.contains('vani-clean-search-input')) {
dTarget = rawInput.closest('form') || rawInput.parentElement;
}
}
if (dTarget && !dTarget.closest('#mspu_div_wrapper')) {
buildCleanSearchBox(dTarget, false);
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', setupAllSearchBars);
} else {
setupAllSearchBars();
}
setTimeout(setupAllSearchBars, 200);
setTimeout(setupAllSearchBars, 700);
})();