<?php
	ini_set('display_errors', 1);
	ini_set('display_startup_errors', 1);
	error_reporting(E_ALL);

	chdir('..');
	include_once 'lib/config.php';
	include 'lib/default.php';
?>
<!DOCTYPE html>
<html lang="<?php echo $lang; ?>">
<head>
	<base href="../" />
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<meta name="color-scheme" content="light dark" />

	<link rel="icon" href="<?php echo $cssVars['--WebsiteIcon']; ?>" />
	<link rel="apple-touch-icon" href="<?php echo $cssVars['--WebsiteIcon']; ?>" />
	<meta name="msapplication-TileImage" content="<?php echo $cssVars['--WebsiteIcon']; ?>" />

	<title>Editor</title>

	<style>
		/* allgemeine Styles */

		html {
			--DefaultFgColor: black;
			--DefaultBgColor: white;

			--MenuFgColor: black;
			--MenuBgColor: white;

			--IconFgColorDefault: #426CA6;
			--IconFgColorOK: #00C000;
			--IconFgColorCancel: #C00000;
			--IconFgColorAbort: #C00000;
			--IconFgColorDelete: #C00000;
			--IconFgColorAdd: #00C000;
			--IconFgColorUpload: #00C000;
			--IconFgColorRestore: #00C000;
			--IconFgColorCheck: #426CA6;
			--IconFgColorInactive: #767676;
			--IconFgColorDisabled: #C0C0C0;
			--IconFgColorSaved: #999999;
			--IconFgColorModified: #E00000;
			--IconFgColorEtc: #426CA6;
			--IconFgColorPdf: #C00000;
			--IconFgColorPhp: #426CA6;
			--IconFgColorXml: #008000;

			--DiffInsBgColor: #C0FFC0;
			--DiffInsBgColorHighlighted: #008000;
			--DiffInsFgColorHighlighted: white;
			--DiffDelBgColor: #FFC0C0;
			--DiffDelBgColorHighlighted: #FF0000;
			--DiffDelFgColorHighlighted: white;
			--DiffSpecialCharFgColor: red;

			--PopupFgColor: #303030;
			--PopupBgColor: #F0F0F0;
			--PopupShadowColor: #303030;
			--InputFgColor: black;
			--InputBgColor: white;
			--InputFgColorHover: blue;
			--InputBorderColor: grey;

			--ToolbarFgColor: black;
			--ToolbarBgColor: silver;
			--ToolFgColor: black;
			--ToolBgColor: white;
			--ToolFgColorDisabled: grey;
			--ToolBgColorDisabled: darkgrey;
			--ToolBgColorHover: #F0F0F0;

			--EditorFgColor: black;
			--EditorBgColor: white;
			--EditorSelectionColor: #C0E0FF;

			--FooterFgColor: black;
			--FooterBgColor: silver;

			--ErrorFgColor: red;
			--WarningFgColor: darkorange;
			--InfoFgColor: blue;

			--SelectSeparatorFgColor: #426CA6;
			--SelectFilteredFgColor: #426CA6;

			--DividerColor: #DCDCDC;
		}

		@media (prefers-color-scheme: dark) {
		html {
			--DefaultFgColor:#E3E3E3;
			--DefaultBgColor: #282828;

			--MenuFgColor: #C7C7C7;
			--MenuBgColor: #1F1F1F;

			--IconFgColorDefault: #99C8FF;
			--IconFgColorOK: #40FF40;
			--IconFgColorCancel: #FF4040;
			--IconFgColorAbort: #FF4040;
			--IconFgColorDelete: #FF4040;
			--IconFgColorAdd: #40FF40;
			--IconFgColorUpload: #40FF40;
			--IconFgColorRestore: #40FF40;
			--IconFgColorCheck: #426CA6;
			--IconFgColorInactive: #AAAAAA;
			--IconFgColorDisabled: #737373;
			--IconFgColorSaved: #999999;
			--IconFgColorModified: #FF8080;
			--IconFgColorEtc: #69B3FF;
			--IconFgColorPdf: #FF4040;
			--IconFgColorPhp: gold;
			--IconFgColorXml: #00C000;

			--DiffInsBgColor: #008000;
			--DiffInsBgColorHighlighted: #00C000;
			--DiffInsFgColorHighlighted: white;
			--DiffDelBgColor: #862020;
			--DiffDelBgColorHighlighted: #FF0000;
			--DiffDelFgColorHighlighted: white;
			--DiffSpecialCharFgColor: #99C8FF;

			--PopupFgColor: #E3E3E3;
			--PopupBgColor: #282828;
			--PopupShadowColor: #000000C0;
			--InputFgColor: #C7C7C7;
			--InputBgColor: #1F1F1F;
			--InputFgColorHover: #99C8FF;
			--InputBorderColor: grey;

			--ToolbarFgColor: #C7C7C7;
			--ToolbarBgColor: #3C3C3C;
			--ToolFgColor: #E3E3E3;
			--ToolBgColor: #1F1F1F;
			--ToolFgColorDisabled: #000000;
			--ToolBgColorDisabled: #323232;
			--ToolBgColorHover: #282828;

			--EditorFgColor: #C7C7C7;
			--EditorBgColor: #1F1F1F;
			--EditorSelectionColor: #3E77AC;

			--FooterFgColor: #C7C7C7;
			--FooterBgColor: #3C3C3C;

			--ErrorFgColor: #FF8080;
			--WarningFgColor: #FFC281;
			--InfoFgColor: #99B6FF;

			--SelectSeparatorFgColor: #99C8FF;
			--SelectFilteredFgColor: #99C8FF;

			--DividerColor: #666666;
		} }

		* {
			box-sizing: border-box;
			user-select: none;
		}

		/**** Fonts ****/

		/* Download unter: https://icomoon.io/app/ */
		@font-face {
			font-family: 'icomoon';
			src: url('fonts/icomoon.eot?p8l4ma');
			src: url('fonts/icomoon.eot?p8l4ma#iefix') format('embedded-opentype'),
			url('fonts/icomoon.ttf?p8l4ma') format('truetype'),
			url('fonts/icomoon.woff?p8l4ma') format('woff'),
			url('fonts/icomoon.svg?p8l4ma#icomoon') format('svg');
			font-weight: normal;
			font-style: normal;
			font-display: block;
		}

		body {
			margin: 0;
			color: var(--DefaultFgColor);
			background-color: var(--DefaultBgColor);
			font-family: sans-serif;
			font-size: 1em;
			line-height: 1.5em;
			hyphens: auto;
		}

		/* Grid-Struktur */

		body {
			display: grid;
			height: 100vh;
			grid-template-areas:
				"menu		preview"
				"toolbar	preview"
				"editor		preview"
				"footer		preview";
			grid-template-columns:
				1fr			100fr;
			grid-template-rows:
				1fr
				1fr
				100fr
				1fr;
		}
		nav { grid-area: menu; }
		header { grid-area: toolbar; }
		main { grid-area: editor; }
		footer { grid-area: footer; }
		aside { grid-area: preview; }

		/* Grid-Items */

		nav {
			color: var(--MenuFgColor);
			background-color: var(--MenuBgColor);
			padding: 0;
			margin: 0;
		}

		header {
			color: var(--ToolbarFgColor);
			background-color: var(--ToolbarBgColor);
			padding: 0 10px;
		}

		main {
			color: var(--EditorFgColor);
			background-color: var(--EditorBgColor);
		}

		footer {
			color: var(--FooterFgColor);
			background-color: var(--FooterBgColor);
			padding: 0 10px;
		}

		aside {
			height: 100%;
			border-left: 1px solid var(--DividerColor);
		}

		#preview {
			display: block; /* Damit die gap unter dem IFRAME verschwindet (wie bei Bildern). */
			width: 100%; height: 100%; /* Mach dich mal schön breit! */
			border: none; /* Weg mit dem häslichen Rahmen des IFRAME! */
		}

		/* Elemente innerhalb der Grid-Items */

		nav p {				/* Oberste Zeile mit Menü und Popups */
			margin: 5px 8px 0 10px;
		}
		header p,			/* Kopfzeile mit Toolbar für Editor*/
		main p,				/* Hauptbereich mit Sourcecode-Editor */
		footer p {			/* Fußzeile mit Statustext */
			margin: 5px 0;
		}

		/* Menü */

		nav button/*,
		nav select,
		nav input*/ {
			vertical-align: middle;
			font-family: sans-serif;
			font-size: 1em;
			padding: 2px 4px;
			margin: 0 0 5px 0;
		}

		/* Menü: Popup-Fenster (Dialoge etc.) */

		div.popup {
			display: none;
			position: absolute;
			left: 50px;
			top: 50px;
			padding: 10px;
			color: var(--PopupFgColor);
			box-shadow: 2px 2px 15px var(--PopupShadowColor);
			background-color: var(--PopupBgColor);
			border-radius: 5px;
		}
		div.popup td.multiline {
			vertical-align: top;
			padding-top: 3px;
		}
		div.popup button {
			height: auto;
			font-family: sans-serif;
			font-size: 1em;
			padding: 10px 20px;
			margin: 10px;
		}
		div.popup .pushbutton {
			width: 30px;
			height: 30px;
			padding: 3px;
			margin: -2px 0 0 5px;
		}
		div.popup div.menu span.fieldset {
			display: inline-block;
			height: 48px;
			border: 1px solid var(--InputBorderColor);
			margin-bottom: 10px;
			margin-right: 10px;
			padding: 10px;
			vertical-align: top;
		}
		div.popup div.menu span.fieldset:last-child {
			margin-right: 0;
		}
		div.popup div.menu button,
		div.popup div.menu select {
			padding: 2px 4px;
			margin: 0 0 0 10px;
			vertical-align: middle;
		}
		div.popup select,
		div.popup textarea,
		div.popup input[type="text"],
		div.popup input[type="file"] {
			height: auto;
			font-family: sans-serif;
			font-size: 1em;
			color: var(--InputFgColor);
			background-color: var(--InputBgColor);
			border: 1px solid var(--InputBorderColor);
			outline: none;
			padding: 5px;
			border-radius: 0;
		}
		div.popup textarea {
			resize: vertical;
			display: block;
		}
		div.popup input[type="checkbox"] {
			position: relative;
			transform: scale(1.5);
			outline: none;
		}
		div.popup input[type="radio"] {
			height: auto;
			vertical-align: initial;
		}
		div.popup div.caption {
			text-align: center;
			font-weight: bold;
			padding: 10px;
		}
		div.popup div.items {
			height: 400px;
			padding: 10px;
			overflow-y: auto;
			color: var(--InputFgColor);
			background-color: var(--InputBgColor);
			border: 1px solid var(--InputBorderColor);
		}
		div.popup div.items label:hover {
			color: var(--InputFgColorHover);
			text-decoration: underline;
			cursor: pointer;
		}
		div.popup div.buttons {
			text-align: center;
			padding: 10px;
		}

		/* Menü: Popup-Fenster mit scrollbaren Listen */

		div.popup.list div.items {
			padding: 0;
			background-color: var(--PopupBgColor);
		}
		div.popup.list table {
			width: 100%;
		}
		div.popup.list pre {
			width: 100%;
			line-height: 1.2em;
			white-space: pre-wrap;
			word-wrap: break-word;
			hyphens: none;
			tab-size: 4;
			margin: 0;
			padding: 0;
			color: var(--InputFgColor);
			background-color: var(--InputBgColor);
		}
		div.popup.list thead {
			position: sticky;
			top: 0;
			z-index: 1; /* sonst erscheinen die Checkboxen in Spalte 1 über dem Tabellen-Header */
		}
		div.popup.list th:not(:first-child),
		div.popup.list td:not(:first-child) {
			border-left: 1px solid var(--InputBorderColor);
		}
		div.popup.list th {
			border-bottom: 1px solid var(--InputBorderColor);
			background-color: var(--PopupBgColor);
			font-weight: normal;
			hyphens: none;
		}
		div.popup.list td {
			background-color: var(--InputBgColor);
		}
		div.popup.list tr:not(:last-child) td {
			border-bottom: 1px solid var(--InputBorderColor);
		}

		div.popup.list td.radio,
		div.popup.list td.checkbox {
			text-align: center;
		}
		div.popup.list td.preview {
			text-align: center;
			font-size: 0.9em;
			width: 200px;
		}
		div.popup.list td.preview img,
		div.popup.list td.preview audio,
		div.popup.list td.preview video {
			max-width: 200px;
			max-height: 200px;
			outline: 0;
		}
		div.popup.list .preview-icon {
			font-family: icomoon;
			font-size: 50px;
			line-height: 50px;
			color: var(--IconFgColorEtc);
		}
		div.popup.list .preview-icon.pdf { color: var(--IconFgColorPdf); }
		div.popup.list .preview-icon.php { color: var(--IconFgColorPhp); }
		div.popup.list .preview-icon.xml { color: var(--IconFgColorXml); }

		div.popup.list td.preview a {
			text-decoration: none;
			color: var(--InputFgColor);
		}
		div.popup.list td.fname {
			line-break: anywhere;
		}
		div.popup.list td.ftime,
		div.popup.list td.fsize {
			text-align: right;
		}
		div.popup.list td.uses {
			text-align: center;
		}

		/* Menü: individuelle Popup-Fenster */

		#edit-filename.fullwidth {
			width: 400px !important;
		}

		#catstagspicker {
			top: 90px;
			left: 90px;
		}

		#select-template div.items {
			max-height: 400px;
		}

		#backup {
			top: 90px;
			left: 90px;
			z-index: 2; /* sonst erscheint der Tabellen-Header von #mediamanager über dem Upload-Fester  */
		}

		#backup span.backup-dir {
			display: inline-block;
			min-width: 33.33%;
			padding-right: 20px;
			white-space: nowrap;
		}
		#backup span.backup-dir.default {
			font-weight: bold;
		}

		#mediamanager option.filtered {
			color: var(--SelectFilteredFgColor);
		}
		#upload {
			top: 90px;
			left: 90px;
			z-index: 2; /* sonst erscheint der Tabellen-Header von #mediamanager über dem Upload-Fester  */
		}
		#upload-file {
			cursor: pointer;
		}
		#upload-file::file-selector-button {
			display: none;
		}

		#diff {
			top: 90px;
			left: 90px;
			z-index: 2; /* sonst erscheint der Tabellen-Header von #mediamanager über dem Upload-Fester  */
		}

		div.heading-uses {
			margin-top: 0.5em;
			margin-bottom: -0.5em;
		}
		span.more-uses {
			color: var(--InputFgColorHover);
			cursor: pointer;
		}
		span.more-uses:hover {
			text-decoration: underline;
		}

		#hint-filename-exists,
		#hint-medianame-exists {
			display: none;
			color: var(--WarningFgColor);
		}
		#edit-row-rename {
			display: none;
		}
		#hint-filename-empty,
		#hint-medianame-empty {
			display: none;
			color: var(--ErrorFgColor);
		}
		.infotext {
			position: absolute;
			bottom: 0;
			left: 10px;
		}

		#select-filemanager-insert {
			margin-left: 0;
		}

		/* Toolbar */

		header > p > * {
			font-family: sans-serif;
			font-size: 1em;
			color: var(--ToolFgColor);
			background-color: var(--ToolBgColor);
			border-radius: 3px;
			cursor: pointer;
		}

		header > p > *:hover {
			background-color: var(--ToolBgColorHover);
		}

		header > p > span.toolbutton {
			display: inline-block;
			padding: 10px;
			margin: 3px 0;
			line-height: 1em;
		}

		header > p > select {
			border: none;
			outline: none;
			margin: 3px 0;
			padding: 8px 5px;
		}

		header > p > select option.separator {
			text-align: center;
			color: var(--SelectSeparatorFgColor);
		}

		.tool-disabled,
		.tool-disabled:hover {
			color: var(--ToolFgColorDisabled);
			background-color: var(--ToolBgColorDisabled);
			cursor: initial;
		}

		mark,
		#label-bgcolor {
			padding: 0.2em;
			margin: -0.2em;
		}

		input[type=color] {
			background-color: transparent;
			border: none;
			cursor: pointer;
			vertical-align: middle;
			margin: -10px 0;
			width: 30px;
			height: 30px;
		}

		/* Sourcecode-Editor */

		main textarea {
			width: 100%;
			height: 100%;
			border: none;
			outline: none;
			font-family: sans-serif;
			font-size: 1em;
			line-height: 1.5em;
			color: var(--EditorFgColor);
			background-color: var(--EditorBgColor);
			hyphens: none;
			tab-size: 4;
			padding: 10px;
			width: 50vw;
			resize: horizontal;
		}

		main textarea.system {
			font-family: monospace;
			line-height: 1.2em;
			white-space: pre-wrap;
			_line-break: anywhere; /* Zeilen werden an jeder beliebigen Stelle umgebrochen */
			word-wrap: break-word; /* Zeilen werden an jedem Wortanfang umgebrochen */
			_word-break: break-all; /* Zeilen werden mitten im Wort, aber erst nach anhängende Whitespaces umgebrochen */
			hyphens: none;
			tab-size: 2;
		}

		main textarea::selection {
			background-color: var(--EditorSelectionColor);
		}

		/* Fußzeile */

		.error {
			text-align: center;
			color: var(--ErrorFgColor);
		}

		.warning {
			text-align: center;
			color: var(--WarningFgColor);
		}

		.info {
			text-align: center;
			color: var(--InfoFgColor);
		}

		/* Button-Icons */

		.icon {
			font-family: icomoon;
			color: var(--IconFgColorDefault);
		}

		button:disabled .icon::before {
			color: var(--IconFgColorDisabled);
		}

		.icon.ok::before { content: "\EA10"; color: var(--IconFgColorOK); }
		.icon.cancel::before { content: "\EA0F"; color: var(--IconFgColorCancel); }
		.icon.abort::before { content: "\EA0F"; color: var(--IconFgColorAbort); }
		.icon.delete::before { content: "\EA0B"; color: var(--IconFgColorDelete); }
		.icon.add::before { content: "\EA0A"; color: var(--IconFgColorAdd); }
		.icon.upload::before { content: "\EA32"; color: var(--IconFgColorUpload); }
		.icon.restore::before { content: "\EA0A"; color: var(--IconFgColorRestore); }
		.icon.uncheck::before { content: "\EA53"; color: var(--IconFgColorInactive); }
		.icon.saved::before { content: "\E962"; color: var(--IconFgColorSaved); }
		.icon.modified::before { content: "\E962"; color: var(--IconFgColorModified); }

		.icon.new::before { content: "\E922"; }
		.icon.files::before { content: "\E930"; }
		.icon.save::before { content: "\E962"; }
		.icon.edit::before { content: "\E905"; }
		.icon.media::before { content: "\E90E"; }
		.icon.view::before { content: "\E956"; }
		.icon.preview::before { content: "\E9CE"; }
		.icon.help::before { content: "\E941"; }
		.icon.date::before { content: "\E953"; }
		.icon.auto::before { content: "\E997"; }
		.icon.undo::before { content: "\E965"; }
		.icon.cats::before { content: "\E930"; }
		.icon.tags::before { content: "\E936"; }
		.icon.check::before { content: "\EA52"; }
		.icon.trash::before { content: "\E9AD"; }
		.icon.link::before { content: "\E9CB"; }
		.icon.backup::before { content: "\E964"; }
		.icon.download::before { content: "\EA36"; }
		.icon.left::before { content: "\EA38"; }
		.icon.right::before { content: "\EA34"; }
		.icon.diff::before { content: "\EA7F"; }

		/* DiffViewer*/

		ins {
			text-decoration: none;
			background-color: var(--DiffInsBgColor);
		}
		del {
			text-decoration: none;
			background-color: var(--DiffDelBgColor);
		}
		ins.highlighted {
			color: var(--DiffInsFgColorHighlighted);
			background-color: var(--DiffInsBgColorHighlighted);
		}
		del.highlighted {
			color: var(--DiffDelFgColorHighlighted);
			background-color: var(--DiffDelBgColorHighlighted);
		}
		.special-char {
			color: var(--DiffSpecialCharFgColor);
		}
		.highlighted .special-char {
			color: revert;
		}

		/* Allgemein */

		ul {
			padding-left: 1.5em;
		}
		.center {
			text-align: center;
		}
		.hidden {
			display: none !important;
		}
	</style>

	<script>
		<?php include 'tableSorter.js'; ?>
		<?php include 'htmldiff.js'; ?>

		"use strict";

		function InitEditor()
		{
			InitTableSorter();

			SendRequest('list-articles', StoreLists, 'article');

			InitColorPicker('bg');
			InitColorPicker('fg');
			InitColorPicker('cc');

			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.addEventListener('blur', OnBlurSourcecode);
			elemSourcecode.addEventListener('input', OnInputSourcecode);
			elemSourcecode.addEventListener('keydown', OnKeyDownSourcecode);
			elemSourcecode.addEventListener('mouseup', OnMouseUpSourcecode);
			elemSourcecode.addEventListener('select', OnSelectSourcecode);

			SetToolbarTitles();
			LoadSnippets();
			SetStatusText();
			EnableControls();
			Preview(true);
		}

		function SetToolbarTitles()
		{
			SendRequest('shortcuts', function(filename, response)
			{
				var titles = response.content;
				var elemsToolButton = document.getElementsByClassName('toolbutton');
				for (var i = 0; i < elemsToolButton.length; i++)
				{
					var elemToolButton = elemsToolButton[i];
					var matches = elemToolButton.getAttributeNode('onclick')?.nodeValue.match(/InsertTag\('([^']+)'\)/);
					if (matches)
					{
						var tag = matches[1];
						var title = titles[tag];
						if (title)
						{
							elemToolButton.title += ' ' + title;
						}
					}
				}
			}, '', 'InsertTag');
		}

		var snippets = {};

		function LoadSnippets()
		{
			SendRequest('snippets', function(filename, response)
			{
				document.getElementById('select-snippet').innerHTML = '<option value=""><?php echo GetString("Insert");?>...</option>' + response.content;
				snippets = response.snippets;
			});
		}

		function OnBlurSourcecode(event)
		{
			if (IsPopupShown())
				return;

			//setTimeout(function() { event.target.focus(); }); // funktioniert nicht; select lässt sich dann nicht mehr aufklappen
			event.target.focus();
		}

		var g_timeoutEditSourcecode = null;

		function DelayPreview()
		{
			if (g_timeoutEditSourcecode)
				TriggerPreview();
		}

		function TriggerPreview()
		{
			clearTimeout(g_timeoutEditSourcecode);
			g_timeoutEditSourcecode = setTimeout(Preview, 1000);
		}

		function OnInputSourcecode()
		{
			SetModified(true);
			SetStatusText();
			EnableControls();
			TriggerPreview();
		}

		function Preview(bInit, previewTitle)
		{
			g_timeoutEditSourcecode = null;

			var isWidget = (g_FileData.type === 'widget' && g_FileData.filename !== 'widgets.xml')
			if (isWidget && previewTitle === undefined)
			{
				GetPreviewTitle(bInit);
				return;
			}

			var filename = g_FileData.filename;
			var type = g_FileData.type;
			var title = isWidget ? previewTitle : g_FileData.title;
			var date = g_FileData.date;
			var cats = g_FileData.cats;
			var tags = g_FileData.tags;
			var sourcecode = document.getElementById('sourcecode').value;
			var preview = document.getElementById('preview');
			var scrollPos = bInit ? 0 : preview.contentWindow.scrollY;

			var xhr = new XMLHttpRequest();
			xhr.open('POST', 'lib/preview.php', true);
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			xhr.onreadystatechange = function()
			{
				if (this.readyState == 4 && this.status == 200)
				{
					preview.srcdoc = this.responseText;
					preview.addEventListener('load', function() { preview.contentWindow.scrollTo(0, scrollPos); },  { once: true });
				}
			}
			var params = 
				'filename=' + encodeURIComponent(filename) +
				'&type=' + encodeURIComponent(type) +
				'&title=' + encodeURIComponent(title) +
				'&date=' + encodeURIComponent(date) +
				'&cats=' + encodeURIComponent(cats) +
				'&tags=' + encodeURIComponent(tags) +
				'&content=' + encodeURIComponent(sourcecode);
			xhr.send(params);
		}

		function GetPreviewTitle(bInit) // Parameter bInit nur "durchreichen"
		{
			SendRequest(g_FileData.type + '-title', function(filename, response)
			{
				var bInit = (response.content['filedata'] === 'true');
				var previewTitle = response.content['previewTitle'];
				Preview(bInit, previewTitle);
			}, g_FileData.type, g_FileData.filename, bInit);
		}

		function CheckDeselectSourcecode(event)
		{
			var iSelStart = event.target?.selectionStart;
			var iSelEnd = event.target?.selectionEnd;
			if (!iSelStart || !iSelEnd || iSelStart == iSelEnd)
				OnDeselectSourcecode();
		}

		function OnMouseUpSourcecode(event)
		{
			setTimeout(function() { CheckDeselectSourcecode(event); });
		}

		function OnKeyDownSourcecode(event)
		{
			setTimeout(function() { CheckDeselectSourcecode(event); });

			// Keycodes siehe https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event

			// Shortcuts
			//console.log(event);
			<?php
				$xmlKeyboard = file_get_contents('lib/keyboard.xml');
				if ($xmlKeyboard)
				{
					$keyboard = new SimpleXMLElement($xmlKeyboard);
					foreach ($keyboard->shortcut as $shortcut)
					{
						printf('if (event.code === "%s" && %sevent.ctrlKey && %sevent.shiftKey && %sevent.altKey && %sevent.metaKey)' . PHP_EOL . '{ event.preventDefault(); ',
							$shortcut['key'],
							$shortcut['ctrl'] == 'true' ? '' : '!',
							$shortcut['shift'] == 'true' ? '' : '!',
							$shortcut['alt'] == 'true' ? '' : '!',
							$shortcut['meta'] == 'true' ? '' : '!'
						);
						foreach ($shortcut->command as $command)
						{
							$commandName = $command['name'];
							$commandValue = $command['value'];
							switch ($commandName)
							{
								case 'InsertTag':
								case 'InsertString':
								case 'InsertSnippet':
									$commandValue = "'$commandValue'";
									break;
								case 'Save':
								case 'Duplicate':
								case 'ScrollLine':
									break;
								default:
									$commandValue = "'" . GetString('UnknownCommand') . ": $commandName'";
									$commandName = "alert";
									break;
							}
							echo "$commandName($commandValue); "; 
						}

						echo '}' . PHP_EOL . 'else ';
					}
				}
			?>
			{
				DelayPreview();

				// Tab-Taste soll nicht die TEXTAREA verlassen, sondern ein Tab einfügen bzw. den Text ein-/ausrücken.
				if (event.key === 'Tab' && !event.ctrlKey && !event.altKey && !event.metaKey)
				{
					event.preventDefault(); InsertTabOrIndentOutdentLines(event.shiftKey)
				}
				// Wenn die Enter-Taste gedrückt wird, soll die Einrückung der vorherigen Zeile übernommen werden (Auto-Indent).
				else if (event.key === 'Enter' && !event.ctrlKey && !event.altKey && !event.metaKey)
				{
					event.preventDefault(); InsertNewlineWithAutoIndent();
				}
			}
		}

		var g_fontSizeSourcecode = 24; // fallback value
		function ScrollLine(numLines)
		{
			var elemSourcecode = document.getElementById('sourcecode');
			//elemSourcecode.scrollTop += g_fontSizeSourcecode * numLines;
			elemSourcecode.scrollBy(0, g_fontSizeSourcecode * numLines);
		}

		function InsertTabOrIndentOutdentLines(shiftPressed)
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			if (iSelStart !== iSelEnd || shiftPressed)
			{
				// Text selektiert oder Shift gedrückt: Zeilen ein- oder ausrücken
				// Selektion auf ganze Zeilen erweitern
				while (iSelStart > 0 && text[iSelStart - 1] !== '\n') iSelStart--;
				while (iSelEnd > iSelStart && text[iSelEnd - 1] === '\n') iSelEnd--;
				while (iSelEnd < text.length - 1 && text[iSelEnd] !== '\n') iSelEnd++;
				if (iSelStart === iSelEnd) return;
				elemSourcecode.setSelectionRange(iSelStart, iSelEnd);

				// selektierten Text bearbeiten
				var selectedText = text.substring(iSelStart, iSelEnd);
				var lengthBefore = selectedText.length;

				// am Beginn der 1. Zeile temporär Newline einfügen
				selectedText = '\n' + selectedText;

				if (shiftPressed)
					selectedText = selectedText.replaceAll('\n\t', '\n');
				else
					selectedText = selectedText.replace(/\n([^\n]+)/g, '\n\t$1');

				// das temporär eingefügte Newline wieder entfernen
				selectedText = selectedText.substring(1);

				// geänderten Textblock einfügen
				document.execCommand('insertText', false, selectedText);

				// Text wieder selektieren
				elemSourcecode.setSelectionRange(iSelStart, iSelEnd - lengthBefore + selectedText.length);
			}
			else
			{
				// kein Text selektiert und Shift nicht gedrückt: Tab einfügen
				document.execCommand('insertText', false, '\t');
			}
		}

		function InsertNewlineWithAutoIndent()
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;
			var iCursorPos = iSelStart;

			// Beginn der Zeile suchen:
			while (iSelStart > 0 && text[iSelStart - 1] !== '\n') iSelStart--;
			iSelEnd = iSelStart;
			// Erstes Nicht-Whitespace der Zeile suchen (maximal bis zur Cursoe-Position):
			while (iSelEnd < iCursorPos  && (text[iSelEnd] === ' ' || text[iSelEnd] === '\t')) iSelEnd++;
			// Ausgabe des Return-Zeichens und ggf. der Whitespaces...
			var selectedText = (iSelStart < iSelEnd) ? text.substring(iSelStart, iSelEnd) : '';
			document.execCommand('insertText', false, '\n' + selectedText);
		}

		function Duplicate()
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			if (iSelStart !== iSelEnd)
			{
				// Text selektiert: Genau diesen Teil duplizieren
				var selectedText = text.substring(iSelStart, iSelEnd);
				// Selektion entfernen, damit sie beim Einfügen nicht ersetzt wird:
				elemSourcecode.setSelectionRange(iSelStart, iSelStart);
				document.execCommand('insertText', false, selectedText);
				// Ursprüngliche Selektion wiederherstellen:
				elemSourcecode.setSelectionRange(iSelStart, iSelEnd);
			}
			else
			{
				// Kein Text selektiert: die gesamte Zeile duplizieren
				var iSelOld = iSelStart; // Cursorposition merken
				// Selektion auf ganze Zeilen erweitern (einschl. abschl. \n)
				// Selektions-Beginn hinter das vorherige \n setzen, aber nicht vor den Textanfang:
				while (iSelStart > 0 && text[iSelStart - 1] !== '\n') iSelStart--;
				// Selektions-Ende auf das nächste \n setzen, aber nicht hinter das Textende:
				while (iSelEnd < text.length && text[iSelEnd] !== '\n') iSelEnd++;
				// Selektions-Ende hinter das gefundene \n setzen:
				if (iSelEnd < text.length) iSelEnd++;
				// Wenn bereits am Textende, ein \n anfügen und Selektion erweitern:
				else { text += '\n'; iSelEnd++; }

				var selectedText = text.substring(iSelStart, iSelEnd);
				elemSourcecode.setSelectionRange(iSelStart, iSelStart);
				document.execCommand('insertText', false, selectedText);
				// Ursprüngliche Cursorposition wiederherstellen:
				elemSourcecode.setSelectionRange(iSelOld, iSelOld);
			}
		}

		function InitColorPicker(prefix)
		{
			var varName = 'BlogEditorColor-' + prefix;
		
			var elemPicker = document.getElementById(prefix + 'colorpicker');
			var elemPal = document.getElementById(prefix + 'palette');
			var elemsOpt = elemPal.getElementsByTagName('option');

			for (var iOpt = 0; iOpt < 16; iOpt++)
			{
				var elemOpt = elemsOpt[iOpt];
				var cssVar = elemOpt.getAttribute('data-var');
				if (cssVar) 
				{
					var color = document.documentElement.style.getPropertyValue(cssVar);
					if (color) elemOpt.value = color.toUpperCase();
				}
				var color = localStorage.getItem(varName + iOpt);
				if (color) elemOpt.value = color.toUpperCase();
			}

			var color = localStorage.getItem(varName);
			if (color) elemPicker.value = color;
			SetLabelColor(prefix, elemPicker.value);
		}

		var g_bClickColor = false;

		function OnClickColor()
		{
			g_bClickColor = true;

			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich
		}

		function OnChangeColor(prefix)
		{
			var varName = 'BlogEditorColor-' + prefix;
		
			var elemPicker = document.getElementById(prefix + 'colorpicker');
			var elemPal = document.getElementById(prefix + 'palette');
			var elemsOpt = elemPal.getElementsByTagName('option');

			var color = elemPicker.value.toUpperCase();
			localStorage.setItem(varName, color);
			SetLabelColor(prefix, color);

			var iOpt = 0;
			for (iOpt = 0; iOpt < elemsOpt.length; iOpt++)
			{
				var elemOpt = elemsOpt[iOpt];
				if (elemOpt.value === color)
					return;
			}
			for (iOpt = 15; iOpt >= 1; iOpt--)
			{
				elemsOpt[iOpt].value = elemsOpt[iOpt - 1].value;
				localStorage.setItem(varName + iOpt, elemsOpt[iOpt].value);
			}
			elemsOpt[0].value = color;
			localStorage.setItem(varName + '0', color);
		}

		function SetLabelColor(prefix, color)
		{
			if (prefix === 'bg')
				document.getElementById('label-bgcolor').style.backgroundColor = color;
			else if (prefix === 'fg')
				document.getElementById('label-fgcolor').style.color = color;
			else if (prefix === 'cc')
				document.getElementById('label-colorcode').style.color = color;
		}

		function FindOuterTag(bDelete)
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			var startTag = '';
			var endTag = '';

			var selectedText = text.substring(iSelStart, iSelEnd);
			var matches = selectedText.match(/<([^\ />]+)[ ]*[^>]*>/i);
			if (matches)
			{
				startTag = matches[0];
				var tag = matches[1];
				var re = new RegExp(`<\/${tag}>`, 'i');
				matches = selectedText.match(re);
				if (matches)
				{
					endTag = matches[0];
					if (bDelete)
					{
						// Erstes Start-Tag löschen
						selectedText = selectedText.replace(startTag, '');

						// Erstes End-Tag löschen
						selectedText = selectedText.replace(endTag, '');

						// Letztes End-Tag löschen
					//	var iLastEndTag = selectedText.lastIndexOf(endTag);
					//	if (iLastEndTag)
					//		selectedText = selectedText.substring(0, iLastEndTag) + selectedText.substring(iLastEndTag + endTag.length);

						// TODO: statt erstem oder letztem zugehöriges End-Tag löschen

						// Selektierten Text ohne die entfernten Tags einfügen
						//elemSourcecode.value = text.substring(0, iSelStart) + startTag + selectedText + endTag + text.substring(iSelEnd);
						document.execCommand('insertText', false, selectedText);

						// Text wieder selektieren
						iSelEnd -= startTag.length + endTag.length;
						elemSourcecode.setSelectionRange(iSelStart, iSelEnd);
					}
					return tag;
				}
			}
			return '';
		}

		function OnSelectSourcecode()
		{
			if (IsPopupShown())
				return;

			var tag = FindOuterTag(false);
			var elemToolRemove = document.getElementById('tool-remove');
			if (tag !== '')
			{
				elemToolRemove.addEventListener('click', RemoveTag);
				elemToolRemove.title = sprintf('<?php echo GetString("Remove#Tag"); ?>', tag.toUpperCase());
				elemToolRemove.classList.remove('tool-disabled');
			}
			else
			{
				elemToolRemove.removeEventListener('click', RemoveTag);
				elemToolRemove.title = '';
				elemToolRemove.classList.add('tool-disabled');
			}
		}

		function RemoveTag()
		{
			FindOuterTag(true);
		}

		function OnDeselectSourcecode()
		{
			OnSelectSourcecode();
		}

		function TrimSelection()
		{
			var elemSourcecode = document.getElementById('sourcecode');

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			while (" \t\r\n".indexOf(text.substring(iSelStart, iSelStart + 1)) != -1 && iSelStart < iSelEnd) iSelStart++;
			while (" \t\r\n".indexOf(text.substring(iSelEnd - 1, iSelEnd)) != -1 && iSelStart < iSelEnd) iSelEnd--;

			if (iSelStart != elemSourcecode.selectionStart || iSelEnd != elemSourcecode.selectionEnd)
				elemSourcecode.setSelectionRange(iSelStart, iSelEnd);
		}

		function InsertTag(tag)
		{
			if (g_bClickColor)
			{
				g_bClickColor = false;
				return;
			}

			TrimSelection();

			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			var selectedText = text.substring(iSelStart, iSelEnd);
			var startTag = '<' + tag + '>';
			var endTag = '</' + tag + '>';

			if (tag === 'bgcolor')
			{
				var elemPicker = document.getElementById('bgcolorpicker');
				var color = elemPicker.value.toUpperCase();

				startTag = '<span style="background-color: ' + color + '; padding: 0.2em; margin: -0.2em;">';
				endTag = '</span>';
			}

			if (tag === 'fgcolor')
			{
				var elemPicker = document.getElementById('fgcolorpicker');
				var color = elemPicker.value.toUpperCase();

				startTag = '<span style="color: ' + color + ';">';
				endTag = '</span>';
			}

			if (tag === 'colorcode')
			{
				var elemPicker = document.getElementById('cccolorpicker');
				var color = elemPicker.value.toUpperCase();

				startTag = color;
				endTag = '';
				selectedText = ''; // Der selektierte Text soll ersetzt werden.
			}

			// Selektierten Text mit Tags einfügen
			//elemSourcecode.value = text.substring(0, iSelStart) + startTag + selectedText + endTag + text.substring(iSelEnd);
			document.execCommand('insertText', false, startTag + selectedText + endTag);

			// Text wieder selektieren
			iSelEnd = iSelStart + startTag.length + selectedText.length + endTag.length
			elemSourcecode.setSelectionRange(iSelStart, iSelEnd);
		}

		function InsertString(str)
		{
//			var elemSourcecode = document.getElementById('sourcecode');
//			elemSourcecode.focus(); // für FF erforderlich
			document.execCommand('insertText', false, str);
		}

		function OnSelectSnippet(elemSelect)
		{
			var filename = elemSelect.value;
			elemSelect.selectedIndex = 0;
			InsertSnippet(filename);
		}

		function InsertSnippet(filename)
		{
			if (filename === '')
				return;

			var snippet = snippets[filename];
			if (snippet)
			{
				var elemSourcecode = document.getElementById('sourcecode');
				elemSourcecode.focus(); // für FF erforderlich

				var text = elemSourcecode.value;
				var iSelStart = elemSourcecode.selectionStart;
				var iSelEnd = elemSourcecode.selectionEnd;
				var selectedText = text.substring(iSelStart, iSelEnd);
				selectedText = selectedText.replace(/\n$/, '');
				elemSourcecode.setSelectionRange(iSelStart, iSelStart + selectedText.length);

				if (snippet.indexOf('@MULTILINE@') != -1)
				{
					// Snippet enhält die Variable @MULTILINE@ -> mehrzeilig
					var snippetLines = snippet.split("\n");
					var iLinePart1 = -1;
					var iLinePart2 = -1;
					var iLinePart3 = -1;
					var iLineLastPart = -1;
					var iLineMultiPart = -1;
					var snippetLineMultiPart = '';
					for (var i = 0; i < snippetLines.length; i++)
					{
						var snippetLine = snippetLines[i];
						if (snippetLine.indexOf('@LINE1@') != -1) iLinePart1 = i; else
						if (snippetLine.indexOf('@LINE2@') != -1) iLinePart2 = i; else
						if (snippetLine.indexOf('@LINE1@') != -1) iLinePart1 = i; else
						if (snippetLine.indexOf('@LASTLINE@') != -1) iLineLastPart = i; else
						if (snippetLine.indexOf('@MULTILINE@') != -1)
						{
							iLineMultiPart = i;
							snippetLineMultiPart = snippetLine;
							snippetLines[iLineMultiPart] = '';
						}
					}
					var selectedLines = selectedText.split("\n");
					for (var i = 0; i < selectedLines.length; i++)
					{
						var value = selectedLines[i];
						if (iLinePart1 !== -1 && i === 0)
							snippetLines[iLinePart1] = snippetLines[iLinePart1].replace('@LINE1@', value);
						else if (iLinePart2 !== -1 && i === 1)
							snippetLines[iLinePart2] = snippetLines[iLinePart2].replace('@LINE2@', value);
						else if (iLinePart3 !== -1 && i === 2)
							snippetLines[iLinePart3] = snippetLines[iLinePart3].replace('@LINE3@', value);
						else if (iLineLastPart !== -1 && i === selectedLines.length - 1)
							snippetLines[iLineLastPart] = snippetLines[iLineLastPart].replace('@LASTLINE@', value);
						else
						{
							var line = snippetLineMultiPart.replace('@MULTILINE@', value);
							if (snippetLines[iLineMultiPart] !== '')
								snippetLines[iLineMultiPart] += "\n";
							snippetLines[iLineMultiPart] += line;
						}
					}
					if (snippetLines[iLineMultiPart] === '')
						snippetLines[iLineMultiPart] = snippetLineMultiPart.replace('@MULTILINE@', '');
					snippet = snippetLines.join("\n");
				}
				else if (snippet.indexOf('@TH@') != -1 || snippet.indexOf('@TD@') != -1)
				{
					// Snippet enthält die Variable @TH@ oder @TD@ -> Tabelle
					var snippetLines = snippet.split("\n");
					var iLineTH = -1;
					var iLineTD = -1;
					var iLineDataRowStart = -1;
					var iLineDataRowEnd = -1;
					var iLineLastPart = -1;
					var snippetLineTD = '';
					for (var i = 0; i < snippetLines.length; i++)
					{
						var snippetLine = snippetLines[i];
						if (snippetLine.indexOf('@TH@') != -1) iLineTH = i; else
						if (snippetLine.indexOf('@TD@') != -1) { iLineTD = i; snippetLineTD = snippetLine; } else
						if (snippetLine.indexOf('<tr>') != -1) iLineDataRowStart = i; else
						if (snippetLine.indexOf('</tr>') != -1) iLineDataRowEnd = i; else
						if (snippetLine.indexOf('@LASTLINE@') != -1) iLineLastPart = i;
					}
					var selectedLines = selectedText.split("\n");
					var nSelectedLines = selectedLines.length;
					if (iLineLastPart != -1) nSelectedLines--;
					var dataRows = [];
					for (var l = 0; l < nSelectedLines; l++)
					{
						var selectedLine = selectedLines[l];
						var parts = selectedLine.split(/[\t\|]/);
						var row = '';
						for (var p = 0; p < parts.length; p++)
						{
							var part = parts[p].trim();
							if (row !== '') row += "\n";
							if (l == 0) 
								row += snippetLines[iLineTH].replace('@TH@', part);
							else
								row += snippetLineTD.replace('@TD@', part);
						}
						if (l == 0)
						{
							snippetLines[iLineTH] = row;
						}
						else
						{
							snippetLines[iLineTD] = row;
							dataRows = dataRows.concat(snippetLines.slice(iLineDataRowStart, iLineDataRowEnd + 1));
						}
					}
					if (iLineLastPart != -1)
					{
						var selectedLine = selectedLines[nSelectedLines].trim();
						snippetLines[iLineLastPart] = snippetLines[iLineLastPart].replace('@LASTLINE@', selectedLine);
					}
					// Puh! Jetzt das Snippet wieder zusammenbasteln ...
					snippetLines = snippetLines.slice(0, iLineDataRowStart).concat(dataRows).concat(snippetLines.slice(iLineDataRowEnd + 1, snippetLines.length));
					snippet = snippetLines.join("\n"); // Na, das war ja einfach... ;-)
				}
				else
				{
					// Snippets enthalten vermutlich die Variablen @PARTn@
					var selectedParts = selectedText.split(/[\n\t\[\|\]]/);
					var lenSel = 0;
					for (var i = 0; i < 5; i++) // 5 Teile sollten wohl reichen...
					{
						var name = '@PART' + (i + 1) + '@';
						if (snippet.indexOf(name) != -1)
						{
							var value = (i < selectedParts.length) ? selectedParts[i] : '';
							snippet = snippet.replaceAll(name, value.trim());
							lenSel += value.length;
							if (i + 1 < selectedParts.length) lenSel++; // Separator
						}
					}
					// Ende der Selektion auf den "unverbrauchten" Teil setzen
					elemSourcecode.setSelectionRange(iSelStart, iSelStart + lenSel);
				}

				// Selektion durch Snippet ersetzen
				document.execCommand('insertText', false, snippet);

				// Cursor hinter das eingefügte Snippet setzen
				elemSourcecode.setSelectionRange(iSelStart + snippet.length, iSelStart + snippet.length);
			}
			else
			{
				alert(sprintf('<?php echo GetString("ErrorFile#NotFound"); ?>', filename));
			}
		}

		  ////////////////////////////////////
		 // Funktionen zur Dateiverwaltung //
		////////////////////////////////////

		// Verzeichnisse, die zur Blog-Software gehören:
		var g_defaultDirs = [ '.', 'cgi-bin', 'fonts', 'lib', 'media', 'snapshots', 'snippets', 'templates', 'textblocks', 'trash', 'widgets' ];

		// Default-Struktur für die Datei-Metadaten
		var g_FileDataDefault =
		{
			filename: '',
			rename: false,
			originalFilename: '',
			filenameEdited: false,
			modified: false,
			// Beginn Header-Variablen
			type: 'post',
			published: false,
			title: '',
			description: '',
			image: '',
			cats: '',
			tags: '',
			date: '',
			listed: false,
			pinned: false,
			front: false,
			base: '',
			// Ende Header-Variablen
			sourcecode: ''
		};

		// Arbeitsstruktur für die aktuell im Editor geöffnete Datei
		var g_FileData = Object.assign({}, g_FileDataDefault);
		g_FileData.date = SetDateToday();

		// Lädt die Datei-Metadaten in den Bearbeitungsdialog
		function GetFileData()
		{
			document.getElementById('edit-filename').value = g_FileData.filename;
			document.getElementById('check-rename').checked = g_FileData.rename;
			document.getElementById('select-type').value = g_FileData.type;
			document.getElementById('check-published').checked = g_FileData.published;
			document.getElementById('edit-date').value = g_FileData.date;
			document.getElementById('edit-title').value = g_FileData.title;
			document.getElementById('edit-description').value = g_FileData.description;
			document.getElementById('edit-image').value = g_FileData.image;
			document.getElementById('edit-cats').value = g_FileData.cats;
			document.getElementById('edit-tags').value = g_FileData.tags;
			document.getElementById('check-listed').checked = g_FileData.listed;
			document.getElementById('check-pinned').checked = g_FileData.pinned;
			document.getElementById('check-front').checked = g_FileData.front;
			document.getElementById('edit-base').value = g_FileData.base;
		}

		// Übernimmt die Datei-Metadaten vom Bearbeitungsdialog in die Datenstruktur
		function SetFileData()
		{
			g_FileData.filename = document.getElementById('edit-filename').value;
			g_FileData.rename = document.getElementById('check-rename').checked;
			g_FileData.type = document.getElementById('select-type').value;
			g_FileData.published = document.getElementById('check-published').checked;
			g_FileData.date = document.getElementById('edit-date').value;
			g_FileData.title = document.getElementById('edit-title').value;
			g_FileData.description = document.getElementById('edit-description').value;
			g_FileData.image = document.getElementById('edit-image').value;
			g_FileData.cats = document.getElementById('edit-cats').value;
			g_FileData.tags = document.getElementById('edit-tags').value;
			g_FileData.listed = document.getElementById('check-listed').checked;
			g_FileData.pinned = document.getElementById('check-pinned').checked;
			g_FileData.front = document.getElementById('check-front').checked;
			g_FileData.base = document.getElementById('edit-base').value;
		}

		function IsFileDataModified()
		{
			if (g_FileData.filename !== document.getElementById('edit-filename').value) return true;
			if (g_FileData.rename !== document.getElementById('check-rename').checked) return true;
			if (g_FileData.type !== document.getElementById('select-type').value) return true;
			if (g_FileData.published !== document.getElementById('check-published').checked) return true;
			if (g_FileData.date !== document.getElementById('edit-date').value) return true;
			if (g_FileData.title !== document.getElementById('edit-title').value) return true;
			if (g_FileData.description !== document.getElementById('edit-description').value) return true;
			if (g_FileData.image !== document.getElementById('edit-image').value) return true;
			if (g_FileData.cats !== document.getElementById('edit-cats').value) return true;
			if (g_FileData.tags !== document.getElementById('edit-tags').value) return true;
			if (g_FileData.listed !== document.getElementById('check-listed').checked) return true;
			if (g_FileData.pinned !== document.getElementById('check-pinned').checked) return true;
			if (g_FileData.front !== document.getElementById('check-front').checked) return true;
			if (g_FileData.base !== document.getElementById('edit-base').value) return true;
			return false;
		}

		  ///////////////////////////
		 // Menü-Ereignis-Handler //
		///////////////////////////

		function OnButtonNew()
		{
			if (!ConfirmDiscard()) return;
			SelectTemplate();
		}

		function OnButtonOpen()
		{
			FileManager('open');
		}

		function OnButtonSave()
		{
			Save();
		}

		function OnButtonEdit()
		{
			FileDataDialog();
		}

		function OnButtonMedia()
		{
			MediaManager('open', 'sourcecode');
		}

		function OnButtonView(preview)
		{
			var filename = g_FileData.filename;
			if (g_FileData.originalFilename === '' || !(g_FileData.type === 'post' || g_FileData.type === 'page' || g_FileData.type === 'index'))
				filename = '';

			if (preview)
				filename += '?preview';

			OpenInNewTab(filename);
		}

		function OnButtonHelp()
		{
			OpenInNewTab('help');
		}

		function OpenInNewTab(href)
		{
			Object.assign(document.createElement('a'),
			{
				target: '_blank',
				rel: 'noopener',
				href: href,
			}).click();
		}
		
		function ConfirmDiscard()
		{
			return !g_FileData.modified || confirm("<?php echo GetString('QuestionDiscardUnsavedModifications'); ?>");
		}

		  //////////////////////////////////////////////////////
		 // Popup-Dialog zur Bearbeitung der Datei-Metadaten //
		//////////////////////////////////////////////////////

		var g_Files = {};
		var g_Cats = {};
		var g_Tags = {};
		var g_Media = {};
		var g_MediaUsage = {};
		var g_bMediaInvalid = true;

		function FileDataDialog(action)
		{
			HideAllPopups();
			var elemPopup = document.getElementById('edit-file-data');

			if (action === 'close' || action === 'save')
			{
				if (IsFileDataModified())
				{
					SetModified(true);
					SetFileData();
					SetStatusText();
					EnableControls();
					Preview();
				}
				if (action === 'save' && g_FileData.modified)
					SaveFile();
			}
			else if (action !== 'cancel')
			{
				GetFileData();
				var elemEditFilename = document.getElementById('edit-filename');
				if (elemEditFilename.value === '')
				{
					if (g_FileData.originalFilename !== '')
						elemEditFilename.value = g_FileData.originalFilename;
					else
						CreateFilename();
				}
				InitFileDataDialog();
				CheckFilename(0);
				EnableControls();

				elemPopup.style.display = 'block';

				var elemEditTitle = document.getElementById('edit-title');
				if (elemEditTitle.value === '')
					elemEditTitle.focus();
			}
		}

		function HideAllPopups()
		{
			var elemsPopup = document.getElementsByClassName('popup');
			for (var i = 0; i < elemsPopup.length; i++)
				elemsPopup[i].style.display = 'none'
		}

		function IsPopupShown()
		{
			var elemsPopup = document.getElementsByClassName('popup');
			for (var i = 0; i < elemsPopup.length; i++)
				if (elemsPopup[i].style.display === 'block')
					return true;
			return false;
		}

		function ResizePopup(idPopup, idScrollarea)
		{
			var elemPopup = document.getElementById(idPopup);
			if (elemPopup.style.display === 'none') return;

			var elemScrollarea = document.getElementById(idScrollarea);
			var maxWidth = (document.documentElement.clientWidth - 2 * elemPopup.offsetLeft) + "px";
			if (idPopup === 'diff')
				elemPopup.style.width = maxWidth;
			else
				elemPopup.style.maxWidth = maxWidth;
			elemScrollarea.style.height = "0";
			var popupHeight = elemPopup.offsetHeight;
			elemScrollarea.style.height = (document.documentElement.clientHeight - popupHeight - 2 * elemPopup.offsetTop) + "px";

			window.addEventListener('resize', function() { ResizePopup(idPopup, idScrollarea); }, { once: true });
		}

		function ScrollToTop(idScrollarea)
		{
			var elemScrollarea = document.getElementById(idScrollarea);
			setTimeout(function() { elemScrollarea.scrollTop = 0; }, 10);
		}

		function GetSelectedType()
		{
			return document.getElementById('select-type').value;
		}

		function InitFileDataDialog()
		{
			var type = GetSelectedType();
			var elemPopup = document.getElementById('edit-file-data');
			var elemsEdit = elemPopup.getElementsByClassName('edit-control-article');

			for (var i = 0; i < elemsEdit.length; i++)
			{
				var elemEdit = elemsEdit[i];
				elemEdit.classList.add('hidden');
				if (type === 'post' && elemEdit.classList.contains('type-post'))
					elemEdit.classList.remove('hidden');
				if (type === 'page' && elemEdit.classList.contains('type-page'))
					elemEdit.classList.remove('hidden');
				if (type === 'index' && elemEdit.classList.contains('type-index'))
					elemEdit.classList.remove('hidden');
			}

			var elemEditFileName = document.getElementById('edit-filename');
			if (type === 'post' || type === 'page' || type === 'index')
				elemEditFileName.classList.remove('fullwidth');
			else
				elemEditFileName.classList.add('fullwidth');
		}

		function SetDateToday(idValue)
		{
			var date = new Date();
			var year = date.getFullYear();
			var month = ("0" + (date.getMonth() + 1)).slice(-2);
			var day = ("0" + date.getDate()).slice(-2);
			var result = year + "-" + month + "-" + day;
			if (idValue) document.getElementById(idValue).value = result;
			return result;
		}

		function CreateFilename()
		{
			var filename = '';
			var title = document.getElementById('edit-title').value;
			if (title !== '')
			{
				filename = title.toLowerCase().trim();

				// Einige Umlaute umwandeln
				filename = filename.replaceAll('ä', 'ae');
				filename = filename.replaceAll("ö", 'oe');
				filename = filename.replaceAll("ü", 'ue');
				filename = filename.replaceAll("ß", 'ss');
				filename = filename.replace(/[áàâ]/g, 'a');
				filename = filename.replace(/[éèê]/g, 'e');
				filename = filename.replace(/[íìî]/g, 'i');
				filename = filename.replace(/[óòô]/g, 'o');
				filename = filename.replace(/[úùû]/g, 'u');

				// Alles, was nicht alphanumerisch oder Whitespace ist, rauswerfen:
				filename = filename.replace(/[^\w\d\s]/g, ' ').trim();

				// Whitespaces in Bindestriche umwandeln
				filename = filename.replace(/[\s]+/g, '-');
			}
			
			document.getElementById('edit-filename').value = filename;
		}

		function OnEditType()
		{
			InitFileDataDialog();
			CheckFilename(0);
		}

		function OnEditTitle()
		{
			EnableControls();

			if (g_FileData.filenameEdited) return; // Wenn der Dateiname bereits manuell geändert wurde, so lassen!
			if (g_FileData.originalFilename !== '') return; // Wenn die Datei schonmal gespeichert wurde, dann den Dateinamen so lassen!

			CreateFilename();
			CheckFilename(1000);
		}

		function OnEditFilename()
		{
			g_FileData.filenameEdited = true;
			CheckFilename(1000);
		}

		var g_timeoutEditFilename;

		function CheckFilename(msDelay)
		{
			clearTimeout(g_timeoutEditFilename);
			g_timeoutEditFilename = setTimeout(function()
			{
				var elemMessage = document.getElementById('hint-filename-empty');
				var elemButton = document.getElementById('button-edit-save');
				var filename = document.getElementById('edit-filename').value;

				if (filename === '')
				{
					elemMessage.style.display = 'block';
					elemButton.disabled = true;

					g_FileData.filenameEdited = false;
					FileExists(filename, { 'content': false });
				}
				else
				{
					elemMessage.style.display = 'none';
					elemButton.disabled = false;

					SendRequest('exists', FileExists, GetSelectedType(), filename);
				}
			}, msDelay);
		}

		function FileExists(filename, response)
		{
			var elemMessageExists = document.getElementById('hint-filename-exists');
			elemMessageExists.style.display = (response.content === true && g_FileData.originalFilename !== filename) ? 'block' : 'none';

			var elemRowRename = document.getElementById('edit-row-rename');
			elemRowRename.style.display = 'none';

			var type = GetSelectedType();
			if (type === 'post' || type === 'page' || type === 'index')
			{
				if (g_FileData.originalFilename !== '' && g_FileData.originalFilename !== filename)
				{
					SendRequest('exists', function(filename, response)
					{
						var elemRowRename = document.getElementById('edit-row-rename');
						if (response.content === true) elemRowRename.style.display = 'table-row';
					}, GetSelectedType(), g_FileData.originalFilename);
				}
			}
		}

		function ResetFilename()
		{
			document.getElementById('edit-filename').value = g_FileData.originalFilename;
			CheckFilename(0);
		}

		function CatsTagsPicker(action)
		{
			var elemPopup = document.getElementById('catstagspicker');

			var caption;
			var list;
			var elemEdit;

			if (action === 'cats')
			{
				caption = "<?php echo GetString('SelectCategories'); ?>";
				list = g_Cats;
				elemEdit = document.getElementById('edit-cats');
				elemPopup.setAttribute('data-action', action);
			}
			else if (action === 'tags')
			{
				caption = "<?php echo GetString('SelectTags'); ?>";
				list = g_Tags;
				elemEdit = document.getElementById('edit-tags');
				elemPopup.setAttribute('data-action', action);
			}
			else if (action === 'insert')
			{
				elemPopup.style.display = 'none';

				if (elemPopup.getAttribute('data-action') === 'cats')
					elemEdit = document.getElementById('edit-cats');
				else if (elemPopup.getAttribute('data-action') === 'tags')
					elemEdit = document.getElementById('edit-tags');
				else return;

				var items = [];
				var elemsItem = document.getElementsByClassName('catstagspicker-item');
				for (var i = 0; i < elemsItem.length; i++)
				{
					var elemItem = elemsItem[i];
					if (elemItem.checked) items.push(elemItem.value);
				}
				elemEdit.value = items.join(', ');

				return;
			}
			else
			{
				elemPopup.style.display = 'none';
				return;
			}

			var usedItems = elemEdit.value.split(/,\s/);
			var htmlItems = '';
			for (var key in list)
			{
				var item = list[key];
				var htmlChecked = usedItems.includes(item) ? 'checked="checked"' : '';
				htmlItems += '<div><input id="cats-tags-item-' + key + '" class="catstagspicker-item" type="checkbox" value="' + item + '" ' + htmlChecked + '> <label for="cats-tags-item-' + key + '">' + item + '</label></div>';
			}

			document.getElementById('catstagspicker-caption').innerHTML = caption;
			document.getElementById('catstagspicker-items').innerHTML = htmlItems;
			elemPopup.style.display = 'block';
			ScrollToTop('catstagspicker-items');
		}

		function SelectTemplate(action)
		{
			HideAllPopups();
			var elemPopup = document.getElementById('select-template');

			if (action === 'ok')
			{
				var filename = GetRadioValue('select-template-item');
				if (filename)
					SendRequest('open', NewFile, 'template', filename);
				else
					NewFile(null, { content: '' });
			}
			else if (action !== 'cancel')
			{
				SendRequest('list-files', BuildFileList, 'template', '');
				function BuildFileList(filename, response)
				{
					var html = '';
					var i = 1; // ein Item 0 gibt es schon (hardcodiert!)
					for (var file in response.files)
					{
						var filename = response.files[file].filename;
						var label = filename.replace(/\.[^\.]+$/, '');
						html +=
							'<div><input id="select-template-item-' + i + '" type="radio" name="select-template-item" value="' + filename + '"> <label for="select-template-item-' + i + '">' + label + '</label></div>';
						i++;
					}
					document.getElementById('select-template-items').innerHTML = html;
					elemPopup.style.display = 'block';
					ResizePopup('select-template', 'select-template-scrollarea');
					ScrollToTop('select-template-scrollarea');
				}
			}
		}

		function NewFile(filename, response)
		{
			SetModified(false);
			g_FileData = Object.assign({}, g_FileDataDefault);
			g_FileData.date = SetDateToday();
			HideAllPopups();
			SetSourcecode(response.content);
			SetStatusText();
			EnableControls();
			Preview(true);
			FileDataDialog();
		}

		function FileManager(action, target)
		{
			var elemPopup = document.getElementById('filemanager');

			if (action === 'load')
			{
				if (!ConfirmDiscard()) return;
				var filename = GetSelectedFile();
				if (filename === '') return;
				SendRequest('open', LoadFile, elemPopup.getAttribute('data-target'), filename);
			}
			else if (action === 'insert')
			{
				if (elemPopup.getAttribute('data-target') === 'article')
				{
					HideAllPopups();

					var elemSelectInsert = document.getElementById('select-filemanager-insert');
					var text = GetSelectedFile(elemSelectInsert.value);

					var elemSourcecode = document.getElementById('sourcecode');
					var iSelStart = elemSourcecode.selectionStart;

					setTimeout(function()
					{
						elemSourcecode.focus();
						document.execCommand('insertText', false, text);
						elemSourcecode.setSelectionRange(iSelStart + text.length, iSelStart + text.length);
					});
				}
			}
			else if (action === 'download')
			{
				if (elemPopup.getAttribute('data-target') === 'backup')
				{
					var filename = GetSelectedFile();
					window.open('backups/' + filename, '_self');
				}
			}
			else if (action === 'delete')
			{
				var filename = GetSelectedFile();
				if (filename === '') return;
				var question = elemPopup.getAttribute('data-target') === 'article'
					? '<?php echo GetString("QuestionMoveFile#ToTrash"); ?>'
					: '<?php echo GetString("QuestionDeleteFile#Permanently"); ?>';
				if (!confirm(sprintf(question, filename))) return;
				SendRequest('delete-file', OnResponse, elemPopup.getAttribute('data-target'), filename);
				function OnResponse(filename, response)
				{
					StoreLists(filename, response);
					EnableControls();
					FileManager('reload');
				}
			}
			else if (action === 'diff')
			{
				DiffViewer('open', elemPopup.getAttribute('data-target'), [ GetSelectedFile() ]);
			}
			else if (action === 'cancel')
			{
				HideAllPopups();
			}
			else if (action === 'open' || action === 'reload')
			{
				if (action === 'open')
				{
					if (!target) target = document.querySelector('input[name="filemanager-elemtype"]:checked')?.value || 'article';
					elemPopup.setAttribute('data-target', target);
				}
				else
				{
					target = elemPopup.getAttribute('data-target');
				}

				document.getElementById('filemanager-elemtype-' + target).checked = true;
				document.getElementById('button-filemanager-delete').title = (target === 'article')
					? '<?php echo GetString("MoveSelectedFileToTrash"); ?>'
					: '<?php echo GetString("DeleteSelectedFilePermanently"); ?>';

				var elemHead = document.getElementById('filemanager-head');
				var elemItems = document.getElementById('filemanager-items');
				var elemInfotext = document.getElementById('filemanager-infotext');

				elemItems.innerHTML = '';
				var html = '';

				document.getElementById('fieldset-filemanager-insert').style.display = target === 'article' ? 'inline-block' : 'none';
				document.getElementById('fieldset-filemanager-backup').style.display = target === 'backup' ? 'inline-block' : 'none';
				document.getElementById('button-filemanager-diff').style.display = target !== 'backup' ? 'inline-block' : 'none';

				if (target === 'article')
				{
					elemHead.innerHTML = '<tr><th></th><th><?php echo GetString("Title");?></th><th><?php echo GetString("Filename");?></th><th><?php echo GetString("Date");?></th><th><?php echo GetString("Type");?></th></tr>';
					var i = 0; var postCount = 0; var pageCount = 0; var indexCount = 0;
					for (var file in g_Files)
					{
						var filename = g_Files[file].filename;
						html +=
							'<tr>' +
							'<td class="radio"><input id="filemanager-item-' + i + '" type="radio" name="filemanager-item" value="' + g_Files[file].filename + '" onchange="EnableControls();"></td>' +
							'<td><label for="filemanager-item-' + i + '">' + g_Files[file].title + '</label></td>' +
							'<td><label for="filemanager-item-' + i + '">' + g_Files[file].filename + '</label></td>' +
							'<td><label for="filemanager-item-' + i + '"><nobr>' + g_Files[file].date + '</nobr></label></td>' +
							'<td><label for="filemanager-item-' + i + '"><nobr>' + { post: '<?php echo GetString("Post");?>', page: '<?php echo GetString("Page");?>', index: '<?php echo GetString("Index");?>' }[g_Files[file].type] + '</nobr></label></td>' +
							'</tr>';
						i++;
						if (g_Files[file].type === 'post') postCount++;
						if (g_Files[file].type === 'page') pageCount++;
						if (g_Files[file].type === 'index') indexCount++;
					}
					elemInfotext.innerHTML = sprintf('<?php echo GetString("Info#Files#Posts#Pages#Indexes");?>', i, postCount, pageCount, indexCount);
					ShowPopup();
				}
				else
				{
					elemHead.innerHTML = '<tr><th></th><th><?php echo GetString("Filename");?></th><th class="sortNumeric"><?php echo GetString("Date");?></th><th class="sortNumeric"><?php echo GetString("Size");?></th></tr>';
					SendRequest('list-files', BuildFileList, target, '');
					function BuildFileList(filename, response)
					{
						var i = 0;

						for (var file in response.files)
						{
							var filename = response.files[file].filename;
							var path = response.files[file].path;
							var size = response.files[file].size;
							var sizeDisplay = response.files[file].sizeDisplay;
							var date = response.files[file].date;
							var dateDisplay = response.files[file].dateDisplay;
							var type = response.files[file].type;
							var ext = response.files[file].ext;

							html +=
								'<tr class="item-row">' +
								'<td class="radio"><input id="filemanager-item-' + i + '" type="radio" name="filemanager-item" value="' + filename + '" onchange="EnableControls();"></td>' +
								'<td class="fname"><label for="filemanager-item-' + i + '">' + filename + '</label></td>' +
								'<td class="ftime" data-sort-value="' + date + '"><label for="filemanager-item-' + i + '"><nobr>' + dateDisplay + '</nobr></label></td>' +
								'<td class="fsize" data-sort-value="' + size + '"><label for="filemanager-item-' + i + '"><nobr>' + sizeDisplay + '</nobr></label></td>' +
								'</tr>';
							i++;
						}
						elemInfotext.innerHTML = sprintf('<?php echo GetString("Info#Files");?>', i);
						ShowPopup();
					}
				}

				function ShowPopup()
				{
					if (action === 'open') HideAllPopups();
					elemItems.innerHTML = html;
					elemPopup.style.display = 'block';
					ResizePopup('filemanager', 'filemanager-scrollarea');

					EnableControls();
					InitTableSorter(document.getElementById('filemanager-table'), true);
					if (action === 'open') ScrollToTop('filemanager-scrollarea');
				}
			}
		}

		function GetSelectedFile(format)
		{
			var filename = GetRadioValue('filemanager-item');
			if (!filename)
				return '';

			if (format === undefined || format === 'filename')
				return filename;

			for (var file in g_Files)
			{
				if (g_Files[file].filename === filename)
				{
					var title = g_Files[file].title;
					if (format === 'link')
						return '<a href="' + filename + '">' + title + '</a>';
					else if (format === 'title')
						return title;
					else if (format === 'title+filename')
						return title + "\n" + filename;
					else if (format === 'filename+title')
						return filename + "\n" + title;
				}
			}
			return '';
		}

		function Backup(action)
		{
			var elemPopup = document.getElementById('backup');

			var elemButtonBackupStart = document.getElementById('button-backup-start');
			var elemBackupMessage = document.getElementById('backup-message');

			if (action === 'open')
			{
				SendRequest('list-dirs', function(filename, response)
				{
					var files = response.files;
					var html = '';
					for (var i = 0; i < files.length; i++)
					{
						var dirname = files[i];
						var htmlClass = IsDefaultDir(dirname) ? 'default' : '';

						html += '<span class="backup-dir ' + htmlClass + '"><input id="check-backup-item-' + i + '" type="checkbox" name="check-backup-item" value="' + dirname + '" onchange="EnableControls();"> <label for="check-backup-item-' + i + '">' + dirname + '</label></span>';
					}

					var elemItems = document.getElementById('backup-items');
					elemItems.innerHTML = html;
					SelectBackupItems('default');
					document.getElementById('backup-filename').value = MakeBackupFilename();
					elemBackupMessage.innerHTML = '<?php echo GetString("Ready"); ?>';
					elemPopup.style.display = 'block';
					EnableControls();
				});
			}
			else if (action === 'backup')
			{
				var filename = document.getElementById('backup-filename').value;
				if (filename === '') return;

				var checkedItems = GetSelectedBackupItems();
				if (checkedItems.length == 0) return;

				elemBackupMessage.innerHTML = '<?php echo GetString("BackupStarted"); ?>';
				elemButtonBackupStart.disabled = true;

				SendRequest('backup', OnResponse, 'backup', filename, JSON.stringify(checkedItems));
				function OnResponse(filename, response)
				{
					if (response.content !== '')
						elemBackupMessage.innerHTML = '<?php echo GetString("Error");?>: ' + response.content;
					else
						elemBackupMessage.innerHTML = '<?php echo GetString("BackupDone");?>';
					FileManager('reload');
					document.getElementById('backup-filename').value = MakeBackupFilename();
				}
			}
			else if (action === 'close')
			{
				elemPopup.style.display = 'none';
			}
		}

		function MakeBackupFilename()
		{
			var date = new Date();
			var year = date.getFullYear();
			var month = ("0" + (date.getMonth() + 1)).slice(-2);
			var day = ("0" + date.getDate()).slice(-2);
			var hour = ("0" + date.getHours()).slice(-2);
			var minute = ("0" + date.getMinutes()).slice(-2);
			var second = ("0" + date.getSeconds()).slice(-2);
			var timestamp = year + "-" + month + "-" + day + "_" + hour + "-" + minute + "-" + second;

			return 'backup_' + timestamp + '.zip';
		}

		function IsDefaultDir(dirname)
		{
			return g_defaultDirs.includes(dirname);
		}

		function SelectBackupItems(mode)
		{
			document.getElementById('check-backup-item-sel-' + mode).checked = true;
			var elemsCheckbox = document.getElementsByName('check-backup-item');
			for (var i = 0; i < elemsCheckbox.length; i++)
			{
				var elemCheckbox = elemsCheckbox[i];
				switch(mode)
				{
					case 'all': // Alle auswählen
						elemCheckbox.checked = true;
						break;
					case 'none': // Alle abwählen
						elemCheckbox.checked = false;
						break;
					case 'invert': // Alle umkehren
						elemCheckbox.checked = !elemCheckbox.checked;
						break;
					case 'default': // Standard-Verzeichnisse auswählen
						elemCheckbox.checked = IsDefaultDir(elemCheckbox.value);
						break;
				}
			}
			EnableControls();
		}

		function GetSelectedBackupItems()
		{
			var checkedItems = [];
			var elemsCheckbox = document.getElementsByName('check-backup-item');
			for (var i = 0; i < elemsCheckbox.length; i++)
			{
				var elemCheckbox = elemsCheckbox[i];
				if (elemCheckbox.checked)
					checkedItems.push(elemCheckbox.value);
			}
			return checkedItems;
		}

		function MediaManager(action, target, checkedItems)
		{
			var elemPopup = document.getElementById('mediamanager');

			if (action === 'upload')
			{
				MediaUpload('open');
			}
			else if (action === 'insert')
			{
				if (elemPopup.getAttribute('data-target') === 'sourcecode')
				{
					HideAllPopups();

					var text = '';
					var filenames = GetSelectedMedia(true);
					for (var i = 0; i < filenames.length; i++)
					{
						var filename = filenames[i];
						text += filename + "\n";
					}
					// ggf.TODO: optional ein zum Dateityp passendes Snippet einfügen (Default vom Benutzer wählbar)
					// - einzelne Datei
					// - mehrere Dateien -> Spalten oder Image-Carousel

					var elemSourcecode = document.getElementById('sourcecode');
					var iSelStart = elemSourcecode.selectionStart;

					setTimeout(function()
					{
						elemSourcecode.focus();
						document.execCommand('insertText', false, text);
						elemSourcecode.setSelectionRange(iSelStart + text.length, iSelStart + text.length);
					});
				}
				else if (elemPopup.getAttribute('data-target') === 'edit-image')
				{
					elemPopup.style.display = 'none';
					elemPopup = document.getElementById('upload');
					elemPopup.style.display = 'none';
					var filename = GetSelectedMedia(true)[0];
					document.getElementById('edit-image').value = filename;
				}
			}
			else if (action === 'delete')
			{
				var checkedItems = GetSelectedMedia();
				if (checkedItems.length == 0) return;
				var question = checkedItems.length > 1
					? sprintf('<?php echo GetString("QuestionMove#MediaFilesToTrash"); ?>', checkedItems.length)
					: sprintf('<?php echo GetString("QuestionMoveMediaFile#ToTrash"); ?>', checkedItems[0]);
				if (!confirm(question)) return;
				SendRequest('delete-media', OnResponse, 'media', '', JSON.stringify(checkedItems));
				function OnResponse(filename, response)
				{
					if (response.content !== '')
						ShowErrorMessage('<?php echo GetString("Error");?>: ' + response.content);
					var checkedItems = GetSelectedMedia();
					g_bMediaInvalid = true;
					MediaManager('reload', null, checkedItems);
				}
			}
			else if (action === 'close')
			{
				if (elemPopup.getAttribute('data-target') !== 'edit-image')
					HideAllPopups();
				else
					elemPopup.style.display = 'none';
			}
			else if (action === 'open' || action === 'reload')
			{
				if (action === 'open')
				{
					elemPopup.setAttribute('data-target', target);
					if (target === 'sourcecode')
						HideAllPopups();
				}

				if (g_bMediaInvalid)
				{
					SendRequest('list-files', function(filename, response)
					{
						g_Media = Object.assign({}, response.files);
						g_bMediaInvalid = false;
						BuildMediaList(); // asynchroner Aufruf
					}, 'media');
				}
				else
				{
					BuildMediaList(); // synchroner Aufruf
				}

				function BuildMediaList()
				{
					var elemItems = document.getElementById('mediamanager-items');
					elemItems.innerHTML = '';
					var i = 0;
					var html = '';
					var types = {}; var exts = {}; var years = {}; var months = {};
					for (var file in g_Media)
					{
						var filename = g_Media[file].filename;
						var path = g_Media[file].path;
						var size = g_Media[file].size;
						var sizeDisplay = g_Media[file].sizeDisplay;
						var date = g_Media[file].date;
						var dateDisplay = g_Media[file].dateDisplay;
						var type = g_Media[file].type; types[type] = { audio: '<?php echo GetString("Audio");?>', video: '<?php echo GetString("Video");?>', img: '<?php echo GetString("Image");?>', etc: '<?php echo GetString("Other");?>' }[type];
						var ext = g_Media[file].ext; exts[ext] = ext;
						var year = new Date(1000 * date).toISOString().substring(0, 4); years[year] = year;
						var month = new Date(1000 * date).toISOString().substring(5, 7); months[month] = month;

						var usesCount = -1;
						if (g_MediaUsage[filename])
						{
							var mediafiles = g_MediaUsage[filename];
							usesCount = mediafiles.length;
						}
						var usesCountDisplay = (usesCount == -1) ? '?' : usesCount;
						var usesInfo = '';
						if (usesCount > 0)
						{
							usesInfo += '<div class="heading-uses"><?php echo GetString("UsedIn");?>:</div>';
							if (usesCount > 3) usesInfo += '<div onclick="ShowMoreUses(this);" data-state="closed" data-uses="' + mediafiles.join('|') + '">';
							usesInfo += '<ul>';
							if (usesCount > 0) usesInfo += '<li>' + mediafiles[0] + '</li>';
							if (usesCount > 1) usesInfo += '<li>' + mediafiles[1] + '</li>';
							if (usesCount == 3) usesInfo += '<li>' + mediafiles[2] + '</li>';
							usesInfo += '</ul>';
							if (usesCount > 3) usesInfo += '<span class="more-uses">' + sprintf('<?php echo GetString("and#MoreFiles");?>', usesCount - 2) + '</span></div>';
						}
						
						var checked = checkedItems && checkedItems.includes(filename) ? 'checked="checked"' : '';

						html +=
							'<tr class="item-row" data-type="' + type + '" data-ext="' + ext + '" data-year="' + year + '" data-month="' + month + '">' +
							'<td class="checkbox"><input id="mediamanager-item-' + i + '" type="checkbox" name="mediamanager-item" value="' + filename + '" data-path="' + path + '" ' + checked + ' onchange="UpdateMediaCount();"></td>' +
							'<td class="preview">' + GetPreview(path, type, ext) + '</td>' +
							'<td class="fname" data-sort-value="' + filename + '"><label for="mediamanager-item-' + i + '"><b>' + filename + '</b></label>' + usesInfo + '</td>' +
							'<td class="ftime" data-sort-value="' + date + '"><label for="mediamanager-item-' + i + '"><nobr>' + dateDisplay + '</nobr></label></td>' +
							'<td class="fsize" data-sort-value="' + size + '"><label for="mediamanager-item-' + i + '"><nobr>' + sizeDisplay + '</nobr></label></td>' +
							'<td class="uses" data-sort-value="' + usesCount + '"><label for="mediamanager-item-' + i + '">' + usesCountDisplay + '</label></td>' +
							'</tr>';
						i++;
					}

					FillMediaSelect('select-filter-type', types, '<?php echo GetString("All");?>');
					FillMediaSelect('select-filter-ext', exts, '*.*');
					FillMediaSelect('select-filter-year', years, '<?php echo GetString("Year");?>');
					FillMediaSelect('select-filter-month', months, '<?php echo GetString("Month");?>');

					elemItems.innerHTML = html;
					elemPopup.style.display = 'block';
					ResizePopup('mediamanager', 'mediamanager-scrollarea');

					UpdateMediaCount();
					if (action === 'open') ScrollToTop('mediamanager-scrollarea');
				}
			}
		}

		function ShowMoreUses(elemMoreUses)
		{
			if (elemMoreUses.getAttribute('data-state') === 'opened')
			{
				elemMoreUses.setAttribute('data-state', 'closed');
				elemMoreUses.innerHTML = elemMoreUses.getAttribute('data-original');
			}
			else
			{
				elemMoreUses.setAttribute('data-state', 'opened');
				elemMoreUses.setAttribute('data-original', elemMoreUses.innerHTML);
				elemMoreUses.innerHTML = '<ul><li>' + elemMoreUses.getAttribute('data-uses').split('|').join('</li><li>') + '</li></ul><span class="more-uses"><?php echo GetString("Hide");?></span>';
			}
		}

		function GetPreview(path, type, ext)
		{
			var htmlPreview = '';
			if (type === 'img')
				htmlPreview = '<a href="' + path + '" target="_blank"><img src="' + path + '" onload="InitMetaData(this);" loading="lazy"></a>';
			else if (type === 'audio')
				htmlPreview = '<audio controls="controls" preload="metadata" onloadedmetadata="InitMetaData(this);"><source src="' + path + '"></audio>';
			else if (type === 'video')
				htmlPreview = '<video controls="controls" preload="metadata" onloadedmetadata="InitMetaData(this);"><source src="' + path + '"></video>';
			else
			{
				var icon = '<span class="preview-icon">&#xE924;</span>';
				if (ext === 'pdf') icon = '<span class="preview-icon pdf">&#xEADF;</span>';
				else if (ext === 'php') icon = '<span class="preview-icon php">&#xE926;</span>';
				else if (ext === 'xml') icon = '<span class="preview-icon xml">&#xE926;</span>';
				htmlPreview = '<a href="' + path + '" target="_blank">' + icon + '<br>' + sprintf('<?php echo GetString("#File");?>', ext.toUpperCase()) + '</a>';
			}
			return htmlPreview;
		}

		// Meta-Daten der Mediendateien ergänzen (ist einfacher mit JavaScript als mit PHP):
		function InitMetaData(elem)
		{
			var metadata = '';
			if (elem.tagName.toLowerCase() === 'img')
			{
				elem.removeAttribute('onload');
				metadata = elem.naturalWidth + '&times;' + elem.naturalHeight;
			}
			else if (elem.tagName.toLowerCase() === 'audio')
			{
				elem.removeAttribute('onloadedmetadata');
				metadata = new Date(1000 * elem.duration).toISOString().substring(11, 19)
			}
			else if (elem.tagName.toLowerCase() === 'video')
			{
				elem.removeAttribute('onloadedmetadata');
				metadata = elem.videoWidth + '&times;' + elem.videoHeight + ', ' + new Date(1000 * elem.duration).toISOString().substring(11, 19);
			}
			elem.insertAdjacentHTML('afterend', '<br>' + metadata);
			document.removeEventListener('DOMContentLoaded', InitMetaData);
		}

		function FillMediaSelect(id, list, firstValue)
		{
			var elemSelect = document.getElementById(id);
			var options = '<option value="">' + firstValue + '</option>';

			var sorted = [];
			for (var item in list)
				sorted.push([item, list[item]]);
			sorted.sort(function(a, b) { return a[1].localeCompare(b[1]); });

			for (var i = 0; i < sorted.length; i++)
			{
				var item = sorted[i][0];
				var itemDisplay = sorted[i][1];
				if (id === 'select-filter-ext') itemDisplay = '*.' + item;
				options += '<option value="' + item + '" class="filtered">' + itemDisplay + '</option>';
			}
			elemSelect.innerHTML = options;
		}

		function ApplyMediaFilter(elemSelect)
		{
			var filterType = document.getElementById('select-filter-type').value;
			var filterExt = document.getElementById('select-filter-ext').value;
			var filterYear = document.getElementById('select-filter-year').value;
			var filterMonth = document.getElementById('select-filter-month').value;

			var elemsItemRows = document.getElementsByClassName('item-row');
			for (var i = 0; i < elemsItemRows.length; i++)
			{
				var elemItemRow = elemsItemRows[i];
				var rowType = elemItemRow.getAttribute('data-type');
				var rowExt = elemItemRow.getAttribute('data-ext');
				var rowYear = elemItemRow.getAttribute('data-year');
				var rowMonth = elemItemRow.getAttribute('data-month');

				var display = 'table-row';
				if (filterType !== '' && filterType !== rowType) display = 'none';
				if (filterExt !== '' && filterExt !== rowExt) display = 'none';
				if (filterYear !== '' && filterYear !== rowYear) display = 'none';
				if (filterMonth !== '' && filterMonth !== rowMonth) display = 'none';

				elemItemRow.style.display = display;
			}
			UpdateMediaCount();
		}

		function UpdateMediaCount()
		{
			UpdateItemCount('mediamanager', '<?php echo GetString("Media");?>');
		}

		function UpdateItemCount(idPopup, labelElements)
		{
			var elemsItem = document.getElementsByName(idPopup + '-item');

			var totalCount = elemsItem.length;
			var checkedCount = 0;
			var displayedCount = 0;

			for (var i = 0; i < totalCount; i++)
			{
				var elemItem = elemsItem[i];
				elemItem.parentNode.setAttribute('data-sort-value', elemItem.checked);
				if (elemItem.checked) checkedCount++;
				if (IsElementDisplayed(elemItem)) displayedCount++;
			}

			var elemTable = document.getElementById(idPopup + '-table');
			InitTableSorter(elemTable);

			var elemInfotext = document.getElementById(idPopup + '-infotext')
			elemInfotext.innerHTML = sprintf('<?php echo GetString("Info#Total#Label#Selected#Visible");?>', totalCount, labelElements, checkedCount, displayedCount);

			EnableControls();
		}

		function GetSelectedMedia(bFullPath)
		{
			var checkedItems = [];
			var elemsItem = document.getElementsByName('mediamanager-item');
			for (var i = 0; i < elemsItem.length; i++)
			{
				var elemItem = elemsItem[i];
				if (elemItem.checked)
					checkedItems.push(bFullPath ? elemItem.getAttribute('data-path') : elemItem.value);
			}
			return checkedItems;
		}

		function SetCheckmark(nameCheckbox, mode)
		{
			var bChecked = false;
			var elemsCheckbox = document.getElementsByName(nameCheckbox);
			for (var i = 0; i < elemsCheckbox.length; i++)
			{
				var elemCheckbox = elemsCheckbox[i];
				if (!IsElementDisplayed(elemCheckbox))
					continue;

				switch(mode)
				{
					case 'all': // Alle auswählen
						elemCheckbox.checked = true;
						break;
					case 'none': // Alle abwählen
						elemCheckbox.checked = false;
						break;
					case 'invert': // Alle umkehren
						elemCheckbox.checked = !elemCheckbox.checked;
						break;
					case 'ranges': // Bereiche auswählen
						if (elemCheckbox.checked)
							bChecked = !bChecked;
						else
							elemCheckbox.checked = bChecked;
						break;
				}
			}
			if (nameCheckbox === 'mediamanager-item')
				UpdateMediaCount();
			else if (nameCheckbox === 'trashmanager-item')
				UpdateTrashCount();
		}

		function IsElementDisplayed(elem)
		{
			if (elem)
			{
				if (elem.style && elem.style.display && elem.style.display === 'none')
					return false;
				else
					return IsElementDisplayed(elem.parentNode);
			}
			else
				return true;
		}

		function MediaUpload(action)
		{
			var elemPopup = document.getElementById('upload');

			var elemButtonUpload = document.getElementById('button-upload-start');
			var elemButtonCancel = document.getElementById('button-upload-cancel');
			var elemButtonClose = document.getElementById('button-upload-close');

			var elemMessage = document.getElementById('upload-message');
			var elemFile = document.getElementById('upload-file');
			var elemProgress = document.getElementById('upload-progress');

			var checkedItems = GetSelectedMedia();

			function InitControls(bBusy)
			{
				elemButtonUpload.disabled = bBusy ? true : false;
				elemButtonCancel.style.display = bBusy ? 'inline-block' : 'none';
				elemButtonClose.style.display = bBusy ? 'none' : 'inline-block';

				elemFile.disabled = bBusy ? true : false;
				if (!bBusy)
				{
					elemFile.value = '';
					var elemMessageExists = document.getElementById('hint-medianame-exists');
					elemMessageExists.style.display = 'none';
				}
			}

			if (action === 'open') // Dialog öffnen
			{
				elemPopup.style.display = 'block';

				InitControls(false);
				elemMessage.innerHTML = '<?php echo GetString("PleaseChooseAFile");?>...';
				elemProgress.value = 0;
			}
			else if (action === 'upload') // Button "Hochladen" betätigt
			{
				elemButtonUpload.disabled = true;
				elemButtonCancel.style.display = 'inline-block';
				elemButtonClose.style.display = 'none';

				InitControls(true);
				elemMessage.innerHTML = '<?php echo GetString("FileIsBeingUploaded");?> (0 %)...';

				var bUploadSuccessful = false;

				var xhr = new XMLHttpRequest();
				elemButtonCancel.addEventListener('click', function() { xhr.abort(); }, { once: true });

				xhr.addEventListener('load', function(event)
				{
					InitControls(false);
					//if (this.readyState == 4 && this.status == 200)
					if (this.status >= 200 && this.status < 300)
					{
						var response = JSON.parse(this.responseText);
						if (response.success)
						{
							elemMessage.innerHTML = '<?php echo GetString("UploadSuccessfulNextFile");?>';

							checkedItems.push(response.content);
							g_bMediaInvalid = true;
							MediaManager('reload', null, checkedItems);
						}
						else
							elemMessage.innerHTML = '<?php echo GetString("Error");?>: ' + response.content;
					}
					else
						elemMessage.innerHTML = '<?php echo GetString("HttpError");?> ' + this.status + ': ' + this.statusText + ' - ' + this.responseText;
				});

				xhr.upload.addEventListener('loadstart', function(event)
				{
					elemMessage.innerHTML = '<?php echo GetString("FileIsUploaded");?> (0 %)...';
					elemProgress.value = 0;
					elemProgress.max = event.total;
				});

				xhr.upload.addEventListener('progress', function(event)
				{
					elemMessage.innerHTML = '<?php echo GetString("FileIsUploaded");?> (' + Math.floor((event.loaded / event.total) * 100) + ' %)...';
					elemProgress.value = event.loaded;
					elemProgress.max = event.total;
				});

				xhr.upload.addEventListener("loadend", function(event)
				{
					bUploadSuccessful = true;
				});

				function OnUploadStopped(event)
				{
					bUploadSuccessful = false;
					InitControls(false);
					elemMessage.innerHTML = '<?php echo GetString("FileNotUploaded");?>: ' + event.type;
				}

				xhr.upload.addEventListener('error', OnUploadStopped);
				xhr.upload.addEventListener('abort', OnUploadStopped);
				xhr.upload.addEventListener('timeout', OnUploadStopped);

				var formData = new FormData();
				formData.append('request', 'upload');
				formData.append('file', elemFile.files[0]);
				if (document.getElementById('check-upload-fmtime').checked)
					formData.append('lastModified', Math.floor(elemFile.files[0].lastModified / 1000));
				xhr.open('POST', 'lib/service.php', true);
				xhr.send(formData);
			}
			else if (action === 'close') // Button "Schließen" betätigt
			{
				elemPopup.style.display = 'none';
			}
		}

		function OnChangeUploadFilename()
		{
			var elemFile = document.getElementById('upload-file');
			var filename = elemFile.files[0].name;
			if (!filename) return;
			SendRequest('exists', function(filename, response)
			{
				var elemMessageExists = document.getElementById('hint-medianame-exists');
				elemMessageExists.style.display = (response.content === true) ? 'block' : 'none';
			}, 'media', filename);
		}

		function TrashManager(action, target, checkedItems)
		{
			var elemPopup = document.getElementById('trashmanager');

			if (action === 'restore')
			{
				var checkedItems = GetSelectedTrash();
				if (checkedItems.length != 1) return;
				SendRequest('exists', OnResponseExists, elemPopup.getAttribute('data-target'), checkedItems[0], 'original');
				function OnResponseExists(filename, response)
				{
					var yes = false;
					if (response.content === true)
						yes = confirm(sprintf('<?php echo GetString("QuestionFile#AlreadyExistsInOriginalFolderRecoverAnyway");?>', filename));
					else
						yes = confirm(sprintf('<?php echo GetString("QuestionRecoverItem#");?>', filename));
					if (yes)
						SendRequest('restore', OnResponseRestore, elemPopup.getAttribute('data-target'), filename);
				}
				function OnResponseRestore(filename, response)
				{
					if (elemPopup.getAttribute('data-target') === 'media')
						g_bMediaInvalid = true;
					else
						StoreLists(filename, response);

					var checkedItems = GetSelectedTrash();
					TrashManager('reload', null, checkedItems);
				}
				
			}
			else if (action === 'delete')
			{
				var checkedItems = GetSelectedTrash();
				if (checkedItems.length == 0) return;
				var question = checkedItems.length > 1
					? sprintf('<?php echo GetString("QuestionDelete#Items"); ?>', checkedItems.length)
					: sprintf('<?php echo GetString("QuestionDeleteItem#"); ?>', checkedItems[0]);
				if (!confirm(question)) return;

				SendRequest('delete-trash', OnResponse, elemPopup.getAttribute('data-target'), '', JSON.stringify(checkedItems));
				function OnResponse(filename, response)
				{
					if (response.content !== '')
						ShowErrorMessage('<?php echo GetString("Error");?>: ' + response.content);
					var checkedItems = GetSelectedTrash();
					TrashManager('reload', null, checkedItems);
				}
			}
			else if (action === 'diff')
			{
				DiffViewer('open', elemPopup.getAttribute('data-target'), GetSelectedTrash(), 'trash');
			}
			else if (action === 'close')
			{
				HideAllPopups();
			}
			else if (action === 'open' || action === 'reload')
			{
				if (action === 'open')
				{
					elemPopup.setAttribute('data-target', target);
				}
				else
				{
					target = elemPopup.getAttribute('data-target');
				}

				document.getElementById('trashmanager-elemtype-' + target).checked = true;
				SendRequest('list-files', BuildTrashList, target, '', 'trash');

				function BuildTrashList(filename, response)
				{
					var elemItems = document.getElementById('trashmanager-items');
					elemItems.innerHTML = '';
					var i = 0;
					var html = '';
					for (var file in response.files)
					{
						var filename = response.files[file].filename;
						var path = response.files[file].path;
						var size = response.files[file].size;
						var sizeDisplay = response.files[file].sizeDisplay;
						var date = response.files[file].date;
						var dateDisplay = response.files[file].dateDisplay;
						var type = response.files[file].type;
						var ext = response.files[file].ext;

						var checked = checkedItems && checkedItems.includes(path) ? 'checked="checked"' : '';

						html +=
							'<tr class="item-row">' +
							'<td class="checkbox"><input id="trashmanager-item-' + i + '" type="checkbox" name="trashmanager-item" value="' + filename + '" ' + checked + ' onchange="OnChangeTrashItem(this);"></td>' +
							'<td class="preview">' + GetPreview(path, type, ext) + '</td>' +
							'<td class="fname"><label for="trashmanager-item-' + i + '">' + filename + '</label></td>' +
							'<td class="ftime" data-sort-value="' + date + '"><label for="trashmanager-item-' + i + '"><nobr>' + dateDisplay + '</nobr></label></td>' +
							'<td class="fsize" data-sort-value="' + size + '"><label for="trashmanager-item-' + i + '"><nobr>' + sizeDisplay + '</nobr></label></td>' +
							'</tr>';
						i++;
					}

					if (action === 'open') HideAllPopups();
					elemItems.innerHTML = html;
					elemPopup.style.display = 'block';
					ResizePopup('trashmanager', 'trashmanager-scrollarea');

					UpdateTrashCount();
					ScrollToTop('trashmanager-scrollarea');
				}
			}
		}

		var g_seqSelectedTrashItem = 0;
		function OnChangeTrashItem(elemCheckbox)
		{
			if (elemCheckbox.checked)
				elemCheckbox.setAttribute('data-sequence', g_seqSelectedTrashItem++);
			UpdateTrashCount();
		}

		function UpdateTrashCount()
		{
			UpdateItemCount('trashmanager', '<?php echo GetString("Items");?>');
		}

		function GetSelectedTrash()
		{
			var sortedItems = [];
			var elemsCheckbox = document.getElementsByName('trashmanager-item');
			for (var i = 0; i < elemsCheckbox.length; i++)
			{
				var elemCheckbox = elemsCheckbox[i];
				if (elemCheckbox.checked)
					sortedItems.push({ value: elemCheckbox.value, sequence: elemCheckbox.getAttribute('data-sequence') });
			}
			sortedItems.sort(function(a, b) { return a.sequence - b.sequence; });
			var checkedItems = [];
			for (var i = 0; i < sortedItems.length; i++)
				checkedItems.push(sortedItems[i].value);
			return checkedItems;
		}

		function DiffViewer(action, target, checkedItems, dirType)
		{
			var elemPopup = document.getElementById('diff');

			if (action === 'open')
			{
				if (checkedItems.length > 0)
				{
					var filename1 = checkedItems[0];
					var filename2 = '<?php echo GetString("Editor");?>';

					var content1 = '';
					var content2 = document.getElementById('sourcecode').value;

					SendRequest('open', OnLoadFile1, target, filename1, dirType);
					
					function OnLoadFile1(filename, response)
					{
						content1 = response.content;
						if (checkedItems.length > 1)
						{
							filename2 = checkedItems[1];
							SendRequest('open', OnLoadFile2, target, filename2, dirType);
						}
						else
						{
							OnLoadFile2(filename2, { content: content2 });
						}
					}

					function OnLoadFile2(filename, response)
					{
						elemPopup.style.display = 'block';
						ResizePopup('diff', 'diff-scrollarea');

						content2 = response.content;
						ShowDiffs(filename1, filename2, content1, content2)
					}
				}
			}
			else if (action === 'close')
			{
				elemPopup.style.display = 'none';
			}
		}

		function ShowDiffs(filename1, filename2, content1, content2)
		{
			var elemOutput = document.getElementById('diff-output');
			var ids = [];

			InitControls();
			setTimeout(Compare);

			function Compare()
			{
				var charReturn = '␍';
				//var charNewline = '↵';
				var charNewline = '␊';
				var charTab = '␉';
				var charSpace = '·';
				
				// Replace some special chars by symbols
				content1 = content1.replaceAll('\r', charReturn);
				content2 = content2.replaceAll('\r', charReturn);

				content1 = content1.replaceAll('\n', charNewline);
				content2 = content2.replaceAll('\n', charNewline);

				content1 = content1.replaceAll('\t', charTab);
				content2 = content2.replaceAll('\t', charTab);

				content1 = content1.replaceAll(' ', charSpace);
				content2 = content2.replaceAll(' ', charSpace);

				// Find differences
				var output = htmldiff(content1, content2);

				// Encode HTML-special chars
				output = output.replaceAll('&', '&amp;');
				output = output.replaceAll('<', '&lt;');
				output = output.replaceAll('>', '&gt;');
				output = output.replaceAll('"', '&quot;');

				// Decode inserted tags
				output = output.replaceAll('[ins]', '<ins>');
				output = output.replaceAll('[/ins]', '</ins>');
				output = output.replaceAll('[del]', '<del>');
				output = output.replaceAll('[/del]', '</del>');

				// Append BR tag to all newline symbols except for those inside of DEL tags
				output = output.replaceAll(charNewline, charNewline + '<br>');
			//	output = output.replace(/<del>.*?<\/del>/g, function(match, capture) { return match.replaceAll(charNewline + '<br>', charNewline); });

				output = output.replaceAll(charReturn, '<span class="special-char">' + charReturn + '</span>');
				output = output.replaceAll(charNewline, '<span class="special-char">' + charNewline + '</span>');
				output = output.replaceAll(charTab, '<span class="special-char">' + charTab + '</span>');
				output = output.replaceAll(charSpace, '<span class="special-char">' + charSpace + '<wbr></span>');

				// Display output
				elemOutput.innerHTML = output;

				// Add an ID to inserted DEL & INS tags
				var elemsTag = elemOutput.getElementsByTagName('*');
				for (var i = 0; i < elemsTag.length; i++)
				{
					var elemTag = elemsTag[i];
					if (elemTag.tagName.toLowerCase() === 'del' || elemTag.tagName.toLowerCase() === 'ins')
					{
						var id = 'diff-' + ids.length;
						elemTag.id = id;
						ids.push(id);
					}
				}

				InitControls(ids.length);
			}

			var skipPos = -1;
			function SkipDiffPrev() { SkipDiff(-1); }
			function SkipDiffNext() { SkipDiff(1); }
			function SkipDiff(skipVal)
			{
				if (skipVal > 0)
				{
					if (skipPos === -1 || skipPos + 1 >= ids.length)
						skipPos = 0;
					else
						skipPos++;
				}
				else if (skipVal < 0)
				{
					if (skipPos === -1 || skipPos - 1 < 0)
						skipPos = ids.length - 1;
					else
						skipPos--;
				}
				InitControls(ids.length, skipPos);
				for (var i = 0; i < ids.length; i++)
				{
					var elemTag = document.getElementById(ids[i]);
					if (i === skipPos)
					{
						elemTag.classList.add('highlighted');
						ScrollIntoView(elemOutput.parentElement, elemTag);
					}
					else
						elemTag.classList.remove('highlighted');
				}
			}

			function InitControls(diffCount, skipPos)
			{
				var elemInfotext = document.getElementById('diff-infotext');
				var elemButtonDiffPrev = document.getElementById('button-diff-prev');
				var elemButtonDiffNext = document.getElementById('button-diff-next');
				var elemInfoFilename1 = document.getElementById('diff-info-filename1');
				var elemInfoFilename2 = document.getElementById('diff-info-filename2');

				if (diffCount === undefined)
				{
					elemButtonDiffPrev.disabled = true;
					elemButtonDiffNext.disabled = true;

					elemButtonDiffPrev.removeEventListener('click', SkipDiffPrev);
					elemButtonDiffNext.removeEventListener('click', SkipDiffNext);

					elemInfotext.innerHTML = '<?php echo GetString("PleaseWait");?>...';

					elemInfoFilename1.innerHTML = filename1;
					elemInfoFilename2.innerHTML = filename2;

					elemOutput.scrollTop = 0;
					elemOutput.innerHTML = '';

					return;
				}

				if (skipPos !== undefined)
				{
					elemInfotext.innerHTML = sprintf('<?php echo GetString("Difference#Of#"); ?>', skipPos + 1, diffCount);
					return;
				}

				if (diffCount > 0)
				{
					elemButtonDiffPrev.disabled = false;
					elemButtonDiffNext.disabled = false;

					elemButtonDiffPrev.addEventListener('click', SkipDiffPrev);
					elemButtonDiffNext.addEventListener('click', SkipDiffNext);
					document.documentElement.addEventListener('keydown', OnKeyDownDiff,  { once: true });

					elemInfotext.innerHTML = sprintf('<?php echo GetString("Difference#Of#"); ?>', '&minus;', diffCount);

					SkipDiffNext();
				}
				else
				{
					elemInfotext.innerHTML = '<?php echo GetString("FilesAreIdentical");?>';
				}
			}

			function ScrollIntoView(parent, child)
			{
				var parentRect = parent.getBoundingClientRect();
				var childRect = child.getBoundingClientRect();

				if (childRect.top < parentRect.top)
					parent.scrollTop -= parentRect.top - childRect.top + parentRect.height / 2;
				else if (childRect.bottom > parentRect.bottom)
					parent.scrollTop += childRect.bottom - parentRect.bottom + parentRect.height / 2;
			}

			function OnKeyDownDiff(event)
			{
				if (event.key === 'ArrowUp' && event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
				{
					event.preventDefault(); SkipDiff(-1);
				}
				if (event.key === 'ArrowDown' && event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
				{
					event.preventDefault(); SkipDiff(1);
				}

				if (document.getElementById('diff').style.display === 'block')
					document.documentElement.addEventListener('keydown', OnKeyDownDiff,  { once: true });
			}
		}

		  /////////////////////////////
		 // Diverse Hilfsfunktionen //
		/////////////////////////////

		function SendRequest(request, callback, target, filename, filedata)
		{
			var xhr = new XMLHttpRequest();
			xhr.open('POST', 'lib/service.php', true);
			xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			//xhr.onreadystatechange = function()
			xhr.onload = function()
			{
				//if (this.readyState == 4 && this.status == 200)
				if (this.status >= 200 && this.status < 300)
				{
					var response = JSON.parse(this.responseText);
					if (response.success)
					{
						if (callback)
							callback(filename, response);
					}
					else
						ShowErrorMessage('<?php echo GetString("Error");?>: ' + response.content);
				}
				else
					ShowErrorMessage('<?php echo GetString("HttpError");?> ' + this.status + ': ' + this.statusText + ' - ' + this.responseText);
			}

			var params =
				'request=' + encodeURIComponent(request);
			if (target) params +=
				'&target=' + encodeURIComponent(target);
			if (filename) params +=
				'&filename=' + encodeURIComponent(filename);
			if (filedata) params +=
				'&filedata=' + encodeURIComponent(filedata);
			xhr.send(params);
		}

		function LoadFile(filename, response)
		{
			SetModified(false);
			g_FileData = Object.assign({}, g_FileDataDefault);
			g_FileData.filename = filename;
			g_FileData.originalFilename = filename;

			// Weitere Metadaten laden
			if (response.headerVars.type)			g_FileData.type			= response.headerVars.type;
			if (response.headerVars.published)		g_FileData.published	= (response.headerVars.published === 'true');
			if (response.headerVars.title)			g_FileData.title		= response.headerVars.title;
			if (response.headerVars.description)	g_FileData.description	= response.headerVars.description;
			if (response.headerVars.image)			g_FileData.image		= response.headerVars.image;
			if (response.headerVars.cats)			g_FileData.cats			= response.headerVars.cats;
			if (response.headerVars.tags)			g_FileData.tags			= response.headerVars.tags;
			if (response.headerVars.date)			g_FileData.date			= response.headerVars.date;
		//	if (response.headerVars.listed)			g_FileData.listed		= (response.headerVars.listed === 'true');
													g_FileData.listed		= DetermineHeaderVarListed(response.headerVars.listed);
			if (response.headerVars.pinned)			g_FileData.pinned		= (response.headerVars.pinned === 'true');
			if (response.headerVars.front)			g_FileData.front		= (response.headerVars.front === 'true');
			if (response.headerVars.base)			g_FileData.base			= response.headerVars.base;

			HideAllPopups();
			SetSourcecode(response.content);
			SetStatusText();
			EnableControls();
			Preview(true);
		}

		function DetermineHeaderVarListed(listed)
		{
			// Defaultwert ist für Beiträge und Seiten unterschiedlich:
			if (typeof listed !== 'undefined')
			{
				return listed === 'true';
			}
			else if (g_FileData.type === 'page')
			{
				return false;
			}
			else
			{
				return true;
			}
		}

		function Save()
		{
			if (g_FileData.modified) 
			{
				if (g_FileData.filename !== '')
					SaveFile();
				else
					FileDataDialog();
			}
		}

		function SaveFile()
		{
			var filename = g_FileData.filename;
			if (filename !== '')
			{
				g_FileData.sourcecode = document.getElementById('sourcecode').value;
				SendRequest('save', OnResponse, g_FileData.type, filename, JSON.stringify(g_FileData));
			}

			function OnResponse(filename, response)
			{
				if (filename === 'snippets.xml')
					LoadSnippets();
				StoreLists(filename, response);
				g_FileData.originalFilename = filename;

				SetModified(false);
				SetStatusText();
				EnableControls();
			}
		}

		function InsertAuthUserFileLine()
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			SendRequest('getvar', function(filename, response)
			{
				var documentRoot = response.content['value'];
				document.execCommand('insertText', false, 'AuthUserFile ' + documentRoot + 'lib/.htpasswd\n');
			}, 'server', 'DOCUMENT_ROOT');
		}

		function EncryptSelectedPassword()
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			var text = elemSourcecode.value;
			var iSelStart = elemSourcecode.selectionStart;
			var iSelEnd = elemSourcecode.selectionEnd;

			if (iSelStart === iSelEnd)
			{
				ShowErrorMessage('<?php echo GetString("PleaseSelectPasswordToEncrypt");?>');
				return;
			}

			var selectedText = text.substring(iSelStart, iSelEnd);
			SendRequest('encrypt', function(filename, response)
			{
				document.execCommand('insertText', false, response.content['encrypted']);
			}, '', selectedText);
		}

		function InsertKeycode()
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.focus(); // für FF erforderlich

			ShowInfoMessage('<?php echo GetString("PleasePressKey");?>');

			function OnKeyDown()
			{
				event.preventDefault();
				document.execCommand('insertText', false, event.code);
			}

			setTimeout(function()
			{
				elemSourcecode.removeEventListener('keydown', OnKeyDown);
			}, 5000);

			elemSourcecode.addEventListener('keydown', OnKeyDown,  { once: true });
		}

		function ShowInfoMessage(messageText)
		{
			ShowMessage(messageText, 'info');
		}

		function ShowWarningMessage(messageText)
		{
			ShowMessage(messageText, 'warning');
		}

		function ShowErrorMessage(messageText)
		{
			ShowMessage(messageText, 'error');
		}

		function ShowMessage(messageText, className)
		{
			SetStatusText('<div class="' + className + '">' + messageText + '</div>')
			setTimeout(SetStatusText, 5000);
		}

		function SetStatusText(statusText)
		{
			if (!statusText)
			{
				var modifiedIndicator = g_FileData.modified ? '<span class="icon modified" title="<?php echo GetString("UnsavedModificationsExisting");?>"></span>' : '<span class="icon saved" title="<?php echo GetString("ArticleIsSaved");?>"></span>';
				var title = g_FileData.title === '' ?  '<i><?php echo GetString("NoTitle");?></i>' : g_FileData.title;
				var filename = g_FileData.filename === '' ? '<i><?php echo GetString("newFile");?></i>' : g_FileData.filename;
				statusText = modifiedIndicator + ' <?php echo GetString("File");?>: ' + (g_FileData.type === 'post' || g_FileData.type === 'page' || g_FileData.type === 'index' ? title + ' (' + filename + ')' : filename);
			}

			var elemStatusText = document.getElementById('statustext');
			elemStatusText.innerHTML = statusText;
		}

		function EnableControls()
		{
			document.getElementById('button-new').disabled = false;
			document.getElementById('button-save').disabled = (!g_FileData.modified);
			document.getElementById('button-edit').disabled = false;
			document.getElementById('button-edit-reset').disabled = (g_FileData.originalFilename === '');
			document.getElementById('button-edit-create').disabled = (document.getElementById('edit-title').value === '');

			var elemSourcecode = document.getElementById('sourcecode');
			if (g_FileData.type === 'system')
			{
				document.getElementById('toolbar-article').classList.add('hidden');
				document.getElementById('toolbar-system').classList.remove('hidden');
				elemSourcecode.classList.add('system');
				g_fontSizeSourcecode = parseFloat(getComputedStyle(elemSourcecode).lineHeight);
			}
			else
			{
				document.getElementById('toolbar-article').classList.remove('hidden');
				document.getElementById('toolbar-system').classList.add('hidden');
				elemSourcecode.classList.remove('system');
				g_fontSizeSourcecode = parseFloat(getComputedStyle(elemSourcecode).lineHeight);
			}

			var elemButtonHtaccess = document.getElementById('tool-htaccess');
			if (g_FileData.type === 'system' && g_FileData.filename === '.htaccess')
				elemButtonHtaccess.classList.remove('hidden');
			else
				elemButtonHtaccess.classList.add('hidden');

			var elemButtonHtpasswd = document.getElementById('tool-htpasswd');
			if (g_FileData.type === 'system' && g_FileData.filename === '.htpasswd')
				elemButtonHtpasswd.classList.remove('hidden');
			else
				elemButtonHtpasswd.classList.add('hidden');

			var elemButtonKeycode = document.getElementById('tool-keycode');
			if (g_FileData.type === 'system' && g_FileData.filename === 'keyboard.xml')
				elemButtonKeycode.classList.remove('hidden');
			else
				elemButtonKeycode.classList.add('hidden');

			if (IsPopupShown())
			{
				
				var selectedFile = GetSelectedFile();
				document.getElementById('button-filemanager-open').disabled = (selectedFile === '' || document.getElementById('filemanager-elemtype-backup').checked);
				document.getElementById('button-filemanager-delete').disabled = (selectedFile === '');
				document.getElementById('button-filemanager-insert').disabled = (selectedFile === '');
				document.getElementById('button-filemanager-backup-download').disabled = (selectedFile === '');
				document.getElementById('button-filemanager-diff').disabled = (selectedFile === '');

				var nSelectedBackupItems = GetSelectedBackupItems().length;
				document.getElementById('button-backup-start').disabled = (nSelectedBackupItems === 0 || document.getElementById('backup-filename').value === '');

				var nSelectedMedia = GetSelectedMedia().length;
				document.getElementById('button-mediamanager-insert').disabled = (nSelectedMedia === 0);
				document.getElementById('button-mediamanager-delete').disabled = (nSelectedMedia === 0);

				var nSelectedTrash = GetSelectedTrash().length;
				document.getElementById('button-trashmanager-restore').disabled = (nSelectedTrash !== 1);
				document.getElementById('button-trashmanager-delete').disabled = (nSelectedTrash === 0);
				document.getElementById('button-trashmanager-diff').disabled = (nSelectedTrash < 1 || nSelectedTrash > 2);
			}
		}

		function SetModified(bModified)
		{
			g_FileData.modified = bModified;
			if (bModified)
				window.addEventListener('beforeunload', OnBeforeUnload);
			else
				window.removeEventListener('beforeunload', OnBeforeUnload);
		}

		function OnBeforeUnload(event)
		{
			//event.preventDefault();
			event.returnValue = true;
		}

		function SetSourcecode(content)
		{
			var elemSourcecode = document.getElementById('sourcecode');
			elemSourcecode.value = content;
			elemSourcecode.setSelectionRange(0, 0); // Cursor an den Anfang setzen (macht er nicht von alleine).
			setTimeout(function() { elemSourcecode.scrollTop = 0; }); // Bei synchronem Aufruf wird komischerweise nicht nach oben gescrollt.
		}

		function StoreLists(filename, response)
		{
			if (!response.files) return; // Listen nur speichern, wenn gefüllt
			g_Files = Object.assign({}, response.files);
			g_Cats = Object.assign({}, response.cats);
			g_Tags = Object.assign({}, response.tags);
			g_MediaUsage = Object.assign({}, response.mediaUsage);
		}

		function sprintf(format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
		{
			var result = '';
			var args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];
			var parts = format.split(/%s|%d/);
			for (var i = 0; i < parts.length; i++)
			{
				result += parts[i];
				if (i < args.length && args[i] !== undefined)
					result += args[i];
			}
			return result;
		}

		function GetRadioValue(name)
		{
			var elemsRadio = document.getElementsByName(name);
			for (var i = 0; i < elemsRadio.length; i++)
			{
				var elemRadio = elemsRadio[i];
				if (elemRadio.checked)
					return elemRadio.value;
			}
			return null;
		}

		document.addEventListener('DOMContentLoaded', InitEditor);

	</script>
