Benutzer:Schnark/js/screenshot.js

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

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
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
//Dokumentation unter [[Benutzer:Schnark/js/screenshot]] <nowiki>
/*global mediaWiki*/
/*global Blob*///für alte jshint-Version
(function ($, mw, libs) {
"use strict";
var useCORS = false, l10n, projectSpecific, undoQueue = [], undoTooltips = [], zindex = 20000;
//jscs:disable maximumLineLength
l10n = {
	en: {
		'size-bytes': '$1 B',
		'size-kilobytes': '$1 KB',
		'size-megabytes': '$1 MB',
		'size-gigabytes': '$1 GB',
		'interlanguage-link-title': '$1 – $2',
		'comma-separator': ', ',

		'screenshot': 'Screenshot',
		'tooltip-t-screenshot': 'Take screenshot',
		'accesskey-t-screenshot': '5',
		'screenshot-key-printscreen': '<Alt>+<Print>', //spitze Klammern werden in Tastatursymbole übersetzt
		'screenshot-key-mac-printscreen': '<cmd \u2318>+<shift \u21e7>+<ctrl>+<4>, <Space>',
		'screenshot-key-unzoom': '<Ctrl>+<0>',
		'screenshot-key-mac-unzoom': '<cmd \u2318>+<0>',
		'screenshot-key-paste': '<Ctrl>+<V>',
		'screenshot-key-mac-paste': '<cmd \u2318>+<V>',
		'screenshot-ok': 'Okay',
		'screenshot-cancel': 'Cancel',
		'screenshot-continue': 'Next',
		'screenshot-finish': 'End',
		'screenshot-upload': 'Upload',
		'screenshot-error': 'There was an error.',
		'screenshot-success': 'Uploaded screenshot successfully.',
		'screenshot-step': 'Step $1: $2', //$1: Nummer des Schritts, $2: Bezeichnung des Schritts
		'screenshot-take': 'Take screenshot',
		'screenshot-step1': 'First, take a screenshot of the current browser window: Scroll to the position you want to shoot and click <kbd>Next</kbd> and then press $1. You have $2&#160;seconds time for taking the screenshot. In case you have zoomed in, please turn off this feature for taking the screenshot and editing by pressing $3. Also, do not resize the browser window after taking the screenshot.', //$1: Tastenkombination, $2: Anzahl Sekunden, $3: Tastenkombination
		'screenshot-copy': 'Transfer screenshot',
		'screenshot-step2': 'Paste the screenshot into the red box. For doing so, press $1.', //$1: Tastenkombination
		'screenshot-missing': 'No screenshot found. Did you really insert one?',
		'screenshot-notfound': 'The screenshot inserted doesn\'t appear to origin from the current window. Just give it a second shot.',
		'screenshot-edit': 'Edit screenshot',
		'screenshot-step3': 'Now you can edit and crop (red frame) the screenshot, which is shown in the background.',
		'screenshot-help-title': 'Help about editing',
		'screenshot-step3-help': 'The red frame is resizable and can be used to crop the screenshot.<br />Toolbar:<ul><li>Pointer: Inserts a pointer (left top corner), can be dragged.</li><li>Arrow/straigt line drawing tool: After selecting this tool, click on the starting point and then at the end point desired.</li><li>Rectangle: After selecting this tool, click the first corner, then the second, diagonally opposite, one.</li><li>Ellipse: Imagine there would be a rectangle surrounding the ellipse.</li><li>Blur: Much like the rectangle tool. It is not the appropriate tool for removing sensitive data!</li><li>Undo: All except color selection.</li><li>Color select button: Clicking it toggles the color picker.</li><li>Show help: Shows this help.</li></ul>',
		'screenshot-toolbar-color': 'Choose color',
		'screenshot-toolbar-color-title': 'Choose color',
		'screenshot-toolbar-insert-cursor': 'Insert pointer',
		'screenshot-toolbar-arrow': 'Draw arrow',
		'screenshot-toolbar-arrow-symbol': '↗',
		'screenshot-toolbar-line': 'Draw straight line',
		'screenshot-toolbar-line-symbol': '\u2571',
		'screenshot-toolbar-rect': 'Draw rectangle',
		'screenshot-toolbar-rect-symbol': '□',
		'screenshot-toolbar-ellipse': 'Draw ellipse',
		'screenshot-toolbar-ellipse-symbol': 'O', //alternativ '\u2B2D', aber schlechtere Font-Unterstützung
		'screenshot-toolbar-blur': 'Blur',
		'screenshot-toolbar-blur-symbol': '\u2591',
		'screenshot-toolbar-undo': 'Undo: $1',
		'screenshot-toolbar-undo-symbol': '\u21b6',
		'screenshot-toolbar-help': 'Show help',
		'screenshot-toolbar-help-symbol': '?',
		'screenshot-upload-head': 'Upload screenshot',
		'screenshot-step4': 'You can $1 (opens in a new tab) and save it for further editing. Or upload it right now. Choose a file name that is not yet in use and write some descriptive words about the file. <span style="color: red;">Make sure to pick the correct license;</span> pre-selection is a suggestion by a small computer program only!', //$1: Link auf Bildschirmfoto (Text: screenshot-step4-link)
		'screenshot-step4-link': 'view the screenshot',
		'screenshot-save': 'Save screenshot',
		'screenshot-step4b': 'You can $1 (opens in a new tab) and save it for further editing and uploading. Uploading is unfortunately impossible because your browser does not support the features necessary.', //$1: Link auf Bildschirmfoto (Text: screenshot-step4-link)
		'screenshot-upload-legend': 'Upload',
		'screenshot-upload-location': 'Wiki:',
		'screenshot-upload-local': 'lokal',
		'screenshot-upload-commons': 'Commons',
		'screenshot-upload-filename': 'File name:',
		'screenshot-upload-description': 'File description:',
		'screenshot-upload-description-replace': 'Edit full file description',
		'screenshot-upload-description-description': 'Description:',
		'screenshot-upload-description-logo': '$1-logo visible', //$1: Name des Projekts
		'screenshot-upload-description-mediawiki': 'Parts of the MediaWiki (user interface elements) visible',
		'screenshot-upload-description-text': 'Text visible',
		'screenshot-upload-description-text-author': 'Author:',
		'screenshot-upload-description-image': 'Image visible (please provide author and license)',
		'screenshot-upload-description-image-author': 'Photographer/Painter/etc.:',
		'screenshot-upload-description-image-license': 'Image license:',
		'screenshot-upload-description-other': 'Further information (Categories etc.)',
		'screenshot-description-ownlanguage': '$1', //$1: {{en|1=Screenshot}}
		'screenshot-preview': 'Show preview',
		'screenshot-preview-title': 'Preview file description',
		'screenshot-filename-error-empty': 'Please provide a file name!',
		'screenshot-filename-error-invalid': 'Please provide a file name without disallowed characters!',
		'screenshot-filename-error-duplicate': 'There is a file with the same name. Please choose a different name.',
		'screenshot-filename-error-protected': 'Please provide a meaningful file name!',
		'screenshot-filename-error-anon': 'You have to login before you can upload screenshots!',
		'screenshot-filename-error-unknown': 'Please choose a different file name or try it again.',
		'screenshot-please-wait': 'Please wait.<br />Screenshot is going to be uploaded.',
		'screenshot-error-body': 'There was an error while uploading the screenshot: <code>$1</code>', //$1: Fehler
		'screenshot-unknown-error': '(unknown error)',
		'screenshot-success-body': 'Your screenshot has been successfully uploaded! Use the following code for including it into pages:<br /><code style="white-space: nowrap;">$1</code><hr />$2', //$1: Code, $2: Info
		'screenshot-info': '$1, $2 ($3×$4, $5)', //$1: Link Bildbeschreibungsseite, $2: Link Vollbild, $3: Breite, $4: Höhe, $5: Dateigröße
		'screenshot-info-description': 'File description page',
		'screenshot-info-full': 'Full screen',
		'screenshot-description-example': 'This is how it looks like'
	},
	de: {
		'size-bytes': '$1 Bytes',
		'screenshot': 'Bildschirmfoto',
		'tooltip-t-screenshot': 'Bildschirmfoto aufnehmen',
		'screenshot-key-printscreen': '<Alt>+<Druck>',
		'screenshot-key-mac-printscreen': '<cmd \u2318>+<shift \u21e7>+<ctrl>+<4>, <Leertaste>',
		'screenshot-key-unzoom': '<Strg>+<0>',
		'screenshot-key-mac-unzoom': '<cmd \u2318>+<0>',
		'screenshot-key-paste': '<Strg>+<V>',
		'screenshot-key-mac-paste': '<cmd \u2318>+<V>',
		'screenshot-ok': 'Okay',
		'screenshot-cancel': 'Abbrechen',
		'screenshot-continue': 'Weiter',
		'screenshot-finish': 'Beenden',
		'screenshot-upload': 'Hochladen',
		'screenshot-error': 'Ein Fehler ist aufgetreten',
		'screenshot-success': 'Bildschirmfoto erfolgreich hochgeladen',
		'screenshot-step': 'Schritt $1: $2',
		'screenshot-take': 'Bildschirmfoto aufnehmen',
		'screenshot-step1': 'Zunächst musst du ein Bildschirmfoto vom aktuellen Browserfenster aufnehmen. Dazu klickst du auf <kbd>Weiter</kbd> und drückst dann die Tastenkombination $1. Selbstverständlich kannst du vorher noch zur gewünschten Stelle scrollen und bei Bedarf den Mauszeiger so positionieren, dass ein Tooltip angezeigt wird. Insgesamt hast du $2&#160;Sekunden Zeit. Falls du die Zoom-Funktion deines Browsers verwendest, solltest du sie zum Aufnehmen und Bearbeiten des Bildschirmfotos ausschalten, drücke dazu die Tastenkombination $3. Nachdem du das Bildschirmfoto aufgenommen hast, solltest du die Größe des Browserfensters nicht mehr verändern.',
		'screenshot-copy': 'Bildschirmfoto übertragen',
		'screenshot-step2': 'Füge nun das aufgenommene Bildschirmfoto in den roten Kasten ein. Dazu drückst du am einfachsten die Tastenkombination $1.',
		'screenshot-missing': 'Du hast offenbar kein Bildschirmfoto eingefügt.',
		'screenshot-notfound': 'Du hast zwar ein Bild eingefügt, aber das scheint kein Bildschirmfoto des aktuellen Fensters zu sein. Versuche es am besten ein weiteres Mal, es kann nämlich Fälle geben, in denen es nicht sofort klappt.',
		'screenshot-edit': 'Bildschirmfoto bearbeiten',
		'screenshot-step3': 'Jetzt kannst du das Bildschirmfoto auf den gewünschten Ausschnitt (roter Rahmen) beschneiden und bei Bedarf bearbeiten.',
		'screenshot-help-title': 'Hilfe zu den Bearbeiten-Funktionen',
		'screenshot-step3-help': 'Der rote Rahmen gibt den gewünschten Beschnitt an, du kannst ihn in der Größe ändern.<br />Funktionen der Werkzeugleiste:<ul><li>Mauszeiger: Fügt den entsprechenden Zeiger ein (links oben), anschließend kann er an die gewünschte Stelle verschoben werden.</li><li>Pfeil/Gerade Linie zeichnen: Nach Auswahl des Werkzeugs klickst du erst den Start- dann den Endpunkt an.</li><li>Rechteck zeichnen: Nach Auswahl des Werkzeugs klickst du erst eine Ecke an, dann die diagonal gegenüberliegende.</li><li>Ellipse zeichnen: Nach Auswahl des Werkzeugs klickst du erst eine Ecke des umbebenden Rechtecks an, dann die diagonal gegenüberliegende.</li><li>Bereich verwischen: Nach Auswahl des Werkzeugs wählst du wie beim Rechteck den Bereich aus, den du verwischen willst. Bei sensiblen Daten solltest du diesen Vorgang auf jeden Fall mehrfach und nur mit kleinen Bereichen durchführen!</li><li>Rückgängig: Macht die letzte Aktion (außer Farbauswahl) rückgängig.</li><li>Farbe wählen: Ein Klick auf das Symbol öffnet bzw. schließt den Farbwähler, die eingestellte Farbe gilt für alle folgenden Zeichenwerkzeuge.</li><li>Hilfe anzeigen: Zeigt diese Hilfe an.</li></ul>',
		'screenshot-toolbar-color': 'Farbe wählen',
		'screenshot-toolbar-color-title': 'Farbe wählen',
		'screenshot-toolbar-insert-cursor': 'Mauszeiger einfügen',
		'screenshot-toolbar-arrow': 'Pfeil zeichnen',
		'screenshot-toolbar-line': 'Gerade Linie zeichnen',
		'screenshot-toolbar-rect': 'Rechteck zeichnen',
		'screenshot-toolbar-ellipse': 'Ellipse zeichnen',
		'screenshot-toolbar-blur': 'Bereich verwischen',
		'screenshot-toolbar-undo': 'Rückgängig: $1',
		'screenshot-toolbar-help': 'Hilfe anzeigen',
		'screenshot-upload-head': 'Bildschirmfoto hochladen',
		'screenshot-step4': 'Du kannst das $1 (wird in einem neuen Tab geöffnet) und zum Weiterbearbeiten abspeichern. Du kannst es aber auch direkt hochladen. Wähle einen freien Dateinamen und mache die nötigen Angaben für die Bildbeschreibungsseite. <span style="color: red;">Beachte dabei vor allem die korrekten Angaben zur Lizenz,</span> die Vorbelegung ist nur ein Vorschlag, den du mit Vorsicht genießen solltest!',
		'screenshot-step4-link': 'Bildschirmfoto jetzt ansehen',
		'screenshot-save': 'Bildschirmfoto speichern',
		'screenshot-step4b': 'Du kannst das $1 (wird in einem neuen Tab geöffnet) und zum Weiterbearbeiten und Hochladen abspeichern. Ein direktes Hochladen ist leider nicht möglich, da dein Browser die dazu nötigen Funktionen nicht unterstützt.',
		'screenshot-upload-legend': 'Hochladen',
		'screenshot-upload-location': 'Wiki:',
		'screenshot-upload-local': 'lokal',
		'screenshot-upload-commons': 'Commons',
		'screenshot-upload-filename': 'Dateiname:',
		'screenshot-upload-description': 'Bildbeschreibung:',
		'screenshot-upload-description-replace': 'Gesamte Bildbeschreibung bearbeiten',
		'screenshot-upload-description-description': 'Beschreibung:',
		'screenshot-upload-description-logo': '$1-Logo sichtbar',
		'screenshot-upload-description-mediawiki': 'Teile von MediaWiki sichtbar',
		'screenshot-upload-description-text': 'Text sichtbar',
		'screenshot-upload-description-text-author': 'Autor:',
		'screenshot-upload-description-image': 'Bild sichtbar (bitte Autor und Lizenz angeben)',
		'screenshot-upload-description-image-author': 'Fotograf/Zeichner/etc.:',
		'screenshot-upload-description-image-license': 'Bildlizenz:',
		'screenshot-upload-description-other': 'Weitere Angaben (Kategorien etc.)',
		'screenshot-description-ownlanguage': '$1\n{{de|1=Bildschirmfoto}}',
		'screenshot-preview': 'Vorschau zeigen',
		'screenshot-preview-title': 'Vorschau der Bildbeschreibung',
		'screenshot-filename-error-empty': 'Bitte gib einen Dateinamen an!',
		'screenshot-filename-error-invalid': 'Bitte gib einen Dateinamen ohne verbotene Sonderzeichen an!',
		'screenshot-filename-error-duplicate': 'Unter diesem Namen gibt es bereits eine Datei, gib bitte einen anderen an!',
		'screenshot-filename-error-protected': 'Bitte gib einen aussagekräftigeren Namen an!',
		'screenshot-filename-error-anon': 'Du musst dich erst einloggen, bevor du das Bildschirmfoto hochladen kannst!',
		'screenshot-filename-error-unknown': 'Bitte gib einen anderen Dateinamen an (oder versuche es erneut)!',
		'screenshot-please-wait': 'Bitte warten.<br />Das Bildschirmfoto wird hochgeladen.',
		'screenshot-error-body': 'Leider trat beim Hochladen ein Fehler auf: <code>$1</code>',
		'screenshot-unknown-error': '(unbekannter Fehler)',
		'screenshot-success-body': 'Dein Bildschirmfoto wurde erfolgreich hochgeladen! Du kannst es nun mit dem folgenden Code in eine Seite einbinden:<br /><code style="white-space: nowrap;">$1</code><hr />$2',
		'screenshot-info-description': 'Bildbeschreibungsseite',
		'screenshot-info-full': 'Vollbild',
		'screenshot-description-example': 'So sieht’s aus'
	},
	'de-formal': {
		'screenshot-step1': 'Zunächst müssen Sie ein Bildschirmfoto vom aktuellen Browserfenster aufnehmen. Dazu klicken Sie auf <kbd>Weiter</kbd> und drücken dann die Tastenkombination $1. Selbstverständlich können Sie vorher noch zur gewünschten Stelle scrollen und bei Bedarf den Mauszeiger so positionieren, dass ein Tooltip angezeigt wird. Insgesamt haben Sie $2&#160;Sekunden Zeit. Falls Sie die Zoom-Funktion Ihres Browsers verwenden, sollten Sie sie zum Aufnehmen und Bearbeiten des Bildschirmfotos ausschalten, drücken Sie dazu die Tastenkombination $3. Nachdem Sie das Bildschirmfoto aufgenommen haben, sollten Sie die Größe des Browserfensters nicht mehr verändern.',
		'screenshot-step2': 'Fügen Sie nun das aufgenommene Bildschirmfoto in den roten Kasten ein. Dazu drücken Sie am einfachsten die Tastenkombination $1.',
		'screenshot-missing': 'Sie haben offenbar kein Bildschirmfoto eingefügt.',
		'screenshot-notfound': 'Sie haben zwar ein Bild eingefügt, aber das scheint kein Bildschirmfoto des aktuellen Fensters zu sein. Versuchen Sie es am besten ein weiteres Mal, es kann nämlich Fälle geben, in denen es nicht sofort klappt.',
		'screenshot-step3': 'Jetzt können Sie das Bildschirmfoto auf den gewünschten Ausschnitt (roter Rahmen) beschneiden und bei Bedarf bearbeiten.',
		'screenshot-step3-help': 'Der rote Rahmen gibt den gewünschten Beschnitt an, Sie können ihn in der Größe ändern.<br />Funktionen der Werkzeugleiste:<ul><li>Mauszeiger: Fügt den entsprechenden Zeiger ein (links oben), anschließend kann er an die gewünschte Stelle verschoben werden.</li><li>Pfeil/Gerade Linie zeichnen: Nach Auswahl des Werkzeugs klicken Sie erst den Start- dann den Endpunkt an.</li><li>Rechteck zeichnen: Nach Auswahl des Werkzeugs klicken Sie erst eine Ecke an, dann die diagonal gegenüberliegende.</li><li>Ellipse zeichnen: Nach Auswahl des Werkzeugs klicken Sie erst eine Ecke des umbebenden Rechtecks an, dann die diagonal gegenüberliegende.</li><li>Bereich verwischen: Nach Auswahl des Werkzeugs wählen Sie wie beim Rechteck den Bereich aus, den Sie verwischen wollen. Bei sensiblen Daten sollten Sie diesen Vorgang auf jeden Fall mehrfach und nur mit kleinen Bereichen durchführen!</li><li>Rückgängig: Macht die letzte Aktion (außer Farbauswahl) rückgängig.</li><li>Farbe wählen: Ein Klick auf das Symbol öffnet bzw. schließt den Farbwähler, die eingestellte Farbe gilt für alle folgenden Zeichenwerkzeuge.</li><li>Hilfe anzeigen: Zeigt diese Hilfe an.</li></ul>',
		'screenshot-step4': 'Sie können das $1 (wird in einem neuen Tab geöffnet) und zum Weiterbearbeiten abspeichern. Sie können es aber auch direkt hochladen. Wählen Sie einen freien Dateinamen und machen Sie die nötigen Angaben für die Bildbeschreibungsseite. <span style="color: red;">Beachten Sie dabei vor allem die korrekten Angaben zur Lizenz,</span> die Vorbelegung ist nur ein Vorschlag, den Sie mit Vorsicht genießen sollten!',
		'screenshot-step4b': 'Sie können das $1 (wird in einem neuen Tab geöffnet) und zum Weiterbearbeiten und Hochladen abspeichern. Ein direktes Hochladen ist leider nicht möglich, da Ihr Browser die dazu nötigen Funktionen nicht unterstützt.',
		'screenshot-filename-error-empty': 'Bitte geben Sie einen Dateinamen an!',
		'screenshot-filename-error-invalid': 'Bitte geben Sie einen Dateinamen ohne verbotene Sonderzeichen an!',
		'screenshot-filename-error-duplicate': 'Unter diesem Namen gibt es bereits eine Datei, geben Sie bitte einen anderen an!',
		'screenshot-filename-error-protected': 'Bitte geben Sie einen aussagekräftigeren Namen an!',
		'screenshot-filename-error-anon': 'Sie müssen sich erst einloggen, bevor Sie das Bildschirmfoto hochladen können!',
		'screenshot-filename-error-unknown': 'Bitte geben Sie einen anderen Dateinamen an (oder versuchen Sie es erneut)!',
		'screenshot-success-body': 'Ihr Bildschirmfoto wurde erfolgreich hochgeladen! Sie können es nun mit dem folgenden Code in eine Seite einbinden:<br /><code style="white-space: nowrap;">$1</code><hr />$2'
	},
	'de-ch': {
		'screenshot-step1': 'Zunächst musst du ein Bildschirmfoto vom aktuellen Browserfenster aufnehmen. Dazu klickst du auf <kbd>Weiter</kbd> und drückst dann die Tastenkombination $1. Selbstverständlich kannst du vorher noch zur gewünschten Stelle scrollen und bei Bedarf den Mauszeiger so positionieren, dass ein Tooltip angezeigt wird. Insgesamt hast du $2&#160;Sekunden Zeit. Falls du die Zoom-Funktion deines Browsers verwendest, solltest du sie zum Aufnehmen und Bearbeiten des Bildschirmfotos ausschalten, drücke dazu die Tastenkombination $3. Nachdem du das Bildschirmfoto aufgenommen hast, solltest du die Grösse des Browserfensters nicht mehr verändern.',
		'screenshot-step3-help': 'Der rote Rahmen gibt den gewünschten Beschnitt an, du kannst ihn in der Grösse ändern.<br />Funktionen der Werkzeugleiste:<ul><li>Mauszeiger: Fügt den entsprechenden Zeiger ein (links oben), anschliessend kann er an die gewünschte Stelle verschoben werden.</li><li>Pfeil/Gerade Linie zeichnen: Nach Auswahl des Werkzeugs klickst du erst den Start- dann den Endpunkt an.</li><li>Rechteck zeichnen: Nach Auswahl des Werkzeugs klickst du erst eine Ecke an, dann die diagonal gegenüberliegende.</li><li>Ellipse zeichnen: Nach Auswahl des Werkzeugs klickst du erst eine Ecke des umbebenden Rechtecks an, dann die diagonal gegenüberliegende.</li><li>Bereich verwischen: Nach Auswahl des Werkzeugs wählst du wie beim Rechteck den Bereich aus, den du verwischen willst. Bei sensiblen Daten solltest du diesen Vorgang auf jeden Fall mehrfach und nur mit kleinen Bereichen durchführen!</li><li>Rückgängig: Macht die letzte Aktion (ausser Farbauswahl) rückgängig.</li><li>Farbe wählen: Ein Klick auf das Symbol öffnet bzw. schliesst den Farbwähler, die eingestellte Farbe gilt für alle folgenden Zeichenwerkzeuge.</li><li>Hilfe anzeigen: Zeigt diese Hilfe an.</li></ul>',
		'screenshot-step4': 'Du kannst das $1 (wird in einem neuen Tab geöffnet) und zum Weiterbearbeiten abspeichern. Du kannst es aber auch direkt hochladen. Wähle einen freien Dateinamen und mache die nötigen Angaben für die Bildbeschreibungsseite. <span style="color: red;">Beachte dabei vor allem die korrekten Angaben zur Lizenz,</span> die Vorbelegung ist nur ein Vorschlag, den du mit Vorsicht geniessen solltest!'
	}
};
//jscs:enable maximumLineLength
projectSpecific = {
'*': {
	thumb: 'thumb',
	upright: 'upright',
	comment: '',
	desc: '',
	authorText: '[{{fullurl:$page|action=history}}]',
	authorImage: '',
	licenseImage: '',
	other: '',
	getDescription: function (data) {
		return data.desc + '\n\n' +
				'URL: ' + data.url + '\n\n' +
				(data.text ? data.authorText + '\n\n' : '') +
				(data.image ? data.authorImage + '\n' + data.licenseImage + '\n' : '') +
				'~~~~~\n\n' +
				data.other;
	}
},
'my_wiki': {
	thumb: 'miniatur',
	upright: 'hochkant',
	comment: 'Bildschirmfoto mit [[Benutzer:Schnark/js/screenshot]] hochgeladen',
	desc: 'Bildschirmfoto',
	authorText: '[{{fullurl:$page|action=history}} Versionsgeschichte]',
	authorImage: '',
	licenseImage: '',
	other: '',
	getDescription: function (data) {
		return 'Angaben:\n' +
			'* Beschreibung: ' + data.desc + '\n' +
			'* Logo: ' + (data.logo ? 'ja' : 'nein') + '\n' +
			'* MediaWiki: ' + (data.mediawiki ? 'ja' : 'nein') + '\n' +
			'* Text: ' + (data.text ? data.authorText : 'nein') + '\n' +
			'* Bild: ' + (data.image ? data.authorImage + '(' + data.licenseImage + ')' : 'nein') + '\n' +
			'* Sonstiges: ' + data.other;
	}
},
dewiki: {
	thumb: 'miniatur',
	upright: 'hochkant',
	comment: 'Bildschirmfoto mit [[Benutzer:Schnark/js/screenshot]] hochgeladen',
	desc: 'Bildschirmfoto',
	authorText: 'siehe [{{fullurl:$page|action=history}} Versionsgeschichte]',
	authorImage: '',
	licenseImage: '{{Bild-CC-by-sa/3.0}}',
	other: '',
	projectName: 'German Wikipedia',
	getDescription: function (data) {
		var authors = [], authorTypes = [], licenses = [], licenseTypes = [];
		if (data.logo) {
			licenses.push('{{Bild-WikimediaCopyright}}');
			licenseTypes.push(' \'\'\'Logo\'\'\': ');
		}
		if (data.text) {
			authors.push(data.authorText);
			authorTypes.push('Text: ');
			licenses.push('{{Bild-CC-by-sa/3.0}}');
			licenseTypes.push('\'\'\'Text\'\'\': ');
		}
		if (data.image) {
			authors.push(data.authorImage);
			authorTypes.push('Bild: ');
			licenses.push(data.licenseImage);
			licenseTypes.push('\'\'\'Bild\'\'\': ');
		}
		if (data.mediawiki) {
			authors.push('[[Spezial:Version|MediaWiki-Entwickler]]');
			authorTypes.push('');
		}
		authors = getAuthorsLicense(authors, authorTypes).join('<br />');
		licenses = getAuthorsLicense(licenses, licenseTypes).join('\n\n');
		if (authors === '') {
			authors = '–';
		}
		if (licenses === '{{Bild-WikimediaCopyright}}') {
			licenses += '\n\n{{Bild-PD-Schöpfungshöhe}}';
		}
		if (licenses === '') {
			licenses = '{{Bild-PD-Schöpfungshöhe}}';
		}
		return '{{Information\n' +
				'|Beschreibung     = ' + data.desc + '\n' +
				'|Quelle           = ' + window.location + '\n' +
				'|Urheber          = ' + authors + '\n' +
				'|Datum            = ~~~~~\n' +
				'|Andere Versionen = \n' +
				'|Anmerkungen      = \n' +
				'}}\n\n' +
				'== Lizenz ==\n' +
				licenses +
				(data.other ? '\n\n' + data.other : '');
	}
},
commonswiki: {
	thumb: 'thumb',
	upright: 'upright',
	comment: 'screenshot uploaded using [[de:Benutzer:Schnark/js/screenshot]]',
	desc: '$ownlanguage',
	authorText: 'see [{{fullurl:$iw$page|action=history}} history]',
	authorImage: '',
	licenseImage: '{{cc-by-sa-3.0}}',
	other: '',
	getDescription: function (data) {
		var authors = [], authorTypes = [], licenses = [], licenseTypes = [],
			date = new Date(), project = getInfoFor().projectName || '', other = data.other;
		if (data.logo && !data.mediawiki) {
			licenses.push('{{Wikimedia trademark}}');
			licenseTypes.push('');
		}
		if (data.text) {
			authors.push(data.authorText);
			authorTypes.push('text: ');
			if (!data.mediawiki) {
				licenses.push('{{cc-by-sa-3.0}}');
				licenseTypes.push('\'\'\'Text\'\'\': ');
			}
		}
		if (data.image) {
			authors.push(data.authorImage);
			authorTypes.push('image: ');
			licenses.push(data.licenseImage);
			licenseTypes.push('\'\'\'Image\'\'\': ');
		}
		authors = getAuthorsLicense(authors, authorTypes).join(', ');
		licenses = getAuthorsLicense(licenses, licenseTypes).join('\n');
		if (authors === '') {
			authors = '—';
		}
		if (data.mediawiki) {
			licenses = '{{Wikimedia project screenshot|logo=' + (data.logo ? 'yes' : 'no') +
				'|project=' + project + '}}\n' + licenses;
		} else {
			if (project !== '') {
				other = '[[Category:' + project + ' screenshots]]\n' + other;
			}
			if (licenses === '') {
				licenses = '{{PD-ineligible}}\n';
			}
		}
		date = String(date.getFullYear()) + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate());

		return '=={{int:filedesc}}==\n' +
				'{{Information\n' +
				'|description=' + data.desc + '\n' +
				'|date=' + date + '\n' +
				'|source=' + window.location + '\n' +
				'|author=' + authors + '\n' +
				'|other_versions=\n' +
				'}}\n\n' +
				'=={{int:license-header}}==\n' +
				licenses +
				(other ? '\n' + other : '');
	}
}
};

function getInfoFor (project) {
	return projectSpecific[project || mw.config.get('wgDBname')] || projectSpecific['*'];
}

function pad (n) {
	return n < 10 ? '0' + String(n) : String(n);
}

function isCompatible () {
	/* Die erste Zeile müsste eigentlich testen, ob das Skript an Bilder der Zwischenablage kommt
	Dafür gibt es eigentlich event.clipboardData, was zumindest in neueren Webkit-Browsern funktioniert.
	Firefox erlaubt es, Bilder in contentEditable divs einzufügen und von dort als data-URL auszulesen
		(ab FF4, davor unbrachbare file:-URL)
	IE dreht wie immer sein eigenes Ding, ein globales clipboardData-Objekt existiert seit Urzeiten,
		kann aber nur auf Text zugreifen
	Die Existenz von FormData ist erstaunlich gut korreliert mit der Möglichkeit an den Screenshot heranzukommen. */
	return 'contentEditable' in document.createElement('div') && isCompatibleUpload() &&
		window.HTMLCanvasElement && HTMLCanvasElement.prototype && HTMLCanvasElement.prototype.getContext;
}

function isCompatibleUpload () {
	return !!window.FormData;
}

function isCompatibleCross () {
	return useCORS || libs.schnarkAjaxProxy;
}

function enableCORS (sites) {
	var re = new RegExp('^(?:' +
		$.map(sites, function (site) {
			return mw.RegExp.escape(site).replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
		}).join('|') + ')$');
	useCORS = (window.XMLHttpRequest && XMLHttpRequest.prototype && 'withCredentials' in XMLHttpRequest.prototype) &&
		re.test(window.location.host);
}

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 isLocal (location) {
	return location === mw.config.get('wgDBname');
}

function showDialog (data) {
	var $dialog = $(mw.html.element('div', {}, new mw.html.Raw(data.content))),
		buttons = [],
		options = {title: data.title, zIndex: zindex + 5};
	if (data.cancel !== false) {
		options.close = function () {
			$dialog.remove();
			data.onCancel();
		};
		buttons.push({
			html: data.cancel || mw.html.element('div', {'class': 'cancel'}, mw.msg('screenshot-cancel')),
			click: function () {
				$dialog.remove();
				data.onCancel();
			}
		});
	}
	if (data.extra) {
		buttons.push({
			html: mw.html.element('div', {'class': 'extra'}, data.extra.text),
			click: data.extra.click
		});
	}
	if (data.cont !== false) {
		buttons.push({
			html: mw.html.element('div', {'class': 'continue'}, new mw.html.Raw(data.cont || mw.msg('screenshot-continue'))),
			click: data.onCont
		});
	}
	options.buttons = buttons;
	options.open = function () {
		var $buttons = $(this).parent().find('.ui-dialog-buttonpane button');
		$buttons.eq(0).focus();
		$buttons.find('.continue').parents('button').button({icons: {secondary: 'ui-icon-circle-arrow-e'}})
			.addClass('ui-button-blue').focus();
		$buttons.find('.cancel').parents('button').button({icons: {secondary: 'ui-icon-circle-close'}})
			.addClass('ui-button-red');
		if (data.extra && data.extra.icon) {
			$buttons.find('.extra').parents('button').button({icons: {secondary: data.extra.icon}});
		}
	};
	if (data.width) {
		options.width = data.width;
	}
	if (data.height) {
		options.height = data.height;
	}
	if (data.modal) {
		options.modal = true;
	}
	if (data.resizable === false) {
		options.resizable = false;
	}
	return $dialog.dialog(options);
}

function hideDialog ($dialog) {
	var oldclose = $dialog.dialog('option', 'close');
	$dialog.dialog('option', 'close', $.noop);
	$dialog.dialog('close');
	$dialog.dialog('option', 'close', oldclose);
}

function getBox ($el) {
	var pos = $el.offset(), $win = $(window);
	return {
		x: pos.left - $win.scrollLeft(),
		y: pos.top - $win.scrollTop(),
		w: $el.outerWidth(),
		h: $el.outerHeight()
	};
}

function unhideMenuItem () {
	$('#t-screenshot').show();
}

function getKey (action) {
	var kbdStyle = 'border: 0.2em solid; border-color: #ddd #bbb #bbb #ddd; padding: 0 0.4em; background: #eee; color: #000;';
	return '<kbd style="white-space: nowrap;">' +
		mw.messages.get('screenshot-key-' + (/mac/i.test(window.navigator.platform) ? 'mac-' : '') + action)
			.replace(/[<>]/g, function (c) {
				return (c === '<') ? '<kbd style="' + kbdStyle + '">' : '</kbd>';
			}) +
		'</kbd>';
}

function getAuthorsLicense (authors, types) {
	var author = false, specific = false, i, ret = [];
	for (i = 0; i < types.length; i++) {
		if (types[i] !== '' && types[i].charAt(0) !== ' ') {
			if (author === false) {
				author = authors[i];
			} else if (authors[i] !== author) {
				specific = true;
			}
		}
	}
	for (i = 0; i < types.length; i++) {
		author = (specific ? types[i].replace(/^ /, '') : '') + authors[i];
		if ($.inArray(author, ret) === -1) {
			ret.push(author);
		}
	}
	return ret;
}

function step1 () {
	var borderColor = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)],
		seconds = 5,
		style = 'position: fixed; z-index:' + zindex + '; width: 1px; height: 1px;' +
			'background-color: rgb(' + borderColor.join(',') + ');',
		$rahmen = $(mw.html.element('div', {style: style + 'top: 0; left: 0;'}, '') +
			mw.html.element('div', {style: style + 'bottom: 0; right: 0;'}, '')),
		$dialog = showDialog({
			title: mw.msg('screenshot-step', 1, mw.msg('screenshot-take')),
			content: mw.msg('screenshot-step1', getKey('printscreen'), seconds, getKey('unzoom')),
			onCancel: unhideMenuItem,
			onCont: function () {
				$dialog.remove();
				$rahmen.appendTo('body');
				window.setTimeout(function () {
					$rahmen.remove();
					step2(borderColor);
				}, seconds * 1000);
			},
			width: '32em'
		});
}

