diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe77d480..95ebf844b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/README.md b/README.md index 596309cf7..71970213c 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/public/css/jquery.terminal.css b/public/css/jquery.terminal.css new file mode 100755 index 000000000..c838aa0d3 --- /dev/null +++ b/public/css/jquery.terminal.css @@ -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 + * 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; +} diff --git a/public/js/jquery.mousewheel-min.js b/public/js/jquery.mousewheel-min.js new file mode 100755 index 000000000..1ff8c8749 --- /dev/null +++ b/public/js/jquery.mousewheel-min.js @@ -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); diff --git a/public/js/jquery.terminal-0.11.6.min.js b/public/js/jquery.terminal-0.11.6.min.js new file mode 100755 index 000000000..c0e461d5e --- /dev/null +++ b/public/js/jquery.terminal-0.11.6.min.js @@ -0,0 +1,37 @@ +/**@license + * __ _____ ________ __ + * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / + * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / + * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ + * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ + * \/ /____/ version 0.11.6 + * + * This file is part of jQuery Terminal. http://terminal.jcubic.pl + * + * Copyright (c) 2010-2016 Jakub Jankiewicz + * Released under the MIT license + * + * Contains: + * + * Storage plugin Distributed under the MIT License + * Copyright (c) 2010 Dave Schindler + * + * jQuery Timers licenced with the WTFPL + * + * + * Cross-Browser Split 1.1.1 + * Copyright 2007-2012 Steven Levithan + * Available under the MIT License + * + * jQuery Caret + * Copyright (c) 2009, Gideon Sireling + * 3 clause BSD License + * + * sprintf.js + * Copyright (c) 2007-2013 Alexandru Marasteanu + * licensed under 3 clause BSD license + * + * Date: Thu, 15 Sep 2016 20:19:15 +0000 + */ +(function(e){var n=function(){if(!n.cache.hasOwnProperty(arguments[0])){n.cache[arguments[0]]=n.parse(arguments[0])}return n.format.call(null,n.cache[arguments[0]],arguments)};n.format=function(e,r){var o=1,a=e.length,s="",l,f=[],c,u,h,p,m,g;for(c=0;c>>0;break;case"x":l=l.toString(16);break;case"X":l=l.toString(16).toUpperCase();break}l=/[def]/.test(h[8])&&h[3]&&l>=0?"+"+l:l;m=h[4]?h[4]=="0"?"0":h[4].charAt(1):" ";g=h[6]-String(l).length;p=h[6]?i(m,g):"";f.push(h[5]?l+p:p+l)}}return f.join("")};n.cache={};n.parse=function(e){var n=e,r=[],t=[],i=0;while(n){if((r=/^[^\x25]+/.exec(n))!==null){t.push(r[0])}else if((r=/^\x25{2}/.exec(n))!==null){t.push("%")}else if((r=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(n))!==null){if(r[2]){i|=1;var o=[],a=r[2],s=[];if((s=/^([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(s[1]);while((a=a.substring(s[0].length))!==""){if((s=/^\.([a-z_][a-z_\d]*)/i.exec(a))!==null){o.push(s[1])}else if((s=/^\[(\d+)\]/.exec(a))!==null){o.push(s[1])}else{throw"[sprintf] huh?"}}}else{throw"[sprintf] huh?"}r[2]=o}else{i|=2}if(i===3){throw"[sprintf] mixing positional and named placeholders is not (yet) supported"}t.push(r)}else{throw"[sprintf] huh?"}n=n.substring(r[0].length)}return t};var r=function(e,r,t){t=r.slice(0);t.splice(0,0,e);return n.apply(null,t)};function t(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}function i(e,n){for(var r=[];n>0;r[--n]=e){}return r.join("")}e.sprintf=n;e.vsprintf=r})(typeof global!="undefined"?global:window);(function(e,n){"use strict";e.omap=function(n,r){var t={};e.each(n,function(e,i){t[e]=r.call(n,e,i)});return t};var r={clone_object:function(n){var r={};if(typeof n=="object"){if(e.isArray(n)){return this.clone_array(n)}else if(n===null){return n}else{for(var t in n){if(e.isArray(n[t])){r[t]=this.clone_array(n[t])}else if(typeof n[t]=="object"){r[t]=this.clone_object(n[t])}else{r[t]=n[t]}}}}return r},clone_array:function(n){if(!e.isFunction(Array.prototype.map)){throw new Error("You'r browser don't support ES5 array map "+"use es5-shim")}return n.slice(0).map(function(e){if(typeof e=="object"){return this.clone_object(e)}else{return e}}.bind(this))}};var t=function(e){return r.clone_object(e)};var i=function(){var e="test",n=window.localStorage;try{n.setItem(e,"1");n.removeItem(e);return true}catch(r){return false}};var o=i();function a(e,n){var r;if(typeof e==="string"&&typeof n==="string"){localStorage[e]=n;return true}else if(typeof e==="object"&&typeof n==="undefined"){for(r in e){if(e.hasOwnProperty(r)){localStorage[r]=e[r]}}return true}return false}function s(e,n){var r,t,i;r=new Date;r.setTime(r.getTime()+31536e6);t="; expires="+r.toGMTString();if(typeof e==="string"&&typeof n==="string"){document.cookie=e+"="+n+t+"; path=/";return true}else if(typeof e==="object"&&typeof n==="undefined"){for(i in e){if(e.hasOwnProperty(i)){document.cookie=i+"="+e[i]+t+"; path=/"}}return true}return false}function l(e){return localStorage[e]}function f(e){var n,r,t,i;n=e+"=";r=document.cookie.split(";");for(t=0;ti&&i!==0||t.call(e,a)===false){h.timer.remove(e,r,t)}s.inProgress=false};s.$timerID=t.$timerID;if(!e.$timers[r][t.$timerID]){e.$timers[r][t.$timerID]=window.setInterval(s,n)}if(!this.global[r]){this.global[r]=[]}this.global[r].push(e)},remove:function(e,n,r){var t=e.$timers,i;if(t){if(!n){for(var o in t){if(t.hasOwnProperty(o)){this.remove(e,o,r)}}}else if(t[n]){if(r){if(r.$timerID){window.clearInterval(t[n][r.$timerID]);delete t[n][r.$timerID]}}else{for(var a in t[n]){if(t[n].hasOwnProperty(a)){window.clearInterval(t[n][a]);delete t[n][a]}}}for(i in t[n]){if(t[n].hasOwnProperty(i)){break}}if(!i){i=null;delete t[n]}}for(i in t){if(t.hasOwnProperty(i)){break}}if(!i){e.$timers=null}}}}});if(/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase())){h(window).one("unload",function(){var e=h.timer.global;for(var n in e){if(e.hasOwnProperty(n)){var r=e[n],t=r.length;while(--t){h.timer.remove(r[t],n)}}}})}(function(e){if(!String.prototype.split.toString().match(/\[native/)){return}var n=String.prototype.split,r=/()??/.exec("")[1]===e,t;t=function(t,i,o){if(Object.prototype.toString.call(i)!=="[object RegExp]"){return n.call(t,i,o)}var a=[],s=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.extended?"x":"")+(i.sticky?"y":""),l=0,f,c,u,h;i=new RegExp(i.source,s+"g");t+="";if(!r){f=new RegExp("^"+i.source+"$(?!\\s)",s)}o=o===e?-1>>>0:o>>>0;while(c=i.exec(t)){u=c.index+c[0].length;if(u>l){a.push(t.slice(l,c.index));if(!r&&c.length>1){c[0].replace(f,function(){for(var n=1;n1&&c.index=o){break}}if(i.lastIndex===c.index){i.lastIndex++}}if(l===t.length){if(h||!i.test("")){a.push("")}}else{a.push(t.slice(l))}return a.length>o?a.slice(0,o):a};String.prototype.split=function(e,n){return t(this,e,n)};return t})();e.fn.caret=function(e){var n=this[0];var r=n.contentEditable==="true";if(arguments.length==0){if(window.getSelection){if(r){n.focus();var t=window.getSelection().getRangeAt(0),i=t.cloneRange();i.selectNodeContents(n);i.setEnd(t.endContainer,t.endOffset);return i.toString().length}return n.selectionStart}if(document.selection){n.focus();if(r){var t=document.selection.createRange(),i=document.body.createTextRange();i.moveToElementText(n);i.setEndPoint("EndToEnd",t);return i.text.length}var e=0,o=n.createTextRange(),i=document.selection.createRange().duplicate(),a=i.getBookmark();o.moveToBookmark(a);while(o.moveStart("character",-1)!==0)e++;return e}return 0}if(e==-1)e=this[r?"text":"val"]().length;if(window.getSelection){if(r){n.focus();window.getSelection().collapse(n.firstChild,e)}else n.setSelectionRange(e,e)}else if(document.body.createTextRange){var o=document.body.createTextRange();o.moveToElementText(n);o.moveStart("character",e);o.collapse(true);o.select()}if(!r)n.focus();return e};function p(e,n){var r=[];var t=e.length;if(tr.length){if(n){break}e=0;n=true}}return r[e]}},append:function(e){r.push(e)}})}function g(n){var r=n instanceof Array?n:n?[n]:[];e.extend(this,{data:function(){return r},map:function(n){return e.map(r,n)},size:function(){return r.length},pop:function(){if(r.length===0){return null}else{var e=r[r.length-1];r=r.slice(0,r.length-1);return e}},push:function(e){r=r.concat([e]);return e},top:function(){return r.length>0?r[r.length-1]:null},clone:function(){return new g(r.slice(0))}})}e.json_stringify=function(r,t){var i="",o;t=t===n?1:t;var a=typeof r;switch(a){case"function":i+=r;break;case"boolean":i+=r?"true":"false";break;case"object":if(r===null){i+="null"}else if(r instanceof Array){i+="[";var s=r.length;for(o=0;o1?",":"";if(t===1){i=i.replace(/,([\]}])/g,"$1")}return i.replace(/([\[{]),/g,"$1")};function d(n,r){var t=true;var i="";if(typeof n==="string"&&n!==""){i=n+"_"}i+="commands";var o=e.Storage.get(i);o=o?e.parseJSON(o):[];var a=o.length-1;e.extend(this,{append:function(n){if(t){if(o[o.length-1]!==n){o.push(n);if(r&&o.length>r){o=o.slice(-r)}a=o.length-1;e.Storage.set(i,e.json_stringify(o))}}},data:function(){return o},reset:function(){a=o.length-1},last:function(){return o[length-1]},end:function(){return a===o.length-1},position:function(){return a},current:function(){return o[a]},next:function(){if(a0){--a}if(e!==-1){return o[a]}},clear:function(){o=[];this.purge()},enabled:function(){return t},enable:function(){t=true},purge:function(){e.Storage.remove(i)},disable:function(){t=false}})}var v=function(){var e=document.createElement("div");e.setAttribute("onpaste","return;");return typeof e.onpaste=="function"}();var y=true;e.fn.cmd=function(r){var t=this;var i=t.data("cmd");if(i){return i}t.addClass("cmd");t.append(''+' ');var o=e(" +
-
-
- @can('send-command', $server) - - - @endcan -
-
+

@can('power-start', $server)@endcan @can('power-restart', $server)@endcan @@ -130,12 +118,12 @@