MediaWiki:Common.js: відмінності між версіями
Wiki (обговорення | внесок) Немає опису редагування |
Wiki (обговорення | внесок) Немає опису редагування |
||
| Рядок 108: | Рядок 108: | ||
'use strict'; | 'use strict'; | ||
// Конфигурация | // Конфигурация в стиле MediaViewer | ||
const config = { | const config = { | ||
overlayBg: 'rgba(0,0,0,0. | overlayBg: 'rgba(0,0,0,0.95)', | ||
imageMaxWidth: '90%', | imageMaxWidth: '90%', | ||
imageMaxHeight: '90%', | imageMaxHeight: '90%', | ||
closeBtnText: ' | closeBtnText: '×', | ||
closeBtnStyle: { | closeBtnStyle: { | ||
background: ' | background: 'rgba(0,0,0,0.7)', | ||
color: 'white', | color: 'white', | ||
border: 'none', | border: 'none', | ||
borderRadius: ' | borderRadius: '50%', | ||
width: '40px', | |||
fontSize: ' | height: '40px', | ||
fontSize: '24px', | |||
cursor: 'pointer', | cursor: 'pointer', | ||
position: 'absolute', | |||
top: '20px', | |||
right: '20px' | |||
}, | |||
zoomBtnStyle: { | |||
background: 'rgba(0,0,0,0.7)', | |||
color: 'white', | |||
border: 'none', | |||
borderRadius: '50%', | |||
width: '40px', | |||
height: '40px', | |||
fontSize: '20px', | |||
cursor: 'pointer', | |||
position: 'absolute', | |||
right: '20px' | |||
} | } | ||
}; | }; | ||
// Функция для создания | let currentScale = 1; | ||
const minScale = 0.5; | |||
const maxScale = 3; | |||
const scaleStep = 0.25; | |||
// Функция для создания оверлея в стиле MediaViewer | |||
function showCustomOverlay(url) { | function showCustomOverlay(url) { | ||
const overlay = document.createElement('div'); | const overlay = document.createElement('div'); | ||
| Рядок 138: | Рядок 158: | ||
overlay.style.justifyContent = 'center'; | overlay.style.justifyContent = 'center'; | ||
overlay.style.alignItems = 'center'; | overlay.style.alignItems = 'center'; | ||
overlay.style.zIndex = '10000'; | overlay.style.zIndex = '10000'; | ||
overlay.style.cursor = ' | overlay.style.cursor = 'default'; | ||
// Контейнер для изображения и кнопок | |||
const container = document.createElement('div'); | |||
container.style.position = 'relative'; | |||
container.style.display = 'flex'; | |||
container.style.justifyContent = 'center'; | |||
container.style.alignItems = 'center'; | |||
container.style.maxWidth = '95vw'; | |||
container.style.maxHeight = '95vh'; | |||
// Изображение | |||
const img = document.createElement('img'); | const img = document.createElement('img'); | ||
img.src = url; | img.src = url; | ||
| Рядок 148: | Рядок 177: | ||
img.style.objectFit = 'contain'; | img.style.objectFit = 'contain'; | ||
img.style.borderRadius = '8px'; | img.style.borderRadius = '8px'; | ||
img.style.boxShadow = '0 10px 30px rgba(0,0,0,0.5)'; | |||
img.style.transition = 'transform 0.3s ease'; | |||
img.style.cursor = 'default'; // Убираем курсор лупы | |||
// Кнопка закрытия (как в MediaViewer) | |||
const closeBtn = document.createElement('button'); | const closeBtn = document.createElement('button'); | ||
closeBtn. | closeBtn.innerHTML = config.closeBtnText; | ||
closeBtn.style. | closeBtn.title = 'Закрити (Esc)'; | ||
closeBtn.style. | closeBtn.style.cssText = Object.entries(config.closeBtnStyle).map(([key, value]) => | ||
`${key}: ${value};`).join(''); | |||
closeBtn.style.zIndex = '10001'; | |||
// Кнопки зума | |||
const zoomInBtn = document.createElement('button'); | |||
zoomInBtn.innerHTML = '+'; | |||
zoomInBtn.title = 'Збільшити (Ctrl + +)'; | |||
// Закрытие | zoomInBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) => | ||
`${key}: ${value};`).join(''); | |||
zoomInBtn.style.top = '70px'; | |||
zoomInBtn.style.zIndex = '10001'; | |||
const zoomOutBtn = document.createElement('button'); | |||
zoomOutBtn.innerHTML = '−'; | |||
zoomOutBtn.title = 'Зменшити (Ctrl + -)'; | |||
zoomOutBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) => | |||
`${key}: ${value};`).join(''); | |||
zoomOutBtn.style.top = '120px'; | |||
zoomOutBtn.style.zIndex = '10001'; | |||
const resetZoomBtn = document.createElement('button'); | |||
resetZoomBtn.innerHTML = '1:1'; | |||
resetZoomBtn.title = 'Скинути масштаб'; | |||
resetZoomBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) => | |||
`${key}: ${value};`).join(''); | |||
resetZoomBtn.style.top = '170px'; | |||
resetZoomBtn.style.zIndex = '10001'; | |||
resetZoomBtn.style.fontSize = '16px'; | |||
// Функции зума | |||
function zoomImage(scale) { | |||
currentScale = Math.max(minScale, Math.min(maxScale, scale)); | |||
img.style.transform = `scale(${currentScale})`; | |||
updateZoomButtons(); | |||
} | |||
function updateZoomButtons() { | |||
zoomInBtn.disabled = currentScale >= maxScale; | |||
zoomOutBtn.disabled = currentScale <= minScale; | |||
zoomInBtn.style.opacity = zoomInBtn.disabled ? '0.5' : '1'; | |||
zoomOutBtn.style.opacity = zoomOutBtn.disabled ? '0.5' : '1'; | |||
} | |||
// Обработчики зума | |||
zoomInBtn.addEventListener('click', (e) => { | |||
e.stopPropagation(); | |||
zoomImage(currentScale + scaleStep); | |||
}); | |||
zoomOutBtn.addEventListener('click', (e) => { | |||
e.stopPropagation(); | |||
zoomImage(currentScale - scaleStep); | |||
}); | |||
resetZoomBtn.addEventListener('click', (e) => { | |||
e.stopPropagation(); | |||
currentScale = 1; | |||
img.style.transform = 'scale(1)'; | |||
updateZoomButtons(); | |||
}); | |||
// Закрытие оверлея | |||
const closeOverlay = () => { | const closeOverlay = () => { | ||
document.body.removeChild(overlay); | document.body.removeChild(overlay); | ||
document.body.style.overflow = 'auto'; | document.body.style.overflow = 'auto'; | ||
currentScale = 1; // Сбрасываем масштаб | |||
}; | }; | ||
closeBtn.addEventListener('click', closeOverlay); | |||
// Закрытие по клику на фон (но не на изображение или кнопки) | |||
overlay.addEventListener('click', (e) => { | overlay.addEventListener('click', (e) => { | ||
if (e.target === overlay) closeOverlay(); | if (e.target === overlay) closeOverlay(); | ||
}); | }); | ||
// Закрытие по ESC | // Закрытие по ESC | ||
const keyHandler = (e) => { | const keyHandler = (e) => { | ||
if (e.key === 'Escape') closeOverlay(); | if (e.key === 'Escape') { | ||
closeOverlay(); | |||
document.removeEventListener('keydown', keyHandler); | |||
} else if (e.ctrlKey) { | |||
if (e.key === '+' || e.key === '=') { | |||
e.preventDefault(); | |||
zoomImage(currentScale + scaleStep); | |||
} else if (e.key === '-') { | |||
e.preventDefault(); | |||
zoomImage(currentScale - scaleStep); | |||
} else if (e.key === '0') { | |||
e.preventDefault(); | |||
currentScale = 1; | |||
img.style.transform = 'scale(1)'; | |||
updateZoomButtons(); | |||
} | |||
} | |||
}; | }; | ||
document.addEventListener('keydown', keyHandler); | document.addEventListener('keydown', keyHandler); | ||
// | // Hover эффекты для кнопок | ||
[closeBtn, zoomInBtn, zoomOutBtn, resetZoomBtn].forEach(btn => { | |||
btn.addEventListener('mouseenter', () => { | |||
btn.style.background = 'rgba(0,0,0,0.9)'; | |||
btn.style.transform = 'scale(1.1)'; | |||
}); | |||
btn.addEventListener('mouseleave', () => { | |||
btn.style.background = config.zoomBtnStyle.background; | |||
btn.style.transform = 'scale(1)'; | |||
}); | |||
}); | }); | ||
overlay.appendChild( | // Сборка интерфейса | ||
container.appendChild(img); | |||
container.appendChild(closeBtn); | |||
container.appendChild(zoomInBtn); | |||
container.appendChild(zoomOutBtn); | |||
container.appendChild(resetZoomBtn); | |||
overlay.appendChild(container); | |||
document.body.appendChild(overlay); | document.body.appendChild(overlay); | ||
document.body.style.overflow = 'hidden'; | |||
// | // Инициализация кнопок зума | ||
updateZoomButtons(); | |||
} | } | ||
| Рядок 208: | Рядок 327: | ||
// Ссылки на файлы, где MediaViewer не срабатывает | // Ссылки на файлы, где MediaViewer не срабатывает | ||
if (target.tagName === 'A' && target.href && target.href.includes('/w/images/')) { | if (target.tagName === 'A' && target.href && target.href.includes('/w/images/')) { | ||
if (!target.closest('.thumb')) { | if (!target.closest('.thumb')) { | ||
e.preventDefault(); | e.preventDefault(); | ||
| Рядок 217: | Рядок 335: | ||
}, true); | }, true); | ||
// Функция добавления кнопки "Закрити" к MediaViewer overlay | // Функция добавления кнопки "Закрити" к MediaViewer overlay | ||
function addCloseButtonToMediaViewer() { | function addCloseButtonToMediaViewer() { | ||
const overlay = document.querySelector('.mediaViewerOverlay, .mwe-popups'); | const overlay = document.querySelector('.mediaViewerOverlay, .mwe-popups'); | ||
| Рядок 224: | Рядок 342: | ||
const closeBtn = document.createElement('button'); | const closeBtn = document.createElement('button'); | ||
closeBtn.innerText = | closeBtn.innerText = 'Закрити'; | ||
closeBtn.style.position = 'absolute'; | closeBtn.style.position = 'absolute'; | ||
closeBtn.style.top = '20px'; | closeBtn.style.top = '20px'; | ||
closeBtn.style.right = '20px'; | closeBtn.style.right = '20px'; | ||
closeBtn.style.padding = | closeBtn.style.padding = '10px 20px'; | ||
closeBtn.style.fontSize = | closeBtn.style.fontSize = '18px'; | ||
closeBtn.style.cursor = | closeBtn.style.cursor = 'pointer'; | ||
closeBtn.style.background = | closeBtn.style.background = '#f44336'; | ||
closeBtn.style.color = | closeBtn.style.color = 'white'; | ||
closeBtn.style.border = | closeBtn.style.border = 'none'; | ||
closeBtn.style.borderRadius = | closeBtn.style.borderRadius = '5px'; | ||
closeBtn.style.zIndex = '10001'; | closeBtn.style.zIndex = '10001'; | ||
| Рядок 242: | Рядок 360: | ||
overlay.appendChild(closeBtn); | overlay.appendChild(closeBtn); | ||
} | } | ||
// MutationObserver отслеживает появление overlay MediaViewer | // MutationObserver отслеживает появление overlay MediaViewer | ||
const observer = new MutationObserver(( | const observer = new MutationObserver(() => addCloseButtonToMediaViewer()); | ||
observer.observe(document.body, { childList: true, subtree: true }); | observer.observe(document.body, { childList: true, subtree: true }); | ||
// | // Стили для улучшения внешнего вида | ||
const style = document.createElement('style'); | const style = document.createElement('style'); | ||
style.textContent = ` | style.textContent = ` | ||
button { | |||
transition: | transition: all 0.2s ease !important; | ||
} | } | ||
button:hover:not(:disabled) { | |||
transform: scale(1. | transform: scale(1.1) !important; | ||
background: rgba(0,0,0,0.9) !important; | |||
} | } | ||
button: | button:disabled { | ||
cursor: not-allowed !important; | |||
} | |||
@media (max-width: 768px) { | |||
button { | |||
width: 35px !important; | |||
height: 35px !important; | |||
font-size: 18px !important; | |||
} | |||
} | } | ||
`; | `; | ||