function step2 (borderColor) {
	var $dialog = showDialog({
		title: mw.msg('screenshot-step', 2, mw.msg('screenshot-copy')),
		content: mw.msg('screenshot-step2', getKey('paste')) + mw.html.element('div', {id: 'ce-container',
			contentEditable: 'true', style: 'overflow: hidden; height: 3em; border: 2px solid red; margin: 0.5em;'}, ''),
		onCancel: unhideMenuItem,
		onCont: function () {
			var $img = $('#ce-container img');
			$dialog.remove();
			extract($img, borderColor);
		}
	});
	$('#ce-container').focus().on('paste', function (e) {
		var clipboardData = e.originalEvent.clipboardData,
			i, blob, img, reader;
		function imgOnload () {
			/*jshint validthis: true*///Event-Handler
			$dialog.remove();
			extract($(this), borderColor);
		}
		function readerOnload (ev) {
			img.src = ev.target.result;
		}
		if (clipboardData && window.FileReader) {
			for (i = 0; i < clipboardData.items.length; i++) {
				if (clipboardData.items[0].type.indexOf('image/') === 0) {
					blob = clipboardData.items[i].getAsFile();
					img = new Image();
					img.onload = imgOnload;
					reader = new FileReader();
					reader.onload = readerOnload;
					reader.readAsDataURL(blob);
					return;
				}
			}
		}
	});
}

