1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-23 17:42:33 +01:00

Merge pull request #86 from Pterodactyl/feature/better-terminal

Add a better console page
This commit is contained in:
Dane Everitt 2016-09-16 15:49:05 -04:00 committed by GitHub
commit c97e0fedfb
9 changed files with 1246 additions and 86 deletions

View File

@ -12,7 +12,8 @@ Requires `Daemon@0.2.0`
* Adds support for suspending servers
* Adds support for viewing SFTP password within the panel ([#74](https://github.com/Pterodactyl/Panel/issues/74), thanks [@ET-Bent](https://github.com/ET-Bent))
* Improved API with support for server suspension and build modification.
* Improved service managment and setup on first install.
* Improved service management and setup on first install.
* New terminal that supports ANSI color codes as well as cleaner output. You can also simply type `start` or `boot` to start your server rather than having to use the start button.
### Bug Fixes
* Fixes password auto-generation on 'Manage Server' page. ([#67](https://github.com/Pterodactyl/Panel/issues/67), thanks [@ET-Bent](https://github.com/ET-Bent))

View File

@ -2,7 +2,7 @@
Pterodactyl is the free game server management panel designed by users, for users. Featuring support for Vanilla Minecraft, Spigot, Source Dedicated Servers, BungeeCord, and many more. Pterodactyl is built on the `Laravel PHP Framework (v5.2)`.
## Support & Documentation
Support for using Pterodactyl can be found on our [community forums](https://community.pterodactyl.io) or on our [Discord chat](https://discord.gg/0gYt8oU8QOkDhKLS).
Support for using Pterodactyl can be found on our [wiki](https://github.com/Pterodactyl/Panel/wiki) or on our [Discord chat](https://discord.gg/0gYt8oU8QOkDhKLS).
## License
```
@ -46,6 +46,8 @@ FuelUX - [license](https://github.com/ExactTarget/fuelux/blob/master/LICENSE) -
jQuery - [license](https://github.com/jquery/jquery/blob/master/LICENSE.txt) - [homepage](http://jquery.com)
jQuery Terminal - [license](https://github.com/jcubic/jquery.terminal/blob/master/LICENSE) - [homepage](http://terminal.jcubic.pl)
MetricsGraphics.js - [license](https://github.com/mozilla/metrics-graphics/blob/master/LICENSE) - [homepage](http://metricsgraphicsjs.org/)
Socket.io - [license](https://github.com/socketio/socket.io/blob/master/LICENSE) - [homepage](http://socket.io)

253
public/css/jquery.terminal.css Executable file
View File

@ -0,0 +1,253 @@
/*!
* __ _____ ________ __
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
* \/ /____/ version 0.11.6
* http://terminal.jcubic.pl
*
* This file is part of jQuery Terminal.
*
* Copyright (c) 2011-2016 Jakub Jankiewicz <http://jcubic.pl>
* Released under the MIT license
*
* Date: Thu, 15 Sep 2016 20:19:20 +0000
*/
.terminal .terminal-output .format, .cmd .format,
.cmd .prompt, .cmd .prompt div, .terminal .terminal-output div div{
display: inline-block;
}
.terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6, .terminal pre, .cmd {
margin: 0;
}
.terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6 {
line-height: 1.2em;
}
/*
.cmd .mask {
width: 10px;
height: 11px;
background: black;
z-index: 100;
}
*/
.cmd .clipboard {
position: absolute;
left: -16px;
top: 0;
width: 10px;
height: 16px;
/* this seems to work after all on Android */
/*left: -99999px;
clip: rect(1px,1px,1px,1px);
/* on desktop textarea appear when paste */
/*
opacity: 0.01;
filter: alpha(opacity = 0.01);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0.01);
*/
background: transparent;
border: none;
color: transparent;
outline: none;
padding: 0;
resize: none;
z-index: 0;
overflow: hidden;
}
.terminal .error {
color: #f00;
}
.terminal {
padding: 10px;
position: relative;
/*overflow: hidden;*/
overflow: auto;
}
.cmd {
padding: 0;
height: 1.3em;
position: relative;
/*margin-top: 3px; */
}
.terminal .inverted, .cmd .inverted, .cmd .cursor.blink {
background-color: #aaa;
color: #000;
}
.cmd .cursor.blink {
-webkit-animation: terminal-blink 1s infinite steps(1, start);
-moz-animation: terminal-blink 1s infinite steps(1, start);
-ms-animation: terminal-blink 1s infinite steps(1, start);
animation: terminal-blink 1s infinite steps(1, start);
}
@-webkit-keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb;
color: #000;
}
}
@-ms-keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb;
color: #000;
}
}
@-moz-keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb;
color: #000;
}
}
@keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb; /* not #aaa because it's seems there is Google Chrome bug */
color: #000;
}
}
.terminal .terminal-output div div, .cmd .prompt {
display: block;
line-height: 14px;
height: auto;
}
.cmd .prompt {
float: left;
}
.terminal, .cmd {
font-family: monospace;
/*font-family: FreeMono, monospace; this don't work on Android */
color: #aaa;
background-color: #000;
font-size: 12px;
line-height: 14px;
}
.terminal-output > div {
/*padding-top: 3px;*/
min-height: 14px;
}
.terminal-output > div > div * {
word-wrap: break-word; /* when echo html */
}
.terminal .terminal-output div span {
display: inline-block;
}
.cmd span {
float: left;
/*display: inline-block; */
}
/* fix double style of selecting text in terminal */
.terminal-output span, .terminal-output a, .cmd div, .cmd span, .terminal td,
.terminal pre, .terminal h1, .terminal h2, .terminal h3, .terminal h4,
.terminal h5, .terminal h6 {
-webkit-touch-callout: initial;
-webkit-user-select: initial;
-khtml-user-select: initial;
-moz-user-select: initial;
-ms-user-select: initial;
user-select: initial;
}
.terminal, .terminal-output, .terminal-output div {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* firefox hack */
@-moz-document url-prefix() {
.terminal, .terminal-output, .terminal-output div {
-webkit-touch-callout: initial;
-webkit-user-select: initial;
-khtml-user-select: initial;
-moz-user-select: initial;
-ms-user-select: initial;
user-select: initial;
}
}
.terminal table {
border-collapse: collapse;
}
.terminal td {
border: 1px solid #aaa;
}
.terminal h1::-moz-selection,
.terminal h2::-moz-selection,
.terminal h3::-moz-selection,
.terminal h4::-moz-selection,
.terminal h5::-moz-selection,
.terminal h6::-moz-selection,
.terminal pre::-moz-selection,
.terminal td::-moz-selection,
.terminal .terminal-output div div::-moz-selection,
.terminal .terminal-output div span::-moz-selection,
.terminal .terminal-output div div a::-moz-selection,
.cmd div::-moz-selection,
.cmd > span::-moz-selection,
.cmd .prompt span::-moz-selection {
background-color: #aaa;
color: #000;
}
/* this don't work in Chrome
.terminal tr td::-moz-selection {
border-color: #000;
}
.terminal tr td::selection {
border-color: #000;
}
*/
.terminal h1::selection,
.terminal h2::selection,
.terminal h3::selection,
.terminal h4::selection,
.terminal h5::selection,
.terminal h6::selection,
.terminal pre::selection,
.terminal td::selection,
.terminal .terminal-output div div::selection,
.terminal .terminal-output div div a::selection,
.terminal .terminal-output div span::selection,
.cmd div::selection,
.cmd > span::selection,
.cmd .prompt span::selection {
background-color: #aaa;
color: #000;
}
.terminal .terminal-output div.error, .terminal .terminal-output div.error div {
color: red;
}
.tilda {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1100;
}
.clear {
clear: both;
}
.terminal a {
color: #0F60FF;
}
.terminal a:hover {
color: red;
}

2
public/js/jquery.mousewheel-min.js vendored Executable file
View File

@ -0,0 +1,2 @@
(function(c){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),e=0,h=0,f=0;a=c.event.fix(b);a.type="mousewheel";if(b.wheelDelta)e=b.wheelDelta/120;if(b.detail)e=-b.detail/3;f=e;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){f=0;h=-1*e}if(b.wheelDeltaY!==undefined)f=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,e,h,f);return(c.event.dispatch||c.event.handle).apply(this,i)}var d=["DOMMouseScroll","mousewheel"];if(c.event.fixHooks)for(var j=d.length;j;)c.event.fixHooks[d[--j]]=
c.event.mouseHooks;c.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=d.length;a;)this.addEventListener(d[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=d.length;a;)this.removeEventListener(d[--a],g,false);else this.onmousewheel=null}};c.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);

37
public/js/jquery.terminal-0.11.6.min.js vendored Executable file

File diff suppressed because one or more lines are too long

317
public/js/unix_formatting.js Executable file
View File

@ -0,0 +1,317 @@
/**@license
* __ _____ ________ __
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
* \/ /____/
* http://terminal.jcubic.pl
*
* This is example of how to create custom formatter for jQuery Terminal
*
* Copyright (c) 2014-2016 Jakub Jankiewicz <http://jcubic.pl>
* Released under the MIT license
*
*/
(function($) {
if (!$.terminal) {
throw new Error('$.terminal is not defined');
}
// ---------------------------------------------------------------------
// :: Replace overtyping (from man) formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.overtyping = function(string) {
return string.replace(/((?:_\x08.|.\x08_)+)/g, function(full, g) {
var striped = full.replace(/_x08|\x08_|_\u0008|\u0008_/g, '');
return '[[u;;]' + striped + ']';
}).replace(/((?:.\x08.)+)/g, function(full, g) {
return '[[b;#fff;]' + full.replace(/(.)(?:\x08|\u0008)\1/g,
function(full, g) {
return g;
}) + ']';
});
};
// ---------------------------------------------------------------------
// :: Html colors taken from ANSI formatting in Linux Terminal
// ---------------------------------------------------------------------
$.terminal.ansi_colors = {
normal: {
black: '#000',
red: '#A00',
green: '#008400',
yellow: '#A50',
blue: '#00A',
magenta: '#A0A',
cyan: '#0AA',
white: '#AAA'
},
faited: {
black: '#000',
red: '#640000',
green: '#006100',
yellow: '#737300',
blue: '#000087',
magenta: '#650065',
cyan: '#008787',
white: '#818181'
},
bold: {
black: '#000',
red: '#F55',
green: '#44D544',
yellow: '#FF5',
blue: '#55F',
magenta: '#F5F',
cyan: '#5FF',
white: '#FFF'
},
// XTerm 8-bit pallete
palette: [
'#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
'#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
'#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
'#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
'#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
'#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
'#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
'#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
'#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
'#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
'#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
'#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
'#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
'#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
'#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
'#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
'#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
'#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
'#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
'#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
'#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
'#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
'#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
'#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
'#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
'#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
'#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
'#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
'#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
'#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
'#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
'#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
'#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
'#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
'#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
'#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
'#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
'#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
'#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
'#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
'#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
'#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
]
};
// ---------------------------------------------------------------------
// :: Replace ANSI formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.from_ansi = (function() {
var color_list = {
30: 'black',
31: 'red',
32: 'green',
33: 'yellow',
34: 'blue',
35: 'magenta',
36: 'cyan',
37: 'white',
39: 'inherit' // default color
};
var background_list = {
40: 'black',
41: 'red',
42: 'green',
43: 'yellow',
44: 'blue',
45: 'magenta',
46: 'cyan',
47: 'white',
49: 'transparent' // default background
};
function format_ansi(code) {
var controls = code.split(';');
var num;
var faited = false;
var reverse = false;
var bold = false;
var styles = [];
var output_color = '';
var output_background = '';
var _8bit_color = false;
var _8bit_background = false;
var process_8bit = false;
var palette = $.terminal.ansi_colors.palette;
for(var i in controls) {
if (controls.hasOwnProperty(i)) {
num = parseInt(controls[i], 10);
if (process_8bit && (_8bit_background || _8bit_color)) {
if (_8bit_color && palette[num]) {
output_color = palette[num];
}
if (_8bit_background && palette[num]) {
output_background = palette[num];
}
} else {
switch(num) {
case 1:
styles.push('b');
bold = true;
faited = false;
break;
case 4:
styles.push('u');
break;
case 3:
styles.push('i');
break;
case 5:
process_8bit = true;
break;
case 38:
_8bit_color = true;
break;
case 48:
_8bit_background = true;
break;
case 2:
faited = true;
bold = false;
break;
case 7:
reverse = true;
break;
default:
if (controls.indexOf('5') == -1) {
if (color_list[num]) {
output_color = color_list[num];
}
if (background_list[num]) {
output_background = background_list[num];
}
}
}
}
}
}
if (reverse) {
if (output_color || output_background) {
var tmp = output_background;
output_background = output_color;
output_color = tmp;
} else {
output_color = 'black';
output_background = 'white';
}
}
var colors, color, background, backgrounds;
if (bold) {
colors = backgrounds = $.terminal.ansi_colors.bold;
} else if (faited) {
colors = backgrounds = $.terminal.ansi_colors.faited;
} else {
colors = backgrounds = $.terminal.ansi_colors.normal;
}
if (_8bit_color) {
color = output_color;
} else if (output_color == 'inherit') {
color = output_color;
} else {
color = colors[output_color];
}
if (_8bit_background) {
background = output_background;
} else if (output_background == 'transparent') {
background = output_background;
} else {
background = backgrounds[output_background];
}
return [styles.join(''), color, background];
}
return function(input) {
//merge multiple codes
/*input = input.replace(/((?:\x1B\[[0-9;]*[A-Za-z])*)/g, function(group) {
return group.replace(/m\x1B\[/g, ';');
});*/
var splitted = input.split(/(\x1B\[[0-9;]*[A-Za-z])/g);
if (splitted.length == 1) {
return input;
}
var output = [];
//skip closing at the begining
if (splitted.length > 3) {
var str = splitted.slice(0,3).join('');
if (str.match(/^\[0*m$/)) {
splitted = splitted.slice(3);
}
}
var next, prev_color, prev_background, code, match;
var inside = false;
for (var i=0; i<splitted.length; ++i) {
match = splitted[i].match(/^\x1B\[([0-9;]*)([A-Za-z])$/);
if (match) {
switch (match[2]) {
case 'm':
if (+match[1] !== 0) {
code = format_ansi(match[1]);
}
if (inside) {
output.push(']');
if (+match[1] === 0) {
//just closing
inside = false;
prev_color = prev_background = '';
} else {
// someone forget to close - move to next
code[1] = code[1] || prev_color;
code[2] = code[2] || prev_background;
output.push('[[' + code.join(';') + ']');
// store colors to next use
if (code[1]) {
prev_color = code[1];
}
if (code[2]) {
prev_background = code[2];
}
}
} else {
if (+match[1] !== 0) {
inside = true;
code[1] = code[1] || prev_color;
code[2] = code[2] || prev_background;
output.push('[[' + code.join(';') + ']');
// store colors to next use
if (code[1]) {
prev_color = code[1];
}
if (code[2]) {
prev_background = code[2];
}
}
}
break;
}
} else {
output.push(splitted[i]);
}
}
if (inside) {
output.push(']');
}
return output.join(''); //.replace(/\[\[[^\]]+\]\]/g, '');
};
})();
$.terminal.defaults.formatters.push($.terminal.overtyping);
$.terminal.defaults.formatters.push($.terminal.from_ansi);
})(jQuery);

View File

@ -0,0 +1,252 @@
/*!
* __ _____ ________ __
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
* \/ /____/ version 0.11.6
* http://terminal.jcubic.pl
*
* This file is part of jQuery Terminal.
*
* Copyright (c) 2011-2016 Jakub Jankiewicz <http://jcubic.pl>
* Released under the MIT license
*
* Date: Thu, 15 Sep 2016 20:19:20 +0000
*/
.terminal .terminal-output .format, .cmd .format,
.cmd .prompt, .cmd .prompt div, .terminal .terminal-output div div{
display: inline-block;
}
.terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6, .terminal pre, .cmd {
margin: 0;
}
.terminal h1, .terminal h2, .terminal h3, .terminal h4, .terminal h5, .terminal h6 {
line-height: 1.2em;
}
/*
.cmd .mask {
width: 10px;
height: 11px;
background: black;
z-index: 100;
}
*/
.cmd .clipboard {
position: absolute;
left: -16px;
top: 0;
width: 10px;
height: 16px;
/* this seems to work after all on Android */
/*left: -99999px;
clip: rect(1px,1px,1px,1px);
/* on desktop textarea appear when paste */
/*
opacity: 0.01;
filter: alpha(opacity = 0.01);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0.01);
*/
background: transparent;
border: none;
color: transparent;
outline: none;
padding: 0;
resize: none;
z-index: 0;
overflow: hidden;
}
.terminal .error {
color: #f00;
}
.terminal {
padding: 10px;
position: relative;
/*overflow: hidden;*/
overflow: auto;
}
.cmd {
padding: 0;
height: 1.3em;
position: relative;
/*margin-top: 3px; */
}
.terminal .inverted, .cmd .inverted, .cmd .cursor.blink {
background-color: #f0f0f0;
color: #e8e8e6;
}
.cmd .cursor.blink {
-webkit-animation: terminal-blink 1s infinite steps(1, start);
-moz-animation: terminal-blink 1s infinite steps(1, start);
-ms-animation: terminal-blink 1s infinite steps(1, start);
animation: terminal-blink 1s infinite steps(1, start);
}
@-webkit-keyframes terminal-blink {
0%, 100% {
background-color: #f0f0f0;
color: #e8e8e6;
}
50% {
background-color: #bbb;
color: #000;
}
}
@-ms-keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb;
color: #000;
}
}
@-moz-keyframes terminal-blink {
0%, 100% {
background-color: #000;
color: #aaa;
}
50% {
background-color: #bbb;
color: #000;
}
}
@keyframes terminal-blink {
0%, 100% {
background-color: #f0f0f0;
color: #e8e8e6;
}
50% {
background-color: #bbb; /* not #aaa because it's seems there is Google Chrome bug */
color: #000;
}
}
.terminal .terminal-output div div, .cmd .prompt {
display: block;
line-height: 14px;
height: auto;
}
.cmd .prompt {
float: left;
}
.terminal, .cmd {
font-family: monospace;
/*font-family: FreeMono, monospace; this don't work on Android */
border-radius: 4px;
color: #f0f0f0 !important;
background-color: #2e2e2d !important;
font-size: 12px;
line-height: 14px;
}
.terminal-output > div {
/*padding-top: 3px;*/
min-height: 14px;
}
.terminal-output > div > div * {
word-wrap: break-word; /* when echo html */
}
.terminal .terminal-output div span {
display: inline-block;
}
.cmd span {
float: left;
/*display: inline-block; */
}
/* fix double style of selecting text in terminal */
.terminal-output span, .terminal-output a, .cmd div, .cmd span, .terminal td,
.terminal pre, .terminal h1, .terminal h2, .terminal h3, .terminal h4,
.terminal h5, .terminal h6 {
-webkit-touch-callout: initial;
-webkit-user-select: initial;
-khtml-user-select: initial;
-moz-user-select: initial;
-ms-user-select: initial;
user-select: initial;
}
.terminal, .terminal-output, .terminal-output div {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* firefox hack */
@-moz-document url-prefix() {
.terminal, .terminal-output, .terminal-output div {
-webkit-touch-callout: initial;
-webkit-user-select: initial;
-khtml-user-select: initial;
-moz-user-select: initial;
-ms-user-select: initial;
user-select: initial;
}
}
.terminal table {
border-collapse: collapse;
}
.terminal td {
border: 1px solid #aaa;
}
.terminal h1::-moz-selection,
.terminal h2::-moz-selection,
.terminal h3::-moz-selection,
.terminal h4::-moz-selection,
.terminal h5::-moz-selection,
.terminal h6::-moz-selection,
.terminal pre::-moz-selection,
.terminal td::-moz-selection,
.terminal .terminal-output div div::-moz-selection,
.terminal .terminal-output div span::-moz-selection,
.terminal .terminal-output div div a::-moz-selection,
.cmd div::-moz-selection,
.cmd > span::-moz-selection,
.cmd .prompt span::-moz-selection {
background-color: #f0f0f0;
color: #2e2e2d;
}
.terminal h1::selection,
.terminal h2::selection,
.terminal h3::selection,
.terminal h4::selection,
.terminal h5::selection,
.terminal h6::selection,
.terminal pre::selection,
.terminal td::selection,
.terminal .terminal-output div div::selection,
.terminal .terminal-output div div a::selection,
.terminal .terminal-output div span::selection,
.cmd div::selection,
.cmd > span::selection,
.cmd .prompt span::selection {
background-color: #f0f0f0;
color: #2e2e2d;
}
.terminal .terminal-output div.error, .terminal .terminal-output div.error div {
color: rgb(227, 50, 0);
}
.tilda {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1100;
}
.clear {
clear: both;
}
.terminal a {
color: #6cb2cc;
}
.terminal a:hover {
color: #39bfb4;
}

View File

@ -0,0 +1,317 @@
/**@license
* __ _____ ________ __
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
* \/ /____/
* http://terminal.jcubic.pl
*
* This is example of how to create custom formatter for jQuery Terminal
*
* Copyright (c) 2014-2016 Jakub Jankiewicz <http://jcubic.pl>
* Released under the MIT license
*
*/
(function($) {
if (!$.terminal) {
throw new Error('$.terminal is not defined');
}
// ---------------------------------------------------------------------
// :: Replace overtyping (from man) formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.overtyping = function(string) {
return string.replace(/((?:_\x08.|.\x08_)+)/g, function(full, g) {
var striped = full.replace(/_x08|\x08_|_\u0008|\u0008_/g, '');
return '[[u;;]' + striped + ']';
}).replace(/((?:.\x08.)+)/g, function(full, g) {
return '[[b;#fff;]' + full.replace(/(.)(?:\x08|\u0008)\1/g,
function(full, g) {
return g;
}) + ']';
});
};
// ---------------------------------------------------------------------
// :: Html colors taken from ANSI formatting in Linux Terminal
// ---------------------------------------------------------------------
$.terminal.ansi_colors = {
normal: {
black: '#2b2b2b',
red: '#c2292b',
green: '#568a34',
yellow: '#f5a536',
blue: '#2469bd',
magenta: '#692496',
cyan: '#18838c',
white: '#f0f0f0'
},
faited: {
black: '#2b2b2b',
red: '#c2292b',
green: '#568a34',
yellow: '#f5a536',
blue: '#2469bd',
magenta: '#692496',
cyan: '#18838c',
white: '#f0f0f0'
},
bold: {
black: '#2b2b2b',
red: '#c2292b',
green: '#568a34',
yellow: '#f5a536',
blue: '#2469bd',
magenta: '#692496',
cyan: '#18838c',
white: '#f0f0f0'
},
// XTerm 8-bit pallete
palette: [
'#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
'#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
'#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
'#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
'#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
'#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
'#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
'#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
'#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
'#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
'#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
'#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
'#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
'#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
'#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
'#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
'#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
'#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
'#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
'#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
'#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
'#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
'#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
'#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
'#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
'#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
'#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
'#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
'#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
'#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
'#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
'#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
'#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
'#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
'#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
'#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
'#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
'#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
'#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
'#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
'#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
'#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
]
};
// ---------------------------------------------------------------------
// :: Replace ANSI formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.from_ansi = (function() {
var color_list = {
30: 'black',
31: 'red',
32: 'green',
33: 'yellow',
34: 'blue',
35: 'magenta',
36: 'cyan',
37: 'white',
39: 'inherit' // default color
};
var background_list = {
40: 'black',
41: 'red',
42: 'green',
43: 'yellow',
44: 'blue',
45: 'magenta',
46: 'cyan',
47: 'white',
49: 'transparent' // default background
};
function format_ansi(code) {
var controls = code.split(';');
var num;
var faited = false;
var reverse = false;
var bold = false;
var styles = [];
var output_color = '';
var output_background = '';
var _8bit_color = false;
var _8bit_background = false;
var process_8bit = false;
var palette = $.terminal.ansi_colors.palette;
for(var i in controls) {
if (controls.hasOwnProperty(i)) {
num = parseInt(controls[i], 10);
if (process_8bit && (_8bit_background || _8bit_color)) {
if (_8bit_color && palette[num]) {
output_color = palette[num];
}
if (_8bit_background && palette[num]) {
output_background = palette[num];
}
} else {
switch(num) {
case 1:
styles.push('b');
bold = true;
faited = false;
break;
case 4:
styles.push('u');
break;
case 3:
styles.push('i');
break;
case 5:
process_8bit = true;
break;
case 38:
_8bit_color = true;
break;
case 48:
_8bit_background = true;
break;
case 2:
faited = true;
bold = false;
break;
case 7:
reverse = true;
break;
default:
if (controls.indexOf('5') == -1) {
if (color_list[num]) {
output_color = color_list[num];
}
if (background_list[num]) {
output_background = background_list[num];
}
}
}
}
}
}
if (reverse) {
if (output_color || output_background) {
var tmp = output_background;
output_background = output_color;
output_color = tmp;
} else {
output_color = 'black';
output_background = 'white';
}
}
var colors, color, background, backgrounds;
if (bold) {
colors = backgrounds = $.terminal.ansi_colors.bold;
} else if (faited) {
colors = backgrounds = $.terminal.ansi_colors.faited;
} else {
colors = backgrounds = $.terminal.ansi_colors.normal;
}
if (_8bit_color) {
color = output_color;
} else if (output_color == 'inherit') {
color = output_color;
} else {
color = colors[output_color];
}
if (_8bit_background) {
background = output_background;
} else if (output_background == 'transparent') {
background = output_background;
} else {
background = backgrounds[output_background];
}
return [styles.join(''), color, background];
}
return function(input) {
//merge multiple codes
/*input = input.replace(/((?:\x1B\[[0-9;]*[A-Za-z])*)/g, function(group) {
return group.replace(/m\x1B\[/g, ';');
});*/
var splitted = input.split(/(\x1B\[[0-9;]*[A-Za-z])/g);
if (splitted.length == 1) {
return input;
}
var output = [];
//skip closing at the begining
if (splitted.length > 3) {
var str = splitted.slice(0,3).join('');
if (str.match(/^\[0*m$/)) {
splitted = splitted.slice(3);
}
}
var next, prev_color, prev_background, code, match;
var inside = false;
for (var i=0; i<splitted.length; ++i) {
match = splitted[i].match(/^\x1B\[([0-9;]*)([A-Za-z])$/);
if (match) {
switch (match[2]) {
case 'm':
if (+match[1] !== 0) {
code = format_ansi(match[1]);
}
if (inside) {
output.push(']');
if (+match[1] === 0) {
//just closing
inside = false;
prev_color = prev_background = '';
} else {
// someone forget to close - move to next
code[1] = code[1] || prev_color;
code[2] = code[2] || prev_background;
output.push('[[' + code.join(';') + ']');
// store colors to next use
if (code[1]) {
prev_color = code[1];
}
if (code[2]) {
prev_background = code[2];
}
}
} else {
if (+match[1] !== 0) {
inside = true;
code[1] = code[1] || prev_color;
code[2] = code[2] || prev_background;
output.push('[[' + code.join(';') + ']');
// store colors to next use
if (code[1]) {
prev_color = code[1];
}
if (code[2]) {
prev_background = code[2];
}
}
}
break;
}
} else {
output.push(splitted[i]);
}
}
if (inside) {
output.push(']');
}
return output.join(''); //.replace(/\[\[[^\]]+\]\]/g, '');
};
})();
$.terminal.defaults.formatters.push($.terminal.overtyping);
$.terminal.defaults.formatters.push($.terminal.from_ansi);
})(jQuery);

View File

@ -26,15 +26,19 @@
@section('scripts')
@parent
{!! Theme::css('css/metricsgraphics.css') !!}
{!! Theme::css('css/jquery.terminal.css') !!}
{!! Theme::js('js/d3.min.js') !!}
{!! Theme::js('js/metricsgraphics.min.js') !!}
{!! Theme::js('js/async.min.js') !!}
{!! Theme::js('js/jquery.mousewheel-min.js') !!}
{!! Theme::js('js/jquery.terminal-0.11.6.min.js') !!}
{!! Theme::js('js/unix_formatting.js') !!}
@endsection
@section('content')
<div class="col-md-12">
<ul class="nav nav-tabs tabs_with_panel" id="config_tabs">
<li id="triggerConsoleView" class="active"><a href="#console" data-toggle="tab">{{ trans('server.index.control') }}</a></li>
<li class="active"><a href="#console" data-toggle="tab">{{ trans('server.index.control') }}</a></li>
@can('view-allocation', $server)<li><a href="#allocation" data-toggle="tab">{{ trans('server.index.allocation') }}</a></li>@endcan
</ul>
<div class="tab-content">
@ -44,25 +48,9 @@
<div class="panel-body">
<div class="row">
<div class="col-md-12">
<textarea id="live_console" class="form-control console" readonly="readonly">Loading Previous Content...</textarea>
<div id="terminal"></div>
</div>
<div class="col-md-6">
<hr />
@can('send-command', $server)
<form action="#" method="post" id="console_command" style="display:none;">
<fieldset>
<div class="input-group">
<input type="text" class="form-control" name="command" id="ccmd" placeholder="{{ trans('server.index.command') }}" />
<span class="input-group-btn">
<button id="sending_command" class="btn btn-primary btn-sm">&rarr;</button>
</span>
</div>
</fieldset>
</form>
<div class="alert alert-danger" id="sc_resp" style="display:none;margin-top: 15px;"></div>
@endcan
</div>
<div class="col-md-6" style="text-align:center;">
<div class="col-md-12" style="text-align:center;">
<hr />
@can('power-start', $server)<button class="btn btn-success btn-sm disabled" data-attr="power" data-action="start">Start</button>@endcan
@can('power-restart', $server)<button class="btn btn-primary btn-sm disabled" data-attr="power" data-action="restart">Restart</button>@endcan
@ -130,12 +118,12 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="PauseConsole">{{ trans('server.index.scrollstop') }}</h4>
<h4 class="modal-title" id="PauseConsole">ScrollStop&trade;</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<textarea id="paused_console" class="form-control console" readonly="readonly"></textarea>
<div id="paused_console" style="height: 300px; overflow-x: scroll;"></div>
</div>
</div>
</div>
@ -151,6 +139,51 @@
<script>
$(window).load(function () {
$('[data-toggle="tooltip"]').tooltip();
var initialStatusSent = false;
var currentStatus = 0;
var terminal = $('#terminal').terminal(function (command, term) {
@can('power-start', $server)
if (currentStatus === 0 && (command === 'start' || command === 'boot')) {
powerToggleServer('start');
}
@endcan
@can('send-command', $server)
if (currentStatus === 0 && !(command === 'start' || command === 'boot')) {
term.error('Server is currently off, type `start` or `boot` to start server.');
}
if (currentStatus !== 0 && command !== '') {
$.ajax({
type: 'POST',
headers: {
'X-Access-Token': '{{ $server->daemonSecret }}',
'X-Access-Server': '{{ $server->uuid }}'
},
contentType: 'application/json; charset=utf-8',
url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/command',
timeout: 10000,
data: JSON.stringify({ command: command })
}).fail(function (jqXHR) {
console.error(jqXHR);
var error = 'An error occured while trying to process this request.';
if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {
error = jqXHR.responseJSON.error;
}
term.error(error);
});
}
@else
term.error('You do not have permission to send commands to this server.');
@endcan
}, {
greetings: '',
name: '{{ $server->uuid }}',
height: 400,
prompt: '{{$server->name}}&#64;{{ $server->uuidShort }}:~$ ',
onBlur: function (terminal) {
return false;
}
});
var showOnlyTotal = true;
$('[data-action="show-all-cores"]').click(function (event) {
@ -311,12 +344,13 @@ $(window).load(function () {
// New Console Data Recieved
socket.on('console', function (data) {
$('#live_console').val($('#live_console').val() + data.line);
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
terminal.echo(data.line);
});
// Update Listings on Initial Status
socket.on('initial_status', function (data) {
currentStatus = data.status;
console.log(data.status);
if (data.status !== 0) {
$.ajax({
type: 'GET',
@ -327,13 +361,10 @@ $(window).load(function () {
url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/log',
timeout: 10000
}).done(function(data) {
$('#live_console').val(data);
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
}).fail(function(jqXHR, textStatus, errorThrown) {
alert('Unable to load initial server log, try reloading the page.');
terminal.echo(data);
}).fail(function() {
terminal.error('Unable to load initial server log, try reloading the page.');
});
} else {
$('#live_console').val('Server is currently off.');
}
updateServerPowerControls(data.status);
updatePlayerListVisibility(data.status);
@ -341,24 +372,14 @@ $(window).load(function () {
// Update Listings on Status
socket.on('status', function (data) {
currentStatus = data.status;
updateServerPowerControls(data.status);
updatePlayerListVisibility(data.status);
});
// Scroll to the top of the Console when switching to that tab.
$('#triggerConsoleView').click(function () {
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
});
if($('triggerConsoleView').is(':visible')) {
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
}
$('a[data-toggle=\'tab\']').on('shown.bs.tab', function (e) {
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
});
// Load Paused Console with Live Console Data
$('#pause_console').click(function(){
$('#paused_console').val($('#live_console').val());
$('#paused_console').html($('#terminal').html());
});
function updatePlayerListVisibility(data) {
@ -413,61 +434,19 @@ $(window).load(function () {
});
@endcan
@can('send-command', $server)
// Send Command to Server
$('#console_command').submit(function (event) {
event.preventDefault();
var ccmd = $('#ccmd').val();
if (ccmd == '') {
return;
}
$('#sending_command').html('<i class=\'fa fa-refresh fa-spin\'></i>').addClass('disabled');
$.ajax({
type: 'POST',
headers: {
'X-Access-Token': '{{ $server->daemonSecret }}',
'X-Access-Server': '{{ $server->uuid }}'
},
contentType: 'application/json; charset=utf-8',
url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server/command',
timeout: 10000,
data: JSON.stringify({ command: ccmd })
}).fail(function (jqXHR) {
console.error(jqXHR);
var error = 'An error occured while trying to process this request.';
if (typeof jqXHR.responseJSON !== 'undefined' && typeof jqXHR.responseJSON.error !== 'undefined') {
error = jqXHR.responseJSON.error;
}
swal({
type: 'error',
title: 'Whoops!',
text: error
});
}).done(function () {
$('#ccmd').val('');
}).always(function () {
$('#sending_command').html('&rarr;').removeClass('disabled');
});
});
@endcan
var can_run = true;
function updateServerPowerControls (data) {
// Reset Console Data
if (data === 2) {
$('#live_console').val($('#live_console').val() + '\n --+ Server Detected as Booting + --\n');
$('#live_console').scrollTop($('#live_console')[0].scrollHeight);
terminal.echo('\n[Daemon] -- + Server Detected as Booting + --\n');
}
// Server is On or Starting
if(data == 1 || data == 2) {
$("#console_command").slideDown();
$('[data-attr="power"][data-action="start"]').addClass('disabled');
$('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').removeClass('disabled');
} else {
$("#console_command").slideUp();
$('[data-attr="power"][data-action="start"]').removeClass('disabled');
$('[data-attr="power"][data-action="stop"], [data-attr="power"][data-action="restart"]').addClass('disabled');
}