mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
821 lines
28 KiB
HTML
821 lines
28 KiB
HTML
{% extends ../base.html %}
|
|
|
|
{% block meta %}
|
|
<!-- <meta http-equiv="refresh" content="60">-->
|
|
{% end %}
|
|
|
|
{% block title %}Crafty Controller - {{ translate('serverDetails', 'serverDetails') }}{% 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['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">
|
|
{% include "parts/server_controls_list.html %}
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 col-sm-12">
|
|
<noscript>
|
|
{{ translate('serverFiles', 'noscript') }}
|
|
</noscript>
|
|
<div id="files-tree-nav" class="overlay">
|
|
|
|
<!-- Button to close the overlay navigation -->
|
|
|
|
<!-- Overlay content -->
|
|
<div id="files-tree-nav-content" class="overlay-content">
|
|
<a onclick="createFileE(event)" href="javascript:void(0)" id="createFile" href="#">{{ translate('serverFiles', 'createFile') }}</a>
|
|
<a onclick="createDirE(event)" href="javascript:void(0)" id="createDir" href="#">{{ translate('serverFiles', 'createDir') }}</a>
|
|
<a onclick="renameItemE(event)" href="javascript:void(0)" id="renameItem" href="#">{{ translate('serverFiles', 'rename') }}</a>
|
|
<a onclick="deleteFileE(event)" href="javascript:void(0)" id="deleteFile" href="#">{{ translate('serverFiles', 'delete') }}</a>
|
|
<a onclick="deleteDirE(event)" href="javascript:void(0)" id="deleteDir" href="#">{{ translate('serverFiles', 'delete') }}</a>
|
|
<a onclick="uploadFilesE(event)" href="javascript:void(0)" id="upload" href="#">Upload Files</a>
|
|
<a onclick="unzipFilesE(event)" href="javascript:void(0)" id="unzip" href="#">Unzip</a>
|
|
<a href="javascript:void(0)" class="closebtn" style="color: red;" onclick="document.getElementById('files-tree-nav').style.display = 'none';">Close</a>
|
|
</div>
|
|
|
|
</div>
|
|
<style>
|
|
/* The Overlay (background) */
|
|
.overlay {
|
|
display: none;
|
|
flex-direction: column;
|
|
background-color: #fff;
|
|
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: #fff;
|
|
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:#f1f3f7;
|
|
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 class="tree-caret tree-ctx-item files-tree-title">
|
|
<i class="far fa-folder"></i>
|
|
<i class="far fa-folder-open"></i>
|
|
{{ translate('serverFiles', 'files') }}
|
|
</div>
|
|
<ul class="tree-nested" id="files-tree">
|
|
<li>{{ translate('serverFiles', 'error') }}</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;
|
|
}
|
|
</style>
|
|
<div class="col-md-6 col-sm-12">
|
|
<h2 id="fileError"></h2>
|
|
<div id="editorParent">
|
|
{{ translate('serverFiles', 'editingFile') }} <span id="editingFile"></span>
|
|
<div id="editor" onresize="editor.resize()" style="resize: both;width: 100%;">file_contents</div>
|
|
<br/>
|
|
</div>
|
|
{{ translate('serverFiles', 'keybindings') }}:
|
|
<div class="btn-group" role="group">
|
|
<button onclick="setKeyboard(event.target)" class="btn btn-primary" data-handler-name="null">{{ translate('serverFiles', 'default') }}</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>
|
|
</div>
|
|
<h3 id="file_warn"></h3>
|
|
<button class="btn btn-success" onclick="save()"><i class="fas fa-save"></i> {{ translate('serverFiles', 'save') }}</button>
|
|
</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>
|
|
|
|
|
|
//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);
|
|
|
|
// 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'
|
|
},
|
|
];
|
|
|
|
var filePath = '';
|
|
|
|
function clickOnFile(event) {
|
|
filePath = event.target.getAttribute('data-path');
|
|
$.ajax({
|
|
type: 'GET',
|
|
url: '/ajax/get_file?id={{ data['server_stats']['server_id']['server_id'] }}&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') }}: " + json.error) // show error
|
|
editor.blur()
|
|
} else {
|
|
$('#editorParent').toggle(true) // show
|
|
$('#fileError').toggle(false) // hide
|
|
setFileName(event.target.innerText);
|
|
editor.session.setValue(json.content);
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
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') %}";
|
|
}
|
|
}
|
|
|
|
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') %}";
|
|
} 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: '/ajax/save_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
file_contents: text,
|
|
file_path: filePath
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
},
|
|
});
|
|
}
|
|
|
|
function createFile(parent, name, callback) {
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "POST",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/create_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
file_parent: parent,
|
|
file_name: name
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
callback();
|
|
},
|
|
});
|
|
}
|
|
|
|
function createDir(parent, name, callback) {
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "POST",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/create_dir?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
dir_parent: parent,
|
|
dir_name: name
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
callback();
|
|
},
|
|
});
|
|
}
|
|
|
|
function renameItem(path, name, callback) {
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "PUT",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/rename_item?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
item_path: path,
|
|
new_item_name: name
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
callback();
|
|
},
|
|
});
|
|
}
|
|
|
|
function deleteFile(path, callback) {
|
|
console.log('Deleting: ' + path)
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "DELETE",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/del_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
file_path: path
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
callback();
|
|
},
|
|
});
|
|
}
|
|
|
|
function deleteDir(path, callback) {
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "DELETE",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/del_dir?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
dir_path: path
|
|
},
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
callback();
|
|
},
|
|
});
|
|
}
|
|
|
|
function unZip(path, callback) {
|
|
var token = getCookie("_xsrf")
|
|
$.ajax({
|
|
type: "POST",
|
|
headers: {'X-XSRFToken': token},
|
|
url: '/ajax/unzip_file?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
data: {
|
|
path: path
|
|
},
|
|
});
|
|
window.location.href = "/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files"
|
|
}
|
|
function uploadFilesE(event){
|
|
path = event.target.parentElement.getAttribute('data-path');
|
|
console.log("PATH: " + path);
|
|
$(function () {
|
|
server_id = {{ data['server_stats']['server_id']['server_id'] }};
|
|
var uploadHtml = "<div>" +
|
|
'<form id="upload_file" enctype="multipart/form-data">'+"<label class='upload-area' style='width:100%;text-align:center;' for='files'>" +
|
|
"<input id='files' name='files' type='file' style='display:none;' multiple='true'>" +
|
|
"<i class='fa fa-cloud-upload fa-3x'></i>" +
|
|
"<br />" +
|
|
"Click Here To Upload" +
|
|
"</label></form>" +
|
|
"<br />" +
|
|
"<ul style='margin-left:5px !important;' id='fileList'></ul>" +
|
|
"</div><div class='clearfix'></div>";
|
|
|
|
bootbox.dialog({
|
|
message: uploadHtml,
|
|
title: "File Upload",
|
|
buttons: {
|
|
success: {
|
|
label: "Upload",
|
|
className: "btn-default",
|
|
callback: function () {
|
|
$('#upload_file').submit(); //.trigger('submit');
|
|
files = document.getElementById("upload_files").files
|
|
for (i = 0; i < files.length; i++){
|
|
|
|
var file = files[i]
|
|
var fileName = files[i].name
|
|
var target = '/upload'
|
|
var mimeType = files[i].type
|
|
|
|
xmlHttpRequest.open('PUT', target, true);
|
|
console.log(xmlHttpRequest);
|
|
xmlHttpRequest.setRequestHeader('Content-Type', mimeType);
|
|
xmlHttpRequest.setRequestHeader('Content-Disposition', 'attachment; filename="' + fileName + '"');
|
|
xmlHttpRequest.send(file);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var fileList = document.getElementById("files");
|
|
fileList.addEventListener("change", function (e) {
|
|
var list = "";
|
|
for (var i = 0; i < this.files.length; i++) {
|
|
list += "<li class='col-xs-12 file-list'>" + this.files[i].name + "</li>"
|
|
}
|
|
|
|
document.getElementById("fileList").innerHTML = list;
|
|
}, false);
|
|
});
|
|
}
|
|
|
|
|
|
function uploadFiles(e){
|
|
path = event.target.parentElement.getAttribute('data-path');
|
|
server_id = {{ data['server_stats']['server_id']['server_id'] }};
|
|
var uploadHtml = '<form enctype="multipart/form-data" action="/ajax/upload_files?id=' + server_id +'&path='+ path +'"method="post">{% raw xsrf_form_html() %}<div class="form-group">'+"<label class='upload-area' style='width:100%;text-align:center;' for='fupload'>" +'<input id="files" type="file" name="files" multiple>' +"<i class='fa fa-cloud-upload fa-3x'></i>" +"<br />" +"Upload Files Here" +"</label>" +"<br />" +"<span style='margin-left:5px !important;' id='fileList'></span>"+'</div><br><br><input id="upload_file" type="submit"value="Upload File" class="btn btn-success hidden"/></form>';
|
|
bootbox.dialog({
|
|
message: uploadHtml,
|
|
title: "Upload Files To "+path,
|
|
});
|
|
}
|
|
|
|
function getTreeView() {
|
|
$.ajax({
|
|
type: "GET",
|
|
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}',
|
|
dataType: 'text',
|
|
success: function(data){
|
|
console.log("got response:");
|
|
console.log(data);
|
|
|
|
dataArr = data.split('\n');
|
|
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
|
text = dataArr.join('\n');
|
|
|
|
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);
|
|
|
|
var toggler = document.getElementsByClassName("tree-caret");
|
|
var i;
|
|
|
|
for (i = 0; i < toggler.length; i++) {
|
|
if (toggler[i].classList.contains('files-tree-title')) continue;
|
|
toggler[i].addEventListener("click", function caretListener() {
|
|
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
|
|
this.classList.toggle("tree-caret-down");
|
|
});
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
function setTreeViewContext() {
|
|
var treeItems = document.getElementsByClassName('tree-ctx-item');
|
|
|
|
for (var i = 0; i < treeItems.length; i++) {
|
|
var treeItem = treeItems[i];
|
|
treeItem.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('tree-folder');
|
|
$('#createFile').toggle(isDir);
|
|
$('#createDir').toggle(isDir);
|
|
$('#deleteDir').toggle(isDir);
|
|
$('#upload').toggle(isDir);
|
|
|
|
var isFile = event.target.classList.contains('tree-file');
|
|
$('#deleteFile').toggle(isFile);
|
|
console.log({ 'event.target': event.target, isDir, isFile });
|
|
|
|
if(event.target.classList.contains('files-tree-title')) {
|
|
$('#createFile').show();
|
|
$('#createDir').show();
|
|
$('#renameItem').hide();
|
|
$('#deleteDir').hide();
|
|
$('#deleteFile').hide();
|
|
$('#upload').show();
|
|
}
|
|
if(event.target.textContent.endsWith('.zip')){
|
|
$('#unzip').show();
|
|
console.log(event.target.textContent)
|
|
}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';
|
|
console.log(domRect)
|
|
console.log(window.innerHeight)
|
|
})
|
|
}
|
|
}
|
|
|
|
document.addEventListener('click', function(e){
|
|
let inside = (e.target.closest('#files-tree-nav'));
|
|
if(!inside){
|
|
let contextMenu = document.getElementById('files-tree-nav');
|
|
contextMenu.setAttribute('style', 'display:none');
|
|
}
|
|
});
|
|
|
|
|
|
function createFileE(event) {
|
|
bootbox.prompt("{% raw translate('serverFiles', 'createFileQuestion') %}", 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') %}", 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 renameItemE(event) {
|
|
bootbox.prompt("{% raw translate('serverFiles', 'renameItemQuestion') %}", function(result) {
|
|
path = event.target.parentElement.getAttribute('data-path');
|
|
name = event.target.parentElement.getAttribute('data-name');
|
|
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');
|
|
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') %}",
|
|
closeButton: false,
|
|
message: "{% raw translate('serverFiles', 'deleteItemQuestionMessage') %}",
|
|
buttons: {
|
|
confirm: {
|
|
label: "{{ translate('serverFiles', 'yesDelete') }}",
|
|
className: 'btn-danger'
|
|
},
|
|
cancel: {
|
|
label: "{{ translate('serverFiles', 'noDelete') }}",
|
|
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') %}",
|
|
closeButton: false,
|
|
message: "{% raw translate('serverFiles', 'deleteItemQuestionMessage') %}",
|
|
buttons: {
|
|
confirm: {
|
|
label: "{{ translate('serverFiles', 'yesDelete') }}",
|
|
className: 'btn-danger'
|
|
},
|
|
cancel: {
|
|
label: "{{ translate('serverFiles', 'noDelete') }}",
|
|
className: 'btn-link'
|
|
}
|
|
},
|
|
callback: function(result) {
|
|
if (!result) return;
|
|
deleteDir(path, function () {
|
|
getTreeView()
|
|
document.getElementById('files-tree-nav').style.display = 'none';
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
document.getElementsByClassName('files-tree-title')[0].addEventListener("click", function caretListener() {
|
|
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
|
|
this.classList.toggle("tree-caret-down");
|
|
});
|
|
|
|
getTreeView();
|
|
setTreeViewContext();
|
|
|
|
function setKeyboard(target) {
|
|
var handlerName = target.getAttribute('data-handler-name');
|
|
if (handlerName == 'null') handlerName = null;
|
|
editor.setKeyboardHandler(handlerName);
|
|
|
|
var nodes = target.parentNode.querySelectorAll("[data-handler-name]");
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
nodes[i].classList.remove('btn-primary');
|
|
nodes[i].classList.add('btn-secondary');
|
|
}
|
|
|
|
target.classList.remove('btn-secondary');
|
|
target.classList.add('btn-primary');
|
|
}
|
|
|
|
</script>
|
|
|
|
{% end %} |