function isColor (data, x, y, borderColor) {
	var i = (y * data.width + x) * 4;
	return data.data[i] === borderColor[0] && data.data[i + 1] === borderColor[1] && data.data[i + 2] === borderColor[2];
}

function fixColor (data, x, y, d) {
	var r = 0, g = 0, b = 0, a = 0;
	r += 2 * data.data[(y * data.width + x + d) * 4];
	g += 2 * data.data[(y * data.width + x + d) * 4 + 1];
	b += 2 * data.data[(y * data.width + x + d) * 4 + 2];
	a += 2 * data.data[(y * data.width + x + d) * 4 + 3];
	r += 2 * data.data[((y + d) * data.width + x) * 4];
	g += 2 * data.data[((y + d) * data.width + x) * 4 + 1];
	b += 2 * data.data[((y + d) * data.width + x) * 4 + 2];
	a += 2 * data.data[((y + d) * data.width + x) * 4 + 3];
	r += data.data[((y + d) * data.width + x + d) * 4];
	g += data.data[((y + d) * data.width + x + d) * 4 + 1];
	b += data.data[((y + d) * data.width + x + d) * 4 + 2];
	a += data.data[((y + d) * data.width + x + d) * 4 + 3];
	data.data[(y * data.width + x) * 4] = Math.round(r / 5);
	data.data[(y * data.width + x) * 4 + 1] = Math.round(g / 5);
	data.data[(y * data.width + x) * 4 + 2] = Math.round(b / 5);
	data.data[(y * data.width + x) * 4 + 3] = Math.round(a / 5);
}

