<?php
	ini_set('open_basedir', dirname(__ROOT__) . DIRECTORY_SEPARATOR);
	
	class fs
	{
		protected $base = null;
		
		protected function real($path)
		{
			$temp = realpath($path);
			if (!$temp) {
				throw new Exception('Path does not exist: ' . $path);
			}
			if ($this->base && strlen($this->base)) {
				if (strpos($temp, $this->base) !== 0) {
					throw new Exception('Path is not inside base (' . $this->base . '): ' . $temp);
				}
			}
			return $temp;
		}
		
		protected function path($id)
		{
			$id = str_replace('/', DIRECTORY_SEPARATOR, $id);
			$id = trim($id, DIRECTORY_SEPARATOR);
			$id = $this->real($this->base . DIRECTORY_SEPARATOR . $id);
			return $id;
		}
		
		protected function id($path)
		{
			$path = $this->real($path);
			$path = substr($path, strlen($this->base));
			$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
			$path = trim($path, '/');
			return strlen($path) ? $path : '/';
		}
		
		public function __construct($base)
		{
			$this->base = $this->real($base);
			if (!$this->base) {
				throw new Exception('Base directory does not exist');
			}
		}
		
		public function lst($id, $with_root = false)
		{
			$dir = $this->path($id);
			$lst = @scandir($dir);
			if (!$lst) {
				throw new Exception('Could not list path: ' . $dir);
			}
			$res = array();
			foreach ($lst as $item) {
				if ($item == '.' || $item == '..' || $item === null) {
					continue;
				}
				$tmp = preg_match('([^ a-zа-я-_0-9.]+)ui', $item);
				if ($tmp === false || $tmp === 1) {
					continue;
				}
				if (is_dir($dir . DIRECTORY_SEPARATOR . $item)) {
					$res[] = array('text' => $item, 'children' => true, 'id' => $this->id($dir . DIRECTORY_SEPARATOR . $item), 'icon' => 'folder');
				} else {
					if ($item == '.DS_Store')
						continue;
					$res[] = array('text' => $item, 'children' => false, 'id' => $this->id($dir . DIRECTORY_SEPARATOR . $item), 'type' => 'file', 'icon' => 'file file-' . substr($item, strrpos($item, '.') + 1));
				}
			}
			if ($with_root && $this->id($dir) === '/') {
				$res = array(array('text' => basename($this->base), 'children' => $res, 'id' => '/', 'icon' => 'folder', 'state' => array('opened' => true, 'disabled' => true)));
			}
			return $res;
		}
		
		public function save($id, $content)
		{
			$dir = $this->path($id);
			if (is_file($dir)) {
				file_put_contents($dir, $content);
				return true;
			}
			return false;
		}
		
		public function data($id)
		{
			if (strpos($id, ":")) {
				$id = array_map(array($this, 'id'), explode(':', $id));
				return array('type' => 'multiple', 'content' => 'Multiple selected: ' . implode(' ', $id));
			}
			$dir = $this->path($id);
			if (is_dir($dir)) {
				return array('type' => 'folder', 'content' => $id);
			}
			if (is_file($dir)) {
				$ext = strpos($dir, '.') !== FALSE ? substr($dir, strrpos($dir, '.') + 1) : '';
				$dat = array('type' => $ext, 'content' => '');
				switch ($ext) {
					case 'txt':
					case 'text':
					case 'md':
					case 'js':
					case 'json':
					case 'css':
					case 'html':
					case 'htm':
					case 'xml':
					case 'c':
					case 'cpp':
					case 'h':
					case 'sql':
					case 'log':
					case 'py':
					case 'rb':
					case 'htaccess':
					case 'php':
						$dat['content'] = file_get_contents($dir);
						break;
					case 'jpg':
					case 'jpeg':
					case 'gif':
					case 'png':
					case 'bmp':
						$dat['content'] = 'data:' . finfo_file(finfo_open(FILEINFO_MIME_TYPE), $dir) . ';base64,' . base64_encode(file_get_contents($dir));
						break;
					default:
						$dat['content'] = 'File not recognized: ' . $this->id($dir);
						break;
				}
				return $dat;
			}
			throw new Exception('Not a valid selection: ' . $dir);
		}
		
		public function create($id, $name, $mkdir = false)
		{
			$dir = $this->path($id);
			if (preg_match('([^ a-zа-я-_0-9.]+)ui', $name) || !strlen($name)) {
				throw new Exception('Invalid name: ' . $name);
			}
			if ($mkdir) {
				mkdir($dir . DIRECTORY_SEPARATOR . $name);
			} else {
				file_put_contents($dir . DIRECTORY_SEPARATOR . $name, '');
			}
			return array('id' => $this->id($dir . DIRECTORY_SEPARATOR . $name));
		}
		
		public function rename($id, $name)
		{
			$dir = $this->path($id);
			if ($dir === $this->base) {
				throw new Exception('Cannot rename root');
			}
			if (preg_match('([^ a-zа-я-_0-9.]+)ui', $name) || !strlen($name)) {
				throw new Exception('Invalid name: ' . $name);
			}
			$new = explode(DIRECTORY_SEPARATOR, $dir);
			array_pop($new);
			array_push($new, $name);
			$new = implode(DIRECTORY_SEPARATOR, $new);
			if ($dir !== $new) {
				if (is_file($new) || is_dir($new)) {
					throw new Exception('Path already exists: ' . $new);
				}
				rename($dir, $new);
			}
			return array('id' => $this->id($new));
		}
		
		public function remove($id)
		{
			$dir = $this->path($id);
			if ($dir === $this->base) {
				throw new Exception('Cannot remove root');
			}
			if (is_dir($dir)) {
				foreach (array_diff(scandir($dir), array(".", "..")) as $f) {
					$this->remove($this->id($dir . DIRECTORY_SEPARATOR . $f));
				}
				rmdir($dir);
			}
			if (is_file($dir)) {
				unlink($dir);
			}
			return array('status' => 'OK');
		}
		
		public function move($id, $par)
		{
			$dir = $this->path($id);
			$par = $this->path($par);
			$new = explode(DIRECTORY_SEPARATOR, $dir);
			$new = array_pop($new);
			$new = $par . DIRECTORY_SEPARATOR . $new;
			rename($dir, $new);
			return array('id' => $this->id($new));
		}
	}
	
	if (get("operation")) {
		$fs = new fs(__ROOT__ . DIRECTORY_SEPARATOR . 'apps' . DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR. 'views' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . themeName() . DIRECTORY_SEPARATOR);
		try {
			$rslt = null;
			switch (get("operation")) {
				case 'get_node':
					$node = isset($_GET['id']) && $_GET['id'] !== '#' ? $_GET['id'] : '/';
					$rslt = $fs->lst($node, (isset($_GET['id']) && $_GET['id'] === '#'));
					break;
				case "get_content":
					$node = isset($_GET['id']) && $_GET['id'] !== '#' ? $_GET['id'] : '/';
					$rslt = $fs->data($node);
					break;
				case "save_content":
					$node = isset($_POST['id']) && $_POST['id'] !== '#' ? $_POST['id'] : '/';
					$rslt = $fs->save($node, $_POST["content"]);
					break;
				case 'create_node':
					$node = isset($_POST['id']) && $_POST['id'] !== '#' ? $_POST['id'] : '/';
					$rslt = $fs->create($node, isset($_POST['text']) ? $_POST['text'] : '', (!isset($_POST['type']) || $_POST['type'] !== 'file'));
					break;
				case 'rename_node':
					$node = isset($_POST['id']) && $_POST['id'] !== '#' ? $_POST['id'] : '/';
					$rslt = $fs->rename($node, isset($_POST['text']) ? $_POST['text'] : '');
					break;
				case 'delete_node':
					$node = isset($_POST['id']) && $_POST['id'] !== '#' ? $_POST['id'] : '/';
					$rslt = $fs->remove($node);
					break;
				case 'move_node':
					$node = isset($_POST['id']) && $_POST['id'] !== '#' ? $_POST['id'] : '/';
					$parn = isset($_POST['parent']) && $_POST['parent'] !== '#' ? $_POST['parent'] : '/';
					$rslt = $fs->move($node, $parn);
					break;
				default:
					throw new Exception('Unsupported operation: ' . $_GET['operation']);
					break;
			}
			header('Content-Type: application/json; charset=utf-8');
			echo json_encode($rslt);
		} catch (Exception $e) {
			header($_SERVER["SERVER_PROTOCOL"] . ' 500 Server Error');
			header('Status:  500 Server Error');
			echo $e->getMessage();
		}
		die();
	}
