1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-10-27 20:32:28 +01:00

File adding support, editor enhancements, JS improved.

This commit is contained in:
Dane Everitt 2016-10-03 20:22:28 -04:00
parent 50b377d08c
commit 81dc74a175
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
4 changed files with 83 additions and 41 deletions

View File

@ -136,7 +136,7 @@ class FileRepository
* *
* @param string $file * @param string $file
* @param string $content * @param string $content
* @return boolean * @return bool
*/ */
public function saveFileContents($file, $content) public function saveFileContents($file, $content)
{ {
@ -149,23 +149,6 @@ class FileRepository
$file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/'; $file->dirname = (in_array($file->dirname, ['.', './', '/'])) ? null : trim($file->dirname, '/') . '/';
$res = $this->client->request('GET', '/server/files/stat/' . rawurlencode($file->dirname.$file->basename) , [
'headers' => $this->headers
]);
$stat = json_decode($res->getBody());
if($res->getStatusCode() !== 200 || !isset($stat->size)) {
throw new DisplayException('The daemon provided a non-200 error code on stat lookup: HTTP\\' . $res->getStatusCode());
}
if (!in_array($stat->mime, HelperRepository::editableFiles())) {
throw new DisplayException('You cannot edit that type of file (' . $stat->mime . ') through the panel.');
}
if ($stat->size > 5000000) {
throw new DisplayException('That file is too large to save in the browser, consider using a SFTP client.');
}
$res = $this->client->request('POST', '/server/file/' . rawurlencode($file->dirname.$file->basename), [ $res = $this->client->request('POST', '/server/file/' . rawurlencode($file->dirname.$file->basename), [
'headers' => $this->headers, 'headers' => $this->headers,
'json' => [ 'json' => [

View File

@ -40,14 +40,44 @@
<form method="post" id="new_file"> <form method="post" id="new_file">
<h4>/home/container/{{ $directory }} <input type="text" id="file_name" class="filename" value="newfile.txt" /></h4> <h4>/home/container/{{ $directory }} <input type="text" id="file_name" class="filename" value="newfile.txt" /></h4>
<div class="form-group"> <div class="form-group">
<div> <div id="fileContents" style="height:500px;"></div>
<textarea name="file_contents" id="fileContents" style="border: 1px solid #dddddd;" class="form-control console"></textarea>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div> <div class="row">
<button class="btn btn-primary btn-sm" id="create_file">{{ trans('strings.save') }}</button> <div class="col-md-8">
<button class="btn btn-default btn-sm" onclick="window.location='/server/{{ $server->uuidShort }}/files?dir=/{{ $directory }}';return false;">{{ trans('server.files.back') }}</button> <button class="btn btn-primary btn-sm" id="create_file">{{ trans('strings.save') }}</button>
<button class="btn btn-default btn-sm" onclick="window.location='/server/{{ $server->uuidShort }}/files?dir=/{{ $directory }}';return false;">{{ trans('server.files.back') }}</button>
</div>
<div class="col-md-4 pull-right">
<select name="aceMode" id="aceMode" class="form-control">
<option value="assembly_x86">Assembly x86</option>
<option value="c_cpp">C/C++</option>
<option value="coffee">CoffeeScript</option>
<option value="csharp">C#</option>
<option value="css">CSS</option>
<option value="golang">Go</option>
<option value="haml">HAML</option>
<option value="html">HTML</option>
<option value="ini">INI</option>
<option value="java">Java</option>
<option value="javascript">JavaScript</option>
<option value="json">JSON</option>
<option value="lua">Lua</option>
<option value="markdown">Markdown</option>
<option value="mysql">MySQL</option>
<option value="objectivec">Objective-C</option>
<option value="perl">Perl</option>
<option value="php">PHP</option>
<option value="properties">Properties</option>
<option value="python">Python</option>
<option value="ruby">Ruby</option>
<option value="rust">Rust</option>
<option value="smarty">Smarty</option>
<option value="textile" selected="selected">Plain Text</option>
<option value="xml">XML</option>
<option value="yaml">YAML</option>
</select>
</div>
</div> </div>
</div> </div>
</form> </form>
@ -66,6 +96,8 @@
@endcan @endcan
</div> </div>
</div> </div>
{!! Theme::js('js/vendor/ace/ace.js') !!}
{!! Theme::js('js/vendor/ace/ext-modelist.js') !!}
<script> <script>
$(window).load(function () { $(window).load(function () {
@ -170,35 +202,54 @@ $(window).load(function () {
} }
@endcan @endcan
$('textarea').keydown(function (e) { const Editor = ace.edit('fileContents');
if (e.keyCode === 9) {
var start = this.selectionStart; Editor.setTheme('ace/theme/chrome');
var end = this.selectionEnd; Editor.getSession().setUseWrapMode(true);
var value = $(this).val(); Editor.setShowPrintMargin(false);
$(this).val(value.substring(0, start) + '\t' + value.substring(end));
this.selectionStart = this.selectionEnd = start + 1; $('#aceMode').on('change', event => {
e.preventDefault(); Editor.getSession().setMode(`ace/mode/${$('#aceMode').val()}`);
}
}); });
$("#create_file").click(function(e) { Editor.commands.addCommand({
name: 'save',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: function(editor) {
save();
},
readOnly: false
});
$('#create_file').on('click', function (e) {
e.preventDefault(); e.preventDefault();
$("#create_file").append(' <i class="fa fa-spinner fa fa-spin"></i>').addClass("disabled"); save();
});
function save() {
var fileName = $('input[name="file"]').val();
$('#create_file').append(' <i class="fa fa-spinner fa fa-spin"></i>').addClass('disabled');
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '{{ route('server.files.save', $server->uuidShort) }}', url: '{{ route('server.files.save', $server->uuidShort) }}',
headers: { 'X-CSRF-Token': '{{ csrf_token() }}' }, headers: { 'X-CSRF-Token': '{{ csrf_token() }}' },
data: { data: {
file: '{{ $directory }}' + $('#file_name').val(), file: '{{ $directory }}' + $('#file_name').val(),
contents: $('#fileContents').val() contents: Editor.getValue()
} }
}).done(function (data) { }).done(function (data) {
window.location.replace('/server/{{ $server->uuidShort }}/files/edit/{{ $directory }}' + $('#file_name').val()); window.location.replace('/server/{{ $server->uuidShort }}/files/edit/{{ $directory }}' + $('#file_name').val());
}).fail(function (jqXHR) { }).fail(function (jqXHR) {
$('#write_status').html('<div class="alert alert-danger">' + jqXHR.responseText + '</div>').show(); $.notify({
$('#create_file').html('{{ trans('strings.save') }}').removeClass('disabled'); message: jqXHR.responseText
}, {
type: 'danger'
});
}).always(function () {
$('#save_file').html('{{ trans('strings.save') }}').removeClass('disabled');
}); });
}); }
}); });
</script> </script>

View File

@ -50,7 +50,7 @@ $(document).ready(function () {
const Editor = ace.edit('editor'); const Editor = ace.edit('editor');
const Modelist = ace.require('ace/ext/modelist') const Modelist = ace.require('ace/ext/modelist')
Editor.setTheme('ace/theme/github'); Editor.setTheme('ace/theme/chrome');
Editor.getSession().setMode(Modelist.getModeForPath('{{ $stat->name }}').mode); Editor.getSession().setMode(Modelist.getModeForPath('{{ $stat->name }}').mode);
Editor.getSession().setUseWrapMode(true); Editor.getSession().setUseWrapMode(true);
Editor.setShowPrintMargin(false); Editor.setShowPrintMargin(false);

View File

@ -99,7 +99,11 @@ class ActionsClass {
inputField.focus(); inputField.focus();
inputField.on('blur keypress', e => { inputField.on('blur keypress', e => {
// Save Field // Save Field
if (e.type === 'blur' || (e.type === 'keypress' && e.which === 27) || currentName === inputField.val()) { if (
(e.type === 'keypress' && e.which === 27)
|| e.type === 'blur'
|| (e.type === 'keypress' && e.which === 13 && currentName === inputField.val())
) {
if (!_.isEmpty(currentLink)) { if (!_.isEmpty(currentLink)) {
nameBlock.html(currentLink); nameBlock.html(currentLink);
} else { } else {
@ -110,6 +114,10 @@ class ActionsClass {
return; return;
} }
if (e.type === 'keypress' && e.which !== 13) return;
console.log('did not');
inputLoader.show(); inputLoader.show();
const currentPath = decodeURIComponent(nameBlock.data('path')); const currentPath = decodeURIComponent(nameBlock.data('path'));