function extract ($img, borderColor) {
	if ($img.length !== 1) {
		showDialog({
			title: mw.msg('screenshot-error'),
			content: mw.msg('screenshot-missing'),
			cont: false,
			cancel: mw.msg('screenshot-ok'),
			onCancel: unhideMenuItem
		});
		return;
	}
	var w = $img[0].width, h = $img[0].height, v,
		$canvas = $(mw.html.element('canvas', {width: w, height: h}, '')),
		canvas = $canvas[0].getContext('2d'),
		imagedata,
		x1 = -1, y1 = -1, x2 = -1, y2 = -1, x, y;
	canvas.drawImage($img[0], 0, 0);
	imagedata = canvas.getImageData(0, 0, w, h);
	v = w / imagedata.width;
	search: for (x = 0; x < imagedata.width; x++) {
		for (y = 0; y < imagedata.height; y++) {
			if (isColor(imagedata, x, y, borderColor)) {
				if (x1 === -1) {
					x1 = x; y1 = y;
					fixColor(imagedata, x, y, 1);
				} else {
					x2 = x; y2 = y;
					fixColor(imagedata, x, y, -1);
					break search;
				}
			}
		}
	}
	w = x2 - x1 + 1; h = y2 - y1 + 1;
	if (x1 === -1 || x2 === -1 || w < 2 || h < 2) {
		showDialog({
			title: mw.msg('screenshot-error'),
			content: mw.msg('screenshot-notfound'),
			cont: false,
			cancel: mw.msg('screenshot-ok'),
			onCancel: unhideMenuItem
		});
		return;
	}
	$canvas.attr({width: Math.round(v * w), height: Math.round(v * h)});
	canvas.putImageData(imagedata, -Math.round(v * x1), -Math.round(v * y1), x1, y1, w, h);
	magicResize($canvas);
}