?>
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	<title>LeaderOS Theme Editor</title>
	<meta name="viewport" content="width=device-width"/>
	<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?cache=<?php echo time() ?>">
	<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css"/>
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css">
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/theme/material-darker.min.css">
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/dialog/dialog.min.css">
	<link rel="preconnect" href="https://fonts.googleapis.com">
	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
	<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
	<script>
		var csrf = '<?php echo csrf_token(); ?>';
	</script>
	<style>
		:root {
			--background-color: #111111;
			--header-background-color: #111111;
			--header-color: #fff;
			--header-border-color: #303030;
			--sidebar-right-border: #303030;
			--file-name-color: #e5e7ebcc;
			--file-name-active-color: #fff;
			--file-name-background: #18191D;
		}
		
		html, body {
			background: var(--background-color);
			font-size: 12px;
			font-family: 'Inter', sans-serif;
			color: #fff;
			margin: 0;
			padding: 0;
		}
		
		#container {
			min-width: 320px;
			margin: 0px auto 0 auto;
			background: var(--background-color);
			border-radius: 0px;
			padding: 0px;
			overflow: hidden;
		}
		
		#sidebar {
			position: relative;
			float: left;
			min-width: 319px;
			border-right: 1px solid var(--sidebar-right-border);
			overflow-y: auto;
			overflow-x: hidden;
			padding: 0px 0;
		}
		
		#data {
			margin-left: 320px;
		}
		
		#data textarea {
			margin: 0;
			padding: 0;
			height: 100%;
			width: 100%;
			border: 0;
			background: #111111;
			display: block;
			line-height: 18px;
			resize: none;
		}
		
		#data, #code {
			font: normal normal normal 13px/22px 'Inter', sans-serif !important;
		}
		.jstree-default-small .jstree-node {
			background-image: none !important;
		}
		
		#tree .file-pdf {
			background-position: -32px 0
		}
		
		#tree .file-as {
			background-position: -36px 0
		}
		
		#tree .file-c {
			background-position: -72px -0px
		}
		
		#tree .file-iso {
			background-position: -108px -0px
		}
		
		#tree .file-htm, #tree .file-html, #tree .file-xml, #tree .file-xsl {
			background-position: -126px -0px
		}
		
		#tree .file-cf {
			background-position: -162px -0px
		}
		
		#tree .file-cpp {
			background-position: -216px -0px
		}
		
		#tree .file-cs {
			background-position: -236px -0px
		}
		
		#tree .file-sql {
			background-position: -272px -0px
		}
		
		#tree .file-xls, #tree .file-xlsx {
			background-position: -362px -0px
		}
		
		#tree .file-h {
			background-position: -488px -0px
		}
		
		#tree .file-crt, #tree .file-pem, #tree .file-cer {
			background-position: -452px -18px
		}
		
		#tree .file-php {
			background-position: -108px -18px
		}
		
		#tree .file-jpg, #tree .file-jpeg, #tree .file-png, #tree .file-gif, #tree .file-bmp {
			background-position: -126px -18px
		}
		
		#tree .file-ppt, #tree .file-pptx {
			background-position: -144px -18px
		}
		
		#tree .file-rb {
			background-position: -180px -18px
		}
		
		#tree .file-text, #tree .file-txt, #tree .file-md, #tree .file-log, #tree .file-htaccess {
			background-position: -254px -18px
		}
		
		#tree .file-doc, #tree .file-docx {
			background-position: -362px -18px
		}
		
		#tree .file-zip, #tree .file-gz, #tree .file-tar, #tree .file-rar {
			background-position: -416px -18px
		}
		
		#tree .file-js {
			background-position: -434px -18px
		}
		
		#tree .file-css {
			background-position: -144px -0px
		}
		
		#tree .file-fla {
			background-position: -398px -0px
		}
		
		.cm-s-material-darker.CodeMirror {
			height: 100% !important;
		}
		
		/* Loading */
		.saving {
			display: flex;
			align-items: center;
		}
		.lds-ring {
			display: inline-block;
			position: relative;
			width: 14px;
			height: 14px;
		}
		
		.lds-ring div {
			box-sizing: border-box;
			display: block;
			position: absolute;
			width: 14px;
			height: 14px;
			margin: 1px;
			border: 2px solid #fff;
			border-radius: 50%;
			animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
			border-color: #fff transparent transparent transparent;
		}
		
		.lds-ring div:nth-child(1) {
			animation-delay: -0.45s;
		}
		
		.lds-ring div:nth-child(2) {
			animation-delay: -0.3s;
		}
		
		.lds-ring div:nth-child(3) {
			animation-delay: -0.15s;
		}
		
		@keyframes lds-ring {
			0% {
				transform: rotate(0deg);
			}
			100% {
				transform: rotate(360deg);
			}
		}
		
		.jstree-default-small .jstree-node {
			margin-left: 12px !important;
		}
		
		.jstree-anchor {
			font-family: 'Inter', sans-serif;
			width: calc(100% - 24px) !important;
			padding: 8px 12px !important;
			box-shadow: none !important;
			color: var(--file-name-color) !important;
		}
		
		.jstree-default > .jstree-striped {
			background: linear-gradient(
					to bottom,
					#1e293b,
					#1e293b 50%,
					#0f172a 50%,
					#0f172a
			);
			background-size: auto 48px;
		}
		
		.jstree-default-small .jstree-node {
			margin-top: 2px;
			margin-bottom: 2px;
			line-height: 24px;
			min-height: 24px;
		}
		
		.jstree-default .jstree-clicked,
		.jstree-default .jstree-hovered {
			font-weight: 500 !important;
			color: var(--file-name-active-color) !important;
			background: var(--file-name-background);
			box-shadow: none !important;
			border-radius: 8px;
		}
		
		#tree {
			position: relative;
			margin: 10px 16px 10px 0;
		}
		
		.header {
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			display: flex;
			justify-content: space-between;
			align-items: center;
			z-index: 999;
			padding: 10px 20px;
			border-bottom: 1px solid var(--header-border-color);
			background-color: var(--header-background-color);
			font-weight: 500;
			font-size: 14px !important;
		}
		
		.wrapper {
			margin-top: 55px;
		}
		
		.btn-save {
			position: relative;
			display: flex;
			align-items: center;
			justify-content: center;
			padding: 10px 15px;
			border-radius: 8px;
			background-color: rgb(59 130 246);
			color: #fff;
			border: none;
			font-family: 'Inter', sans-serif;
			font-weight: 500;
			font-size: 12px;
			cursor: pointer;
			transition: background-color .3s;
		}
		
		.btn-save:hover {
			background-color: rgb(59 130 246 / 80%);
		}
		
		.header .header-title {
			display: flex;
			align-items: center;
			gap: 8px;
			transition: color .3s;
			color: var(--header-color) !important;
			text-decoration: none;
		}
		
		.vakata-context, .vakata-context ul {
			background-color: #18191D !important;
			color: rgb(209 213 219) !important;
			box-shadow: none !important;
			border-radius: 6px !important;
			padding: 0 !important;
			min-width: 120px;
			border-color: #4b556333 !important;
		}
		
		.vakata-context ul {
			margin-left: 4px !important;
		}
		
		.vakata-context li {
			border: none !important;
		}
		.vakata-context li > a {
			padding: 3px 12px !important;
			font-size: 10px !important;
			color: rgb(209 213 219) !important;
			text-shadow: none !important;
			border-bottom: 1px solid #4b556333;
		}
		.vakata-context li:first-child > a {
			border-radius: 6px 6px 0 0 !important;
		}
		.vakata-context li:last-child > a {
			border-radius: 0 0 6px 6px !important;
			border-bottom: 0 !important;
		}
		.vakata-context li.vakata-context-hover > a,
		.vakata-context li>a:hover {
			background-color: rgb(59 130 246);
			box-shadow: none !important;
		}
		.vakata-context li>a.vakata-context-parent {
			background-size: 12px;
			background-image: url('dashboard.data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABxSURBVFiF7ZMxCoAwEATF7yhaiB9KEMT/d2LGJkWIFlrEg7gDV+Zm4EjTCCFeAMzAZCk/4iwWAVOUAwSrCJdFbIpQhCJihE8iDmB8+rYt1BQK7b1yc4JV8url/rfyPvvr7jN5ErCbyJOIDhhM5EJUywliDULIRPT49QAAAABJRU5ErkJggg==') !important;
			background-position: right 10px center;
		}
		.vakata-context li>a>i, .vakata-context-separator, .vakata-contextmenu-sep {
			display: none !important;
		}
		
		#tree .folder {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/folder.png'); ?>');
			background-size: cover;
			margin-right: 6px;
		}
		#tree .file {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/file.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		#theme\.json_anchor .file {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/theme-json.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		
		#tree .file-css {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/css.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		#tree .file-eot, #tree .file-ttf, #tree .file-woff, #tree .file-woff2, #tree .file-otf {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/font.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		#tree .file-php {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/php.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		#tree .file-js {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/js.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		#tree .file-jpg, #tree .file-jpeg, #tree .file-png, #tree .file-gif, #tree .file-bmp, #tree .file-svg {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/image.png'); ?>') !important;
			background-size: cover !important;
			margin-right: 6px;
		}
		.jstree-default-small>.jstree-container-ul .jstree-loading>.jstree-ocl {
			background: url('/apps/dashboard/public/assets/img/theme-editor/loading.svg') !important;
			background-size: cover !important;
			opacity: 0.6;
		}
		.jstree-node {
			position: relative;
		}
		.jstree-icon.jstree-ocl {
			position: absolute;
			top: 8px;
			right: 10px;
		}
		.jstree-default-small .jstree-open>.jstree-ocl {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/right-arrow.png'); ?>') !important;
			background-size: cover !important;
			transform: rotate(90deg);
			opacity: 0.6;
		}
		.jstree-default-small .jstree-closed>.jstree-ocl {
			background: url('dashboard.<?php echo $this->asset('/img/theme-editor/right-arrow.png'); ?>') !important;
			background-size: cover !important;
			opacity: 0.6;
		}
		.breadcrumb-path {
			display: none;
			padding: 10px 14px;
			font-weight: 500;
			font-size: 12px !important;
			border-radius: 10px;
			color: rgba(255, 255, 255, 0.8);
			background-color: rgba(255, 255, 255, 0.05);
		}
		.toggle-sidebar-icon {
			display: none;
		}
		.toggle-sidebar-icon-bar {
			width: 18px;
			height: 1.5px;
			background-color: rgba(255, 255, 255, 1);
			margin: 4px 0;
		}
		@media (max-width: 768px) {
			.toggle-sidebar-icon {
				display: block !important;
				cursor: pointer;
			}
			.theme-editor-icon {
				display: none !important;
			}
			.breadcrumb-path-wrapper {
				display: none !important;
			}
		}
		.CodeMirror-dialog {
			background-color: #191919 !important;
		}
		.CodeMirror-dialog-top {
			border-color: var(--sidebar-right-border);
		}
	</style>
