Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
//Dokumentation unter [[Benutzer:Schnark/js/popuprefs]] <nowiki>
/*global mediaWiki*/

(function ($, mw) {
"use strict";

var config = {
	//delay before showing/hiding the popup
	showDelay: 200,
	hideDelay: 200,
	//animation
	animationDelay: 200,
	//style for popup
	paddingStyle: '5px',
	borderStyle: '2px solid #36c', //'2px solid #00f', '1px solid InfoText', '2px solid #080086'
	backgroundColor: '#eaf3ff', //'#def', 'InfoBackground', '#f7f7f7'
	maxWidth: '36em', //'500px'
	//boxShadow: '2px 4px 2px rgba(0,0,0,0.3)',
	fixFontSize: mw.config.get('skin') !== 'vector',
	//style: '',
	maxHeightDiff: 20, //margin, border, padding + a bit safety

	//classes for popup, first used as main one
	classes: ['popupref', 'mw-body-content', 'mw-parser-output'], //['popupref']
	//selector for references
	selector: 'sup.reference a, .reference sup a, sup.mw-ref a, sup > a[href^="#"], a[href^="#CITEREF"]'
}, useAnimationEvent;

function show ($this, e) {
	var footnote = document.getElementById(($this.attr('href') || '').replace(/^#/, '')), data;
	footnote = getPopupContent(footnote);
	if (!footnote) {
		return;
	}
	data = $this.data();
	if (data.willShow) {
		return;
	}
	if (data.willHide) {
		$this.data('willHide', false);
		window.clearTimeout(data.hideTimer);
		return;
	}
	if (data.popupVisible) {
		return;
	}
	$this.data({
		willShow: true,
		showTimer: window.setTimeout(function () {
			$this.data({
				willShow: false,
				popupVisible: true,
				popupRef: reallyShow(footnote, e.clientX, e.clientY)
					.on('mouseenter', function () {
						show($this, e);
					}).on('mouseleave', function () {
						hide($this);
					})
			});
		}, config.showDelay)
	});
}

function getPopupContent (el) {
	var $footnote, $content, $back;
	if (!el) {
		return false;
	}
	$footnote = $(el).clone();
	$content = $footnote.find('.reference-text, .mw-reference-text');
	if ($content.length === 1) {
		$footnote = $content;
	} else {
		$back = $footnote.find('.mw-cite-backlink');
		if ($back.length !== 1) {
			$back = $footnote.find('a').eq(0);
		}
		$back.remove();
	}
	if ($footnote.text().trim() === '') {
		//HACK en hat einige Fußnoten-Vorlagen, bei denen der Inhalt nach
		//dem angesprungenen Element folgt
		$footnote = $(el).parent('dd').clone();
		if ($footnote.text().trim() === '') {
			return false;
		}
	}
	return $footnote.wrapInner('<div>').children().unwrap(); //replace <li> with <div>;
}

function getPos (x, y, w, h, W, H, rtl) {
	var d = 5;
	if (rtl) {
		if (d + w > x) {
			x = 2;
			d = 20;
			if (w + 4 > W) {
				x = 0;
			}
		} else {
			x = x - w - d;
		}
	} else {
		if (x + d + w > W) {
			x = W - w - 2;
			d = 20;
			if (x < 2) {
				x = 0;
			}
		} else {
			x = x + d;
		}
	}
	if (y < h + d) {
		if (y + d + h < H) {
			y = y + d;
		} else {
			y = 0;
		}
	} else {
		y = y - h - d;
	}
	return {x: x, y: y};
}

function reallyShow ($footnote, x, y) {
	var $window = $(window), $popup, pos;
	$popup = $('<div>').attr('class', config.classes.join(' ')).append($footnote);
	mw.hook('wikipage.content').fire($popup);
	$popup.appendTo($('body'));
	pos = getPos(
		x, y,
		$popup.outerWidth(), $popup.outerHeight(),
		$window.width(), $window.height(),
		$('html').attr('dir') === 'rtl'
	);
	return $popup.css({
		left: pos.x,
		top: pos.y,
		maxHeight: $window.height() - config.maxHeightDiff
	}).removeClass('animated-fade-out').addClass('animated-fade-in');
}

function hide ($this) {
	var data = $this.data();
	if (data.willHide) {
		return;
	}
	if (data.willShow) {
		$this.data('willShow', false);
		window.clearTimeout(data.showTimer);
		return;
	}
	if (!data.popupVisible) {
		return;
	}
	$this.data({
		willHide: true,
		hideTimer: window.setTimeout(function () {
			$this.data({
				willHide: false,
				popupVisible: false
			});
			reallyHide(data.popupRef);
		}, config.hideDelay)
	});
}

function reallyHide ($popup) {
	function callback () {
		if ($popup.find(config.selector).length) {
			//Popup hat selbst Fußnoten, für die noch Popups sichtbar sein könnten
			//und die Daten behalten werden müssen
			$popup.detach();
		} else {
			$popup.remove();
		}
	}
	if (useAnimationEvent) {
		$popup.removeClass('animated-fade-in').addClass('animated-fade-out')[0].onanimationend = callback;
	} else {
		callback();
	}
}

function getAnimationPrefix () {
	var div = document.createElement('div'), style = div.style;
	useAnimationEvent = 'onanimationend' in div;
	if ('animationName' in style) {
		return '';
	}
	if ('WebkitAnimationName' in style) {
		return '-webkit-';
	}
	if ('MozAnimationName' in style) {
		return '-moz-';
	}
	if ('OAnimationName' in style) {
		return '-o-';
	}
	useAnimationEvent = false;
	return false;
}

function buildCSS () {
	var css = '',
		prefix = getAnimationPrefix(),
		baseStyle = 'position: fixed;' +
			'z-index: 200;' +
			'overflow: auto;' +
			'margin: 0;';
	//body zur Sicherheit ergänzt um auf jeden Fall spezifischer als nur eine Klasse zu sein
	css += 'body .' + config.classes[0] + '{';
	css += baseStyle;
	css += 'padding:' + (config.paddingStyle || '0') + ';';
	css += 'border:' + (config.borderStyle || 'none') + ';';
	css += 'background-color:' + (config.backgroundColor || 'white') + ';';
	if (config.maxWidth) {
		css += 'max-width:' + config.maxWidth + ';';
	}
	if (config.boxShadow) {
		css += 'box-shadow:' + config.boxShadow + ';';
	}
	if (config.fixFontSize) {
		css += 'font-size:' + $('#mw-content-text').css('font-size') + ';';
	}
	if (config.style) {
		css += config.style;
	}
	css += '}';
	if (prefix !== false) {
		css += '@' + prefix + 'keyframes fading-in-animation {' +
			'from {' +
				'opacity: 0;' +
			'}' +
			'to {' +
				'opacity: 1;' +
			'}' +
		'}' +
		'@' + prefix + 'keyframes fading-out-animation {' +
			'from {' +
				'opacity: 1;' +
			'}' +
			'to {' +
				'opacity: 0;' +
			'}' +
		'}' +
		'.animated-fade-in {' +
			prefix + 'animation: fading-in-animation ' + config.animationDelay + 'ms;' +
		'}' +
		'.animated-fade-out {' + //we can't use the same animation reversed, as it wouldn't run again
			prefix + 'animation: fading-out-animation ' + config.animationDelay + 'ms;' +
			'opacity: 0;' +
		'}';
	}
	return css;
}

function init ($content) {
	$content.find(config.selector)
		.on('mouseenter', function (e) {
			if (e.buttons) {
				return;
			}
			show($(this), e);
		}).on('mouseleave', function () {
			hide($(this));
		});
}

mw.hook('userjs.load-script.popuprefs').fire(config);

mw.loader.using('mediawiki.util').then(function () {
	$(function () {
		mw.util.addCSS(buildCSS());
	});
	mw.hook('wikipage.content').add(init);
});

})(jQuery, mediaWiki);
//</nowiki>