mirror of
https://github.com/pterodactyl/panel.git
synced 2024-11-25 18:42:31 +01:00
Merge pull request #140 from Pterodactyl/feature/file-uploader
Add support for new file upload mechanics
This commit is contained in:
commit
2c6ad1b8ca
@ -3,7 +3,7 @@ This file is a running track of new features and fixes to each version of the pa
|
||||
|
||||
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||
|
||||
## v0.5.0-pre.2 (Bodacious Boreopterus)
|
||||
## v0.5.0-pre.3 (Bodacious Boreopterus)
|
||||
|
||||
### Added
|
||||
* Return node configuration from remote API by using `/api/nodes/{id}/config` endpoint. Only accepts SSL connections.
|
||||
@ -13,6 +13,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||
### Changed
|
||||
* Creating a user, server, or node now returns `HTTP/1.1 200` and a JSON element with the user/server/node's ID.
|
||||
* Environment setting script is much more user friendly and does not require an excessive amount of clicking and typing.
|
||||
* File upload method switched from BinaryJS to Socket.io implementation to fix bugs as well as be a little speedier and allow upload throttling.
|
||||
|
||||
## v0.5.0-pre.2 (Bodacious Boreopterus)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
15
public/js/vendor/upload/client.min.js
vendored
Normal file
15
public/js/vendor/upload/client.min.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/* Socket IO File Upload Client-Side Library
|
||||
* Copyright (C) 2015 Shane Carr and others
|
||||
* Released under the X11 License
|
||||
* For more information, visit: https://github.com/vote539/socketio-file-upload
|
||||
*/
|
||||
|
||||
(function(g,d,f){"function"===typeof define&&define.amd?define(d,f):"object"===typeof module&&module.exports?module.exports=f():g[d]=f()})(this,"SocketIOFileUpload",function(){return function(g){var d=this;if(!window.File||!window.FileReader)throw Error("Socket.IO File Upload: Browser Not Supported");var f={},q=[],u=[],k={};d.fileInputElementId="siofu_input";d.resetFileInputs=!0;d.useText=!1;d.serializedOctets=!1;d.useBuffer=!0;d.chunkSize=102400;d.chunkDelay=0;var r=function(a,b){var c=document.createEvent("Event");
|
||||
c.initEvent(a,!1,!1);for(var y in b)b.hasOwnProperty(y)&&(c[y]=b[y]);return d.dispatchEvent(c)},p=[],e=function(a,b,c,d){a.addEventListener(b,c,d);p.push(arguments)},t=function(a,b,c,d){a.removeEventListener&&a.removeEventListener(b,c,d)},z=function(){for(var a=p.length-1;0<=a;a--)t.apply(this,p[a]);p=[]},A=function(a){if(null!==d.maxFileSize&&a.size>d.maxFileSize)r("error",{file:a,message:"Attempt by client to upload file exceeding the maximum file size",code:1});else if(r("start",{file:a})){var b=
|
||||
new FileReader,c=q.length,f=d.useText,v=0,k;b._realReader&&(b=b._realReader);q.push(a);var p={id:c},w=d.chunkSize;if(w>=a.size||0>=w)w=a.size;var x=function(){if(!p.abort){var c=a.slice(v,Math.min(v+w,a.size));f?b.readAsText(c):b.readAsArrayBuffer(c)}},l=function(e){if(!p.abort){var l=Math.min(v+w,a.size);a:{var q=v;e=e.target.result;var u=!1;if(!f)try{var m=new Uint8Array(e);if(d.serializedOctets)e=m;else if(d.useBuffer)e=m.buffer;else{var u=!0,n,t=m.buffer.byteLength,h="";for(n=0;n<t;n+=3)h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[m[n]>>
|
||||
2],h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(m[n]&3)<<4|m[n+1]>>4],h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(m[n+1]&15)<<2|m[n+2]>>6],h+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[m[n+2]&63];2===t%3?h=h.substring(0,h.length-1)+"=":1===t%3&&(h=h.substring(0,h.length-2)+"==");e=h}}catch(z){g.emit("siofu_done",{id:c,interrupt:!0});break a}g.emit("siofu_progress",{id:c,size:a.size,start:q,end:l,content:e,base64:u})}r("progress",
|
||||
{file:a,bytesLoaded:l,name:k});v+=w;v<a.size?setTimeout(x,d.chunkDelay):(g.emit("siofu_done",{id:c}),r("load",{file:a,reader:b,name:k}))}};e(b,"load",l);e(b,"error",function(){g.emit("siofu_done",{id:c,interrupt:!0});t(b,"load",l)});e(b,"abort",function(){g.emit("siofu_done",{id:c,interrupt:!0});t(b,"load",l)});g.emit("siofu_start",{name:a.name,mtime:a.lastModifiedDate,meta:a.meta,size:a.size,encoding:f?"text":"octet",id:c});u.push(function(a){k=a;x()});return p}},x=function(a){if(0!==a.length){for(var b=
|
||||
0;b<a.length;b++)a[b].meta||(a[b].meta={});if(r("choose",{files:a}))for(b=0;b<a.length;b++){var c=A(a[b]);k[c.id]=c}}},l=function(a){var b=a.target.files||a.dataTransfer.files;a.preventDefault();x(b);if(d.resetFileInputs){try{a.target.value=""}catch(e){}if(a.target.value){var b=document.createElement("form"),c=a.target.parentNode,f=a.target.nextSibling;b.appendChild(a.target);b.reset();c.insertBefore(a.target,f)}}};this.submitFiles=function(a){a&&x(a)};this.listenOnSubmit=function(a,b){b.files&&e(a,
|
||||
"click",function(){x(b.files)},!1)};this.listenOnArraySubmit=function(a,b){for(var c in b)this.listenOnSubmit(a,b[c])};this.listenOnInput=function(a){a.files&&e(a,"change",l,!1)};this.listenOnDrop=function(a){e(a,"dragover",function(a){a.preventDefault()},!1);e(a,"drop",l)};this.prompt=function(){var a;a=document.getElementById(d.fileInputElementId);a||(a=document.createElement("input"),a.setAttribute("type","file"),a.setAttribute("id",d.fileInputElementId),a.style.display="none",document.body.appendChild(a));
|
||||
e(a,"change",l,!1);var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null);a.dispatchEvent(b)};this.destroy=function(){z();var a=document.getElementById(d.fileInputElementId);a&&a.parentNode.removeChild(a);for(var b in k)k.hasOwnProperty(b)&&(k[b].abort=!0);k=u=q=f=null};this.addEventListener=function(a,b){f[a]||(f[a]=[]);f[a].push(b)};this.removeEventListener=function(a,b){if(!f[a])return!1;for(var c=0;c<f[a].length;c++)if(f[a][c]===b)return f[a].splice(c,
|
||||
1),!0;return!1};this.dispatchEvent=function(a){var b=f[a.type];if(!b)return!0;for(var c=!0,d=0;d<b.length;d++)!1===b[d](a)&&(c=!1);return c};e(g,"siofu_ready",function(a){u[a.id](a.name)});e(g,"siofu_complete",function(a){r("complete",{file:q[a.id],detail:a.detail,success:a.success})});e(g,"siofu_error",function(a){r("error",{file:q[a.id],message:a.message,code:0});k[a.id].abort=!0})}});
|
@ -25,7 +25,7 @@
|
||||
|
||||
@section('scripts')
|
||||
@parent
|
||||
{!! Theme::js('js/binaryjs.js') !!}
|
||||
{!! Theme::js('js/vendor/upload/client.min.js') !!}
|
||||
{!! Theme::js('js/vendor/lodash/lodash.js') !!}
|
||||
@endsection
|
||||
|
||||
@ -102,11 +102,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">Edit the path location above <strong>before you upload files</strong>. They will automatically be placed in the directory you specify above. You can change this each time you upload a new file without having to press anything else.</div>
|
||||
<div class="alert alert-warning">Edit the path location above <strong>before you upload files</strong>. They will automatically be placed in the directory you specify above. You can change this each time you upload a new file without having to press anything else. <em>The directory must exist before performing an upload.</em></div>
|
||||
<div class="alert alert-danger" id="upload_error" style="display: none;"></div>
|
||||
<input type="file" id="fileinput" name="fileUpload[]" multiple="" style="display:none;"/>
|
||||
<div id="uploader_box" class="well well-sm" style="cursor:pointer;">
|
||||
<center><h2 style="margin-bottom: 25px;">Connecting...</h2></center>
|
||||
<center><h2 style="margin-bottom: 25px;">Drag and Drop File Here</h2></center>
|
||||
</div>
|
||||
<span id="file_progress"></span>
|
||||
</div>
|
||||
@ -124,99 +124,90 @@ $(window).load(function () {
|
||||
var newFileContents;
|
||||
|
||||
@can('upload-files', $server)
|
||||
var client = new BinaryClient('{{ $node->scheme === 'https' ? 'wss' : 'ws' }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/upload/', {
|
||||
chunkSize: 40960
|
||||
var notifyUploadSocketError = false;
|
||||
var uploadSocket = io('{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/upload/{{ $server->uuid }}', {
|
||||
'query': 'token={{ $server->daemonSecret }}'
|
||||
});
|
||||
// Wait for connection to BinaryJS server
|
||||
client.on('open', function() {
|
||||
|
||||
var box = $('#uploader_box');
|
||||
box.on('dragenter', doNothing);
|
||||
box.on('dragover', doNothing);
|
||||
box.html('<center><h2 style="margin-bottom:25px;">Drag or Click to Upload</h2></center>');
|
||||
box.on('click', function () {
|
||||
$('#fileinput').click();
|
||||
});
|
||||
box.on('drop', function (e, files) {
|
||||
|
||||
if (typeof files !== 'undefined') {
|
||||
e.originalEvent = {
|
||||
dataTransfer: {
|
||||
files: files.currentTarget.files
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// e.preventDefault();
|
||||
$.each(e.originalEvent.dataTransfer.files, function(index, value) {
|
||||
|
||||
var file = e.originalEvent.dataTransfer.files[index];
|
||||
var identifier = Math.random().toString(36).slice(2);
|
||||
|
||||
$('#file_progress').append('<div class="well well-sm" id="file-upload-' + identifier +'"> \
|
||||
<div class="row"> \
|
||||
<div class="col-md-12"> \
|
||||
<h6>Uploading ' + file.name + '</h6> \
|
||||
<span class="prog-bar-text-' + identifier +'" style="font-size: 10px;position: absolute;margin: 3px 0 0 15px;">Waiting...</span> \
|
||||
<div class="progress progress-striped active"> \
|
||||
<div class="progress-bar progress-bar-info prog-bar-' + identifier +'" style="width: 0%"></div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div>');
|
||||
|
||||
// Add to list of uploaded files
|
||||
var stream = client.send(file, {
|
||||
token: "{{ $server->daemonSecret }}",
|
||||
server: "{{ $server->uuid }}",
|
||||
path: $("#u_file_name").val(),
|
||||
name: file.name,
|
||||
size: file.size
|
||||
});
|
||||
|
||||
var tx = 0;
|
||||
stream.on('data', function(data) {
|
||||
if(data.error) {
|
||||
$("#upload_error").html(data.error).show();
|
||||
$("#file-upload-" + identifier).hide();
|
||||
} else {
|
||||
tx += data.rx;
|
||||
|
||||
if(tx >= 0.999) {
|
||||
$('.prog-bar-text-' + identifier).text('Upload Complete');
|
||||
$('.prog-bar-' + identifier).css('width', '100%').parent().removeClass('active').removeClass('progress-striped');
|
||||
} else {
|
||||
$('.prog-bar-text-' + identifier).text(Math.round(tx * 100) + '%');
|
||||
$('.prog-bar-' + identifier).css('width', tx * 100 + '%');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('close', function(data) {
|
||||
$("#upload_error").html("The BinaryJS data stream was closed by the server. Please refresh the page and try again.").show();
|
||||
$("#file-upload-" + identifier).hide();
|
||||
});
|
||||
|
||||
stream.on('error', function(data) {
|
||||
console.error("An error was encountered with the BinaryJS upload stream.");
|
||||
});
|
||||
|
||||
socket.io.on('connect_error', function (err) {
|
||||
siofu.destroy();
|
||||
$('#applyUpdate').removeClass('fa-circle-o-notch fa-spinner fa-spin').addClass('fa-question-circle').css({ color: '#FF9900' });
|
||||
if(typeof notifyUploadSocketError !== 'object') {
|
||||
notifyUploadSocketError = $.notify({
|
||||
message: 'There was an error connecting to the Upload Socket for this server.'
|
||||
}, {
|
||||
type: 'danger',
|
||||
delay: 0
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// listen for a file being chosen
|
||||
$('#fileinput').change(function (event) {
|
||||
$('#uploader_box').trigger('drop', [event, event.currentTarget]);
|
||||
$('#fileinput').val('');
|
||||
uploadSocket.on('error', err => {
|
||||
siofu.destroy();
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
uploadSocket.on('connect', function () {
|
||||
if (notifyUploadSocketError !== false) {
|
||||
notifyUploadSocketError.close();
|
||||
notifyUploadSocketError = false;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', function (err) {
|
||||
console.error('There was an error while attemping to connect to the websocket: ' + err + '\n\nPlease try loading this page again.');
|
||||
});
|
||||
|
||||
|
||||
var siofu = new SocketIOFileUpload(uploadSocket);
|
||||
siofu.chunkDelay = 50;
|
||||
|
||||
document.getElementById("uploader_box").addEventListener("click", siofu.prompt, false);
|
||||
siofu.listenOnDrop(document.getElementById("uploader_box"));
|
||||
|
||||
siofu.addEventListener('start', function (event) {
|
||||
event.file.meta.path = $("#u_file_name").val();
|
||||
event.file.meta.identifier = Math.random().toString(36).slice(2);
|
||||
|
||||
$('#file_progress').append('<div class="well well-sm" id="file-upload-' + event.file.meta.identifier +'"> \
|
||||
<div class="row"> \
|
||||
<div class="col-md-12"> \
|
||||
<h6>Uploading ' + event.file.name + '</h6> \
|
||||
<span class="prog-bar-text-' + event.file.meta.identifier +'" style="font-size: 10px;position: absolute;margin: 3px 0 0 15px;">Waiting...</span> \
|
||||
<div class="progress progress-striped active"> \
|
||||
<div class="progress-bar progress-bar-info prog-bar-' + event.file.meta.identifier +'" style="width: 0%"></div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div>');
|
||||
});
|
||||
|
||||
siofu.addEventListener('progress', function(event) {
|
||||
console.log(event.file);
|
||||
var percent = event.bytesLoaded / event.file.size * 100;
|
||||
if (percent >= 100) {
|
||||
$('.prog-bar-text-' + event.file.meta.identifier).text('Upload Complete');
|
||||
$('.prog-bar-' + event.file.meta.identifier).css('width', '100%').removeClass('progress-bar-info').addClass('progress-bar-success').parent().removeClass('active progress-striped');
|
||||
$('.prog-bar-text-' + event.file.meta.identifier).parents().eq(2).delay(5000).slideUp();
|
||||
} else {
|
||||
$('.prog-bar-text-' + event.file.meta.identifier).text(Math.round(percent) + '%');
|
||||
$('.prog-bar-' + event.file.meta.identifier).css('width', percent + '%');
|
||||
}
|
||||
});
|
||||
|
||||
// Do something when a file is uploaded:
|
||||
siofu.addEventListener('complete', function(event){
|
||||
if (!event.success) {
|
||||
$("#upload_error").html('An error was encountered while attempting to upload this file. Does the target directory exist?').show();
|
||||
$("#file-upload-" + event.file.meta.identifier).hide();
|
||||
}
|
||||
});
|
||||
|
||||
siofu.addEventListener('error', function(event){
|
||||
$("#upload_error").html('An error was encountered while attempting to upload this file. Does the target directory exist?').show();
|
||||
$("#file-upload-" + event.file.meta.identifier).hide();
|
||||
});
|
||||
|
||||
// Deal with DOM quirks
|
||||
function doNothing (e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
@endcan
|
||||
|
||||
const Editor = ace.edit('fileContents');
|
||||
|
Loading…
Reference in New Issue
Block a user