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/notizen]] <nowiki>
/*global mediaWiki, OO*/

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

//jscs:disable maximumLineLength
var l10n = {
	en: {
		'pagetitle': '$1 - {{SITENAME}}',
		'brackets': '[$1]',

		'wikinotes': 'Wikinotes',
		'wikinotes-star': '\u2736',
		'wikinotes-minutes': 'minutes',
		'wikinotes-hours': 'hours',
		'wikinotes-days': 'days',
		'wikinotes-weeks': 'weeks',
		'wikinotes-months': 'months',
		'wikinotes-years': 'years',
		'wikinotes-date-time-format': '${day|#}. ${month|short} ${year|#} ${hour|0}:${minute|0}',
		'wikinotes-alarm': '<i>$2</i> on $1',
		'wikinotes-disable-alarm': '\u2713',
		'wikinotes-disable-alarm-title': 'disable alarm',
		'wikinotes-delete-note': '\u2715',
		'wikinotes-delete-note-title': 'delete note',
		'wikinotes-alarms': '{{PLURAL:$1|This note requires|These notes require}} your attention: $2',
		'wikinotes-no-notes': 'You did\'t add notes to any page.',
		'wikinotes-list-head': 'You added these notes to pages ($1 | $2 | $3):',
		'wikinotes-list-delete-all': 'delete all notes',
		'wikinotes-list-export-import': 'export/import',
		'wikinotes-bookmarklet': 'backup for Wikinotes',
		'wikinotes-bookmarklet-title': 'Install this link as bookmarklet to get a backup of your current notes',
		'wikinotes-export-import-notes': 'These data encoded as JSON represent your current notes. You can save them as backup, restore them when needed, or edit them.',
		'wikinotes-storage-error': 'A storage error occured, changes to the notes could not be saved.',
		'wikinotes-json-error': 'The JSON is not valid: $1',
		'wikinotes-list-page': 'page',
		'wikinotes-list-title': 'title',
		'wikinotes-list-alarm': 'alarm',
		'wikinotes-list-delete': 'delete note',
		'wikinotes-no-alarm': '(no alarm)',
		'wikinotes-list-alarm-rule': 'regularily all $1 $2',
		'wikinotes-delete-from-list': 'delete',
		'wikinotes-dialog': 'Add new note',
		'wikinotes-dialog-intro': 'This dialog allows you to add a new note and set an alarm for it if you want to.',
		'wikinotes-dialog-note': 'Note',
		'wikinotes-dialog-title': 'Title:',
		'wikinotes-dialog-content': 'Content:',
		'wikinotes-dialog-alarm': 'Alarm',
		'wikinotes-dialog-alarm-type': 'Type of alarm:',
		'wikinotes-dialog-alarm-type-none': 'no alarm',
		'wikinotes-dialog-alarm-type-once': 'once',
		'wikinotes-dialog-alarm-type-regular-times': 'alarm at regular times',
		'wikinotes-dialog-alarm-type-regular-period': 'alarm in regular periods',
		'wikinotes-dialog-alarm-time': 'Date:',
		'wikinotes-dialog-expire': 'Alarm expires after (0, if it should\'t expire):',
		'wikinotes-dialog-rule': 'Rule for alarms:',
		'wikinotes-dialog-save': 'Save',
		'wikinotes-dialog-cancel': 'Cancel',
		'wikinotes-new': 'new note',
		'wikinotes-new-title': 'Opens dialog to add a new note'
	},
	de: {
		'pagetitle': '$1 – {{SITENAME}}',
		'wikinotes': 'Wikinotizen',
		'wikinotes-minutes': 'Minuten',
		'wikinotes-hours': 'Stunden',
		'wikinotes-days': 'Tage',
		'wikinotes-weeks': 'Wochen',
		'wikinotes-months': 'Monate',
		'wikinotes-years': 'Jahre',
		'wikinotes-alarm': '<i>$2</i> auf $1',
		'wikinotes-disable-alarm-title': 'Alarm ausschalten',
		'wikinotes-delete-note-title': 'Notiz löschen',
		'wikinotes-alarms': '{{PLURAL:$1|Folgende Notiz erfordert|Folgende Notizen erfordern}} Aufmerksamkeit: $2',
		'wikinotes-no-notes': 'Du hast noch zu keiner Seite Notizen hinzugefügt.',
		'wikinotes-list-head': 'Folgende Notizen hast du zu Seiten hinzugefügt ($1 | $2 | $3):',
		'wikinotes-list-delete-all': 'alle Notizen löschen',
		'wikinotes-list-export-import': 'Export/Import',
		'wikinotes-bookmarklet': 'Sicherungskopie für Wikinotes',
		'wikinotes-bookmarklet-title': 'Installiere diesen Link als Bookmarklet um eine Sicherungskopie deiner aktuellen Notizen zu sichern',
		'wikinotes-export-import-notes': 'Folgende Daten im JSON-Format repräsentieren die aktuellen Notizen. Du kannst sie als Sicherungskopie speichern, bei Bedarf wiederherstellen oder nach Belieben ändern.',
		'wikinotes-storage-error': 'Ein Speicherfehler trat auf, Änderungen an den Notizen konnten nicht gespeichert werden.',
		'wikinotes-json-error': 'Die JSON-Daten sind nicht korrekt: $1',
		'wikinotes-list-page': 'Seite',
		'wikinotes-list-title': 'Titel',
		'wikinotes-list-alarm': 'Alarm',
		'wikinotes-list-delete': 'Notiz löschen',
		'wikinotes-no-alarm': '(kein Alarm)',
		'wikinotes-list-alarm-rule': 'regelmäßig alle $1 $2',
		'wikinotes-delete-from-list': 'löschen',
		'wikinotes-dialog': 'Neue Notiz erstellen',
		'wikinotes-dialog-intro': 'Mit diesem Dialog kannst du eine neue Notiz erstellen und – falls gewünscht – einen Alarm für sie einrichten.',
		'wikinotes-dialog-note': 'Notiz',
		'wikinotes-dialog-title': 'Titel:',
		'wikinotes-dialog-content': 'Inhalt:',
		'wikinotes-dialog-alarm': 'Alarm',
		'wikinotes-dialog-alarm-type': 'Art des Alarms:',
		'wikinotes-dialog-alarm-type-none': 'kein Alarm',
		'wikinotes-dialog-alarm-type-once': 'einmaliger Alarm',
		'wikinotes-dialog-alarm-type-regular-times': 'Alarm zu regelmäßigen Zeitpunkten',
		'wikinotes-dialog-alarm-type-regular-period': 'Alarm in regelmäßigen Abständen',
		'wikinotes-dialog-alarm-time': 'Zeitpunkt:',
		'wikinotes-dialog-expire': 'Alarm erlischt nach (0, falls er nicht automatisch erlöschen soll):',
		'wikinotes-dialog-rule': 'Häufigkeit des Alarms:',
		'wikinotes-dialog-save': 'Speichern',
		'wikinotes-dialog-cancel': 'Abbrechen',
		'wikinotes-new': 'neue Notiz',
		'wikinotes-new-title': 'Öffnet den Dialog zum Erstellen einer neuen Notiz'
	},
	'de-ch': {
		'wikinotes-list-alarm-rule': 'regelmässig alle $1 $2',
		'wikinotes-dialog-alarm-type-regular-times': 'Alarm zu regelmässigen Zeitpunkten',
		'wikinotes-dialog-alarm-type-regular-period': 'Alarm in regelmässigen Abständen'
	},
	'de-formal': {
		'wikinotes-no-notes': 'Sie haben noch zu keiner Seite Notizen hinzugefügt.',
		'wikinotes-list-head': 'Folgende Notizen haben Sie zu Seiten hinzugefügt ($1 | $2 | $3):',
		'wikinotes-bookmarklet-title': 'Installieren Sie diesen Link als Bookmarklet um eine Sicherungskopie Ihrer aktuellen Notizen zu sichern',
		'wikinotes-export-import-notes': 'Folgende Daten im JSON-Format repräsentieren die aktuellen Notizen. Sie können sie als Sicherungskopie speichern, bei Bedarf wiederherstellen oder nach Belieben ändern.',
		'wikinotes-dialog-intro': 'Mit diesem Dialog können Sie eine neue Notiz erstellen und – falls gewünscht – einen Alarm für sie einrichten.'
	}
//jscs:enable maximumLineLength

}, sectLinksHook, cachedData, hasOwn = Object.prototype.hasOwnProperty;