</head>
<body id="container">
<div class="header">
	<div style="display: flex; align-items: center; gap: 16px;">
		<div class="header-title">
			<div class="toggle-sidebar-icon" data-open="true">
				<div class="toggle-sidebar-icon-bar"></div>
				<div class="toggle-sidebar-icon-bar"></div>
				<div class="toggle-sidebar-icon-bar"></div>
			</div>
			<div class="theme-editor-icon" style="display: flex; justify-content: center; align-items: center; background-color: rgb(219 234 254); width: 2.25rem; height: 2.25rem; border-radius: .75rem;">
				<img style="width: 1.5rem; height: 1.5rem;" src="<?php echo $this->asset('/img/leaderos-icon.png'); ?>" alt="LeaderOS Logo">
			</div>
			<span><?php e__('Theme Editor') ?></span>
		</div>
		<div class="breadcrumb-path-wrapper">
			<div class="breadcrumb-path"></div>
		</div>
	</div>
	<div>
		<button class="btn-save">
			<span class="default-text"><?php e__('Save Changes') ?></span>
			<div class="saving" style="display: none;">
				<span class="loading" style="position: absolute;">
					<div class="lds-ring">
						<div></div>
						<div></div>
						<div></div>
						<div></div>
					</div>
				</span>
				<span style="margin-left: 22px;"><?php e__('Saving...') ?></span>
			</div>
		</button>
	</div>