function magicResize ($canvas) {
	var wC = $canvas.attr('width'), hC = $canvas.attr('height'),
		wB = $('body').width(), hB = $('body').height(),
		fW = wB / wC, fH = hB / hC,
		factor = Math.min(fW, fH),
		w = Math.min(Math.floor(wC * factor), wB), h = Math.min(Math.floor(hC * factor), hB),
		canvas = $canvas[0].getContext('2d'), img;
	if (factor === 1) {
		step3($canvas);
		return;
	}
	img = new Image();
	img.onload = function () {
		$canvas.attr({width: w, height: h});
		canvas.drawImage(img, 0, 0, w, h);
		step3($canvas);
	};
	img.src = $canvas[0].toDataURL('image/png');
}

function step3 ($canvas) {
	var $dialog = showDialog({
		title: mw.msg('screenshot-step', 3, mw.msg('screenshot-edit')),
		content: mw.html.element('div', {id: 'screenshot-toolbar', style: 'border: 1px solid #666;'}, '') +
			mw.msg('screenshot-step3'),
		width: 390,
		onCancel: function () {
			$colorDialog.remove();
			$('#cut-div').remove();
			$('img.screenshot-combine').remove();
			undoQueue = []; undoTooltips = [];
			$canvas.remove();
			unhideMenuItem();
		},
		onCont: function () {
			var canvas = $canvas[0].getContext('2d'),
				$cut = $('#cut-div'),
				box = getBox($cut),
				imagedata;
			$colorDialog.remove();
			combineImages(canvas);
			imagedata = canvas.getImageData(box.x, box.y, box.w, box.h);
			$canvas.attr({width: box.w, height: box.h});
			canvas.putImageData(imagedata, 0, 0);
			$cut.remove();
			undoQueue = []; undoTooltips = [];
			$dialog.remove();
			getUrlAndFile($canvas[0], function (url, file) {
				$canvas.remove();
				step4(url, file);
			});
		}
	}),
	$colorDialog,
	w = $canvas.attr('width') - 2, h = $canvas.attr('height') - 2; //2: Rahmenbreite (je 2 mal 1 Pixel)
	$canvas.css({zIndex: zindex, position: 'fixed', top: 0, left: 0}).appendTo('body');
	$(mw.html.element('div', {id: 'cut-div'}, '')).css({
		borderColor: 'red',
		borderStyle: 'solid',
		borderWidth: '1px',
		position: 'fixed',
		top: '0px',
		left: '0px',
		width: w,
		height: h,
		zIndex: zindex + 1
	}).appendTo('body').resizable({maxWidth: w, maxHeight: h, handles: 'all'});
	$colorDialog = createToolbar($('#screenshot-toolbar'), $dialog);
}

function createToolbarButton (html, tip) {
	var style = 'height: 32px; width: 32px; padding: 0px; font-size: 20px; text-align: center; vertical-align: middle;';
	return $(mw.html.element('button', {title: tip, style: style}, new mw.html.Raw(html)));
}

function makeColorButton (c, id, tooltip) {
	var options = {style: 'background-color: ' + c + '; width: 24px; height: 24px; margin: auto;'};
	if (id) {
		options.id = id;
	}
	return createToolbarButton(mw.html.element('div', options, new mw.html.Raw('&#160;')), tooltip || c);
}

function makeColorDialog (c) {
	var $dialog = showDialog({
		title: mw.msg('screenshot-toolbar-color-title'),
		content: mw.html.element('div', {id: 'colorButtons'}, '') +
			mw.html.element('div', {id: 'farbtastic', style: 'margin-left: 32px; margin-top: 5px;'}, ''),
		width: 300,
		height: 330,
		resizable: false,
		cancel: false,
		cont: false
	}), farbtastic, $colorButtons = $('#colorButtons');
	$.each(['#000000', '#800000', '#008000', '#808000', '#000080', '#800080', '#008080', '#C0C0C0',
		'#808080', '#FF0000', '#00FF00', '#FFFF00', '#0000FF', '#FF00FF', '#00FFFF', '#FFFFFF'], function (i, c) {
		if (i === 8) {
			$colorButtons.append(mw.html.element('br'));
		}
		makeColorButton(c).click(function () {
			farbtastic.setColor(c);
		}).appendTo($colorButtons);
	});
	farbtastic = $.farbtastic($('#farbtastic'), function (c) {
		$('#screenshotBackgroundColor').css('background-color', c);
	}).setColor(c);
	return $dialog.dialog('close');
}

function createToolbar ($toolbar, $dialog) {
	var cursors = ['data:image/png;base64,' + //Pointer
		'iVBORw0KGgoAAAANSUhEUgAAABMAAAAYCAYAAAAYl8YPAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/' +
		'oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oGBhA5NghChMYAAAFdSURBVDjLrVV/C4Iw' +
		'EH1XK9SGW0Oi7//9smloYeX1T5uTZiX1YHBMeffu54iZ8S8spj5orVlrPc8TM78crTU7SCk59k/sRJX1' +
		'fe/t5XL5W5jX69Xb5/P5N7JQjVLqN7IkSbxd1zWklCyl/FgMEbvsus7baZrieDw6lczMEEKgLEv6ikyI' +
		'4fp+v4/y5xwZY7jve1hr6W2YIUHY1MYYb18uF1hroZTiEVme56yU4t1uxwBANEQQ2qfTydvr9RoAUFUV' +
		'XD6F817XtZfftu2oAA5N00SdpGk6KAtboSxLbDabj23gigIAt9ttILPWUpZl0Tx91V+LxbgAbdtSURR4' +
		'ks+e75dqOrlzlblZHpFZa2m73c7eY1FlYfzfwhiDqqooSnY4HGapc6mZnICwh+aQTW7N54Z9i/1+zx83' +
		'bTgu7xBOx+TWcMiyDKvVCkSEruuQ5zmapoEQAsz8stLpn0/dA4k3DbMumUlFAAAAAElFTkSuQmCC',
		'data:image/png;base64,' + //Auto
		'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAWCAYAAADwza0nAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNI' +
		'Uk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAALXSURBVHjajJNBSFpxHMe/NB94' +
		'2DMrX+QhNx9ah3wZRW9joe0w1rYaXgYRAzeUREKoxQ4LPTSc5GuI4LYugQSBx0YdtrE5GiVjwoJZ0sVC' +
		'5EkImdbhaRC8/07FYlv5hd/hx48Pv+8Pfl/09/c/7e7u/rC4uOisVqsghNRUV5RKpSOdTj8+PDw0d3Z2' +
		'FhobG9MUReEy1R0fH6O3txcsy15zu93BZDJpQy3SarWR4eFhUiwWycjICBkYGMikUqlHl1mtA4CTkxM0' +
		'NTVBEATQNG2YmJh4ncvlHl5o9c+mtbUVgiCgubn5+vj4eCibzdpqAgGAZVn4/X7Ismz0er2Bg4MDa00g' +
		'ABiNRszMzKBarXZMTU1FisXinZpAAOjo6EAwGEShUDB7vd7w0dGRpSYQANrb2xEIBFAoFEzT09PhSqVy' +
		'syYQADiOQygUQqlU6hEE4a0kSbcAQHERlEwmsbCwALVaDVEUsbKy0qNWq98MDg6++gtcX19HNpuF3W7H' +
		'xsYGYrEYeJ7/urq6+h6AMpfLXVWpVMfnrG5tbWFsbAzxeBynj9HW1ob5+fkfsVjsHU3TIY1G87KlpeXj' +
		'FZqm7xsMhhscx2FychJ6vf5LQ0PDd1mWzVarFel0GplMRuVyubY8Ho+o0+nAMAzAsmzEYDAQm81GnE7n' +
		'xv7+vpHjuCejo6OEEEL8fj/p6uoiOzs7L879qkKhwO7uLhiGSc3Ozj6XJCmj1Wp/JhKJ+NraGmw2G0wm' +
		'E5aWlh5UKhXz2V2RSOTe3NxcUBTFAUIIotEoWJYFAI/b7SaEEBIIBEhfXx/J5/PPzoK8vLy8w/N8vL6+' +
		'fhcANjc3odPpMDQ0VKEoSi/LspHneWxvb6NcLivNZvMviqIKKJVKkCTpn5kLhUKu01t9Ph+xWCwkn8+P' +
		'n+Xxf2IYJiFJ0jefz4e9vT3Y7fZPGo3mMwBcuFEURYTD4bsAFh0OR7RcLt8+nf0eAO8upcEtDpHVAAAA' +
		'AElFTkSuQmCC'],
		i, $colorDialog;

	for (i = 0; i < cursors.length; i++) {
		createToolbarButton(
			mw.html.element('img', {src: cursors[i]}), mw.msg('screenshot-toolbar-insert-cursor'))
				.click(clickInsertCursor)
				.appendTo($toolbar);
	}
	$toolbar.append('&#160;');
	createToolbarButton(mw.msg('screenshot-toolbar-arrow-symbol'), mw.msg('screenshot-toolbar-arrow'))
		.click(function () {
			clickDrawThing('arrow', mw.msg('screenshot-toolbar-arrow'), $dialog);
		}).appendTo($toolbar);
	createToolbarButton(mw.msg('screenshot-toolbar-line-symbol'), mw.msg('screenshot-toolbar-line'))
		.click(function () {
			clickDrawThing('line', mw.msg('screenshot-toolbar-line'), $dialog);
		}).appendTo($toolbar);
	createToolbarButton(mw.msg('screenshot-toolbar-rect-symbol'), mw.msg('screenshot-toolbar-rect'))
		.click(function () {
			clickDrawThing('rect', mw.msg('screenshot-toolbar-rect'), $dialog);
		}).appendTo($toolbar);
	createToolbarButton(mw.msg('screenshot-toolbar-ellipse-symbol'), mw.msg('screenshot-toolbar-ellipse'))
		.click(function () {
			clickDrawThing('ellipse', mw.msg('screenshot-toolbar-ellipse'), $dialog);
		}).appendTo($toolbar);
	$toolbar.append('&#160;');
	createToolbarButton(mw.msg('screenshot-toolbar-blur-symbol'), mw.msg('screenshot-toolbar-blur'))
		.click(function () {
			clickDrawThing('blur', mw.msg('screenshot-toolbar-blur'), $dialog);
		}).appendTo($toolbar);
	$toolbar.append('&#160;');
	createToolbarButton(
		mw.html.element('span', {id: 'screenshot-undo-inner', style: 'font-weight: bold;'},
			mw.msg('screenshot-toolbar-undo-symbol')), mw.msg('screenshot-toolbar-undo', '')
	).click(clickUndo)
		.appendTo($toolbar);
	updateUndo();
	$toolbar.append('&#160;');
	$colorDialog = makeColorDialog('#008000');
	makeColorButton('#008000', 'screenshotBackgroundColor', mw.msg('screenshot-toolbar-color')).click(function () {
		if ($colorDialog.dialog('isOpen')) {
			$colorDialog.dialog('close');
		} else {
			$colorDialog.dialog('open');
		}
	}).appendTo($toolbar);
	$toolbar.append('&#160;');
	createToolbarButton(mw.msg('screenshot-toolbar-help-symbol'), mw.msg('screenshot-toolbar-help'))
		.click(function () {
			showDialog({
				title: mw.msg('screenshot-help-title'),
				content: mw.msg('screenshot-step3-help'),
				width: '60em',
				cont: false,
				cancel: mw.msg('screenshot-ok'),
				onCancel: $.noop
			});
		}).appendTo($toolbar);
	return $colorDialog;
}