function initL10N (l10n, keep) {
	var i, chain = mw.language.getFallbackLanguageChain();
	keep = $.grep(mw.messages.get(keep), function (val) {
		return val !== null;
	});
	for (i = chain.length - 1; i >= 0; i--) {
		if (chain[i] in l10n) {
			mw.messages.set(l10n[chain[i]]);
		}
	}
	mw.messages.set(keep);
}

function getCSS () {
	var star = mw.msg('wikinotes-star');
	return '#wikinotes-alarm { border: 3px solid #d33; }' +
		'aside.wikinote { display: block; border-radius: 1em; background-color: #fc3;' +
			'padding: 0.2em; margin-right: 2em; min-width: 7em; float: left; }' +
		'aside.active-alarm { border: 3px solid #d33; }' +
		'aside.inactive-alarm h5::after { content: "' + star + '"; color: #72777d; font-size: 150%; }' +
		'aside.active-alarm h5::after { content: "' + star + '"; color: #d33; font-size: 170%; }' +
		'aside.wikinote .delete-note { float: right; }' +
		'html.ve-activated .wikinotes-add-new, html.ve-activated .wikinote { display: none; }';
}

function random () {
	return String(Math.floor(Math.random() * 10000 + 1));
}

function getData () {
	if (cachedData) {
		return cachedData;
	}
	var data = mw.storage.get('schnark-wikinotes');
	if (data) {
		data = JSON.parse(data);
	} else {
		data = {};
	}
	cachedData = data;
	return data;
}

