Diferencia entre revisiones de «MediaWiki:Common.js»
Apariencia
Página reemplazada por «→Cualquier código JavaScript escrito aquí se cargará para todos los usuarios en cada carga de página: » Etiqueta: Reemplazo |
Sin resumen de edición |
||
| (No se muestran 8 ediciones intermedias del mismo usuario) | |||
| Línea 1: | Línea 1: | ||
/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios en cada carga de página */ | /* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios en cada carga de página */ | ||
// Este script resalta y permite navegar entre términos de búsqueda en el artículo destino | |||
(function() { | |||
// Variables globales para el seguimiento de la navegación | |||
var currentHighlightIndex = -1; // Índice del resaltado actual | |||
var highlightElements = []; // Array de todos los elementos resaltados | |||
/** | |||
* Verifica si llegamos desde una búsqueda | |||
* @returns {boolean} true si venimos de una búsqueda | |||
*/ | |||
function isComingFromSearch() { | |||
var referrer = document.referrer; | |||
return referrer.includes('Special:Search') || | |||
referrer.includes('title=Special:Search') || | |||
referrer.includes('search=') || | |||
referrer.includes('Special:Buscar') || | |||
document.location.search.includes('highlight='); | |||
} | |||
/** | |||
* Obtiene los términos de búsqueda del referrer o parámetros de URL | |||
* @returns {Array} Array de términos de búsqueda | |||
*/ | |||
function getSearchTerms() { | |||
// Intenta obtener términos del parámetro highlight (usado por MediaWiki) | |||
var urlParams = new URLSearchParams(window.location.search); | |||
var highlight = urlParams.get('highlight'); | |||
if (highlight) { | |||
return [highlight]; | |||
} | |||
// Si no hay highlight, intenta obtener del referrer | |||
var referrer = document.referrer; | |||
if (!referrer) return []; | |||
var referrerUrl = new URL(referrer); | |||
var search = referrerUrl.searchParams.get('search') || | |||
referrerUrl.searchParams.get('query'); | |||
if (!search) return []; | |||
// Limpia espacios extras y trata toda la búsqueda como un solo término | |||
search = search.trim(); | |||
return [search]; | |||
} | |||
/** | |||
* Crea y agrega los controles de navegación en la página | |||
*/ | |||
function createNavigationControls() { | |||
var nav = document.createElement('div'); | |||
nav.className = 'search-navigation'; | |||
nav.innerHTML = [ | |||
'<div class="search-nav-controls">', | |||
'<button id="prevMatch">↑ Anterior</button>', | |||
'<span id="matchCounter">0 de 0</span>', | |||
'<button id="nextMatch">↓ Siguiente</button>', | |||
'</div>' | |||
].join(''); | |||
document.body.appendChild(nav); | |||
// Estilos CSS para los controles de navegación | |||
var style = document.createElement('style'); | |||
style.textContent = [ | |||
'.search-navigation {', | |||
'position: fixed;', | |||
'bottom: 20px;', | |||
'right: 20px;', | |||
'z-index: 1000;', | |||
'}', | |||
'.search-nav-controls {', | |||
'background: white;', | |||
'padding: 10px;', | |||
'border-radius: 8px;', | |||
'box-shadow: 0 2px 10px rgba(0,0,0,0.1);', | |||
'display: flex;', | |||
'gap: 10px;', | |||
'align-items: center;', | |||
'}', | |||
'.search-nav-controls button {', | |||
'padding: 5px 10px;', | |||
'border: 1px solid #ccc;', | |||
'border-radius: 4px;', | |||
'background: #f0f0f0;', | |||
'cursor: pointer;', | |||
'}', | |||
'.search-nav-controls button:hover {', | |||
'background: #e0e0e0;', | |||
'}', | |||
'.searchmatch {', | |||
'background-color: #ffeb3b;', | |||
'padding: 2px;', | |||
'border-radius: 2px;', | |||
'}', | |||
'.searchmatch.current {', | |||
'background-color: #ffa000;', | |||
'color: white;', | |||
'}' | |||
].join('\n'); | |||
document.head.appendChild(style); | |||
// Agregar listeners para los botones de navegación | |||
document.getElementById('prevMatch').addEventListener('click', navigateToPrevious); | |||
document.getElementById('nextMatch').addEventListener('click', navigateToNext); | |||
} | |||
/** | |||
* Actualiza el contador de coincidencias | |||
*/ | |||
function updateMatchCounter() { | |||
var counter = document.getElementById('matchCounter'); | |||
if (counter && highlightElements.length > 0) { | |||
counter.textContent = (currentHighlightIndex + 1) + ' de ' + highlightElements.length; | |||
} | |||
} | |||
/** | |||
* Navega a una coincidencia específica | |||
* @param {number} index - Índice de la coincidencia | |||
*/ | |||
function navigateToMatch(index) { | |||
if (highlightElements.length === 0) return; | |||
// Quita el resaltado especial del elemento actual | |||
if (currentHighlightIndex >= 0) { | |||
highlightElements[currentHighlightIndex].classList.remove('current'); | |||
} | |||
// Maneja el ciclo de navegación | |||
currentHighlightIndex = index; | |||
if (currentHighlightIndex >= highlightElements.length) { | |||
currentHighlightIndex = 0; | |||
} | |||
if (currentHighlightIndex < 0) { | |||
currentHighlightIndex = highlightElements.length - 1; | |||
} | |||
// Resalta y hace scroll al elemento actual | |||
var element = highlightElements[currentHighlightIndex]; | |||
element.classList.add('current'); | |||
element.scrollIntoView({ | |||
behavior: 'smooth', | |||
block: 'center' | |||
}); | |||
updateMatchCounter(); | |||
} | |||
/** | |||
* Navega a la siguiente coincidencia | |||
*/ | |||
function navigateToNext() { | |||
navigateToMatch(currentHighlightIndex + 1); | |||
} | |||
/** | |||
* Navega a la coincidencia anterior | |||
*/ | |||
function navigateToPrevious() { | |||
navigateToMatch(currentHighlightIndex - 1); | |||
} | |||
/** | |||
* Resalta los términos de búsqueda en el contenido del artículo | |||
*/ | |||
function highlightSearchTerms() { | |||
// Solo procede si venimos de una búsqueda | |||
if (!isComingFromSearch()) return; | |||
var terms = getSearchTerms(); | |||
if (!terms.length) return; | |||
var content = document.getElementById('mw-content-text'); | |||
if (!content) return; | |||
terms.forEach(function(term) { | |||
// Ignora términos muy cortos | |||
if (term.length < 3) return; | |||
// Escapa caracteres especiales en el término de búsqueda | |||
var escapedTerm = term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | |||
//usa una expresion regular que buscar un matcheo parcial, es decir el termino buscado | |||
//puede estar contenido en una palabra con diferente significado | |||
var regex = new RegExp('\\b(' + escapedTerm + '\\w*)', 'gi'); | |||
// Crea un TreeWalker para recorrer todos los nodos de texto | |||
var walker = document.createTreeWalker( | |||
content, | |||
NodeFilter.SHOW_TEXT, | |||
null, | |||
false | |||
); | |||
// Recolecta todos los nodos de texto | |||
var node; | |||
var nodes = []; | |||
while (node = walker.nextNode()) { | |||
nodes.push(node); | |||
} | |||
// Procesa cada nodo de texto | |||
nodes.forEach(function(node) { | |||
if (node.parentNode.nodeName !== 'SCRIPT' && | |||
node.parentNode.nodeName !== 'STYLE' && | |||
!node.parentNode.classList.contains('searchmatch')) { | |||
var text = node.textContent; | |||
if (regex.test(text)) { | |||
var span = document.createElement('span'); | |||
span.innerHTML = text.replace(regex, '<span class="searchmatch">$1</span>'); | |||
node.parentNode.replaceChild(span, node); | |||
} | |||
} | |||
}); | |||
}); | |||
// Recolecta todas las coincidencias resaltadas | |||
highlightElements = Array.from(document.getElementsByClassName('searchmatch')); | |||
// Si hay coincidencias, crea los controles y navega al primer resultado | |||
if (highlightElements.length > 0) { | |||
createNavigationControls(); | |||
navigateToMatch(0); | |||
} | |||
} | |||
// Agrega soporte para navegación con teclas | |||
document.addEventListener('keydown', function(e) { | |||
if (e.key === 'F3' || (e.ctrlKey && e.key === 'g')) { | |||
e.preventDefault(); | |||
navigateToNext(); | |||
} else if (e.shiftKey && e.key === 'F3' || (e.ctrlKey && e.shiftKey && e.key === 'g')) { | |||
e.preventDefault(); | |||
navigateToPrevious(); | |||
} | |||
}); | |||
// Inicia el script cuando la página esté lista | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', highlightSearchTerms); | |||
} else { | |||
highlightSearchTerms(); | |||
} | |||
})(); | |||
Revisión actual - 16:22 31 mar 2025
/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios en cada carga de página */
// Este script resalta y permite navegar entre términos de búsqueda en el artículo destino
(function() {
// Variables globales para el seguimiento de la navegación
var currentHighlightIndex = -1; // Índice del resaltado actual
var highlightElements = []; // Array de todos los elementos resaltados
/**
* Verifica si llegamos desde una búsqueda
* @returns {boolean} true si venimos de una búsqueda
*/
function isComingFromSearch() {
var referrer = document.referrer;
return referrer.includes('Special:Search') ||
referrer.includes('title=Special:Search') ||
referrer.includes('search=') ||
referrer.includes('Special:Buscar') ||
document.location.search.includes('highlight=');
}
/**
* Obtiene los términos de búsqueda del referrer o parámetros de URL
* @returns {Array} Array de términos de búsqueda
*/
function getSearchTerms() {
// Intenta obtener términos del parámetro highlight (usado por MediaWiki)
var urlParams = new URLSearchParams(window.location.search);
var highlight = urlParams.get('highlight');
if (highlight) {
return [highlight];
}
// Si no hay highlight, intenta obtener del referrer
var referrer = document.referrer;
if (!referrer) return [];
var referrerUrl = new URL(referrer);
var search = referrerUrl.searchParams.get('search') ||
referrerUrl.searchParams.get('query');
if (!search) return [];
// Limpia espacios extras y trata toda la búsqueda como un solo término
search = search.trim();
return [search];
}
/**
* Crea y agrega los controles de navegación en la página
*/
function createNavigationControls() {
var nav = document.createElement('div');
nav.className = 'search-navigation';
nav.innerHTML = [
'<div class="search-nav-controls">',
'<button id="prevMatch">↑ Anterior</button>',
'<span id="matchCounter">0 de 0</span>',
'<button id="nextMatch">↓ Siguiente</button>',
'</div>'
].join('');
document.body.appendChild(nav);
// Estilos CSS para los controles de navegación
var style = document.createElement('style');
style.textContent = [
'.search-navigation {',
'position: fixed;',
'bottom: 20px;',
'right: 20px;',
'z-index: 1000;',
'}',
'.search-nav-controls {',
'background: white;',
'padding: 10px;',
'border-radius: 8px;',
'box-shadow: 0 2px 10px rgba(0,0,0,0.1);',
'display: flex;',
'gap: 10px;',
'align-items: center;',
'}',
'.search-nav-controls button {',
'padding: 5px 10px;',
'border: 1px solid #ccc;',
'border-radius: 4px;',
'background: #f0f0f0;',
'cursor: pointer;',
'}',
'.search-nav-controls button:hover {',
'background: #e0e0e0;',
'}',
'.searchmatch {',
'background-color: #ffeb3b;',
'padding: 2px;',
'border-radius: 2px;',
'}',
'.searchmatch.current {',
'background-color: #ffa000;',
'color: white;',
'}'
].join('\n');
document.head.appendChild(style);
// Agregar listeners para los botones de navegación
document.getElementById('prevMatch').addEventListener('click', navigateToPrevious);
document.getElementById('nextMatch').addEventListener('click', navigateToNext);
}
/**
* Actualiza el contador de coincidencias
*/
function updateMatchCounter() {
var counter = document.getElementById('matchCounter');
if (counter && highlightElements.length > 0) {
counter.textContent = (currentHighlightIndex + 1) + ' de ' + highlightElements.length;
}
}
/**
* Navega a una coincidencia específica
* @param {number} index - Índice de la coincidencia
*/
function navigateToMatch(index) {
if (highlightElements.length === 0) return;
// Quita el resaltado especial del elemento actual
if (currentHighlightIndex >= 0) {
highlightElements[currentHighlightIndex].classList.remove('current');
}
// Maneja el ciclo de navegación
currentHighlightIndex = index;
if (currentHighlightIndex >= highlightElements.length) {
currentHighlightIndex = 0;
}
if (currentHighlightIndex < 0) {
currentHighlightIndex = highlightElements.length - 1;
}
// Resalta y hace scroll al elemento actual
var element = highlightElements[currentHighlightIndex];
element.classList.add('current');
element.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
updateMatchCounter();
}
/**
* Navega a la siguiente coincidencia
*/
function navigateToNext() {
navigateToMatch(currentHighlightIndex + 1);
}
/**
* Navega a la coincidencia anterior
*/
function navigateToPrevious() {
navigateToMatch(currentHighlightIndex - 1);
}
/**
* Resalta los términos de búsqueda en el contenido del artículo
*/
function highlightSearchTerms() {
// Solo procede si venimos de una búsqueda
if (!isComingFromSearch()) return;
var terms = getSearchTerms();
if (!terms.length) return;
var content = document.getElementById('mw-content-text');
if (!content) return;
terms.forEach(function(term) {
// Ignora términos muy cortos
if (term.length < 3) return;
// Escapa caracteres especiales en el término de búsqueda
var escapedTerm = term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
//usa una expresion regular que buscar un matcheo parcial, es decir el termino buscado
//puede estar contenido en una palabra con diferente significado
var regex = new RegExp('\\b(' + escapedTerm + '\\w*)', 'gi');
// Crea un TreeWalker para recorrer todos los nodos de texto
var walker = document.createTreeWalker(
content,
NodeFilter.SHOW_TEXT,
null,
false
);
// Recolecta todos los nodos de texto
var node;
var nodes = [];
while (node = walker.nextNode()) {
nodes.push(node);
}
// Procesa cada nodo de texto
nodes.forEach(function(node) {
if (node.parentNode.nodeName !== 'SCRIPT' &&
node.parentNode.nodeName !== 'STYLE' &&
!node.parentNode.classList.contains('searchmatch')) {
var text = node.textContent;
if (regex.test(text)) {
var span = document.createElement('span');
span.innerHTML = text.replace(regex, '<span class="searchmatch">$1</span>');
node.parentNode.replaceChild(span, node);
}
}
});
});
// Recolecta todas las coincidencias resaltadas
highlightElements = Array.from(document.getElementsByClassName('searchmatch'));
// Si hay coincidencias, crea los controles y navega al primer resultado
if (highlightElements.length > 0) {
createNavigationControls();
navigateToMatch(0);
}
}
// Agrega soporte para navegación con teclas
document.addEventListener('keydown', function(e) {
if (e.key === 'F3' || (e.ctrlKey && e.key === 'g')) {
e.preventDefault();
navigateToNext();
} else if (e.shiftKey && e.key === 'F3' || (e.ctrlKey && e.shiftKey && e.key === 'g')) {
e.preventDefault();
navigateToPrevious();
}
});
// Inicia el script cuando la página esté lista
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', highlightSearchTerms);
} else {
highlightSearchTerms();
}
})();