function clickInsertCursor () {
	/*jshint validthis: true*///Event-Handler
	var src = $(this).find('img').attr('src'),
		$img = $(mw.html.element('img', {src: src}));
	$img.addClass('screenshot-combine')
		.css({position: 'fixed', top: 10, left: 10, zIndex: zindex + 1, cursor: 'move'})
		.appendTo('body')
		.draggable({scroll: false});
	queueUndo(function () {
		$img.remove();
	}, mw.msg('screenshot-toolbar-insert-cursor'));
}

function clickDrawThing (thing, tooltip, $dialog) {
	var $canvas = $('canvas'),
		canvas = $('canvas')[0].getContext('2d'),
		imagedata = canvas.getImageData(0, 0, canvas.canvas.width, canvas.canvas.height);

	function undoFunction () {
		canvas.putImageData(imagedata, 0, 0);
	}

	hideDialog($dialog);
	get2Points($canvas, function (x1, y1, x2, y2) {
		canvas.strokeStyle = $('#screenshotBackgroundColor').css('background-color');
		canvas.fillStyle = $('#screenshotBackgroundColor').css('background-color');
		drawThing(canvas, thing, x1, y1, x2, y2);
		queueUndo(undoFunction, tooltip);
		$dialog.dialog('open');
	}, thing);
}

function showHelper ($helper, x1, y1, x2, y2, type) {
	var css = {};
	if (type === 'line' || type === 'arrow') {
		css.left = x1;
		css.top = y1;
		css.width = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
		css['border-top'] = '1px dashed black';
		css['transform-origin'] = 'top left';
		css.transform = 'rotate(' + Math.atan2(y2 - y1, x2 - x1) + 'rad)';
		$.each(['ms', 'moz', 'o', 'webkit'], function (i, prefix) {
			css['-' + prefix + '-transform-origin'] = css['transform-origin'];
			css['-' + prefix + '-transform'] = css.transform;
		});
	} else {
		css.left = Math.min(x1, x2);
		css.top = Math.min(y1, y2);
		css.width = Math.abs(x2 - x1);
		css.height = Math.abs(y2 - y1);
		css.border = '1px dashed black';
		if (type === 'ellipse') {
			css.borderRadius = '50%';
		}
	}
	$helper.css(css);
}

function drawThing (canvas, thing, x1, y1, x2, y2) {
	var d, dummy, id, nid, x, y, xx, yy, r, g, b, a, n;
	switch (thing) {
	case 'line':
		canvas.lineWidth = 3;
		canvas.lineCap = 'round';
		canvas.beginPath();
		canvas.moveTo(x1, y1);
		canvas.lineTo(x2, y2);
		canvas.closePath();
		canvas.stroke();
		break;
	case 'rect':
		canvas.lineWidth = 3;
		canvas.lineCap = 'butt';
		canvas.beginPath();
		canvas.rect(x1, y1, x2 - x1, y2 - y1);
		canvas.closePath();
		canvas.stroke();
		break;
	case 'ellipse':
		x = (x1 + x2) / 2; xx = Math.abs(x2 - x1) / 2;
		y = (y1 + y2) / 2; yy = Math.abs(y2 - y1) / 2;
		r = Math.sqrt(xx * yy);
		xx /= r; yy /= r;
		canvas.save();
		canvas.beginPath();
		canvas.scale(xx, yy);
		canvas.arc(x / xx, y / yy, r, 0, 2 * Math.PI);
		canvas.closePath();
		canvas.restore();
		canvas.lineWidth = 3;
		canvas.stroke();
		break;
	case 'arrow':
		d = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
		canvas.lineWidth = 5;
		canvas.lineCap = 'round';
		canvas.beginPath();
		canvas.moveTo(x1, y1);
		canvas.lineTo(x2 - (x2 - x1) * 5 / d, y2 - (y2 - y1) * 5 / d);
		canvas.closePath();
		canvas.stroke();
		canvas.lineWidth = 1;
		canvas.beginPath();
		canvas.moveTo(x2, y2);
		canvas.lineTo(x2 - 15 / d * ((x2 - x1) * Math.sqrt(3) + y1 - y2), y2 + 15 / d * (x1 - x2 + (y1 - y2) * Math.sqrt(3)));
		canvas.lineTo(x2 - 15 / d * ((x2 - x1) * Math.sqrt(3) - y1 + y2), y2 + 15 / d * (x2 - x1 + (y1 - y2) * Math.sqrt(3)));
		canvas.lineTo(x2, y2);
		canvas.closePath();
		canvas.fill();
		break;
	case 'blur':
		if (x2 < x1) {
			dummy = x1; x1 = x2; x2 = dummy;
		}
		if (y2 < y1) {
			dummy = y1; y1 = y2; y2 = dummy;
		}
		id = canvas.getImageData(x1, y1, x2 - x1, y2 - y1);
		nid = canvas.createImageData(x2 - x1, y2 - y1);
		for (x = 0; x < nid.width; x++) {
			for (y = 0; y < nid.height; y++) {
				r = 0; g = 0; b = 0; a = 0; n = 0;
				for (xx = Math.max(x - 2, 0); xx < Math.min(x + 3, id.width); xx++) {
					for (yy = Math.max(y - 2, 0); yy < Math.min(y + 3, id.height); yy++) {
						n++;
						r += id.data[(yy * id.width + xx) * 4];
						g += id.data[(yy * id.width + xx) * 4 + 1];
						b += id.data[(yy * id.width + xx) * 4 + 2];
						a += id.data[(yy * id.width + xx) * 4 + 3];
					}
				}
				nid.data[(y * nid.width + x) * 4] = Math.round(r / n);
				nid.data[(y * nid.width + x) * 4 + 1] = Math.round(g / n);
				nid.data[(y * nid.width + x) * 4 + 2] = Math.round(b / n);
				nid.data[(y * nid.width + x) * 4 + 3] = Math.round(a / n);
			}
		}
		canvas.putImageData(nid, x1, y1);
		break;
	}
}

function get1Point ($canvas, callback) {
	var $obj = $canvas.add('#cut-div');
	function handler (e) {
		$obj.off('click', handler).css('cursor', '');
		callback(e.clientX, e.clientY);
	}
	$obj.css('cursor', 'crosshair').click(handler);
}

function get2Points ($canvas, callback, helper) {
	get1Point($canvas, function (x0, y0) {
		var $helper = $('<div>').css({position: 'fixed', zIndex: zindex + 1}).appendTo('body'),
			$obj = $canvas.add('#cut-div').add($helper);

		function handler (e) {
			showHelper($helper, x0, y0, e.clientX, e.clientY, helper);
		}

		$obj.mousemove(handler);
		get1Point($canvas.add($helper), function (x1, y1) {
			$obj.off('mousemove', handler);
			$helper.remove();
			callback(x0, y0, x1, y1);
		});
	});
}

function clickUndo () {
	if (undoQueue.length) {
		(undoQueue.pop())();
		undoTooltips.shift();
	}
	updateUndo();
}

function queueUndo (f, t) {
	undoQueue.push(f);
	undoTooltips.unshift(t);
	updateUndo();
}

function updateUndo () {
	var active = undoQueue.length > 0;
	$('#screenshot-undo-inner')
		.css('color', active ? '#00f' : '#777')
		.parents('button')
			.prop('disabled', !active)
			.attr('title', mw.msg('screenshot-toolbar-undo', undoTooltips[0] || ''));
}

function combineImages (canvas) {
	$('img.screenshot-combine').each(function () {
		var box = getBox($(this));
		canvas.drawImage(this, box.x, box.y);
	}).remove();
}

function dataURLtoBlob (url) {
	var binary, array, i;
	if (!window.atob || !window.Uint8Array || !window.Blob) {
		return null;
	}
	binary = atob(url.split(',')[1]);
	array = new Uint8Array(binary.length);
	for (i = 0; i < binary.length; i++) {
		array[i] = binary.charCodeAt(i);
	}
	return new Blob([array], {type: 'image/png'});
}

function getUrlAndFile (canvas, callback) {
	var url = canvas.toDataURL('image/png');
	if (canvas.toBlob) {
		canvas.toBlob(function (file) {
			callback(url, file);
		}, 'image/png');
	} else if (canvas.mozGetAsFile) {
		callback(url, canvas.mozGetAsFile('blob', 'image/png'));
	} else {
		callback(url, dataURLtoBlob(url));
	}
}