function setData (data) {
	if (!mw.storage.set('schnark-wikinotes', JSON.stringify(data))) {
		window.alert(mw.msg('wikinotes-storage-error'));
		return;
	}
	cachedData = data;
}

function deleteData () {
	if (!mw.storage.remove('schnark-wikinotes')) {
		window.alert(mw.msg('wikinotes-storage-error'));
		return;
	}
	cachedData = {};
}

function resetData () {
	cachedData = false;
}

function addNote (note) {
	var data = getData(), key = random();
	while (key in data) {
		key += random();
	}
	note.key = key;
	data[key] = note;
	setData(data);
	return key;
}

function updateNote (key, note) {
	var data = getData();
	$.extend(data[key], note);
	setData(data);
}

function deleteNote (key) {
	var data = getData();
	delete data[key];
	setData(data);
}

function exportImportNotes () {
	var data = getData();
	data = JSON.stringify(data);
	data = window.prompt(mw.msg('wikinotes-export-import-notes'), data);
	if (data !== null) {
		try {
			data = JSON.parse(data);
		} catch (e) {
			window.alert(mw.msg('wikinotes-json-error', String(e)));
			return;
		}
		setData(data);
	}
}

function nextTime (start, rule) {
	var date, toMS = {
		's': 1000,
		'm': 1000 * 60,
		'h': 1000 * 60 * 60,
		'd': 1000 * 60 * 60 * 24,
		'w': 1000 * 60 * 60 * 24 * 7
	};
	if (!rule) {
		return false;
	}
	if (rule.unit in toMS) {
		return start + toMS[rule.unit] * rule.count;
	}
	date = new Date(start);
	if (rule.unit === 'M') {
		date.setMonth(date.getMonth() + rule.count);
	} else {
		date.setFullYear(date.getFullYear() + rule.count);
	}
	return Number(date);
}

function updateExpiredAlarm (alarm) {
	do {
		alarm.time = nextTime(alarm.time, alarm.rule);
	} while (alarm.time && alarm.time + alarm.expire < Date.now());
	if (!alarm.time) {
		return false;
	}
	return alarm;
}

function updateAlarm (alarm) {
	var time = nextTime(alarm.rule && alarm.rule.fromNow ? Date.now() : alarm.time, alarm.rule);
	if (!time) {
		return false;
	}
	alarm.time = time;
	return alarm;
}