</div>
<div class="wrapper">
	<div id="sidebar">
		<div id="tree"></div>
	</div>
	<div id="data">
		<div class="content code"><textarea id="code"></textarea></div>
		<div class="content folder" style="display:none;"></div>
		<div class="content image" style="display:none; position:relative;"><img src="" alt=""
		                                                                         style="display:block; position:absolute; left:50%; top:50%; padding:0; max-height:90%; max-width:90%;"/>
		</div>
		<div class="content default" style="text-align:center;">Select a file from the tree.</div>
	</div>
</div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/jstree.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/edit/matchbrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/css/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/javascript/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/htmlmixed/htmlmixed.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/clike/clike.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/xml/xml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/php/php.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/dialog/dialog.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/search/search.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/search/searchcursor.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/addon/search/jump-to-line.min.js"></script>
<script>
	$(function () {
		$(".toggle-sidebar-icon").on("click", function () {
			var isOpen = $(this).data("open");
			if (isOpen == true) {
				$("#sidebar").css("display", "none");
				$("#data").css("margin-left", "0");
				$(this).data("open", false);
			} else {
				$("#sidebar").css("display", "block");
				$("#data").css("margin-left", "320px");
				$(this).data("open", true);
			}
		});
		$(document).bind("keyup keydown", function (e) {
			if ((e.ctrlKey && e.which == 83) || (e.metaKey && e.which == 83)) {
				e.preventDefault();
				saveFile();
			}
		});
		
		$(".btn-save").on("click", function (e) {
			e.preventDefault();
			saveFile();
		})
		
		function saveFile() {
			var btn = $(".btn-save");
			btn.attr("disabled", "disabled");
			btn.css("pointer-events", "none");
			btn.css("opacity", "0.5");
			
			$(".btn-save .saving").css("display", "flex");
			$(".btn-save .default-text").css("display", "none");
			var data = {
				csrf_token: csrf,
				id: $("#tree").jstree(true).get_selected(true)[0].id,
				content: $("#code").data('CodeMirrorInstance').doc.getValue()
			};
			$.post("?operation=save_content", data, function (response) {
				$(".saving").css("display", "none");
				$(".btn-save .default-text").css("display", "block");
				$(".btn-save .default-text").text("<?php e__("Saved!") ?>");
				btn.attr("disabled", null);
				btn.css("pointer-events", "auto");
				btn.css("opacity", "1");
				setTimeout(function () {
					$(".btn-save .default-text").text("<?php e__("Save Changes") ?>");
				}, 1000);
			});
		}
		
		$(window).resize(function () {
			var h = Math.max($(window).height() - 55, 420);
			$('#container, #data, #sidebar, #data .content').height(h).filter('.default').css('lineHeight', h + 'px');
		}).resize();
		
		$('#tree')
			.jstree({
				'core': {
					'data': {
						'url': '?operation=get_node',
						'data': function (node) {
							return {
								'id': node.id
							};
						}
					},
					'check_callback': function (o, n, p, i, m) {
						if (m && m.dnd && m.pos !== 'i') {
							return false;
						}
						if (o === "move_node" || o === "copy_node") {
							if (this.get_node(n).parent === this.get_node(p).id) {
								return false;
							}
						}
						return true;
					},
					'force_text': true,
					'themes': {
						'responsive': false,
						'variant': 'small',
						'stripes': false
					}
				},
				'sort': function (a, b) {
					return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : (this.get_type(a) >= this.get_type(b) ? 1 : -1);
				},
				'contextmenu': {
					'items': function (node) {
						var tmp = $.jstree.defaults.contextmenu.items();
						delete tmp.create.action;
						delete tmp.ccp;
						tmp.create.label = "New";
						tmp.create.submenu = {
							"create_folder": {
								"separator_after": true,
								"label": "Folder",
								"action": function (data) {
									var inst = $.jstree.reference(data.reference);
									var obj = inst.get_node(data.reference);
									inst.create_node(obj, {type: "default"}, "last", function (new_node) {
										setTimeout(function () {
											inst.edit(new_node);
										}, 0);
									});
								}
							},
							"create_file": {
								"label": "File",
								"action": function (data) {
									var inst = $.jstree.reference(data.reference);
									var obj = inst.get_node(data.reference);
									inst.create_node(obj, {type: "file"}, "last", function (new_node) {
										setTimeout(function () {
											inst.edit(new_node);
										}, 0);
									});
								}
							}
						};
						if (this.get_type(node) === "file") {
							delete tmp.create;
						}
						return tmp;
					}
				},
				'types': {
					'default': {'icon': 'folder'},
					'file': {'valid_children': [], 'icon': 'file'}
				},
				'unique': {
					'duplicate': function (name, counter) {
						return name + ' ' + counter;
					}
				},
				'plugins': ['state', 'dnd', 'sort', 'types', 'contextmenu', 'unique']
			})
			.on('delete_node.jstree', function (e, data) {
				$.post('?operation=delete_node', {
					'csrf_token': csrf,
					'id': data.node.id
				})
					.fail(function () {
						data.instance.refresh();
					});
			})
			.on('create_node.jstree', function (e, data) {
				$.post('?operation=create_node', {
					'csrf_token': csrf,
					'type': data.node.type,
					'id': data.node.parent,
					'text': data.node.text
				})
					.done(function (d) {
						data.instance.set_id(data.node, d.id);
					})
					.fail(function () {
						data.instance.refresh();
					});
			})
			.on('rename_node.jstree', function (e, data) {
				$.post('?operation=rename_node', {
					'csrf_token': csrf,
					'id': data.node.id,
					'text': data.text
				})
					.done(function (d) {
						data.instance.set_id(data.node, d.id);
					})
					.fail(function () {
						data.instance.refresh();
					});
			})
			.on('move_node.jstree', function (e, data) {
				$.post('?operation=move_node', {
					'csrf_token': csrf,
					'id': data.node.id,
					'parent': data.parent
				})
					.done(function (d) {
						//data.instance.load_node(data.parent);
						data.instance.refresh();
					})
					.fail(function () {
						data.instance.refresh();
					});
			})
			.on('changed.jstree', function (e, data) {
				if (data && data.selected && data.selected.length) {
					$.get('?operation=get_content&id=' + data.selected.join(':'), function (d) {
						if (d && typeof d.type !== 'undefined') {
							$(".breadcrumb-path").css("display", "block").text(data.selected.join(':'));
							$('#data .content').hide();
							switch (d.type) {
								case 'text':
								case 'txt':
								case 'md':
								case 'htaccess':
								case 'log':
								case 'sql':
								case 'php':
									initCodeEditor("application/x-httpd-php", d.content);
									break;
								case 'js':
								case 'json':
									initCodeEditor("application/ld+json", d.content);
									break;
								case 'css':
									initCodeEditor("css", d.content);
									break;
								case 'html':
									initCodeEditor("html", d.content);
									break;
								case 'png':
								case 'jpg':
								case 'jpeg':
								case 'bmp':
								case 'gif':
									$('#data .image img').one('load', function () {
										$(this).css({
											'marginTop': '-' + $(this).height() / 2 + 'px',
											'marginLeft': '-' + $(this).width() / 2 + 'px'
										});
									}).attr('src', d.content);
									$('#data .image').show();
									break;
								default:
									$('#data .default').html(d.content).show();
									break;
							}
						}
					});
				} else {
					$('#data .content').hide();
					$('#data .default').html('Select a file from the tree.').show();
				}
			});
	});
	
	function initCodeEditor(language, data) {
		$('#data .code').show();
		$('#code').val(data);
		var editor;
		if ($('#code').data('CodeMirrorInstance')) {
			editor = $('#code').data('CodeMirrorInstance');
			editor.setOption("mode", language);
			editor.setValue(data);
		} else {
			editor = CodeMirror.fromTextArea(document.getElementById("code"), {
				lineNumbers: true,
				matchBrackets: true,
				mode: language,
				theme: "material-darker",
				indentUnit: 2,
				indentWithTabs: true,
				enterMode: "keep",
				tabMode: "shift",
			});
			
			editor.focus();
		}
		$('#code').data('CodeMirrorInstance', editor);
	}
</script>
</body>
</html>