function step4 (url, file) {
	var uploadLocal = !getInfoFor().noLocalUpload,
		uploadCommons = !isLocal('commonswiki') && isCompatibleCross(),
		$dialog;

	if (!file || !isCompatibleUpload() || (!uploadLocal && !uploadCommons)) {
		step4b(url);
		return;
	}

	$dialog = showDialog({
		title: mw.msg('screenshot-step', 4, mw.msg('screenshot-upload-head')),
		content: mw.msg('screenshot-step4',
			mw.html.element('a', {href: url, target: '_blank'},
			mw.msg('screenshot-step4-link'))) + getUploadForm(uploadLocal && uploadCommons, uploadLocal),
		width: '70em',
		extra: {
			text: mw.msg('screenshot-preview'),
			icon: 'ui-icon-document',
			click: function () {
				var data = retrieveData();
				showPreview(data.location, 'File:' + data.filename, data.description);
			}
		},
		cancel: mw.msg('screenshot-finish'),
		cont: mw.msg('screenshot-upload'),
		onCancel: unhideMenuItem,
		onCont: function () {
			var data = retrieveData();
			getToken(data.location, data.filename, function (token, error) {
				if (token) {
					hideDialog($dialog);
					removeFilenameError();
					upload(data.location, data.filename, data.description, token,
						isLocal(data.location) || useCORS ? file : url, $dialog);
				} else {
					showFilenameError(error);
				}
			});
		}
	});
	$('#replaceTextarea').click(function (e) {
		e.preventDefault();
		replaceTextarea();
	});
	$('#upload-description-logo').prop('checked', true);
	$('#upload-description-mediawiki').prop('checked', true);
	$('#upload-description-text').prop('checked', true).change(function () {
		var d = !$('#upload-description-text').prop('checked');
		$('#upload-description-text-author').prop('disabled', d);
		$('label[for="upload-description-text-author"]').css('color', d ? '#888' : '');
	}).change();
	$('#upload-description-image').prop('checked', true).change(function () {
		var d = !$('#upload-description-image').prop('checked');
		$('#upload-description-image-author').prop('disabled', d);
		$('#upload-description-image-license').prop('disabled', d);
		$('label[for="upload-description-image-author"], label[for="upload-description-image-license"]')
			.css('color', d ? '#888' : '');
	}).change();
	$('#upload-location').change(function () {
		prefillDescription(retrieveData().location);
	}).change();
	$('#upload-filename').blur(function () {
		var data = retrieveData();
		getToken(data.location, data.filename, function (token, error) {
			if (!token) {
				showFilenameError(error, true);
			}
		});
	}).keydown(removeFilenameError).focus();
}

function step4b (url) {
	showDialog({
		title: mw.msg('screenshot-step', 4, mw.msg('screenshot-save')),
		content: mw.msg('screenshot-step4b',
			mw.html.element('a', {href: url, target: '_blank'}, mw.msg('screenshot-step4-link'))),
		cont: false,
		cancel: mw.msg('screenshot-ok'),
		onCancel: unhideMenuItem
	});
}

function getUploadForm (showSelect, selectLocal) {
	var select =
		mw.html.element('label', {'for': 'upload-location'}, mw.msg('screenshot-upload-location')) +
		mw.html.element('br') +
		mw.html.element('select', {id: 'upload-location', size: 1}, new mw.html.Raw(
			mw.html.element('option', {selected: selectLocal, value: mw.config.get('wgDBname')},
				mw.msg('screenshot-upload-local')) +
			mw.html.element('option', {selected: !selectLocal, value: 'commonswiki'}, mw.msg('screenshot-upload-commons'))
		)) +
		mw.html.element('br');
	if (!showSelect) {
		select = mw.html.element('div', {style: 'display: none;'}, new mw.html.Raw(select));
	}
	return mw.html.element('fieldset', {}, new mw.html.Raw(
		mw.html.element('legend', {}, mw.msg('screenshot-upload-legend')) +
		select +
		mw.html.element('label', {'for': 'upload-filename'}, mw.msg('screenshot-upload-filename')) +
		mw.html.element('br') +
		mw.html.element('span', {}, mw.config.get('wgFormattedNamespaces')[6] + ':') +
		mw.html.element('input', {id: 'upload-filename', size: 30, maxLength: 230}) +
		mw.html.element('span', {}, '.png') +
		mw.html.element('span', {id: 'upload-filename-error',
			style: 'margin-left: 1em; font-size: 80%; font-weight: bold; color: red;'}, '') +
		mw.html.element('br') +
		mw.html.element('fieldset', {id: 'upload-description-container'}, new mw.html.Raw(
			mw.html.element('legend', {}, mw.msg('screenshot-upload-description')) +
			mw.html.element('div', {style: 'font-size: smaller; text-align: right; margin-top: -1em;'}, new mw.html.Raw(
				mw.html.element('a', {href: '#', id: 'replaceTextarea', style: 'font-weight: bold;'},
					mw.msg('screenshot-upload-description-replace')))) +
			mw.html.element('label', {'for': 'upload-description-description'},
				mw.msg('screenshot-upload-description-description')) +
			mw.html.element('br') +
			mw.html.element('textarea', {id: 'upload-description-description',
				style: 'width: 100%;', rows: 2, cols: 50}, '') +
			mw.html.element('input', {id: 'upload-description-logo', type: 'checkbox'}) +
			mw.html.element('label', {'for': 'upload-description-logo'},
				mw.msg('screenshot-upload-description-logo', mw.config.get('wgSiteName'))) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-mediawiki', type: 'checkbox'}) +
			mw.html.element('label', {'for': 'upload-description-mediawiki'},
				mw.msg('screenshot-upload-description-mediawiki')) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-text', type: 'checkbox'}) +
			mw.html.element('label', {'for': 'upload-description-text'}, mw.msg('screenshot-upload-description-text')) +
			mw.html.element('br') +
			mw.html.element('label', {'for': 'upload-description-text-author', style: 'margin-left: 2em;'},
				mw.msg('screenshot-upload-description-text-author')) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-text-author', style: 'margin-left: 2em;', size: 60}) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-image', type: 'checkbox'}) +
			mw.html.element('label', {'for': 'upload-description-image'}, mw.msg('screenshot-upload-description-image')) +
			mw.html.element('br') +
			mw.html.element('label', {'for': 'upload-description-image-author', style: 'margin-left: 2em;'},
				mw.msg('screenshot-upload-description-image-author')) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-image-author', style: 'margin-left: 2em;', size: 60}) +
			mw.html.element('br') +
			mw.html.element('label', {'for': 'upload-description-image-license', style: 'margin-left: 2em;'},
				mw.msg('screenshot-upload-description-image-license')) +
			mw.html.element('br') +
			mw.html.element('input', {id: 'upload-description-image-license', style: 'margin-left: 2em;', size: 60}) +
			mw.html.element('br') +
			mw.html.element('label', {'for': 'upload-description-other'}, mw.msg('screenshot-upload-description-other')) +
			mw.html.element('br') +
			mw.html.element('textarea', {id: 'upload-description-other', 'class': 'monospace',
				style: 'width: 100%;', rows: 2, cols: 50}, '')
		))
	));
}

function replaceTextarea () {
	var desc = retrieveData().description;
	$('#upload-description-container').replaceWith(
		mw.html.element('label', {'for': 'upload-description'}, mw.msg('screenshot-upload-description')) +
		mw.html.element('br') +
		mw.html.element('textarea', {id: 'upload-description', 'class': 'monospace', style: 'width: 100%;',
			rows: 10, cols: 50}, '')
	);
	$('#upload-description').val(desc);
}

function showFilenameError (error, dontFocus) {
	$('#upload-filename-error').text(error);
	if (!dontFocus) {
		$('#upload-filename').focus();
	}
}

function removeFilenameError () {
	showFilenameError('', true);
}

function retrieveData () {
	var location = $('#upload-location :selected').val(),
		filename = $('#upload-filename').val() + '.png',
		description, $textarea = $('#upload-description');
	if ($textarea.length === 1) {
		description = $textarea.val();
	} else {
		description = composeDescription(location, {
			desc: $('#upload-description-description').val(),
			logo: $('#upload-description-logo').prop('checked'),
			mediawiki: $('#upload-description-mediawiki').prop('checked'),
			text: $('#upload-description-text').prop('checked'),
			authorText: $('#upload-description-text-author').val(),
			image: $('#upload-description-image').prop('checked'),
			authorImage: $('#upload-description-image-author').val(),
			licenseImage: $('#upload-description-image-license').val(),
			other: $('#upload-description-other').val()
		});
	}
	return {location: location, filename: filename, description: description};
}

function getIW (wiki) { //Interwikilink-Präfix für Wiki von Commons aus
	var special = {
		commonswiki: 'c',
		wikidatawiki: 'd',
		mediawikiwiki: 'mw',
		metawiki: 'm'
	}, regular = {
		wiki: 'w',
		wikibooks: 'b',
		wikinews: 'n',
		wikiquote: 'q',
		wikisource: 's',
		wikiversity: 'v',
		wikivoyage: 'voy',
		wiktionary: 'wikt'
	}, iw;
	if (special[wiki]) {
		iw = special[wiki];
	} else {
		for (iw in regular) {
			if (regular.hasOwnProperty(iw) && wiki.slice(-iw.length) === iw) {
				iw = regular[iw] + ':' + wiki.slice(0, -iw.length).replace(/_/g, '-');
				break;
			}
		}
	}
	iw += ':';
	iw = iw.replace(/^c:/, '') //Commons auf sich selbst
		.replace(/^w:/, '') //für Wikipedia reicht Sprache
		.replace(/:en:$/, ':'); //Englisch muss nicht angegeben werden
	return iw;
}

function prefillDescription (location) {
	var data = getInfoFor(location),
		iw = getIW(mw.config.get('wgDBname')),
		$textarea = $('#upload-description');

	$.each(data, function (p, v) { //überschreiben macht nichts
		if (typeof v === 'string') {
			data[p] =
				v.replace(/\$ownlanguage/g, mw.message('screenshot-description-ownlanguage', '{{en|1=Screenshot}}').plain())
					.replace(/\$title/g, mw.config.get('wgTitle'))
					.replace(/\$page/g, mw.config.get('wgPageName'))
					.replace(/\$iw/g, iw);
		}
	});

	if ($textarea.length === 1) {
		$textarea.val(composeDescription(location, $.extend({}, data, {logo: true, text: true, image: true})));
	} else {
		$('#upload-description-description').val(data.desc);
		$('#upload-description-text-author').val(data.authorText);
		if (data.authorImage) {
			$('#upload-description-image-author').val(data.authorImage);
		}
		$('#upload-description-image-license').val(data.licenseImage);
		if (data.other) {
			$('#upload-description-other').val(data.other);
		}
	}
}

function composeDescription (location, data) {
	return getInfoFor(location).getDescription(data);
}

function waitPreview (on) {
	$('.ui-dialog-buttonpane .extra').parents('button').button('option', 'disabled', on);
}