function updateAlarmFor (key) {
	updateNote(key, {alarm: updateAlarm(getData()[key].alarm)});
}

function updateExpiredNotes () {
	var key, data = getData(), note;
	for (key in data) {
		if (hasOwn.call(data, key)) {
			note = data[key];
			if (note.alarm && note.alarm.expire && note.alarm.time + note.alarm.expire < Date.now()) {
				updateNote(key, {alarm: updateExpiredAlarm(note.alarm)});
			}
		}
	}
}

function getActiveAlarms () {
	var key, data = getData(), note, list = [];
	for (key in data) {
		if (hasOwn.call(data, key)) {
			note = data[key];
			if (note.alarm && note.alarm.time <= Date.now()) {
				list.push(note);
			}
		}
	}
	return list;
}

function getNotesForPage () {
	var key, data = getData(), note, list = [];
	for (key in data) {
		if (hasOwn.call(data, key)) {
			note = data[key];
			if (note.page === mw.config.get('wgPageName')) {
				list.push(note);
			}
		}
	}
	return list;
}

function getAllNotes () {
	var key, data = getData(), list = [];
	for (key in data) {
		if (hasOwn.call(data, key)) {
			list.push(data[key]);
		}
	}
	return list;
}

function formatAlarm (note) {
	return mw.html.element('li', {'data-wikinoteskey': note.key}, new mw.html.Raw(
		mw.msg('wikinotes-alarm',
			mw.html.element('a', {href: mw.util.getUrl(note.page)}, note.page),
			mw.html.escape(note.title)
		) + ' ' +
		mw.html.element('a', {
			href: '#',
			'class': 'disable-alarm',
			title: mw.msg('wikinotes-disable-alarm-title')
		}, mw.msg('wikinotes-disable-alarm'))
	));
}

function formatNote (note) {
	var classes = ['wikinote'];
	if (note.alarm) {
		if (note.alarm.time <= Date.now()) {
			classes.push('active-alarm');
		} else {
			classes.push('inactive-alarm');
		}
	}
	return mw.html.element('aside', {
		'class': classes.join(' '),
		'data-wikinoteskey': note.key
	}, new mw.html.Raw(
		mw.html.element('a', {
			href: '#',
			'class': 'delete-note',
			title: mw.msg('wikinotes-delete-note-title')
		}, mw.msg('wikinotes-delete-note')) + '\n' +
		mw.html.element('h5', {}, note.title) + '\n' +
		mw.html.element('div', {}, note.content)
	));
}

function formatRow (note) {
	var alarm, unitToMsg = {
		m: 'wikinotes-minutes',
		h: 'wikinotes-hours',
		d: 'wikinotes-days',
		w: 'wikinotes-weeks',
		M: 'wikinotes-months',
		Y: 'wikinotes-years'
	};
	if (!note.alarm) {
		alarm = mw.msg('wikinotes-no-alarm');
	} else {
		alarm = (new Date(note.alarm.time)).toLocaleString();
		if (note.alarm.rule) {
			alarm += mw.html.element('br') +
				mw.msg('wikinotes-list-alarm-rule', note.alarm.rule.count, mw.msg(unitToMsg[note.alarm.rule.unit]));
		}
	}
	return mw.html.element('tr', {'data-wikinoteskey': note.key}, new mw.html.Raw([
		mw.html.element('td', {}, new mw.html.Raw(
			mw.html.element('a', {href: mw.util.getUrl(note.page + (note.section ? '#' + note.section : ''))},
				note.page.replace(/_/g, ' '))
		)),
		mw.html.element('td', {}, note.title),
		mw.html.element('td', {}, new mw.html.Raw(alarm)),
		mw.html.element('td', {}, new mw.html.Raw(
			mw.html.element('a', {href: '#', 'class': 'delete-note'}, mw.msg('wikinotes-delete-from-list'))
		))
	].join('')));
}

function onDeleteClick (e) {
	/*jshint validthis: true*///Event-Handler
	e.preventDefault();
	var $note = $(this).parents('.wikinote');
	deleteNote($note.data('wikinoteskey'));
	$note.remove();
}

