MediaWiki:Common.js

注意: 保存後、変更を確認するにはブラウザーのキャッシュを消去する必要がある場合があります。

  • Firefox / Safari: Shift を押しながら 再読み込み をクリックするか、Ctrl-F5 または Ctrl-R を押してください (Mac では ⌘-R)
  • Google Chrome: Ctrl-Shift-R を押してください (Mac では ⌘-Shift-R)
  • Internet Explorer / Microsoft Edge: Ctrl を押しながら 最新の情報に更新 をクリックするか、Ctrl-F5 を押してください
  • Opera: Ctrl-F5を押してください
/* ここにあるすべての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();
	});
});

/* =========================================================
 * Infobox 画像スライダー
 * ========================================================= */

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

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

		var slider = this;

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

		slider.dataset.infoboxSliderReady = '1';

		var track =
			slider.querySelector('.ts-infobox-slider__track');

		if (!track) {
			return;
		}

		var slides =
			track.querySelectorAll('.ts-infobox-slider__slide');

		if (!slides.length) {
			return;
		}

		/*
		 * 1枚だけなら矢印を作らない
		 */
		if (slides.length === 1) {
			slider.classList.add(
				'ts-infobox-slider--single'
			);
			return;
		}


		/* -----------------------------------------
		   戻るボタン
		   ----------------------------------------- */

		var prev =
			document.createElement('button');

		prev.type = 'button';

		prev.className =
			'ts-infobox-slider__nav ' +
			'ts-infobox-slider__prev';

		prev.innerHTML = '&#8249;';

		prev.setAttribute(
			'aria-label',
			'前の画像'
		);


		/* -----------------------------------------
		   次へボタン
		   ----------------------------------------- */

		var next =
			document.createElement('button');

		next.type = 'button';

		next.className =
			'ts-infobox-slider__nav ' +
			'ts-infobox-slider__next';

		next.innerHTML = '&#8250;';

		next.setAttribute(
			'aria-label',
			'次の画像'
		);


		slider.appendChild(prev);
		slider.appendChild(next);


		/* -----------------------------------------
		   ボタン状態
		   ----------------------------------------- */

		function updateButtons() {

			var max =
				track.scrollWidth -
				track.clientWidth;

			prev.disabled =
				track.scrollLeft <= 3;

			next.disabled =
				track.scrollLeft >= max - 3;
		}


		/* -----------------------------------------
		   1枚分移動
		   ----------------------------------------- */

		function move(direction) {

			track.scrollBy({
				left:
					direction *
					track.clientWidth,

				behavior: 'smooth'
			});
		}


		prev.addEventListener(
			'click',
			function () {
				move(-1);
			}
		);


		next.addEventListener(
			'click',
			function () {
				move(1);
			}
		);


		track.addEventListener(
			'scroll',
			function () {
				window.requestAnimationFrame(
					updateButtons
				);
			},
			{
				passive: true
			}
		);


		window.addEventListener(
			'resize',
			updateButtons
		);


		updateButtons();

	});

});