{% extends ../base.html %}

{% block meta %}
{% end %}

{% block title %}Crafty Controller - {{ translate('serverDetails', 'serverDetails', data['lang']) }}{% end %}

{% block content %}

<div class="content-wrapper">

  <!-- Page Title Header Starts-->
  <div class="row page-title-header">
    <div class="col-12">
      <div class="page-header">
        <h4 class="page-title">
          {{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
          data['server_stats']['server_id']['server_name'] }}
          <br />
          <small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
        </h4>
      </div>
    </div>

  </div>
  <!-- Page Title Header Ends-->

  {% include "parts/details_stats.html" %}

  <div class="row">

    <div class="col-sm-12 grid-margin">
      <div class="card">
        <div class="card-body  pt-0">
          <span class="d-none d-sm-block">
            {% include "parts/server_controls_list.html %}
          </span>
          <span class="d-block d-sm-none">
            {% include "parts/m_server_controls_list.html %}
          </span>

          <div class="row">
            <div class="col-md-6 col-sm-12">
              <noscript>
                {{ translate('serverFiles', 'noscript', data['lang']) }}
              </noscript>
              <div id="files-tree-nav" class="overlay" style="background-color: #9f9daf !important;">

                <!-- Button to close the overlay navigation -->

                <!-- Overlay content -->
                <div id="files-tree-nav-content" class="overlay-content" style="background-color: #9f9daf;">
                  <h4 id="context-title" style="color:#4b00ff; text-align: center; padding: 3px;">
                  </h4>
                  <p style="width: 90%; border-bottom: 2px solid black; margin:0 auto;"></p>
                  <a onclick="createFileE(event)" href="javascript:void(0)" id="createFile" href="#">{{
                    translate('serverFiles', 'createFile', data['lang']) }}</a>
                  <a onclick="createDirE(event)" href="javascript:void(0)" id="createDir" href="#">{{
                    translate('serverFiles', 'createDir', data['lang']) }}</a>
                  <a onclick="renameItemE(event)" href="javascript:void(0)" id="renameItem" href="#">{{
                    translate('serverFiles', 'rename', data['lang']) }}</a>
                  <a onclick="uploadFilesE(event)" href="javascript:void(0)" id="upload" href="#">{{
                    translate('serverFiles', 'upload', data['lang']) }}</a>
                  <a onclick="unzipFilesE(event)" href="javascript:void(0)" id="unzip" href="#">{{
                    translate('serverFiles', 'unzip', data['lang']) }}</a>
                  <a onclick="downloadFileE(event)" href="javascript:void(0)" id="downloadFile" href="#">{{
                    translate('serverFiles', 'download', data['lang']) }}</a>
                  <a onclick="deleteFileE(event)" href="javascript:void(0)" id="deleteFile" href="#"
                    style="color: red">{{ translate('serverFiles', 'delete', data['lang']) }}</a>
                  <a onclick="deleteDirE(event)" href="javascript:void(0)" id="deleteDir" href="#" style="color: red">{{
                    translate('serverFiles', 'delete', data['lang']) }}</a>
                  <a href="javascript:void(0)" class="closebtn" style="color: #8862e0;"
                    onclick="document.getElementById('files-tree-nav').style.display = 'none';">{{
                    translate('serverFiles', 'close', data['lang']) }}</a>
                </div>

              </div>
              <style>
                /* The Overlay (background) */
                .overlay {
                  display: none;
                  flex-direction: column;
                  background-color: #9f9daf;
                  border-radius: 10px;
                  box-shadow: 0 10px 20px rgb(64 64 64 / 5%);
                  padding: 10px 0;
                  z-index: 10000;
                  overflow: scroll;

                }

                .overlay::-webkit-scrollbar {
                  display: none;
                }

                /* Hide scrollbar for IE, Edge and Firefox */
                .overlay {
                  -ms-overflow-style: none;
                  /* IE and Edge */
                  scrollbar-width: none;
                  /* Firefox */
                }

                /* Position the content inside the overlay */
                .overlay-content {
                  display: flex;
                  flex-direction: column;
                  background-color: #9f9daf;
                  border-radius: 10px;
                  box-shadow: 0 10px 20px rgb(64 64 64 / 5%);
                  padding: 10px 0;
                }

                /* The navigation links inside the overlay */
                .overlay a {
                  font: inherit;
                  border: 0;
                  padding: 10px 30px 10px 15px;
                  width: 100%;
                  display: flex;
                  align-items: center;
                  position: relative;
                  text-decoration: unset;
                  color: #000;
                  font-weight: 500;
                  transition: 0.5s linear;
                  -webkit-transition: 0.5s linear;
                  -moz-transition: 0.5s linear;
                  -ms-transition: 0.5s linear;
                  -o-transition: 0.5s linear;
                }

                /* When you mouse over the navigation links, change their color */
                .overlay a:hover,
                .overlay a:focus {
                  background: grey;
                  color: #4b00ff;
                }

                /* Position the close button (top right corner) */
                .overlay .closebtn .closebtn:hover {
                  background-color: red;
                  color: red;
                  z-index: 10000;
                }

                /* When the height of the screen is less than 450 pixels, change the font-size of the links and position the close button again, so they don't overlap */
                @media screen and (max-height: 450px) {
                  .overlay a {
                    font-size: 20px
                  }

                  .overlay .closebtn {
                    font-size: 40px;
                    top: 15px;
                    right: 35px;
                  }
                }
              </style>
              <ul class="tree-view">
                <li>
                  <div id="root_dir" class="tree-ctx-item" data-path="{{ data['server_stats']['server_id']['path'] }}">
                    <span id="{{ data['server_stats']['server_id']['path'] }}span"
                      class="files-tree-title tree-caret-down root-dir"
                      data-path="{{ data['server_stats']['server_id']['path'] }}" onclick="getToggleMain(event)">
                      <i class="far fa-folder"></i>
                      <i class="far fa-folder-open"></i>
                      {{ translate('serverFiles', 'files', data['lang']) }}
                    </span>
                  </div>
                  <ul class="tree-nested d-block" id="files-tree">
                    <li><i class="fa fa-spin fa-spinner"></i>{{ translate('serverFiles', 'loadingRecords', data['lang'])
                      }}</li>

                  </ul>
                </li>
              </ul>
            </div>
            <style>
              /* Remove default bullets */
              .tree-view,
              .tree-nested {
                list-style-type: none;
                margin: 0;
                padding: 0;
                margin-left: 10px;
              }

              /* Style the items */
              .tree-item,
              .files-tree-title {
                cursor: pointer;
                user-select: none;
                /* Prevent text selection */
              }

              /* Create the caret/arrow with a unicode, and style it */
              .tree-caret .fa-folder {
                display: inline-block;
              }

              .tree-caret .fa-folder-open {
                display: none;
              }

              /* Rotate the caret/arrow icon when clicked on (using JavaScript) */
              .tree-caret-down .fa-folder {
                display: none;
              }

              .tree-caret-down .fa-folder-open {
                display: inline-block;
              }

              /* Hide the nested list */
              .tree-nested {
                display: none;
              }

              html,
              body,
              body>.container-scroller {
                overflow: initial;
              }

              .editorManager {
                top: 63px;
                position: sticky;
              }
            </style>
            <div id="editor_container" class="col-md-6 col-sm-12">
              <br>
              <br>
              <div class="editorManager">
                <h2 id="fileError"></h2>
                <div id="editorParent">
                  {{ translate('serverFiles', 'editingFile', data['lang']) }} <span id="editingFile"></span>
                  <div id="editor" onresize="editor.resize()" style="resize: both;width: 100%;">file_contents</div>
                  <br />
                </div>
                {{ translate('serverFiles', 'keybindings', data['lang']) }}:
                <div class="btn-group" role="group">
                  <button onclick="setKeyboard(event.target)" class="btn btn-primary" data-handler-name="null">{{
                    translate('serverFiles', 'default', data['lang']) }}</button>
                  <button onclick="setKeyboard(event.target)" class="btn btn-secondary"
                    data-handler-name="ace/keyboard/vim">Vim</button>
                  <button onclick="setKeyboard(event.target)" class="btn btn-secondary"
                    data-handler-name="ace/keyboard/emacs">Emacs</button>
                  <button onclick="setKeyboard(event.target)" class="btn btn-secondary"
                    data-handler-name="ace/keyboard/sublime">Sublime</button>
                  <span class="d-none d-md-block ">&nbsp;&nbsp;&nbsp;<button class="btn btn-info" id="screen-size">{{
                      translate('serverFiles',
                      'size', data['lang']) }}</button></span>
                </div>
                <h3 id="file_warn"></h3>
                <button class="btn btn-success" onclick="save()"><i class="fas fa-save"></i> {{ translate('serverFiles',
                  'save', data['lang']) }}</button>
                <span style="color: #2fb689; margin-left: 10px;" id="save_status"></span>
              </div>
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>



</div>
<!-- content-wrapper ends -->

{% end %}

{% block js %}
<script src="/static/assets/vendors/ace-builds/src-min/ace.js" type="text/javascript" charset="utf-8"></script>

<script>

  const serverId = new URLSearchParams(document.location.search).get('id')


  //used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
  function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
  }


  let editor = ace.edit('editor');
  editor.setTheme('ace/theme/dracula');
  editor.session.setUseSoftTabs(true);
  editor.commands.addCommand({
    name: 'saveFile',
    bindKey: {
      win: 'Ctrl-S',
      mac: 'Command-S',
      sender: 'editor|cli'
    },
    exec: function (env, args, request) {
      save()
    }
  });

  // mouseup = css resize end
  document.addEventListener("mouseup", function (e) {
    editor.resize();
  });

  let extensionChanges = [
    {
      regex: /^js$/,
      replaceWith: 'ace/mode/javascript'
    },
    {
      regex: /^py$/,
      replaceWith: 'ace/mode/python'
    },
    {
      regex: /^html$/,
      replaceWith: 'ace/mode/html'
    },
    {
      regex: /^yml$/,
      replaceWith: 'ace/mode/yaml'
    },
    {
      regex: /^yaml$/,
      replaceWith: 'ace/mode/yaml'
    },
    {
      regex: /^txt$/,
      replaceWith: 'ace/mode/text'
    },
    {
      regex: /^json$/,
      replaceWith: 'ace/mode/json'
    },
    {
      regex: /^java$/,
      replaceWith: 'ace/mode/java'
    },
    {
      regex: /^cpp$/,
      replaceWith: 'ace/mode/c_cpp'
    },
    {
      regex: /^c$/,
      replaceWith: 'ace/mode/c_cpp'
    },
    {
      regex: /^css$/,
      replaceWith: 'ace/mode/css'
    },
    {
      regex: /^scss$/,
      replaceWith: 'ace/mode/scss'
    },
    {
      regex: /^sass$/,
      replaceWith: 'ace/mode/sass'
    },
    {
      regex: /^lua$/,
      replaceWith: 'ace/mode/lua'
    },
    {
      regex: /^php$/,
      replaceWith: 'ace/mode/php'
    },
    {
      regex: /^ps1$/,
      replaceWith: 'ace/mode/powershell'
    },
    {
      regex: /^svg$/,
      replaceWith: 'ace/mode/svg'
    },
    {
      regex: /^sh$/,
      replaceWith: 'ace/mode/sh'
    },
    {
      regex: /^xml$/,
      replaceWith: 'ace/mode/xml'
    },
    {
      regex: /^ts$/,
      replaceWith: 'ace/mode/typescript'
    },
    {
      regex: /^properties$/,
      replaceWith: 'ace/mode/properties'
    },
    {
      regex: /^log$/,
      replaceWith: 'ace/mode/txt'
    },
  ];

  let filePath = '', serverFileContent = '';

  function clickOnFile(event) {
    filePath = event.target.getAttribute('data-path');
    $.ajax({
      type: 'GET',
      url: "/files/get_file?id=" + serverId + "&file_path=" + encodeURIComponent(filePath),
      dataType: 'text',
      success: function (data) {
        console.log('Got File Contents From Server');
        json = JSON.parse(data)
        if (json.error) {
          $('#editorParent').toggle(false) // hide
          $('#fileError').toggle(true)     // show
          $('#fileError').text("{{ translate('serverFiles', 'fileReadError', data['lang']) }}: " + json.error) // show error
          editor.blur()
        } else {
          $('#editorParent').toggle(true) // show
          $('#fileError').toggle(false)   // hide
          setFileName(event.target.innerText);
          editor.session.setValue(json.content);
          serverFileContent = json.content;
          setSaveStatus(true);
        }
      },
    });
  }

  function setFileName(name) {
    let fileName = name || 'default.txt';
    document.getElementById('editingFile').innerText = fileName;

    if (fileName.match('.')) {

      // The pop method removes and returns the last element.
      setMode(fileName
        .split('.')
        .pop()
        .replace('ace/mode/', ''));

    } else {
      setMode('txt');
      document
        .querySelector('#file_warn')
        .innerText = "{% raw translate('serverFiles', 'unsupportedLanguage', data['lang']) %}";
    }
  }

  var onlongtouch;
  var timer;
  var touchduration = 500; //length of time we want the user to touch before we do something
  const longtouch = new Event('longtouch');

  function touchstart(event) {
    if (!timer) {
      timer = setTimeout(onlongtouch, touchduration, event);
    }
  }

  function touchend(event) {
    //stops short touches from firing the event
    if (timer) {
      clearTimeout(timer);
      console.log('Timer: ' + timer)
      timer = null;
    }
  }

  onlongtouch = function (e) {
    console.log('iOS long touch detected!');
    if ([
      'iPad Simulator',
      'iPhone Simulator',
      'iPod Simulator',
      'iPad',
      'iPhone',
      'iPod'
    ].includes(navigator.platform)
      // iPad on iOS 13 detection
      || (navigator.userAgent.includes("Mac") && "ontouchend" in document)) {
      e.preventDefault();
      e.stopImmediatePropagation();
      var ctxmenuPath = e.target.getAttribute('data-path');
      var ctxmenuName = e.target.getAttribute('data-name');

      document.getElementById('context-title').innerHTML = ctxmenuName;
      if (!ctxmenuPath) {
        return;
      }
      $('#renameItem').show();

      var isDir = e.target.classList.contains('files-tree-title');
      $('#createFile').toggle(isDir);
      $('#createDir').toggle(isDir);
      $('#deleteDir').toggle(isDir);
      $('#upload').toggle(isDir);

      var isFile = e.target.classList.contains('tree-file');
      $('#deleteFile').toggle(isFile);
      $('#downloadFile').toggle(isFile);

      if (e.target.classList.contains('root-dir')) {
        $('#createFile').show();
        $('#createDir').show();
        $('#renameItem').hide();
        $('#deleteDir').hide();
        $('#deleteFile').hide();
        $('#downloadFile').hide();
        $('#upload').show();
      }
      if (e.target.textContent.endsWith('.zip')) {
        $('#unzip').show();
      } else {
        $('#unzip').hide();
      }

      var clientX = e.layerX + 2;
      var clientY = e.layerY + 5;



      document.getElementById('files-tree-nav-content')
        .setAttribute('data-path', ctxmenuPath);
      document.getElementById('files-tree-nav-content')
        .setAttribute('data-name', ctxmenuName);
      document.getElementById("files-tree-nav").style.display = "flex";
      document.getElementById("files-tree-nav").style.position = "fixed";
      domRect = document.getElementById("files-tree-nav").getBoundingClientRect();
      sum = (clientY + domRect['height']) - window.innerHeight
      if (domRect['height'] + clientY > window.innerHeight) {
        clientY = clientY - sum;
      }
      document.getElementById("files-tree-nav").style.top = clientY + 'px';
      document.getElementById("files-tree-nav").style.left = clientX + 'px';
      timer = null;
    };
  }
  /**
    * @param {boolean} saved
  */
  const setSaveStatus = (saved) => {
    document.getElementById('save_status').innerHTML = `<i class="fal ${saved ? "fa-file-check" : "fa-file"}"></i>`;
    document.getElementById('save_status').style.color = saved ? '#2fb689' : 'gray';
  }
  ['change', 'undo', 'redo'].forEach(event => editor.on(event, (event) => setSaveStatus(serverFileContent === editor.session.getValue())))
  $('#screen-size').on('click', function (e) {
    $('#editor_container').toggleClass(`col-md-6`)

  });
  setFileName();
  $('#editorParent').toggle(false) // show
  $('#fileError').toggle(false)    // hide
  editor.blur()

  function setMode(extension) {
    // if the extension matches with the RegEx it will return the replaceWith
    // property. else it will return the one it has. defaults to the extension.
    // this runs for each element in extensionChanges.
    let aceMode = extensionChanges.reduce((output, element) => {
      return extension.match(element.regex)
        ? element.replaceWith
        : output;
    }, extension);

    if (!aceMode.startsWith('ace/mode/')) {
      document
        .querySelector('#file_warn')
        .innerText = "{% raw translate('serverFiles', 'unsupportedLanguage', data['lang']) %}";
    } else {
      document
        .querySelector('#file_warn')
        .innerText = '';

      console.log(aceMode || 'ace/mode/text');
      editor.session.setMode(aceMode || 'ace/mode/text');
    }
  }



  function save() {
    let text = editor.session.getValue();

    var token = getCookie("_xsrf")
    $.ajax({
      type: "PUT",
      headers: { 'X-XSRFToken': token },
      url: "/files/save_file?id=" + serverId,
      data: {
        file_contents: text,
        file_path: filePath
      },
      success: (data) => {
        serverFileContent = text;
        setSaveStatus(true)
      }
    });
  }

  function createFile(parent, name, callback) {
    var token = getCookie("_xsrf")
    $.ajax({
      type: "POST",
      headers: { 'X-XSRFToken': token },
      url: "/files/create_file?id=" + serverId,
      data: {
        file_parent: parent,
        file_name: name
      },
      success: function (data) {
        console.log("got response:");
        callback();
      },
    });
  }

  function createDir(parent, name, callback) {
    var token = getCookie("_xsrf")
    $.ajax({
      type: "POST",
      headers: { 'X-XSRFToken': token },
      url: "/files/create_dir?id=" + serverId,
      data: {
        dir_parent: parent,
        dir_name: name
      },
      success: function (data) {
        console.log("got response:");
        callback();
      },
    });
  }

  function renameItem(path, name, callback) {
    var token = getCookie("_xsrf")
    $.ajax({
      type: "PATCH",
      headers: { 'X-XSRFToken': token },
      url: "/files/rename_file?id=" + serverId,
      data: {
        item_path: path,
        new_item_name: name
      },
      success: function (data) {
        console.log("got response:");
        callback();
      },
    });
  }

  function deleteFile(path, callback) {
    console.log('Deleting: ' + path)
    var token = getCookie("_xsrf")
    $.ajax({
      type: "DELETE",
      headers: { 'X-XSRFToken': token },
      url: "/files/del_file?id=" + serverId,
      data: {
        file_path: path
      },
      success: function (data) {
        console.log("got response:");
        callback();
      },
    });
  }

  function deleteDir(path, callback) {
    var token = getCookie("_xsrf")
    $.ajax({
      type: "DELETE",
      headers: { 'X-XSRFToken': token },
      url: "/files/del_dir?id=" + serverId,
      data: {
        dir_path: path
      },
      success: function (data) {
        console.log("got response:");
        callback();
      },
    });
  }

  function unZip(path, callback) {
    console.log('path: ', path)
    var token = getCookie("_xsrf")
    $.ajax({
      type: "POST",
      headers: { 'X-XSRFToken': token },
      url: "/files/unzip_file?id=" + serverId,
      data: {
        path: path
      },
      success: function (data) {
        window.location.href = "/panel/server_detail?id=" + serverId + "&subpage=files";
      },
    });
  }

  function sendFile(file, path, serverId, left, onProgress) {
    let xmlHttpRequest = new XMLHttpRequest();
    let token = getCookie("_xsrf")
    let fileName = file.name
    let target = '/upload?server_id=' + serverId
    let mimeType = file.type
    let size = file.size

    xmlHttpRequest.open('POST', target, true);
    xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
    xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
    xmlHttpRequest.setRequestHeader('X-Content-Length', size);
    xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
    xmlHttpRequest.setRequestHeader('X-Path', path);
    xmlHttpRequest.setRequestHeader('X-Files-Left', left);
    xmlHttpRequest.setRequestHeader('X-FileName', fileName);
    xmlHttpRequest.setRequestHeader('X-ServerId', serverId);
    xmlHttpRequest.upload.addEventListener('progress', (event) =>
      onProgress(Math.floor(event.loaded / event.total * 100)), false);
    xmlHttpRequest.addEventListener('load', (event) => {
      if (event.target.responseText == 'success') {
        console.log('Upload for file', file.name, 'was successful!')
      }
      else {
        alert('Upload failed with response: ' + event.target.responseText);
        doUpload = false;
      }
    }, false);
    xmlHttpRequest.addEventListener('error', (e) => {
      console.error('Error while uploading file', file.name + '.', 'Event:', e)
    }, false);
    xmlHttpRequest.send(file);
  }

  let uploadWaitDialog;
  let doUpload = true;

  function uploadFilesE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    $(function () {
      var uploadHtml = "<div>" +
        '<form id="upload_file"  enctype="multipart/form-data">' + "<label class='upload-area' style='width:100%;text-align:center;' for='files'>" +
        "<i class='fa fa-cloud-upload fa-3x'></i>" +
        "<br />" +
        "{{translate('serverFiles', 'clickUpload', data['lang'])}}" +
        "<input style='margin-left: 21%;' id='files' name='files' type='file' multiple='true'>" +
        "</label></form>" +
        "<br />" +
        "<ul style='margin-left:5px !important;' id='fileList'></ul>" +
        "</div><div class='clearfix'></div>";
      bootbox.dialog({
        message: uploadHtml,
        title: "{{ translate('serverFiles', 'uploadTitle', data['lang'])}}" + path,
        buttons: {
          success: {
            label: "{{ translate('serverFiles', 'upload', data['lang']) }}",
            className: "btn-default",
            callback: async function () {
              var height = files.files.length * 50;

              var waitMessage = '<p class="text-center mb-0">' +
                '<i class="fa fa-spin fa-cog"></i>' +
                "{{ translate('serverFiles', 'waitUpload', data['lang']) }}" + '<br>' +
                '<strong>' + "{{ translate('serverFiles', 'stayHere', data['lang']) }}" + '</strong>' +
                '</p>' +
                '<div class="progress" id="upload-progress-bar-parent" style="height:' + height + 'px; width:100%; display: block;">' +
                '</div>'
              files = document.getElementById("files");
              uploadWaitDialog = bootbox.dialog({
                message: waitMessage,
                closeButton: false
              });

              let nFiles = files.files.length;
              for (i = 0; i < nFiles; i++) {
                if (!doUpload) {
                  doUpload = true;
                  hideUploadBox();
                  break;
                }

                const progressHtml = `
                <div style="width: 100%; min-width: 100%;">
                  ${files.files[i].name}:
                  <br><div
                    id="upload-progress-bar-${i + 1}"
                    class="progress-bar progress-bar-striped progress-bar-animated"
                    role="progressbar"
                    style="width: 100%; height: 10px;"
                    aria-valuenow="0"
                    aria-valuemin="0"
                    aria-valuemax="100"
                  ></div>
                </div><br>
                `;
                $('#upload-progress-bar-parent').append(progressHtml);

                sendFile(files.files[i], path, serverId, nFiles - i - 1, (progress) => {
                  $(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
                  $(`#upload-progress-bar-${i + 1}`).css('width', progress + '%')
                });
              }
              hideUploadBox();
              //$('#upload_file').submit(); //.trigger('submit');
            }
          }
        }
      });

      var fileList = document.getElementById("files");
      fileList.addEventListener("change", function (e) {
        var list = "";
        let files = Array.from(this.files)
        files.forEach(file => {
          list += "<li class='col-xs-12 file-list'>" + file.name + "</li>"
        })

        document.getElementById("fileList").innerHTML = list;
      }, false);
    });
  }

  function getTreeView(event) {
    const path = $('#root_dir').data('path');;

    $.ajax({
      type: "GET",
      url: "/files/get_tree?id=" + serverId + "&path=" + path,
      dataType: 'text',
      success: function (data) {
        console.log("got response:");

        dataArr = data.split('\n');
        serverDir = dataArr.shift(); // Remove & return first element (server directory)
        text = dataArr.join('\n');

        try {
          document.getElementById(path).innerHTML += text;
          event.target.parentElement.classList.add("clicked");
        } catch {
          document.getElementById('files-tree').innerHTML = text;
        }


        document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
        document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');

        setTimeout(function () { setTreeViewContext() }, 1000);
      },
    });
  }

  function getToggleMain(event) {
    path = event.target.parentElement.getAttribute('data-path');
    document.getElementById("files-tree").classList.toggle("d-block");
    document.getElementById(path + "span").classList.toggle("tree-caret-down");
    document.getElementById(path + "span").classList.toggle("tree-caret");
  }

  function getDirView(event) {
    let path = event.target.parentElement.getAttribute('data-path');

    if (document.getElementById(path).classList.contains('clicked')) {

      var toggler = document.getElementById(path + "span");

      if (toggler.classList.contains('files-tree-title')) {
        document.getElementById(path + "ul").classList.toggle("d-block");
        document.getElementById(path + "span").classList.toggle("tree-caret-down");
      }
      return;
    } else {
      $.ajax({
        type: "GET",
        url: "/files/get_dir?id=" + serverId + "&path=" + path,
        dataType: 'text',
        success: function (data) {
          console.log("got response:");

          dataArr = data.split('\n');
          serverDir = dataArr.shift(); // Remove & return first element (server directory)
          text = dataArr.join('\n');

          try {
            document.getElementById(path + "span").classList.add('tree-caret-down');
            document.getElementById(path).innerHTML += text;
            document.getElementById(path).classList.add("clicked");
          } catch {
            console.log("Bad")
          }

          setTimeout(function () { setTreeViewContext() }, 1000);

          var toggler = document.getElementById(path);

          if (toggler.classList.contains('files-tree-title')) {
            document.getElementById(path + "span").addEventListener("click", function caretListener() {
              document.getElementById(path + "ul").classList.toggle("d-block");
              document.getElementById(path + "span").classList.toggle("tree-caret-down");
            });
          }
        },
      });
    }
  }

  function setTreeViewContext() {
    var treeItems = Array.from(document.getElementsByClassName('tree-ctx-item'));

    treeItems.forEach(item => {
      if ([
        'iPad Simulator',
        'iPhone Simulator',
        'iPod Simulator',
        'iPad',
        'iPhone',
        'iPod'
      ].includes(navigator.platform)
        // iPad on iOS 13 detection
        || (navigator.userAgent.includes("Mac") && "ontouchend" in document)) {
        item.addEventListener("touchstart", touchstart, false);
        item.addEventListener("touchend", touchend, false);
      }
      item.addEventListener('contextmenu', function contextListener(event) {
        event.preventDefault();
        var ctxmenuPath = event.target.getAttribute('data-path');
        var ctxmenuName = event.target.getAttribute('data-name');
        if (!ctxmenuPath) {
          console.log({ 'event.target': event.target, ctxmenuPath });
          return;
        }
        $('#renameItem').show();

        var isDir = event.target.classList.contains('files-tree-title');
        $('#createFile').toggle(isDir);
        $('#createDir').toggle(isDir);
        $('#deleteDir').toggle(isDir);
        $('#upload').toggle(isDir);

        document.getElementById('context-title').innerHTML = ctxmenuName;

        var isFile = event.target.classList.contains('tree-file');
        $('#deleteFile').toggle(isFile);
        $('#downloadFile').toggle(isFile);

        if (event.target.classList.contains('root-dir')) {
          $('#createFile').show();
          $('#createDir').show();
          $('#renameItem').hide();
          $('#deleteDir').hide();
          $('#deleteFile').hide();
          $('#downloadFile').hide();
          $('#upload').show();
        }
        if (event.target.textContent.endsWith('.zip')) {
          $('#unzip').show();
        } else {
          $('#unzip').hide();
        }

        var clientX = event.clientX;
        var clientY = event.clientY;

        document.getElementById('files-tree-nav-content')
          .setAttribute('data-path', ctxmenuPath);
        document.getElementById('files-tree-nav-content')
          .setAttribute('data-name', ctxmenuName);
        document.getElementById("files-tree-nav").style.display = "flex";
        document.getElementById("files-tree-nav").style.position = "fixed";
        domRect = document.getElementById("files-tree-nav").getBoundingClientRect();
        sum = (clientY + domRect['height']) - window.innerHeight
        if (domRect['height'] + clientY > window.innerHeight) {
          clientY = clientY - sum
        }
        document.getElementById("files-tree-nav").style.top = clientY + 'px';
        document.getElementById("files-tree-nav").style.left = clientX + 'px';
      })
    })
  }

  document.addEventListener('click', function (e) {
    let inside = (e.target.closest('#files-tree-nav'));
    let contextMenu = document.getElementById('files-tree-nav');
    if (!inside) {
      contextMenu.setAttribute('style', 'display:none');
    } else {
      contextMenu.setAttribute('style', 'display:none');
    }
  });

  if (webSocket) {
    webSocket.on('close_upload_box', function (close_upload_box) {
      hideUploadBox();
    });
  }
  function hideUploadBox() {
    if (!uploadWaitDialog) return;
    uploadWaitDialog.modal('hide');
    getTreeView();
  }

  function createFileE(event) {
    bootbox.prompt("{% raw translate('serverFiles', 'createFileQuestion', data['lang']) %}", function (result) {
      path = event.target.parentElement.getAttribute('data-path');
      name = event.target.parentElement.getAttribute('data-name');
      if (!result) return;

      createFile(path, result, function () {
        getTreeView()
        document.getElementById('files-tree-nav').style.display = 'none';
      });
    })
  }

  function createDirE(event) {
    bootbox.prompt("{% raw translate('serverFiles', 'createDirQuestion', data['lang']) %}", function (result) {
      path = event.target.parentElement.getAttribute('data-path');
      name = event.target.parentElement.getAttribute('data-name');
      if (!result) return;

      createDir(path, result, function () {
        getTreeView()
        document.getElementById('files-tree-nav').style.display = 'none';
      });
    })
  }
  function downloadFileE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    name = event.target.parentElement.getAttribute('data-name');
    window.location.href = `/panel/download_file?id=${serverId}&path=${path}&name=${name}`;
  }

  function renameItemE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    name = event.target.parentElement.getAttribute('data-name');
    bootbox.prompt({
      title: "{% raw translate('serverFiles', 'renameItemQuestion', data['lang']) %}",
      value: name,
      callback: function (result) {
        if (!result) return;
        renameItem(path, result, function () {
          getTreeView()
          document.getElementById('files-tree-nav').style.display = 'none';
        });
      }
    });
  }
  function unzipFilesE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    console.log(path)
    unZip(path)
  }

  function deleteFileE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    name = event.target.parentElement.getAttribute('data-name');
    bootbox.confirm({
      size: "",
      title: "{% raw translate('serverFiles', 'deleteItemQuestion', data['lang']) %}",
      closeButton: false,
      message: "{% raw translate('serverFiles', 'deleteItemQuestionMessage', data['lang']) %}",
      buttons: {
        confirm: {
          label: "{{ translate('serverFiles', 'yesDelete', data['lang']) }}",
          className: 'btn-danger'
        },
        cancel: {
          label: "{{ translate('serverFiles', 'noDelete', data['lang']) }}",
          className: 'btn-link'
        }
      },
      callback: function (result) {
        if (!result) return;
        deleteFile(path, function () {
          getTreeView()
          document.getElementById('files-tree-nav').style.display = 'none';
        });
      }
    });
  }

  function deleteDirE(event) {
    path = event.target.parentElement.getAttribute('data-path');
    name = event.target.parentElement.getAttribute('data-name');
    bootbox.confirm({
      size: "",
      title: "{% raw translate('serverFiles', 'deleteItemQuestion', data['lang']) %}",
      closeButton: false,
      message: "{% raw translate('serverFiles', 'deleteItemQuestionMessage', data['lang']) %}",
      buttons: {
        confirm: {
          label: "{{ translate('serverFiles', 'yesDelete', data['lang']) }}",
          className: 'btn-danger'
        },
        cancel: {
          label: "{{ translate('serverFiles', 'noDelete', data['lang']) }}",
          className: 'btn-link'
        }
      },
      callback: function (result) {
        if (!result) return;
        deleteDir(path, function () {
          getTreeView()
          document.getElementById('files-tree-nav').style.display = 'none';
        });
      }
    });
  }

  getTreeView();
  setTreeViewContext();

  function setKeyboard(target) {
    var handlerName = target.getAttribute('data-handler-name');
    if (handlerName == 'null') handlerName = null;
    editor.setKeyboardHandler(handlerName, () => {
      if (handlerName == 'ace/keyboard/vim') {
        require("ace/keyboard/vim").Vim.defineEx('write', 'w', function () {
          save();
        });
      }
    });

    var nodes = target.parentNode.querySelectorAll("[data-handler-name]");
    nodes.forEach(node => {
      node.classList.remove('btn-primary');
      node.classList.add('btn-secondary');
    })

    target.classList.remove('btn-secondary');
    target.classList.add('btn-primary');
  }



</script>

{% end %}