function showOneNote (note, $content) {
	var $head = note.section && $content.find('#' + $.escapeSelector(note.section)),
		$note = $($.parseHTML(formatNote(note)));
	$note.find('.delete-note').on('click', onDeleteClick);
	if ($head && $head.length) {
		$head.parent('h1, h2, h3, h4, h5, h6').after($note);
	} else {
		$content.prepend($note);
	}
}

function showNotesForPage ($content) {
	if ($content.attr('id') !== 'mw-content-text') {
		return;
	}
	var i, list = getNotesForPage();
	if (list.length === 0) {
		return;
	}
	for (i = 0; i < list.length; i++) {
		showOneNote(list[i], $content);
	}
}

function showActiveAlarms () {
	var i, list = getActiveAlarms(), html = [];
	if (list.length === 0) {
		return;
	}
	for (i = 0; i < list.length; i++) {
		html.push(formatAlarm(list[i]));
	}
	html = mw.html.element('ul', {}, new mw.html.Raw(html.join('')));
	html = mw.html.element('div', {id: 'wikinotes-alarm'}, new mw.html.Raw(mw.msg('wikinotes-alarms', list.length, html)));
	$('#wikinotes-alarm').remove();
	$('#content').prepend(html);
	$('#wikinotes-alarm .disable-alarm').on('click', function (e) {
		e.preventDefault();
		var $this = $(this);
		updateAlarmFor($this.parents('li').data('wikinoteskey'));
		$this.remove();
	});
}

function showAllNotes () {
	var i, bookmarklet = 'javascript', list = getAllNotes(), html = [];
	document.title = mw.msg('pagetitle', mw.msg('wikinotes'));
	$('#firstHeading').html(mw.msg('wikinotes'));
	if (list.length === 0) {
		$('#mw-content-text').html(mw.msg('wikinotes-no-notes'));
		return;
	}
	bookmarklet += ':';
	bookmarklet += 'mw.libs.restoreWikinotes(' + JSON.stringify(getData()) + ')';
	html.push(mw.html.element('tr', {}, new mw.html.Raw([
		mw.html.element('th', {}, mw.msg('wikinotes-list-page')),
		mw.html.element('th', {}, mw.msg('wikinotes-list-title')),
		mw.html.element('th', {}, mw.msg('wikinotes-list-alarm')),
		mw.html.element('th', {}, mw.msg('wikinotes-list-delete'))
	].join(''))));
	for (i = 0; i < list.length; i++) {
		html.push(formatRow(list[i]));
	}
	html = mw.html.element('table', {id: 'wikinotes-table', 'class': 'wikitable'}, new mw.html.Raw(html.join('')));
	html = mw.html.element('p', {}, new mw.html.Raw(
		mw.msg('wikinotes-list-head',
			mw.html.element('a', {id: 'export-import-notes', href: '#'}, mw.msg('wikinotes-list-export-import')),
			mw.html.element('a', {id: 'delete-all-notes', href: '#'}, mw.msg('wikinotes-list-delete-all')),
			mw.html.element('a', {title: mw.msg('wikinotes-bookmarklet-title'), href: bookmarklet},
				mw.msg('wikinotes-bookmarklet'))
		)
	)) + html;
	$('#mw-content-text').html(html);
	$('tr .delete-note').on('click', function (e) {
		e.preventDefault();
		var $tr = $(this).parents('tr');
		deleteNote($tr.data('wikinoteskey'));
		$tr.remove();
	});
	$('#export-import-notes').on('click', function (e) {
		e.preventDefault();
		exportImportNotes();
	});
	$('#delete-all-notes').on('click', function (e) {
		e.preventDefault();
		deleteData();
		$('#wikinotes-table').remove();
	});
	mw.hook('wikipage.content').fire($('#mw-content-text'));
}