</head>

<body>
	<nav>
		<p>
			<button id="button-new" onclick="OnButtonNew();" title="<?php echo GetString('CreateNewArticle');?>"><span class="icon new"></span> <?php echo GetString('New');?></button>
			<button id="button-files" onclick="OnButtonOpen();" title="<?php echo GetString('OpenFile');?>"><span class="icon files"></span> <?php echo GetString('Open');?></button>
			<button id="button-save" onclick="OnButtonSave();" title="<?php echo GetString('SaveFile');?>"><span class="icon save"></span> <?php echo GetString('Save');?></button>
			<button id="button-edit" onclick="OnButtonEdit();" title="<?php echo GetString('EditFileInfo');?>"><span class="icon edit"></span> <?php echo GetString('Edit');?></button>
			<button id="button-media" onclick="OnButtonMedia();" title="<?php echo GetString('OpenMediaManager');?>"><span class="icon media"></span> <?php echo GetString('Media');?></button>
			<button id="button-view" onclick="OnButtonView();" title="<?php echo GetString('ViewArticleInNewTab');?>"><span class="icon view"></span> <?php echo GetString('View');?></button>
			<button id="button-preview" onclick="OnButtonView(true);" title="<?php echo GetString('PreviewArticleInNewTab');?>"><span class="icon preview"></span> <?php echo GetString('Preview');?></button>
			<button id="button-help" onclick="OnButtonHelp();" title="<?php echo GetString('OpenHelpPageInNewTab');?>"><span class="icon help"></span> <?php echo GetString('Help');?></button>
		</p>

		<div id="edit-file-data" class="popup">
			<table cellspacing="10" cellpadding="0" border="0">
			<tr>
				<td colspan="2" align="center"><b><?php echo GetString('EditFileInfo');?></b></td>
			</tr>
			<tr>
				<td><label for="select-type"><?php echo GetString('FileType');?>:</label></td>
				<td>
					<select id="select-type" onchange="OnEditType();">
						<option value="post"><?php echo GetString('Post');?></option>
						<option value="page"><?php echo GetString('Page');?></option>
						<option value="template"><?php echo GetString('Template');?></option>
						<option value="textblock"><?php echo GetString('TextBlock');?></option>
						<option value="snippet"><?php echo GetString('Snippet');?></option>
						<option value="widget"><?php echo GetString('Widget');?></option>
						<option value="index"><?php echo GetString('Index');?></option>
						<option value="system"><?php echo GetString('SystemFile');?></option>
					</select>
				</td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><label for="edit-date"><?php echo GetString('Date');?>:</label></td>
				<td><input id="edit-date" type="text" placeholder="<?php echo GetString('YYYY-MM-DD');?>" style="width: 100px;" title="<?php echo GetString('ArticlesWithALaterDateAreListedAbove');?>"><button onclick="SetDateToday('edit-date');" class="pushbutton" title="<?php echo GetString('InsertTodaysDate');?>"><span class="icon date"></span></button></td>
			</tr>
			<tr class="edit-control-article type-post type-page type-index">
				<td><label for="edit-title"><?php echo GetString('Title');?>:</label></td>
				<td><input id="edit-title" onchange="OnEditTitle();" onkeyup="OnEditTitle();" type="text" placeholder="<?php echo GetString('PleaseEnterArticleTitle');?>..." style="width: 400px;"></td>
			</tr>
			<tr>
				<td class="multiline"><label for="edit-filename"><?php echo GetString('Filename');?>:</label></td>
				<td><input id="edit-filename" onkeyup="OnEditFilename();" type="text" placeholder="<?php echo GetString('PleaseEnterFilename');?>..." style="width: 330px;" title="<?php echo GetString('HintFilenameOnlyNumbersLettersDashesNoUmlautsSpecialCharsSpaces');?>"><button id="button-edit-create" onclick="CreateFilename(); CheckFilename(0);" class="pushbutton edit-control-article type-post type-page type-index" title="<?php echo GetString('CreateFilenameAutomaticallyFromTitle');?>"><span class="icon auto"></span></button><button id="button-edit-reset" onclick="ResetFilename();" class="pushbutton edit-control-article type-post type-page type-index" title="<?php echo GetString('RestoreOriginalFilename');?>"><span class="icon undo"></span></button><div id="hint-filename-exists">⚠ <?php echo GetString('FileWithThisNameExisting');?></div><div id="hint-filename-empty">⚠ <?php echo GetString('PleaseEnterFilename');?></div></td>
			</tr>
			<tr id="edit-row-rename" class="edit-control-article type-post type-page type-index">
				<td><?php echo GetString('Rename');?>:</td>
				<td><input id="check-rename" type="checkbox"> <label for="check-rename"><?php echo GetString('RemoveOriginalFileAndCreateSnapshot');?></label></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><label for="edit-cats"><?php echo GetString('BaseUrl');?>:</label></td>
				<td><input id="edit-base" type="text" placeholder="" style="width: 200px;"></td>
			</tr>
			<tr class="edit-control-article type-post type-page type-index">
				<td class="multiline"><label for="edit-description"><?php echo GetString('Description');?>:</label></td>
				<td><textarea id="edit-description" rows="4" style="width: 400px;" placeholder="<?php echo GetString('ShortContentDescriptionOrTeaser');?>..."></textarea></td>
			</tr>
			<tr class="edit-control-article type-post type-page type-index">
				<td><label for="edit-image"><?php echo GetString('ArticleImage');?>:</label></td>
				<td><input id="edit-image" type="text" placeholder="<?php echo GetString('ForArticleIndexOrSharing');?>" style="width: 365px;"><button onclick="MediaManager('open', 'edit-image');" class="pushbutton" title="<?php echo GetString('SelectAnArticleImage');?>"><span class="icon media"></span></button></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><label for="edit-cats"><?php echo GetString('Categories');?>:</label></td>
				<td><input id="edit-cats" type="text" placeholder="<?php echo GetString('CommaSeparatedListOfCategories');?>" style="width: 365px;"><button onclick="CatsTagsPicker('cats');" class="pushbutton" title="<?php echo GetString('SelectCategories');?>"><span class="icon cats"></span></button></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><label for="edit-tags"><?php echo GetString('Tags');?>:</label></td>
				<td><input id="edit-tags" type="text" placeholder="<?php echo GetString('CommaSeparatedListOfTags');?>" style="width: 365px;"><button onclick="CatsTagsPicker('tags');" class="pushbutton" title="<?php echo GetString('SelectTags');?>"><span class="icon tags"></span></button></td>
			</tr>
			<tr class="edit-control-article type-post type-page type-index">
				<td><?php echo GetString('Published');?>:</td>
				<td><input id="check-published" type="checkbox"> <label for="check-published"><?php echo GetString('ArticleIsPublished');?></label></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><?php echo GetString('List');?>:</td>
				<td><input id="check-listed" type="checkbox"> <label for="check-listed"><?php echo GetString('ListArticleOnIndexPage');?></label></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><?php echo GetString('Pin');?>:</td>
				<td><input id="check-pinned" type="checkbox"> <label for="check-pinned"><?php echo GetString('KeepArticleOnTopOnIndexPage');?></label></td>
			</tr>
			<tr class="edit-control-article type-post type-page">
				<td><?php echo GetString('Complete');?>:</td>
				<td><input id="check-front" type="checkbox"> <label for="check-front"><?php echo GetString('DisplayEntireArticleOnIndexPage');?></label></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button id="button-edit-save" onclick="FileDataDialog('save');" title="<?php echo GetString('SaveArticle');?>"><span class="icon save"></span> <?php echo GetString('Save');?></button>
					<button id="button-edit-close" onclick="FileDataDialog('close');" title="<?php echo GetString('CopyAboveInformationIntoArticleWithoutSaving');?>"><span class="icon ok"></span> <?php echo GetString('Close');?></button>
					<button onclick="FileDataDialog('cancel');" title="<?php echo GetString('DiscardChangesMadeHere');?>"><span class="icon cancel"></span> <?php echo GetString('Cancel');?></button>
				</td>
			</tr>
			</table>
		</div>

		<div id="catstagspicker" class="popup">
			<div id="catstagspicker-caption" class="caption"></div>
			<div id="catstagspicker-items" class="items"></div>
			<div class="buttons">
				<button onclick="CatsTagsPicker('insert');"><span class="icon ok"></span> <?php echo GetString('OK');?></button>
				<button onclick="CatsTagsPicker(null);"><span class="icon cancel"></span> <?php echo GetString('Cancel');?></button>
			</div>
		</div>

		<div id="select-template" class="popup">
			<div class="caption"><?php echo GetString('SelectTemplate');?></div>
			<div id="select-template-scrollarea" class="items">
				<div><input id="select-template-item-0" type="radio" name="select-template-item" value="" checked="checked"> <label for="select-template-item-0"><?php echo GetString('EmptyPage');?></label></div>
				<div id="select-template-items"></div>
			</div>
			<div class="buttons">
				<button onclick="SelectTemplate('ok');"><span class="icon ok"></span> <?php echo GetString('OK');?></button>
				<button onclick="SelectTemplate('cancel');"><span class="icon cancel"></span> <?php echo GetString('Cancel');?></button>
			</div>
		</div>

		<div id="filemanager" class="popup list">
			<div class="caption"><?php echo GetString('Files');?></div>
			<div class="menu">
				<span class="fieldset">
					<?php echo GetString('List');?>:
					<input id="filemanager-elemtype-article" type="radio" name="filemanager-elemtype" value="article" onchange="FileManager('open', 'article');">
					<label for="filemanager-elemtype-article"><?php echo GetString('Articles');?></label>
					<input id="filemanager-elemtype-template" type="radio" name="filemanager-elemtype" value="template" onchange="FileManager('open', 'template');">
					<label for="filemanager-elemtype-template"><?php echo GetString('Templates');?></label>
					<input id="filemanager-elemtype-textblock" type="radio" name="filemanager-elemtype" value="textblock" onchange="FileManager('open', 'textblock');">
					<label for="filemanager-elemtype-textblock"><?php echo GetString('TextBlocks');?></label>
					<input id="filemanager-elemtype-snippet" type="radio" name="filemanager-elemtype" value="snippet" onchange="FileManager('open', 'snippet');">
					<label for="filemanager-elemtype-snippet"><?php echo GetString('Snippets');?></label>
					<input id="filemanager-elemtype-widget" type="radio" name="filemanager-elemtype" value="widget" onchange="FileManager('open', 'widget');">
					<label for="filemanager-elemtype-widget"><?php echo GetString('Widgets');?></label>
					<input id="filemanager-elemtype-system" type="radio" name="filemanager-elemtype" value="system" onchange="FileManager('open', 'system');">
					<label for="filemanager-elemtype-system"><?php echo GetString('System');?></label>
					<input id="filemanager-elemtype-backup" type="radio" name="filemanager-elemtype" value="backup" onchange="FileManager('open', 'backup');">
					<label for="filemanager-elemtype-backup"><?php echo GetString('Backups');?></label>
				</span><span class="fieldset">
					<?php echo GetString('Functions');?>:
					<button id="button-filemanager-delete" onclick="FileManager('delete');" title="<?php echo GetString('MoveSelectedFileToTrash');?>"><span class="icon delete"></span> <?php echo GetString('Delete');?></button>
					<button id="button-filemanager-trash" onclick="TrashManager('open', 'article');" title="<?php echo GetString('ShowTrash');?>"><span class="icon trash"></span> <?php echo GetString('Trash');?></button>
					<button id="button-filemanager-diff" onclick="FileManager('diff');" title="<?php echo GetString('CompareFiles');?>"><span class="icon diff"></span> <?php echo GetString('Compare');?></button>
				</span><span class="fieldset" id="fieldset-filemanager-insert">
					<select id="select-filemanager-insert">
						<option value="link"><?php echo GetString('Link');?></option>
						<option value="title"><?php echo GetString('Title');?></option>
						<option value="filename"><?php echo GetString('Filename');?></option>
						<option value="title+filename"><?php echo GetString('Title');?>+<?php echo GetString('Filename');?></option>
						<option value="filename+title"><?php echo GetString('Filename');?>+<?php echo GetString('Title');?></option>
					</select>
					<button id="button-filemanager-insert" onclick="FileManager('insert');" title="<?php echo GetString('InsertIntoEditor');?>"><span class="icon link"></span> <?php echo GetString('Insert');?></button>
				</span><span class="fieldset" id="fieldset-filemanager-backup">
					<?php echo GetString('Backup');?>:
					<button id="button-filemanager-backup-create" onclick="Backup('open');"><span class="icon backup"></span> <?php echo GetString('Create');?></button>
					<button id="button-filemanager-backup-download" onclick="FileManager('download');"><span class="icon download"></span> <?php echo GetString('Download');?></button>
				</span>
			</div>
			<div id="filemanager-scrollarea" class="items">
				<table id="filemanager-table" class="sorted" cellspacing="0" cellpadding="5">
				<thead id="filemanager-head"><tr><td></td></tr></thead>
				<tbody id="filemanager-items"></tbody>
				</table>
			</div>
			<div class="buttons">
				<button id="button-filemanager-open" onclick="FileManager('load');" title="<?php echo GetString('OpenSelectedFileInEditor');?>"><span class="icon ok"></span> <?php echo GetString('Open');?></button>
				<button onclick="FileManager('cancel');"><span class="icon cancel"></span> <?php echo GetString('Cancel');?></button>
			</div>
			<span id="filemanager-infotext" class="infotext"></span>
		</div>

		<div id="backup" class="popup">
			<table cellspacing="10" cellpadding="0" border="0">
			<tr>
				<td colspan="2" align="center"><b><?php echo GetString('Backup');?></b></td>
			</tr>
			<tr>
				<td><label for="backup-filename"><?php echo GetString('Filename');?>:</label></td>
				<td><input id="backup-filename" onchange="EnableControls();" type="text" placeholder="<?php echo GetString('PleaseEnterFilename');?>..." style="width: 400px;">
			</tr>
			<tr>
				<td><?php echo GetString('Select');?>:</td>
				<td>
					<input id="check-backup-item-sel-all" type="radio" name="backup-item-sel" onchange="SelectBackupItems('all');">
					<label for="check-backup-item-sel-all"><?php echo GetString('All');?></label>
					<input id="check-backup-item-sel-none" type="radio" name="backup-item-sel" onchange="SelectBackupItems('none');">
					<label for="check-backup-item-sel-none"><?php echo GetString('None');?></label>
					<input id="check-backup-item-sel-invert" type="radio" name="backup-item-sel" onchange="SelectBackupItems('invert');">
					<label for="check-backup-item-sel-invert"><?php echo GetString('Invert');?></label>
					<input id="check-backup-item-sel-default" type="radio" name="backup-item-sel" onchange="SelectBackupItems('default');">
					<label for="check-backup-item-sel-default"><?php echo GetString('Default');?></label>
				</td>
			</tr>
			<tr>
				<td style="vertical-align: top;"><?php echo GetString('Directories');?>:</td>
				<td><div id="backup-items" style="width: 400px;"></div></td>
			</tr>
			<tr>
				<td style="vertical-align: top;"><?php echo GetString('Message');?>:</td>
				<td><div id="backup-message" style="width: 400px;"></div></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button id="button-backup-start" onclick="Backup('backup');" title="<?php echo GetString('CreateBackup');?>"><span class="icon ok"></span> <?php echo GetString('Start');?></button>
					<button id="button-upload-close" onclick="Backup('close');"><span class="icon cancel"></span> <?php echo GetString('Close');?></button>
				</td>
			</tr>
			</table>
		</div>

		<div id="mediamanager" class="popup list">
			<div class="caption"><?php echo GetString('Media');?></div>
			<div class="menu">
				<span class="fieldset">
					<?php echo GetString('Select');?>:
					<button onclick="SetCheckmark('mediamanager-item', 'all');" title="<?php echo GetString('All');?>"><span class="icon check"></span> <span class="icon check"></span> <span class="icon check"></span></button>
					<button onclick="SetCheckmark('mediamanager-item', 'none');" title="<?php echo GetString('None');?>"><span class="icon uncheck"></span> <span class="icon uncheck"></span> <span class="icon uncheck"></span></button>
					<button onclick="SetCheckmark('mediamanager-item', 'invert');" title="<?php echo GetString('Invert');?>"><span class="icon check"></span> &#x21C6; <span class="icon uncheck"></span></button>
					<button onclick="SetCheckmark('mediamanager-item', 'ranges');" title="<?php echo GetString('Ranges');?>"><span class="icon check"></span> ... <span class="icon check"></span></button>
				</span><span class="fieldset">
					<?php echo GetString('Filter');?>:
					<select id="select-filter-type" onchange="ApplyMediaFilter();" title="<?php echo GetString('MediaType');?>"></select>
					<select id="select-filter-ext" onchange="ApplyMediaFilter();" title="<?php echo GetString('FileExtension');?>"></select>
					<select id="select-filter-year" onchange="ApplyMediaFilter();" title="<?php echo GetString('FileYear');?>"></select>
					<select id="select-filter-month" onchange="ApplyMediaFilter();" title="<?php echo GetString('FileMonth');?>"></select>
				</span><span class="fieldset">
					<?php echo GetString('Functions');?>:
					<button id="button-mediamanager-upload" onclick="MediaManager('upload');" title="<?php echo GetString('UploadNewMediaFile');?>"><span class="icon add"></span> <?php echo GetString('Add');?></button>
					<button id="button-mediamanager-delete" onclick="MediaManager('delete');" title="<?php echo GetString('MoveSelectedMediaToTrash');?>"><span class="icon delete"></span> <?php echo GetString('Delete');?></button>
					<button id="button-mediamanager-trash" onclick="TrashManager('open', 'media');" title="<?php echo GetString('ShowTrash');?>"><span class="icon trash"></span> <?php echo GetString('Trash');?></button>
				</span>
			</div>
			<div id="mediamanager-scrollarea" class="items">
				<table id="mediamanager-table" class="sorted" cellspacing="0" cellpadding="5">
				<thead>
					<tr>
						<th></th>
						<th><?php echo GetString('Preview');?></th>
						<th><?php echo GetString('Filename');?></th>
						<th class="sortNumeric"><?php echo GetString('Date');?></th>
						<th class="sortNumeric"><?php echo GetString('Size');?></th>
						<th class="sortNumeric"><?php echo GetString('Uses');?></th>
					</tr>
				</thead>
				<tbody id="mediamanager-items"></tbody>
				</table>
			</div>
			<div class="buttons">
				<button id="button-mediamanager-insert" onclick="MediaManager('insert');" title="<?php echo GetString('InsertSelectedMediaIntoEditor');?>"><span class="icon ok"></span> <?php echo GetString('Insert');?></button>
				<button onclick="MediaManager('close');"><span class="icon cancel"></span> <?php echo GetString('Close');?></button>
			</div>
			<span id="mediamanager-infotext" class="infotext"></span>
		</div>

		<div id="upload" class="popup">
			<table cellspacing="10" cellpadding="0" border="0">
			<tr>
				<td colspan="2" align="center"><b><?php echo GetString('Upload');?></b></td>
			</tr>
			<tr>
				<td><label for="upload-file"><?php echo GetString('File');?>:</label></td>
				<td><input id="upload-file" onchange="OnChangeUploadFilename();" type="file" style="width: 400px;"><div id="hint-medianame-exists">🛈 <?php echo GetString('FileWithThisNameExisting');?></div></td>
			</tr>
			<tr>
				<td><?php echo GetString('Date');?>:</td>
				<td><input id="check-upload-fmtime" type="checkbox"> <label for="check-upload-fmtime"><?php echo GetString('KeepOriginalFileDate');?></label></td>
			</tr>
			<tr>
				<td colspan="2" id="upload-message"></td>
			</tr>
			<tr>
				<td colspan="2"><progress id="upload-progress" style="width: 100%;"></progress></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button id="button-upload-start" onclick="MediaUpload('upload');" title="<?php echo GetString('UploadMediaFile');?>"><span class="icon upload"></span> <?php echo GetString('Upload');?></button>
					<button id="button-upload-cancel" title="<?php echo GetString('AbortUpload');?>"><span class="icon abort"></span> <?php echo GetString('Cancel');?></button>
					<button id="button-upload-close" onclick="MediaUpload('close');"><span class="icon cancel"></span> <?php echo GetString('Close');?></button>
				</td>
			</tr>
			</table>
		</div>

		<div id="trashmanager" class="popup list">
			<div class="caption"><?php echo GetString('Trash');?></div>
			<div class="menu">
				<span class="fieldset">
					<?php echo GetString('Select');?>:
					<button onclick="SetCheckmark('trashmanager-item', 'all');" title="<?php echo GetString('All');?>"><span class="icon check"></span> <span class="icon check"></span> <span class="icon check"></span></button>
					<button onclick="SetCheckmark('trashmanager-item', 'none');" title="<?php echo GetString('None');?>"><span class="icon uncheck"></span> <span class="icon uncheck"></span> <span class="icon uncheck"></span></button>
					<button onclick="SetCheckmark('trashmanager-item', 'invert');" title="<?php echo GetString('Invert');?>"><span class="icon check"></span> &#x21C6; <span class="icon uncheck"></span></button>
					<button onclick="SetCheckmark('trashmanager-item', 'ranges');" title="<?php echo GetString('Ranges');?>"><span class="icon check"></span> ... <span class="icon check"></span></button>
				</span><span class="fieldset">
					<?php echo GetString('List');?>:
					<input id="trashmanager-elemtype-article" type="radio" name="trashmanager-elemtype" value="article" onchange="TrashManager('open', 'article');">
					<label for="trashmanager-elemtype-article"><?php echo GetString('Articles');?></label>
					<input id="trashmanager-elemtype-snapshot" type="radio" name="trashmanager-elemtype" value="snapshot" onchange="TrashManager('open', 'snapshot');">
					<label for="trashmanager-elemtype-snapshot"><?php echo GetString('Snapshots');?></label>
					<input id="trashmanager-elemtype-media" type="radio" name="trashmanager-elemtype" value="media" onchange="TrashManager('open', 'media');">
					<label for="trashmanager-elemtype-media"><?php echo GetString('Media');?></label>
				</span><span class="fieldset">
					<?php echo GetString('Functions');?>:
					<button id="button-trashmanager-restore" onclick="TrashManager('restore');" title="<?php echo GetString('RecoverSelectedItems');?>"><span class="icon restore"></span> <?php echo GetString('Recover');?></button>
					<button id="button-trashmanager-delete" onclick="TrashManager('delete');" title="<?php echo GetString('DeleteSelectedItemsPermanently');?>"><span class="icon delete"></span> <?php echo GetString('DeletePermanently');?></button>
					<button id="button-trashmanager-diff" onclick="TrashManager('diff');" title="<?php echo GetString('CompareFiles');?>"><span class="icon diff"></span> <?php echo GetString('Compare');?></button>
				</span>
			</div>
			<div id="trashmanager-scrollarea" class="items">
				<table id="trashmanager-table" class="sorted" cellspacing="0" cellpadding="5">
				<thead>
					<tr>
						<th></th>
						<th><?php echo GetString('Preview');?></th>
						<th><?php echo GetString('Filename');?></th>
						<th class="sortNumeric"><?php echo GetString('Date');?></th>
						<th class="sortNumeric"><?php echo GetString('Size');?></th>
					</tr>
				</thead>
				<tbody id="trashmanager-items"></tbody>
				</table>
			</div>
			<div class="buttons">
				<button onclick="TrashManager('close');"><span class="icon cancel"></span> <?php echo GetString('Close');?></button>
			</div>
			<span id="trashmanager-infotext" class="infotext"></span>
		</div>

		<div id="diff" class="popup list">
			<div class="caption"><?php echo GetString('ViewDifferences');?></div>
			<div class="menu">
				<span class="fieldset">
					<?php echo GetString('Skip');?>:
					<button id="button-diff-prev" title="<?php echo GetString('PreviousDifference');?>"><span class="icon left"></span></button>
					<button id="button-diff-next" title="<?php echo GetString('NextDifference');?>"><span class="icon right"></span></button>
				</span><span class="fieldset">
					<?php echo GetString('File');?> 1: <span id="diff-info-filename1"></span>
				</span><span class="fieldset">
					<?php echo GetString('File');?> 2: <span id="diff-info-filename2"></span>
				</span>
			</div>
			<div id="diff-scrollarea" class="items">
				<pre id="diff-output"></pre>
			</div>
			<div class="buttons">
				<button onclick="DiffViewer('close');"><span class="icon cancel"></span> <?php echo GetString('Close');?></button>
			</div>
			<span id="diff-infotext" class="infotext"></span>
		</div>

	</nav>
	<header>
		<p id="toolbar-article">
			<span class="toolbutton" onclick="InsertTag('p');" title="<?php echo GetString('Paragraph');?>">P</span>
			<span class="toolbutton" onclick="InsertTag('h2');" title="<?php echo GetString('Heading');?> 2">H2</span>
			<span class="toolbutton" onclick="InsertTag('h3');" title="<?php echo GetString('Heading');?> 3">H3</span>
			<span class="toolbutton" onclick="InsertTag('h4');" title="<?php echo GetString('Heading');?> 4">H4</span>
			<span class="toolbutton" onclick="InsertTag('h5');" title="<?php echo GetString('Heading');?> 5">H5</span>
			<span class="toolbutton" onclick="InsertTag('b');" title="<?php echo GetString('Bold');?>"><b>B</b></span>
			<span class="toolbutton" onclick="InsertTag('i');" title="<?php echo GetString('Italic');?>"><i>I</i></span>
			<span class="toolbutton" onclick="InsertTag('u');" title="<?php echo GetString('Underlined');?>"><u>U</u></span>
			<span class="toolbutton" onclick="InsertTag('mark');" title="<?php echo GetString('Highlighter');?>"><mark>A</mark></span>
			<span class="toolbutton" onclick="InsertTag('bgcolor');" title="<?php echo GetString('BackgroundColor');?>"><span id="label-bgcolor">A</span>
				<input type="color" value="#FFFF00" list="bgpalette" onclick="OnClickColor();" onchange="OnChangeColor('bg');" id="bgcolorpicker"></span>
				<datalist id="bgpalette">
					<option value="#FFFF00"></option>	<!-- gelb -->
					<option value="#80FF80"></option>	<!-- grün -->
					<option value="#D0F0F0"></option>	<!-- cyan -->
					<option value="#C0E0FF"></option>	<!-- blau -->
					<option value="#FFC0FF"></option>	<!-- pink -->
					<option value="#FFB1B1"></option>	<!-- rot -->
					<option value="#FFB873"></option>	<!-- orange -->
					<option value="#F3F4F7" data-var="--QuoteBgColor"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
					<option value="#CCCCCC"></option>
				</datalist>
			<span class="toolbutton" onclick="InsertTag('fgcolor');" title="<?php echo GetString('FontColor');?>"><span id="label-fgcolor">A</span>
				<input type="color" value="#0000FF" list="fgpalette" onclick="OnClickColor();" onchange="OnChangeColor('fg');" id="fgcolorpicker"></span>
				<datalist id="fgpalette">
					<option value="#7783BD" data-var="--LinkFgColor"></option>
					<option value="#A3B1FA" data-var="--AccentColor"></option>
					<option value="#ABB8C3" data-var="--NavButtonBgColor"></option>
					<option value="#0693E3"></option>	<!-- himmelblau -->
					<option value="#FF0000"></option>	<!-- rot -->
					<option value="#00C000"></option>	<!-- grün -->
					<option value="#0000FF"></option>	<!-- blau -->
					<option value="#C000C0"></option>	<!-- violett -->
					<option value="#FF8000"></option>	<!-- orange -->
					<option value="#666666"></option>
					<option value="#666666"></option>
					<option value="#666666"></option>
					<option value="#666666"></option>
					<option value="#666666"></option>
					<option value="#666666"></option>
					<option value="#666666"></option>
				</datalist>
			<span class="toolbutton tool-disabled" id="tool-remove">&times;</span>
			<select id="select-snippet" onchange="OnSelectSnippet(this);"></select>
		</p>
		<p id="toolbar-system">
			<span class="toolbutton" onclick="InsertTag('colorcode');" title="<?php echo GetString('ColorCode');?>"><span id="label-colorcode">A</span>
				<input type="color" value="#A3B1FA" list="ccpalette" onclick="OnClickColor();" onchange="OnChangeColor('cc');" id="cccolorpicker"></span>
				<datalist id="ccpalette">
					<option value="#999999" data-var="--LinkFgColor"></option>
					<option value="#999999" data-var="--AccentColor"></option>
					<option value="#999999" data-var="--ContentBgImageColor"></option>
					<option value="#999999" data-var="--NavButtonBgColor"></option>
					<option value="#999999" data-var="--TableBgColorHead"></option>
					<option value="#999999" data-var="--DefaultBgColor"></option>
					<option value="#999999" data-var="--QuoteBgColor"></option>
					<option value="#999999" data-var="--DefaultFgColor"></option>
					<option value="#999999" data-var="--HeadingFgColor"></option>
					<option value="#999999" data-var="--MenuFgColor"></option>
					<option value="#999999" data-var="--ContentFgColor"></option>
					<option value="#999999" data-var="--InputFgColor"></option>
					<option value="#999999" data-var="--MetaDataColor"></option>
					<option value="#999999" data-var="--InputBorderColor"></option>
					<option value="#999999" data-var="--ImageBorderColor"></option>
					<option value="#999999" data-var="--ContentBgColor"></option>
				</datalist>
			<span id="tool-htaccess" class="toolbutton" onclick="InsertAuthUserFileLine();" title="<?php echo GetString('InsertAuthUserFileLine');?>"><?php echo GetString('AuthUserFile');?></span>
			<span id="tool-htpasswd" class="toolbutton" onclick="EncryptSelectedPassword();" title="<?php echo GetString('EncryptSelectedPassword');?>"><?php echo GetString('EncryptPassword');?></span>
			<span id="tool-keycode" class="toolbutton" onclick="InsertKeycode();" title="<?php echo GetString('InsertKeycode');?>"><?php echo GetString('Keycode');?></span>
		</p>
	</header>
	<main>
		<textarea id="sourcecode" placeholder="<?php echo GetString('EnterHtmlCode');?>..."></textarea>
	</main>
	<footer>
		<p id="statustext"></p>
	</footer>  
	<aside>
		<iframe id="preview"></iframe>
	</aside>
</body>
</html>
