「MediaWiki:Mobile.js」の版間の差分

(ページの作成:「→‎ここにある全てのJavaScriptはモバイル版サイトの利用者に影響します: →‎========================================================= * 外部画像ギャラリー * =========================================================: mw.hook('wikipage.content').add(function ($content) { $content.find('.ts-gallery').each(function () { var gallery = this; →‎二重初期化防止: if (gallery.dataset.galleryReady === '1') { return;…」)
(相違点なし)

2026年9月2日 (水) 06:41時点における版

/* ここにある全てのJavaScriptはモバイル版サイトの利用者に影響します */
/* =========================================================
 * 外部画像ギャラリー
 * ========================================================= */

mw.hook('wikipage.content').add(function ($content) {

	$content.find('.ts-gallery').each(function () {

		var gallery = this;

		/* 二重初期化防止 */
		if (gallery.dataset.galleryReady === '1') {
			return;
		}

		gallery.dataset.galleryReady = '1';

		var track = gallery.querySelector('.ts-gallery__track');

		if (!track) {
			return;
		}

		/* 戻るボタン */
		var prev = document.createElement('button');
		prev.type = 'button';
		prev.className = 'ts-gallery__nav ts-gallery__prev';
		prev.innerHTML = '‹';
		prev.setAttribute('aria-label', '前の画像');

		/* 進むボタン */
		var next = document.createElement('button');
		next.type = 'button';
		next.className = 'ts-gallery__nav ts-gallery__next';
		next.innerHTML = '›';
		next.setAttribute('aria-label', '次の画像');

		gallery.appendChild(prev);
		gallery.appendChild(next);

		/* 1回に移動する距離 */
		function getStep() {

			var item = track.querySelector('.ts-gallery__item');

			if (!item) {
				return track.clientWidth * 0.85;
			}

			var style = window.getComputedStyle(track);
			var gap = parseFloat(style.columnGap || style.gap) || 0;

			return item.getBoundingClientRect().width + gap;
		}

		/* ボタン状態更新 */
		function updateButtons() {

			var maxScroll =
				track.scrollWidth - track.clientWidth;

			var scrollable = maxScroll > 5;

			gallery.classList.toggle(
				'ts-gallery--scrollable',
				scrollable
			);

			prev.disabled =
				!scrollable ||
				track.scrollLeft <= 5;

			next.disabled =
				!scrollable ||
				track.scrollLeft >= maxScroll - 5;
		}

		prev.addEventListener('click', function () {

			track.scrollBy({
				left: -getStep(),
				behavior: 'smooth'
			});
		});

		next.addEventListener('click', function () {

			track.scrollBy({
				left: getStep(),
				behavior: 'smooth'
			});
		});

		var ticking = false;

		track.addEventListener('scroll', function () {

			if (!ticking) {

				window.requestAnimationFrame(function () {
					updateButtons();
					ticking = false;
				});

				ticking = true;
			}

		}, { passive: true });

		window.addEventListener('resize', updateButtons);

		/* 画像読み込み後にも判定 */
		var images = track.querySelectorAll('img');

		images.forEach(function (image) {
			image.addEventListener('load', updateButtons);
		});

		updateButtons();
	});
});