function getNoteDialog () {

	function CountUnitInputWidget (config) {
		CountUnitInputWidget.parent.apply(this, arguments);
		this.defaultNumber = config.min || 0;
		this.countInput = new OO.ui.NumberInputWidget({
			input: {value: this.defaultNumber},
			min: this.defaultNumber,
			isInteger: true,
			disabled: this.isDisabled()
		});
		this.unitInput = new OO.ui.DropdownWidget({
			$overlay: config.$overlay,
			menu: {
				items: config.unitItems
			},
			disabled: this.isDisabled()
		});

		this.countInput.connect(this, {
			change: this.emit.bind(this, 'change'),
			enter: this.emit.bind(this, 'enter')
		});
		this.unitInput.getMenu().connect(this, {
			select: this.emit.bind(this, 'change')
		});

		this.countInput.$element.css({width: '30%'});
		this.unitInput.$element.css({width: '60%'});
		this.$element.append(
			(new OO.ui.HorizontalLayout({items: [
				this.countInput, this.unitInput
			]})).$element
		);
	}

	OO.inheritClass(CountUnitInputWidget, OO.ui.Widget);

	CountUnitInputWidget.prototype.getValue = function () {
		var val = Math.round(Number(this.countInput.getValue()));
		if (isNaN(val) || val < this.defaultNumber) {
			val = this.defaultNumber;
		}
		return [
			val,
			this.unitInput.getMenu().findSelectedItem().getData()
		];
	};

	CountUnitInputWidget.prototype.getMenu = function () {
		return this.unitInput.getMenu();
	};

	CountUnitInputWidget.prototype.setDisabled = function () {
		CountUnitInputWidget.parent.prototype.setDisabled.apply(this, arguments);
		if (this.countInput) {
			this.countInput.setDisabled(this.isDisabled());
		}
		if (this.unitInput) {
			this.unitInput.setDisabled(this.isDisabled());
		}
		return this;
	};

	function NoteDialog (config) {
		NoteDialog.parent.apply(this, arguments);
		this.staticData = config.data || {};
	}

	OO.inheritClass(NoteDialog, OO.ui.ProcessDialog);
	NoteDialog.static.name = 'schnark-note';
	NoteDialog.static.size = 'large';
	NoteDialog.static.title = mw.msg('wikinotes-dialog');
	NoteDialog.static.actions = [
		{
			action: 'save',
			label: mw.msg('wikinotes-dialog-save'),
			flags: ['primary', 'progressive']
		}, {
			label: mw.msg('wikinotes-dialog-cancel'),
			flags: ['safe', 'close']
		}
	];

	NoteDialog.prototype.initialize = function () {
		var fieldsetBasic, fieldsetAdvanced;
		NoteDialog.parent.prototype.initialize.apply(this, arguments);

		//Basic layout
		this.panel = new OO.ui.PanelLayout({$: this.$, padded: true, expanded: false});
		fieldsetBasic = new OO.ui.FieldsetLayout({label: mw.msg('wikinotes-dialog-note')});
		fieldsetAdvanced = new OO.ui.FieldsetLayout({label: mw.msg('wikinotes-dialog-alarm')});
		this.panel.$element.append((new OO.ui.LabelWidget({label: mw.msg('wikinotes-dialog-intro')})).$element);
		this.panel.$element.append(fieldsetBasic.$element);
		this.panel.$element.append(fieldsetAdvanced.$element);

		//Inputs for basic data
		this.titleInput = new OO.ui.TextInputWidget();
		this.contentInput = new OO.ui.MultilineTextInputWidget();
		fieldsetBasic.addItems([
			new OO.ui.FieldLayout(this.titleInput, {
				label: mw.msg('wikinotes-dialog-title'),
				align: 'top'
			}),
			new OO.ui.FieldLayout(this.contentInput, {
				label: mw.msg('wikinotes-dialog-content'),
				align: 'top'
			})
		]);

		//Inputs for advanced data
		this.alarmTypeInput = new OO.ui.DropdownWidget({
			$overlay: this.$overlay,
			menu: {
				items: [
					new OO.ui.MenuOptionWidget({
						data: 'none',
						label: mw.msg('wikinotes-dialog-alarm-type-none')
					}),
					new OO.ui.MenuOptionWidget({
						data: 'once',
						label: mw.msg('wikinotes-dialog-alarm-type-once')
					}),
					new OO.ui.MenuOptionWidget({
						data: 'regularTimes',
						label: mw.msg('wikinotes-dialog-alarm-type-regular-times')
					}),
					new OO.ui.MenuOptionWidget({
						data: 'regularPeriod',
						label: mw.msg('wikinotes-dialog-alarm-type-regular-period')
					})
				]
			}
		});
		this.dateInput = new mw.widgets.datetime.DateTimeInputWidget({
			//$overlay: this.$overlay,
			formatter: {format: mw.msg('wikinotes-date-time-format'), local: true},
			min: new Date(),
			value: new Date(Number(new Date()) + 24 * 60 * 60 * 1000),
			clearable: false
		});
		this.expireInput = new CountUnitInputWidget({
			$overlay: this.$overlay,
			unitItems: [
				new OO.ui.MenuOptionWidget({
					data: 1000 * 60,
					label: mw.msg('wikinotes-minutes')
				}),
				new OO.ui.MenuOptionWidget({
					data: 1000 * 60 * 60,
					label: mw.msg('wikinotes-hours')
				}),
				new OO.ui.MenuOptionWidget({
					data: 1000 * 60 * 60 * 24,
					label: mw.msg('wikinotes-days')
				}),
				new OO.ui.MenuOptionWidget({
					data: 1000 * 60 * 60 * 24 * 7,
					label: mw.msg('wikinotes-weeks')
				})
			]
		});
		this.ruleInput = new CountUnitInputWidget({
			$overlay: this.$overlay,
			min: 1,
			unitItems: [
				new OO.ui.MenuOptionWidget({
					data: 'h',
					label: mw.msg('wikinotes-hours')
				}),
				new OO.ui.MenuOptionWidget({
					data: 'd',
					label: mw.msg('wikinotes-days')
				}),
				new OO.ui.MenuOptionWidget({
					data: 'w',
					label: mw.msg('wikinotes-weeks')
				}),
				new OO.ui.MenuOptionWidget({
					data: 'M',
					label: mw.msg('wikinotes-months')
				}),
				new OO.ui.MenuOptionWidget({
					data: 'Y',
					label: mw.msg('wikinotes-years')
				})
			]
		});
		this.alarmTypeInput.getMenu()
			.connect(this, {select: 'onAlarmTypeChange'})
			.selectItemByData('none');
		this.expireInput.getMenu().selectItemByData(1000 * 60 * 60 * 24);
		this.ruleInput.getMenu().selectItemByData('d');
		fieldsetAdvanced.addItems([
			new OO.ui.FieldLayout(this.alarmTypeInput, {
				label: mw.msg('wikinotes-dialog-alarm-type'),
				align: 'top'
			}),
			new OO.ui.FieldLayout(this.dateInput, {
				label: mw.msg('wikinotes-dialog-alarm-time'),
				align: 'top'
			}),
			new OO.ui.FieldLayout(this.expireInput, {
				label: mw.msg('wikinotes-dialog-expire'),
				align: 'top'
			}),
			new OO.ui.FieldLayout(this.ruleInput, {
				label: mw.msg('wikinotes-dialog-rule'),
				align: 'top'
			})
		]);

		this.$body.append(this.panel.$element);
	};

	NoteDialog.prototype.getActionProcess = function (action) {
		if (action === 'save') {
			return new OO.ui.Process(function () {
				this.saveNote(this.staticData.page, this.staticData.section);
				this.close();
			}, this);
		}
		return NoteDialog.parent.prototype.getActionProcess.apply(this, arguments);
	};

	NoteDialog.prototype.getBodyHeight = function () {
		return this.panel.$element.outerHeight(true) + 100;
	};

	NoteDialog.prototype.onAlarmTypeChange = function () {
		var alarmType = this.alarmTypeInput.getMenu().findSelectedItem().getData();
		if (alarmType === 'none') {
			this.dateInput.setDisabled(true);
			this.expireInput.setDisabled(true);
			this.ruleInput.setDisabled(true);
		} else if (alarmType === 'once') {
			this.dateInput.setDisabled(false);
			this.expireInput.setDisabled(false);
			this.ruleInput.setDisabled(true);
		} else {
			this.dateInput.setDisabled(false);
			this.expireInput.setDisabled(false);
			this.ruleInput.setDisabled(false);
		}
	};

	NoteDialog.prototype.saveNote = function (page, section) {
		var note = {}, alarmType, alarm, date, rule, expire;

		note.title = this.titleInput.getValue();
		note.content = this.contentInput.getValue();

		alarmType = this.alarmTypeInput.getMenu().findSelectedItem().getData();
		if (alarmType === 'none') {
			alarm = false;
		} else {
			date = this.dateInput.getValueAsDate();
			if (!date || Number(date) < Number(new Date())) {
				date = new Date();
			}
			date = Number(date);
			if (alarmType === 'once') {
				alarm = {time: date};
			} else {
				rule = this.ruleInput.getValue();
				alarm = {
					time: date,
					rule: {
						count: rule[0],
						unit: rule[1]
					}
				};
				if (alarmType === 'regularPeriod') {
					alarm.rule.fromNow = true;
				}
			}
			expire = this.expireInput.getValue();
			expire = expire[0] * expire[1];
			if (expire > 0) {
				alarm.expire = expire;
			}
		}
		note.alarm = alarm;
		note.page = page;
		if (section) {
			note.section = section;
		}
		addNote(note);
		showOneNote(note, $('#mw-content-text'));
	};

	return NoteDialog;
}