function showPreview (location, filename, description) {
	waitPreview(true);
	ajax(location, {
		type: 'POST',
		data: {action: 'parse', title: filename, prop: 'text|categorieshtml|langlinks',
			pst: true, disableeditsection: true, preview: true,
			text: description, format: 'json', formatversion: 2},
		dataType: 'json'
	}, function (json) {
		waitPreview(false);
		if (!json || !json.parse || !json.parse.text) {
			return;
		}
		var html = json.parse.text;
		if (json.parse.categorieshtml) {
			html += json.parse.categorieshtml;
		}
		if (json.parse.langlinks && json.parse.langlinks.length) {
			html += '<hr>' + $.map(json.parse.langlinks, function (ll) {
				return mw.html.element('a', {
					href: ll.url,
					title: mw.msg('interlanguage-link-title', ll.langname, ll.title)
				}, ll.autonym);
			}).join(mw.msg('comma-separator'));
		}
		html = $('<div>').html(html).find('a').each(function () { //relative Links auf andere Projekte, neuer Tab
			var $a = $(this), href = $a.attr('href') || '';
			if (location === 'commonswiki' && href && href.charAt(0) === '/' && href.charAt(1) !== '/') {
				$a.attr('href', 'https://commons.wikimedia.org' + href);
			}
			$a.attr('target', '_blank');
		}).end().html();
		showDialog({
			title: mw.msg('screenshot-preview-title'),
			content: html,
			modal: true,
			cont: false,
			cancel: mw.msg('screenshot-ok'),
			onCancel: function () {},
			width: '60em',
			height: 400
		});
	}, function () {
		waitPreview(false);
	});
}

function getToken (location, filename, callback) {
	if (filename === '.png') {
		callback(false, mw.msg('screenshot-filename-error-empty'));
	} else if (/[:#|\\\/]/.test(filename)) {
		callback(false, mw.msg('screenshot-filename-error-invalid'));
	} else {
		ajax(location, {
			type: 'GET',
			data: {action: 'query', prop: 'info|imageinfo', meta: 'tokens', inprop: 'protection',
				titles: 'File:' + filename, assert: 'user', format: 'json', formatversion: 2},
			dataType: 'json'
		}, function (json) {
			if (!json) {
				return callback(false, mw.msg('screenshot-filename-error-unknown'));
			}
			if (json.error && json.error.code === 'assertuserfailed') {
				return callback(false, mw.msg('screenshot-filename-error-anon'));
			}
			if (!json.query) {
				return callback(false, mw.msg('screenshot-filename-error-unknown'));
			}
			if (!json.query.tokens) {
				return callback(false, mw.msg('screenshot-filename-error-unknown'));
			}
			if (!json.query.pages) {
				return callback(false, mw.msg('screenshot-filename-error-unknown'));
			}
			if (!json.query.pages[0]) {
				return callback(false, mw.msg('screenshot-filename-error-unknown'));
			}
			if (!json.query.pages[0].missing) {
				return callback(false, mw.msg('screenshot-filename-error-duplicate'));
			}
			if (json.query.pages[0].invalid) {
				return callback(false, mw.msg('screenshot-filename-error-invalid'));
			}
			if (json.query.pages[0].imagerepository === 'shared') {
				return callback(false, mw.msg('screenshot-filename-error-duplicate'));
			}
			if (json.query.pages[0].protection.length > 0) {
				return callback(false, mw.msg('screenshot-filename-error-protected'));
			}
			callback(json.query.tokens.csrftoken, mw.msg('screenshot-filename-error-unknown'));
		}, function () {
			callback(false, mw.msg('screenshot-filename-error-unknown'));
		});
	}
}

function pleaseWait (on) {
	if (on) {
		var contentHtml, $el, x, y, $window = $(window);
		contentHtml = mw.msg('screenshot-please-wait') +
				mw.html.element('div', {id: 'screenshot-upload-progressbar'}, '');
		$el = $(mw.html.element('div', {
			id: 'screenshot-please-wait',
			style: 'position: fixed; cursor: wait; border: 1px solid black; text-align: center;' +
				'padding: 2em; background-color: white; top:0;'
			}, new mw.html.Raw(contentHtml)));

		$el.appendTo($('body'));
		x = Math.round(($window.width() - $el.outerWidth()) / 2);
		y = Math.round(($window.height() - $el.outerHeight()) / 2);
		$el.css({left: x, top: y});
	} else {
		$('#screenshot-please-wait').remove();
	}
}

function showProgress (val) {
	$('#screenshot-upload-progressbar').progressbar({value: val});
}

function upload (location, filename, description, token, file, $dialog) {
	var data = {
		action: 'upload',
		format: 'json',
		formatversion: 2,
		ignorewarnings: true,
		filename: filename,
		comment: getInfoFor(location).comment,
		text: description,
		file: file,
		token: token
	};
	pleaseWait(true);
	ajaxUpload(location, {
		type: 'POST',
		data: data,
		contentType: false,
		processData: false,
		xhr: function () {
			var xhr = $.ajaxSettings.xhr();
			if (xhr.upload && xhr.upload.addEventListener) {
				xhr.upload.addEventListener('progress', function (e) {
					if (e.lengthComputable) {
						showProgress(100 * e.loaded / (e.total || 1));
					}
				}, false);
			}
			return xhr;
		},
		dataType: 'json'
	}, function (result, data) {
		pleaseWait(false);
		if (result) {
			finalStepSuccess(data, $dialog);
		} else {
			finalStepError(data, $dialog);
		}
	});
}

function finalStepSuccess (data, $dialog) {
	$dialog.remove();
	showDialog({
		title: mw.msg('screenshot-success'),
		content: mw.msg('screenshot-success-body', formatCode(data.filename, data.imageinfo || {}),
			formatInfo(data.imageinfo || {})),
		width: 'auto',
		cont: false,
		cancel: mw.msg('screenshot-ok'),
		onCancel: unhideMenuItem
	});
}

function finalStepError (data, $dialog) {
	showDialog({
		title: mw.msg('screenshot-error'),
		content: mw.msg('screenshot-error-body', data.error || mw.msg('screenshot-unknown-error')),
		cont: false,
		cancel: mw.msg('screenshot-ok'),
		onCancel: function () {
			$dialog.dialog('open');
		}
	});
}

function formatCode (filename, ii) {
	var useUpright = (ii.width || 1) / (ii.height || 1) > 5;
	return '[[' + mw.config.get('wgFormattedNamespaces')[6] + ':' + filename.replace(/_/g, ' ') + '|' +
			getInfoFor().thumb + '|' +
			(useUpright ? getInfoFor().upright + '=2|' : '') +
			mw.msg('screenshot-description-example') + ']]';
}

function formatSize (size) {
	var sizesMsg = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
	while (sizesMsg.length > 1 && size >= 1024) {
		size /= 1024;
		sizesMsg.shift();
	}
	return mw.msg(sizesMsg[0], Math.round(size));
}

function formatInfo (data) {
	var linkDescr = mw.html.element('a', {href: data.descriptionurl || '#'},
			mw.msg('screenshot-info-description')),
		linkFull = mw.html.element('a', {href: data.url || '#'}, mw.msg('screenshot-info-full')),
		size = formatSize(data.size || 0);
	return mw.msg('screenshot-info', linkDescr, linkFull, data.width || 0, data.height || 0, size);
}

function ajaxUpload (location, data, callback) {
	if (isLocal(location) || useCORS) {
		data.data = prepareData(data.data);
	}
	ajax(location, data, function (json) {
			var success = json && json.upload && json.upload.result === 'Success',
				data = success ? json.upload : {error: json && json.error && json.error.info};
			callback(success, data);
		}, function () {
			callback(false, {});
		});
}

function prepareData (data) {
	var formData = new FormData(), item;
	for (item in data) {
		if (data.hasOwnProperty(item)) {
			formData.append(item, data[item]);
		}
	}
	return formData;
}

function ajax (location, data, onSuccess, onError) {
	if (isLocal(location)) {
		data.url = mw.util.wikiScript('api');
		data.success = onSuccess;
		data.error = onError;
		$.ajax(data);
	} else if (useCORS) {
		data.url = 'https://commons.wikimedia.org/w/api.php?' +
			'origin=' + window.location.protocol + '//' + window.location.host;
		data.xhrFields = {withCredentials: true};
		data.success = onSuccess;
		data.error = onError;
		$.ajax(data);
	} else {
		delete data.xhr;
		libs.schnarkAjaxProxy('https://commons.wikimedia.org', data, onSuccess, onError);
	}
}

function init () {
	var css =
		'#ce-container img {' +
			'width: 100%;' +
			'height: auto;' +
		'}' +
		'.monospace {' +
			'font-family: monospace, Courier !important;' +
		'}';
	mw.util.addCSS(css);
	initL10N(l10n, ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes',
		'interlanguage-link-title', 'comma-separator']);
	enableCORS([
		'*.wikipedia.org',
		'*.wikinews.org',
		'*.wiktionary.org',
		'*.wikibooks.org',
		'*.wikiversity.org',
		'*.wikisource.org',
		'wikisource.org',
		'*.wikiquote.org',
		'*.wikidata.org',
		'wikidata.org',
		'*.wikivoyage.org',
		'www.mediawiki.org',
		'wikimediafoundation.org',
		'advisory.wikimedia.org',
		'auditcom.wikimedia.org',
		'boardgovcom.wikimedia.org',
		'board.wikimedia.org',
		'chair.wikimedia.org',
		'chapcom.wikimedia.org',
		'checkuser.wikimedia.org',
		'collab.wikimedia.org',
		'commons.wikimedia.org',
		'donate.wikimedia.org',
		'exec.wikimedia.org',
		'grants.wikimedia.org',
		'incubator.wikimedia.org',
		'internal.wikimedia.org',
		'login.wikimedia.org',
		'meta.wikimedia.org',
		'movementroles.wikimedia.org',
		'office.wikimedia.org',
		'otrs-wiki.wikimedia.org',
		'outreach.wikimedia.org',
		'quality.wikimedia.org',
		'searchcom.wikimedia.org',
		'spcom.wikimedia.org',
		'species.wikimedia.org',
		'steward.wikimedia.org',
		'strategy.wikimedia.org',
		'usability.wikimedia.org',
		'wikimania????.wikimedia.org',
		'wikimaniateam.wikimedia.org'
	]);
	$(mw.util.addPortletLink('p-tb',
		'#',
		mw.msg('screenshot'),
		't-screenshot',
		mw.msg('tooltip-t-screenshot'),
		mw.msg('accesskey-t-screenshot')
	)).click(function (e) {
		e.preventDefault();
		mw.loader.using(['jquery.ui', /*'mediawiki.ui.button',*/
			'jquery.ui', 'jquery.farbtastic'],
			function () {
				$('#t-screenshot').hide();
				step1();
			}
		);
	});
}

if (isCompatible()) {
	mw.loader.using(['mediawiki.util', 'mediawiki.language'], function () {
		$(init);
	});
}

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