function showNewNoteDialog (section) {
	var NoteDialog, windowManager, noteDialog;
	NoteDialog = getNoteDialog();
	windowManager = new OO.ui.WindowManager();
	$('body').append(windowManager.$element);
	noteDialog = new NoteDialog({data: {
		page: mw.config.get('wgPageName'),
		section: section
	}});
	windowManager.addWindows([noteDialog]);
	windowManager.openWindow(noteDialog);
}

function addNewNote (e) {
	/*jshint validthis: true*///Event-Handler
	var section = $(this).find('a').data('wikinotessection');
	e.preventDefault();
	mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets', 'mediawiki.widgets.datetime', 'oojs-ui-windows']).then(function () {
		showNewNoteDialog(section);
	});
}

function initAlarms () {
	updateExpiredNotes();
	$(function () {
		showActiveAlarms();
		window.setInterval(function () {
			resetData();
			showActiveAlarms();
		}, 5 * 60 * 1000);
	});
}

function initNew ($content) {
	if ($content.attr('id') !== 'mw-content-text') {
		return;
	}
	//TODO mw.hook('wikipage.title').add(...) und gleich wie section-links.js
	$content = $content.add($('#firstHeading').parent());
	$content.find('.wikinotes-add-new').remove();
	$content.find('h1, h2, h3, h4, h5, h6').each(function (i, h) {
		var $h = $(h), hash = $h.find('.mw-headline').attr('id') || '';
		if (i === 0 || hash !== '') {
			$h.append($('<span>')
				.addClass('wikinotes-add-new mw-editsection-like')
				.html(mw.msg('brackets', mw.html.element('a', {href: '#', 'class': 'internal',
					title: mw.msg('wikinotes-new-title'), 'data-wikinotessection': hash},
					mw.msg('wikinotes-new'))))
			);
		}
	});
	$content.find('.wikinotes-add-new').on('click', addNewNote);
	if (!sectLinksHook) {
		mw.hook('userjs.section-links').add(function (callback, $content) {
			callback($content.find('.wikinotes-add-new'), mw.msg('wikinotes-new-title'), 'note');
		});
		sectLinksHook = true;
	}
}

function init () {
	initL10N(l10n, ['pagetitle', 'brackets']);
	mw.util.addCSS(getCSS());
	initAlarms();
	if (
		mw.config.get('wgNamespaceNumber') === -1 &&
		(mw.config.get('wgTitle') === 'Wikinotes' || mw.config.get('wgTitle') === mw.msg('wikinotes'))
	) {
		mw.config.set('wgCanonicalSpecialPageName', 'Wikinotes');
		$(showAllNotes);
	}
	mw.hook('wikipage.content').add(showNotesForPage).add(initNew);
}

if (mw.config.get('wgAction') === 'view') {
	mw.loader.using(['mediawiki.util', 'mediawiki.language', 'mediawiki.storage', 'mediawiki.jqueryMsg']).then(init);
}

mw.libs.restoreWikinotes = setData;

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