mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
aaPanel 6.6.9
Optimize PHP Manager Optimize file manager move file logic Optimize online editor
This commit is contained in:
-104
@@ -1,104 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* Implements the attach method, that attaches the terminal to a WebSocket stream.
|
||||
*/
|
||||
|
||||
(function (attach) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = attach(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], attach);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
attach(window.Terminal);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Attaches the given terminal to the given socket.
|
||||
*
|
||||
* @param {Terminal} term - The terminal to be attached to the given socket.
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
exports.attach = function (term, socket, bidirectional, buffered) {
|
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
|
||||
term.socket = socket;
|
||||
|
||||
term._flushBuffer = function () {
|
||||
term.write(term._attachSocketBuffer);
|
||||
term._attachSocketBuffer = null;
|
||||
};
|
||||
|
||||
term._pushToBuffer = function (data) {
|
||||
if (term._attachSocketBuffer) {
|
||||
term._attachSocketBuffer += data;
|
||||
} else {
|
||||
term._attachSocketBuffer = data;
|
||||
setTimeout(term._flushBuffer, 10);
|
||||
}
|
||||
};
|
||||
|
||||
var myTextDecoder;
|
||||
|
||||
term._getMessage = function (ev) {
|
||||
var str;
|
||||
if (typeof ev.data === "object") {
|
||||
if (ev.data instanceof ArrayBuffer) {
|
||||
if (!myTextDecoder) {
|
||||
myTextDecoder = new TextDecoder();
|
||||
}
|
||||
|
||||
str = myTextDecoder.decode( ev.data );
|
||||
}
|
||||
else {
|
||||
throw "TODO: handle Blob?";
|
||||
}
|
||||
}
|
||||
|
||||
if (buffered) {
|
||||
term._pushToBuffer(str || ev.data);
|
||||
} else {
|
||||
term.write(str || ev.data);
|
||||
}
|
||||
};
|
||||
|
||||
term._sendData = function (data) {
|
||||
socket.send(data);
|
||||
};
|
||||
|
||||
socket.addEventListener('message', term._getMessage);
|
||||
|
||||
if (bidirectional) {
|
||||
term.on('data', term._sendData);
|
||||
}
|
||||
|
||||
socket.addEventListener('close', term.detach.bind(term, socket));
|
||||
socket.addEventListener('error', term.detach.bind(term, socket));
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the given terminal from the given socket
|
||||
*
|
||||
* @param {Terminal} term - The terminal to be detached from the given socket.
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
exports.detach = function (term, socket) {
|
||||
term.off('data', term._sendData);
|
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket;
|
||||
|
||||
if (socket) {
|
||||
socket.removeEventListener('message', term._getMessage);
|
||||
}
|
||||
|
||||
delete term.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches the current terminal to the given socket
|
||||
*
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
Terminal.prototype.attach = function (socket, bidirectional, buffered) {
|
||||
return exports.attach(this, socket, bidirectional, buffered);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the current terminal from the given socket.
|
||||
*
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
Terminal.prototype.detach = function (socket) {
|
||||
return exports.detach(this, socket);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).attach=e()}}(function(){return function f(a,i,u){function s(t,e){if(!i[t]){if(!a[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(c)return c(t,!0);var r=new Error("Cannot find module '"+t+"'");throw r.code="MODULE_NOT_FOUND",r}var o=i[t]={exports:{}};a[t][0].call(o.exports,function(e){return s(a[t][1][e]||e)},o,o.exports,f,a,i,u)}return i[t].exports}for(var c="function"==typeof require&&require,e=0;e<u.length;e++)s(u[e]);return s}({1:[function(e,t,n){"use strict";function r(e,t,n,r){var o,f=e;function a(e,t){r?f.__pushToBuffer(e||t):f.write(e||t)}n=void 0===n||n,f.__socket=t,f.__flushBuffer=function(){f.write(f.__attachSocketBuffer),f.__attachSocketBuffer=null},f.__pushToBuffer=function(e){f.__attachSocketBuffer?f.__attachSocketBuffer+=e:(f.__attachSocketBuffer=e,setTimeout(f.__flushBuffer,10))},f.__getMessage=function(e){if("object"==typeof e.data)if(o=o||new TextDecoder,e.data instanceof ArrayBuffer)a(o.decode(e.data));else{var t=new FileReader;t.addEventListener("load",function(){a(o.decode(t.result))}),t.readAsArrayBuffer(e.data)}else{if("string"!=typeof e.data)throw Error('Cannot handle "'+typeof e.data+'" websocket message.');a(e.data)}},f.__sendData=function(e){1===t.readyState&&t.send(e)},f._core.register(i(t,"message",f.__getMessage)),n&&(f.__dataListener=f.onData(f.__sendData),f._core.register(f.__dataListener)),f._core.register(i(t,"close",function(){return u(f,t)})),f._core.register(i(t,"error",function(){return u(f,t)}))}function i(e,t,n){return e.addEventListener(t,n),{dispose:function(){n&&(e.removeEventListener(t,n),n=null)}}}function u(e,t){var n=e;n.__dataListener.dispose(),(t=(n.__dataListener=void 0)===t?n.__socket:t)&&t.removeEventListener("message",n.__getMessage),delete n.__socket}Object.defineProperty(n,"__esModule",{value:!0}),n.attach=r,n.detach=u,n.apply=function(e){e.prototype.attach=function(e,t,n){r(this,e,t,n)},e.prototype.detach=function(e){u(this,e)}}},{}]},{},[1])(1)});
|
||||
@@ -0,0 +1,93 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../src/xterm.css" />
|
||||
<link rel="stylesheet" href="../../demo/style.css" />
|
||||
<script src="../../src/xterm.js"></script>
|
||||
<script src="attach.js"></script>
|
||||
<style>
|
||||
body {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
color: #444;
|
||||
border-bottom: 1px solid #ddd;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
input, button {
|
||||
line-height: 22px;
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
input {
|
||||
height: 22px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 28px;
|
||||
background-color: #ccc;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<h1>
|
||||
xterm.js: socket attach
|
||||
</h1>
|
||||
<p>
|
||||
Attach the terminal to a WebSocket terminal stream with ease. Perfect for attaching to your
|
||||
Docker containers.
|
||||
</p>
|
||||
<h2>
|
||||
Socket information
|
||||
</h2>
|
||||
<form id="socket-form">
|
||||
<input id="socket-url"
|
||||
type="text"
|
||||
placeholder="Enter socket url (e.g. ws://mysock)"
|
||||
autofocus />
|
||||
<button>
|
||||
Attach
|
||||
</button>
|
||||
</form>
|
||||
<div id="terminal-container"></div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
var term = new Terminal(),
|
||||
container = document.getElementById('terminal-container'),
|
||||
socketUrl = document.getElementById('socket-url'),
|
||||
socketForm = document.getElementById('socket-form');
|
||||
|
||||
socketForm.addEventListener('submit', function (ev) {
|
||||
ev.preventDefault();
|
||||
var url = socketUrl.value,
|
||||
sock = new WebSocket(url);
|
||||
sock.addEventListener('open', function () {
|
||||
term.attach(sock);
|
||||
});
|
||||
});
|
||||
|
||||
term.open(container);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "xterm.attach",
|
||||
"main": "attach.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* Fit terminal columns and rows to the dimensions of its DOM element.
|
||||
*
|
||||
* ## Approach
|
||||
*
|
||||
* Rows: Truncate the division of the terminal parent element height by the
|
||||
* terminal row height.
|
||||
* Columns: Truncate the division of the terminal parent element width by the
|
||||
* terminal character width (apply display: inline at the terminal
|
||||
* row and truncate its width with the current number of columns).
|
||||
*/
|
||||
|
||||
(function (fit) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fit(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fit);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fit(window.Terminal);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
var exports = {};
|
||||
|
||||
exports.proposeGeometry = function (term) {
|
||||
if (!term.element.parentElement) {
|
||||
return null;
|
||||
}
|
||||
var parentElementStyle = window.getComputedStyle(term.element.parentElement);
|
||||
var parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
||||
var parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17);
|
||||
var elementStyle = window.getComputedStyle(term.element);
|
||||
var elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom'));
|
||||
var elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left'));
|
||||
var availableHeight = parentElementHeight - elementPaddingVer;
|
||||
var availableWidth = parentElementWidth - elementPaddingHor;
|
||||
var geometry = {
|
||||
cols: Math.floor(availableWidth / term.charMeasure.width),
|
||||
rows: Math.floor(availableHeight / Math.floor(term.charMeasure.height * term.getOption('lineHeight')))
|
||||
};
|
||||
|
||||
return geometry;
|
||||
};
|
||||
|
||||
exports.fit = function (term) {
|
||||
// Wrap fit in a setTimeout as charMeasure needs time to get initialized
|
||||
// after calling Terminal.open
|
||||
setTimeout(function () {
|
||||
var geometry = exports.proposeGeometry(term);
|
||||
|
||||
if (geometry) {
|
||||
// Force a full render
|
||||
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
|
||||
term.renderer.clear();
|
||||
term.resize(geometry.cols, geometry.rows);
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
Terminal.prototype.proposeGeometry = function () {
|
||||
return exports.proposeGeometry(this);
|
||||
};
|
||||
|
||||
Terminal.prototype.fit = function () {
|
||||
return exports.fit(this);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).fit=e()}}(function(){return function i(l,u,f){function p(t,e){if(!u[t]){if(!l[t]){var r="function"==typeof require&&require;if(!e&&r)return r(t,!0);if(a)return a(t,!0);var o=new Error("Cannot find module '"+t+"'");throw o.code="MODULE_NOT_FOUND",o}var n=u[t]={exports:{}};l[t][0].call(n.exports,function(e){return p(l[t][1][e]||e)},n,n.exports,i,l,u,f)}return u[t].exports}for(var a="function"==typeof require&&require,e=0;e<f.length;e++)p(f[e]);return p}({1:[function(e,t,r){"use strict";function o(e){if(!e.element.parentElement)return null;var t=window.getComputedStyle(e.element.parentElement),r=parseInt(t.getPropertyValue("height")),o=Math.max(0,parseInt(t.getPropertyValue("width"))),n=window.getComputedStyle(e.element),i=r-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),l=o-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-e._core.viewport.scrollBarWidth;return{cols:Math.floor(l/e._core._renderCoordinator.dimensions.actualCellWidth),rows:Math.floor(i/e._core._renderCoordinator.dimensions.actualCellHeight)}}function n(e){var t=o(e);t&&(e.rows===t.rows&&e.cols===t.cols||(e._core._renderCoordinator.clear(),e.resize(t.cols,t.rows)))}Object.defineProperty(r,"__esModule",{value:!0}),r.proposeGeometry=o,r.fit=n,r.apply=function(e){e.prototype.proposeGeometry=function(){return o(this)},e.prototype.fit=function(){n(this)}}},{}]},{},[1])(1)});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "xterm.fit",
|
||||
"main": "fit.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.xterm.fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
z-index: 255;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (fullscreen) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fullscreen(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fullscreen);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fullscreen(window.Terminal);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Toggle the given terminal's fullscreen mode.
|
||||
* @param {Terminal} term - The terminal to toggle full screen mode
|
||||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false)
|
||||
*/
|
||||
exports.toggleFullScreen = function (term, fullscreen) {
|
||||
var fn;
|
||||
|
||||
if (typeof fullscreen == 'undefined') {
|
||||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add';
|
||||
} else if (!fullscreen) {
|
||||
fn = 'remove';
|
||||
} else {
|
||||
fn = 'add';
|
||||
}
|
||||
|
||||
term.element.classList[fn]('fullscreen');
|
||||
};
|
||||
|
||||
Terminal.prototype.toggleFullscreen = function (fullscreen) {
|
||||
exports.toggleFullScreen(this, fullscreen);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
.xterm.fullscreen{position:fixed;top:0;bottom:0;left:0;right:0;width:auto;height:auto;z-index:255}
|
||||
/*# sourceMappingURL=fullscreen.min.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).fullscreen=e()}}(function(){return function i(f,l,s){function u(n,e){if(!l[n]){if(!f[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(c)return c(n,!0);var o=new Error("Cannot find module '"+n+"'");throw o.code="MODULE_NOT_FOUND",o}var r=l[n]={exports:{}};f[n][0].call(r.exports,function(e){return u(f[n][1][e]||e)},r,r.exports,i,f,l,s)}return l[n].exports}for(var c="function"==typeof require&&require,e=0;e<s.length;e++)u(s[e]);return u}({1:[function(e,n,t){"use strict";function o(e,n){(void 0===n?e.element.classList.contains("fullscreen")?e.element.classList.remove:e.element.classList.add:n?e.element.classList.add:e.element.classList.remove).bind(e.element.classList)("fullscreen")}Object.defineProperty(t,"__esModule",{value:!0}),t.toggleFullScreen=o,t.apply=function(e){e.prototype.toggleFullScreen=function(e){o(this,e)}}},{}]},{},[1])(1)});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "xterm.fullscreen",
|
||||
"main": "fullscreen.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var SearchHelper = (function () {
|
||||
function SearchHelper(_terminal) {
|
||||
this._terminal = _terminal;
|
||||
}
|
||||
SearchHelper.prototype.findNext = function (term) {
|
||||
if (!term || term.length === 0) {
|
||||
return false;
|
||||
}
|
||||
var result;
|
||||
var startRow = this._terminal.buffer.ydisp;
|
||||
if (this._terminal.selectionManager.selectionEnd) {
|
||||
startRow = this._terminal.selectionManager.selectionEnd[1];
|
||||
}
|
||||
for (var y = startRow + 1; y < this._terminal.buffer.ybase + this._terminal.rows; y++) {
|
||||
result = this._findInLine(term, y);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
for (var y = 0; y < startRow; y++) {
|
||||
result = this._findInLine(term, y);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._selectResult(result);
|
||||
};
|
||||
SearchHelper.prototype.findPrevious = function (term) {
|
||||
if (!term || term.length === 0) {
|
||||
return false;
|
||||
}
|
||||
var result;
|
||||
var startRow = this._terminal.buffer.ydisp;
|
||||
if (this._terminal.selectionManager.selectionStart) {
|
||||
startRow = this._terminal.selectionManager.selectionStart[1];
|
||||
}
|
||||
for (var y = startRow - 1; y >= 0; y--) {
|
||||
result = this._findInLine(term, y);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
for (var y = this._terminal.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) {
|
||||
result = this._findInLine(term, y);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._selectResult(result);
|
||||
};
|
||||
SearchHelper.prototype._findInLine = function (term, y) {
|
||||
var lowerStringLine = this._terminal.buffer.translateBufferLineToString(y, true).toLowerCase();
|
||||
var lowerTerm = term.toLowerCase();
|
||||
var searchIndex = lowerStringLine.indexOf(lowerTerm);
|
||||
if (searchIndex >= 0) {
|
||||
return {
|
||||
term: term,
|
||||
col: searchIndex,
|
||||
row: y
|
||||
};
|
||||
}
|
||||
};
|
||||
SearchHelper.prototype._selectResult = function (result) {
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length);
|
||||
this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp, false);
|
||||
return true;
|
||||
};
|
||||
return SearchHelper;
|
||||
}());
|
||||
exports.SearchHelper = SearchHelper;
|
||||
|
||||
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var SearchHelper_1 = require("./SearchHelper");
|
||||
(function (addon) {
|
||||
if (typeof window !== 'undefined' && 'Terminal' in window) {
|
||||
addon(window.Terminal);
|
||||
}
|
||||
else if (typeof exports === 'object' && typeof module === 'object') {
|
||||
module.exports = addon(require('../../Terminal').Terminal);
|
||||
}
|
||||
else if (typeof define === 'function') {
|
||||
define(['../../xterm'], addon);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
Terminal.prototype.findNext = function (term) {
|
||||
if (!this._searchHelper) {
|
||||
this.searchHelper = new SearchHelper_1.SearchHelper(this);
|
||||
}
|
||||
return this.searchHelper.findNext(term);
|
||||
};
|
||||
Terminal.prototype.findPrevious = function (term) {
|
||||
if (!this._searchHelper) {
|
||||
this.searchHelper = new SearchHelper_1.SearchHelper(this);
|
||||
}
|
||||
return this.searchHelper.findPrevious(term);
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
|
||||
},{"../../Terminal":undefined,"./SearchHelper":1}]},{},[2])
|
||||
//# sourceMappingURL=search.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "xterm.terminado",
|
||||
"main": "terminado.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* This module provides methods for attaching a terminal to a terminado
|
||||
* WebSocket stream.
|
||||
*/
|
||||
|
||||
(function (attach) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = attach(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], attach);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
attach(window.Terminal);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Attaches the given terminal to the given socket.
|
||||
*
|
||||
* @param {Terminal} term - The terminal to be attached to the given socket.
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) {
|
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
|
||||
term.socket = socket;
|
||||
|
||||
term._flushBuffer = function () {
|
||||
term.write(term._attachSocketBuffer);
|
||||
term._attachSocketBuffer = null;
|
||||
};
|
||||
|
||||
term._pushToBuffer = function (data) {
|
||||
if (term._attachSocketBuffer) {
|
||||
term._attachSocketBuffer += data;
|
||||
} else {
|
||||
term._attachSocketBuffer = data;
|
||||
setTimeout(term._flushBuffer, 10);
|
||||
}
|
||||
};
|
||||
|
||||
term._getMessage = function (ev) {
|
||||
var data = JSON.parse(ev.data)
|
||||
if( data[0] == "stdout" ) {
|
||||
if (buffered) {
|
||||
term._pushToBuffer(data[1]);
|
||||
} else {
|
||||
term.write(data[1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
term._sendData = function (data) {
|
||||
socket.send(JSON.stringify(['stdin', data]));
|
||||
};
|
||||
|
||||
term._setSize = function (size) {
|
||||
socket.send(JSON.stringify(['set_size', size.rows, size.cols]));
|
||||
};
|
||||
|
||||
socket.addEventListener('message', term._getMessage);
|
||||
|
||||
if (bidirectional) {
|
||||
term.on('data', term._sendData);
|
||||
}
|
||||
term.on('resize', term._setSize);
|
||||
|
||||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket));
|
||||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket));
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the given terminal from the given socket
|
||||
*
|
||||
* @param {Xterm} term - The terminal to be detached from the given socket.
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
exports.terminadoDetach = function (term, socket) {
|
||||
term.off('data', term._sendData);
|
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket;
|
||||
|
||||
if (socket) {
|
||||
socket.removeEventListener('message', term._getMessage);
|
||||
}
|
||||
|
||||
delete term.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches the current terminal to the given socket
|
||||
*
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
Terminal.prototype.terminadoAttach = function (socket, bidirectional, buffered) {
|
||||
return exports.terminadoAttach(this, socket, bidirectional, buffered);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the current terminal from the given socket.
|
||||
*
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
Terminal.prototype.terminadoDetach = function (socket) {
|
||||
return exports.terminadoDetach(this, socket);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).terminado=e()}}(function(){return function i(f,s,u){function a(t,e){if(!s[t]){if(!f[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(_)return _(t,!0);var r=new Error("Cannot find module '"+t+"'");throw r.code="MODULE_NOT_FOUND",r}var o=s[t]={exports:{}};f[t][0].call(o.exports,function(e){return a(f[t][1][e]||e)},o,o.exports,i,f,s,u)}return s[t].exports}for(var _="function"==typeof require&&require,e=0;e<u.length;e++)a(u[e]);return a}({1:[function(e,t,n){"use strict";function r(e,t,n,r){var o=e;n=void 0===n||n,o.__socket=t,o.__flushBuffer=function(){o.write(o.__attachSocketBuffer),o.__attachSocketBuffer=null},o.__pushToBuffer=function(e){o.__attachSocketBuffer?o.__attachSocketBuffer+=e:(o.__attachSocketBuffer=e,setTimeout(o.__flushBuffer,10))},o.__getMessage=function(e){var t=JSON.parse(e.data);"stdout"===t[0]&&(r?o.__pushToBuffer(t[1]):o.write(t[1]))},o.__sendData=function(e){t.send(JSON.stringify(["stdin",e]))},o.__setSize=function(e){t.send(JSON.stringify(["set_size",e.rows,e.cols]))},t.addEventListener("message",o.__getMessage),n&&o._core.register(o.onData(o.__sendData)),o._core.register(o.onResize(o.__setSize)),t.addEventListener("close",function(){return i(o,t)}),t.addEventListener("error",function(){return i(o,t)})}function i(e,t){var n=e;n.__dataListener.dispose(),(t=(n.__dataListener=void 0)===t?n.__socket:t)&&t.removeEventListener("message",n.__getMessage),delete n.__socket}Object.defineProperty(n,"__esModule",{value:!0}),n.terminadoAttach=r,n.terminadoDetach=i,n.apply=function(e){e.prototype.terminadoAttach=function(e,t,n){return r(this,e,t,n)},e.prototype.terminadoDetach=function(e){return i(this,e)}}},{}]},{},[1])(1)});
|
||||
@@ -0,0 +1,29 @@
|
||||
(function (addon) {
|
||||
if (typeof window !== 'undefined' && 'Terminal' in window) {
|
||||
addon(window.Terminal);
|
||||
}
|
||||
else if (typeof exports === 'object' && typeof module === 'object') {
|
||||
module.exports = addon(require('../../Terminal').Terminal);
|
||||
}
|
||||
else if (typeof define === 'function') {
|
||||
define(['../../xterm'], addon);
|
||||
}
|
||||
})(function (Terminal) {
|
||||
Terminal.prototype.winptyCompatInit = function () {
|
||||
var _this = this;
|
||||
var isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
|
||||
if (!isWindows) {
|
||||
return;
|
||||
}
|
||||
this.on('lineFeed', function () {
|
||||
var line = _this.buffer.lines.get(_this.buffer.ybase + _this.buffer.y - 1);
|
||||
var lastChar = line[_this.cols - 1];
|
||||
if (lastChar[3] !== 32) {
|
||||
var nextLine = _this.buffer.lines.get(_this.buffer.ybase + _this.buffer.y);
|
||||
nextLine.isWrapped = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
//# sourceMappingURL=winptyCompat.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../../src/addons/winptyCompat/winptyCompat.ts"],"names":[],"mappings":"AAQA,CAAC,UAAU,KAAK;IACd,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,WAAW,IAAI,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC;QAI1D,KAAK,CAAO,MAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC;QAIrE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC;QAIxC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC,CAAC,CAAC,UAAC,QAAa;IACf,QAAQ,CAAC,SAAS,CAAC,gBAAgB,GAAG;QAAA,iBAyBrC;QAvBC,IAAM,SAAS,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1F,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC;QACT,CAAC;QAYD,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE;YAClB,IAAM,IAAI,GAAG,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1E,IAAM,QAAQ,GAAG,IAAI,CAAC,KAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;YACrC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAY,CAAC,CAAC,CAAC;gBACjC,IAAM,QAAQ,GAAG,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACpE,QAAS,CAAC,SAAS,GAAG,IAAI,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","file":"winptyCompat.js","sourceRoot":"."}
|
||||
@@ -0,0 +1,87 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var expressWs = require('express-ws')(app);
|
||||
var os = require('os');
|
||||
var pty = require('node-pty');
|
||||
|
||||
var terminals = {},
|
||||
logs = {};
|
||||
|
||||
app.use('/build', express.static(__dirname + '/../../../../build'));
|
||||
app.use('/demo', express.static(__dirname + '/../../../../demo'));
|
||||
app.use('/zmodemjs', express.static(__dirname + '/../../../../node_modules/zmodem.js/dist'));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.sendFile(__dirname + '/index.html');
|
||||
});
|
||||
|
||||
app.get('/style.css', function(req, res){
|
||||
res.sendFile(__dirname + '/style.css');
|
||||
});
|
||||
|
||||
app.get('/main.js', function(req, res){
|
||||
res.sendFile(__dirname + '/main.js');
|
||||
});
|
||||
|
||||
app.post('/terminals', function (req, res) {
|
||||
var cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
encoding: null,
|
||||
name: 'xterm-color',
|
||||
cols: cols || 80,
|
||||
rows: rows || 24,
|
||||
cwd: process.env.PWD,
|
||||
env: process.env
|
||||
});
|
||||
|
||||
console.log('Created terminal with PID: ' + term.pid);
|
||||
terminals[term.pid] = term;
|
||||
logs[term.pid] = '';
|
||||
term.on('data', function(data) {
|
||||
logs[term.pid] += data;
|
||||
});
|
||||
res.send(term.pid.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.post('/terminals/:pid/size', function (req, res) {
|
||||
var pid = parseInt(req.params.pid),
|
||||
cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = terminals[pid];
|
||||
|
||||
term.resize(cols, rows);
|
||||
console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.ws('/terminals/:pid', function (ws, req) {
|
||||
var term = terminals[parseInt(req.params.pid)];
|
||||
console.log('Connected to terminal ' + term.pid);
|
||||
ws.send(logs[term.pid]);
|
||||
|
||||
term.on('data', function(data) {
|
||||
try {
|
||||
ws.send(data);
|
||||
} catch (ex) {
|
||||
// The WebSocket is not open, ignore
|
||||
}
|
||||
});
|
||||
ws.on('message', function(msg) {
|
||||
term.write(msg);
|
||||
});
|
||||
ws.on('close', function () {
|
||||
term.kill();
|
||||
console.log('Closed terminal ' + term.pid);
|
||||
// Clean things up
|
||||
delete terminals[term.pid];
|
||||
delete logs[term.pid];
|
||||
});
|
||||
});
|
||||
|
||||
var port = process.env.PORT || 3000,
|
||||
host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0';
|
||||
|
||||
console.log('App listening to http://' + host + ':' + port);
|
||||
app.listen(port, host);
|
||||
@@ -0,0 +1,128 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>xterm.js demo</title>
|
||||
<link rel="stylesheet" href="/build/xterm.css" />
|
||||
<link rel="stylesheet" href="/build/addons/fullscreen/fullscreen.css" />
|
||||
<link rel="stylesheet" href="/demo/style.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
||||
<script src="/build/xterm.js" ></script>
|
||||
|
||||
<script src="/build/addons/attach/attach.js" ></script>
|
||||
<script src="/zmodemjs/zmodem.js"></script>
|
||||
<script src="/build/addons/zmodem/zmodem.js" ></script>
|
||||
|
||||
<script src="/build/addons/fit/fit.js" ></script>
|
||||
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
|
||||
<script src="/build/addons/search/search.js" ></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>xterm.js: xterm, in the browser</h1>
|
||||
|
||||
<div id="terminal-container"></div>
|
||||
|
||||
<div id="zmodem_controls">
|
||||
<form id="zm_start" style="display: none" action="javascript:void(0)">
|
||||
ZMODEM detected: Start ZMODEM session?
|
||||
<label><input id="zmstart_yes" name="zmstart" type=radio checked value="1"> Yes</label>
|
||||
|
||||
<label><input name="zmstart" type=radio value=""> No</label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<form id="zm_offer" style="display: none" action="javascript:void(0)">
|
||||
<p>ZMODEM File offered!</p>
|
||||
|
||||
<label><input id="zmaccept_yes" name="zmaccept" type=radio checked value="1"> Accept</label>
|
||||
|
||||
<label><input name="zmaccept" type=radio value=""> Skip</label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<div id="zm_file" style="display: none">
|
||||
<div>Name: <span id="name"></span></div>
|
||||
<div>Size: <span id="size"></span></div>
|
||||
<div>Last modified: <span id="mtime"></span></div>
|
||||
<div>Mode: <span id="mode"></span></div>
|
||||
<br>
|
||||
<div>Conversion: <span id="zfile_conversion"></span></div>
|
||||
<div>Management: <span id="zfile_management"></span></div>
|
||||
<div>Transport: <span id="zfile_transport"></span></div>
|
||||
<div>Sparse? <span id="zfile_sparse"></span></div>
|
||||
<br>
|
||||
<div>Files remaining in batch: <span id="files_remaining"></span></div>
|
||||
<div>Bytes remaining in batch: <span id="bytes_remaining"></span></div>
|
||||
</div>
|
||||
|
||||
<form id="zm_progress" style="display: none" action="javascript:void(0)">
|
||||
<div><span id="percent_received"></span>% (<span id="bytes_received"></span> bytes) received</div>
|
||||
<button id="zm_progress_skipper" type="button" onclick="skip_current_file();">Skip File</button>
|
||||
</form>
|
||||
|
||||
<form id="zm_choose" style="display: none" action="javascript:void(0)">
|
||||
<label>Choose file(s): <input id="zm_files" type="file" multiple></label>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Actions</h2>
|
||||
<p>
|
||||
<label>Find next <input id="find-next"/></label>
|
||||
<label>Find previous <input id="find-previous"/></label>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Options</h2>
|
||||
<p>
|
||||
<label><input type="checkbox" id="option-cursor-blink"> cursorBlink</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" checked id="zmodem-auto"> Accept all ZMODEM prompts<sup>*</sup></label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
cursorStyle
|
||||
<select id="option-cursor-style">
|
||||
<option value="block">block</option>
|
||||
<option value="underline">underline</option>
|
||||
<option value="bar">bar</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
bellStyle
|
||||
<select id="option-bell-style">
|
||||
<option value="">none</option>
|
||||
<option value="sound">sound</option>
|
||||
<option value="visual">visual</option>
|
||||
<option value="both">both</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>scrollback <input type="number" id="option-scrollback" value="1000" /></label>
|
||||
</p>
|
||||
<p>
|
||||
<label>tabStopWidth <input type="number" id="option-tabstopwidth" value="8" /></label>
|
||||
</p>
|
||||
<div>
|
||||
<h3>Size</h3>
|
||||
<div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="cols">Columns</label>
|
||||
<input type="number" id="cols" />
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="rows">Rows</label>
|
||||
<input type="number" id="rows" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p><strong>Attention:</strong> The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.</p>
|
||||
<p><sup>*</sup> ZMODEM file transfers are supported via an addon. To try it out, install <a href="https://ohse.de/uwe/software/lrzsz.html"><code>lrzsz</code></a> onto the remote peer, then run <code>rz</code> to send from your browser or <code>sz <file></code> to send from the remote peer.</p>
|
||||
<script src="main.js" defer ></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,383 @@
|
||||
"use strict";
|
||||
|
||||
var term,
|
||||
protocol,
|
||||
socketURL,
|
||||
socket,
|
||||
pid;
|
||||
|
||||
var terminalContainer = document.getElementById('terminal-container'),
|
||||
actionElements = {
|
||||
findNext: document.querySelector('#find-next'),
|
||||
findPrevious: document.querySelector('#find-previous')
|
||||
},
|
||||
optionElements = {
|
||||
cursorBlink: document.querySelector('#option-cursor-blink'),
|
||||
cursorStyle: document.querySelector('#option-cursor-style'),
|
||||
scrollback: document.querySelector('#option-scrollback'),
|
||||
tabstopwidth: document.querySelector('#option-tabstopwidth'),
|
||||
bellStyle: document.querySelector('#option-bell-style')
|
||||
},
|
||||
colsElement = document.getElementById('cols'),
|
||||
rowsElement = document.getElementById('rows');
|
||||
|
||||
function setTerminalSize() {
|
||||
var cols = parseInt(colsElement.value, 10);
|
||||
var rows = parseInt(rowsElement.value, 10);
|
||||
var viewportElement = document.querySelector('.xterm-viewport');
|
||||
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
|
||||
var width = (cols * term.charMeasure.width + 20 /*room for scrollbar*/).toString() + 'px';
|
||||
var height = (rows * term.charMeasure.height).toString() + 'px';
|
||||
|
||||
terminalContainer.style.width = width;
|
||||
terminalContainer.style.height = height;
|
||||
term.resize(cols, rows);
|
||||
}
|
||||
|
||||
colsElement.addEventListener('change', setTerminalSize);
|
||||
rowsElement.addEventListener('change', setTerminalSize);
|
||||
|
||||
actionElements.findNext.addEventListener('keypress', function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
term.findNext(actionElements.findNext.value);
|
||||
}
|
||||
});
|
||||
actionElements.findPrevious.addEventListener('keypress', function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
term.findPrevious(actionElements.findPrevious.value);
|
||||
}
|
||||
});
|
||||
|
||||
optionElements.cursorBlink.addEventListener('change', function () {
|
||||
term.setOption('cursorBlink', optionElements.cursorBlink.checked);
|
||||
});
|
||||
optionElements.cursorStyle.addEventListener('change', function () {
|
||||
term.setOption('cursorStyle', optionElements.cursorStyle.value);
|
||||
});
|
||||
optionElements.bellStyle.addEventListener('change', function () {
|
||||
term.setOption('bellStyle', optionElements.bellStyle.value);
|
||||
});
|
||||
optionElements.scrollback.addEventListener('change', function () {
|
||||
term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10));
|
||||
});
|
||||
optionElements.tabstopwidth.addEventListener('change', function () {
|
||||
term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10));
|
||||
});
|
||||
|
||||
createTerminal();
|
||||
|
||||
function createTerminal() {
|
||||
// Clean terminal
|
||||
while (terminalContainer.children.length) {
|
||||
terminalContainer.removeChild(terminalContainer.children[0]);
|
||||
}
|
||||
term = new Terminal({
|
||||
cursorBlink: optionElements.cursorBlink.checked,
|
||||
scrollback: parseInt(optionElements.scrollback.value, 10),
|
||||
tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10)
|
||||
});
|
||||
term.on('resize', function (size) {
|
||||
if (!pid) {
|
||||
return;
|
||||
}
|
||||
var cols = size.cols,
|
||||
rows = size.rows,
|
||||
url = '/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows;
|
||||
|
||||
fetch(url, {method: 'POST'});
|
||||
});
|
||||
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
|
||||
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
|
||||
|
||||
term.open(terminalContainer);
|
||||
term.fit();
|
||||
|
||||
// fit is called within a setTimeout, cols and rows need this.
|
||||
setTimeout(function () {
|
||||
colsElement.value = term.cols;
|
||||
rowsElement.value = term.rows;
|
||||
|
||||
// Set terminal size again to set the specific dimensions on the demo
|
||||
setTerminalSize();
|
||||
|
||||
fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then(function (res) {
|
||||
|
||||
res.text().then(function (pid) {
|
||||
window.pid = pid;
|
||||
socketURL += pid;
|
||||
socket = new WebSocket(socketURL);
|
||||
socket.onopen = runRealTerminal;
|
||||
socket.onclose = runFakeTerminal;
|
||||
socket.onerror = runFakeTerminal;
|
||||
|
||||
term.zmodemAttach(socket, {
|
||||
noTerminalWriteOutsideSession: true,
|
||||
} );
|
||||
|
||||
term.on("zmodemRetract", () => {
|
||||
start_form.style.display = "none";
|
||||
start_form.onsubmit = null;
|
||||
});
|
||||
|
||||
term.on("zmodemDetect", (detection) => {
|
||||
function do_zmodem() {
|
||||
term.detach();
|
||||
let zsession = detection.confirm();
|
||||
|
||||
var promise;
|
||||
|
||||
if (zsession.type === "receive") {
|
||||
promise = _handle_receive_session(zsession);
|
||||
}
|
||||
else {
|
||||
promise = _handle_send_session(zsession);
|
||||
}
|
||||
|
||||
promise.catch( console.error.bind(console) ).then( () => {
|
||||
term.attach(socket);
|
||||
} );
|
||||
}
|
||||
|
||||
if (_auto_zmodem()) {
|
||||
do_zmodem();
|
||||
}
|
||||
else {
|
||||
start_form.style.display = "";
|
||||
start_form.onsubmit = function(e) {
|
||||
start_form.style.display = "none";
|
||||
|
||||
if (document.getElementById("zmstart_yes").checked) {
|
||||
do_zmodem();
|
||||
}
|
||||
else {
|
||||
detection.deny();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// UI STUFF
|
||||
|
||||
function _show_file_info(xfer) {
|
||||
var file_info = xfer.get_details();
|
||||
|
||||
document.getElementById("name").textContent = file_info.name;
|
||||
document.getElementById("size").textContent = file_info.size;
|
||||
document.getElementById("mtime").textContent = file_info.mtime;
|
||||
document.getElementById("files_remaining").textContent = file_info.files_remaining;
|
||||
document.getElementById("bytes_remaining").textContent = file_info.bytes_remaining;
|
||||
|
||||
document.getElementById("mode").textContent = "0" + file_info.mode.toString(8);
|
||||
|
||||
var xfer_opts = xfer.get_options();
|
||||
["conversion", "management", "transport", "sparse"].forEach( (lbl) => {
|
||||
document.getElementById(`zfile_${lbl}`).textContent = xfer_opts[lbl];
|
||||
} );
|
||||
|
||||
document.getElementById("zm_file").style.display = "";
|
||||
}
|
||||
function _hide_file_info() {
|
||||
document.getElementById("zm_file").style.display = "none";
|
||||
}
|
||||
|
||||
function _save_to_disk(xfer, buffer) {
|
||||
return Zmodem.Browser.save_to_disk(buffer, xfer.get_details().name);
|
||||
}
|
||||
|
||||
var skipper_button = document.getElementById("zm_progress_skipper");
|
||||
var skipper_button_orig_text = skipper_button.textContent;
|
||||
|
||||
function _show_progress() {
|
||||
skipper_button.disabled = false;
|
||||
skipper_button.textContent = skipper_button_orig_text;
|
||||
|
||||
document.getElementById("bytes_received").textContent = 0;
|
||||
document.getElementById("percent_received").textContent = 0;
|
||||
|
||||
document.getElementById("zm_progress").style.display = "";
|
||||
}
|
||||
|
||||
function _update_progress(xfer) {
|
||||
var total_in = xfer.get_offset();
|
||||
|
||||
document.getElementById("bytes_received").textContent = total_in;
|
||||
|
||||
var percent_received = 100 * total_in / xfer.get_details().size;
|
||||
document.getElementById("percent_received").textContent = percent_received.toFixed(2);
|
||||
}
|
||||
|
||||
function _hide_progress() {
|
||||
document.getElementById("zm_progress").style.display = "none";
|
||||
}
|
||||
|
||||
var start_form = document.getElementById("zm_start");
|
||||
|
||||
function _auto_zmodem() {
|
||||
return document.getElementById("zmodem-auto").checked;
|
||||
}
|
||||
|
||||
// END UI STUFF
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
function _handle_receive_session(zsession) {
|
||||
zsession.on("offer", function(xfer) {
|
||||
current_receive_xfer = xfer;
|
||||
|
||||
_show_file_info(xfer);
|
||||
|
||||
var offer_form = document.getElementById("zm_offer");
|
||||
|
||||
function on_form_submit() {
|
||||
offer_form.style.display = "none";
|
||||
|
||||
//START
|
||||
//if (offer_form.zmaccept.value) {
|
||||
if (_auto_zmodem() || document.getElementById("zmaccept_yes").checked) {
|
||||
_show_progress();
|
||||
|
||||
var FILE_BUFFER = [];
|
||||
xfer.on("input", (payload) => {
|
||||
_update_progress(xfer);
|
||||
FILE_BUFFER.push( new Uint8Array(payload) );
|
||||
});
|
||||
xfer.accept().then(
|
||||
() => {
|
||||
_save_to_disk(xfer, FILE_BUFFER);
|
||||
},
|
||||
console.error.bind(console)
|
||||
);
|
||||
}
|
||||
else {
|
||||
xfer.skip();
|
||||
}
|
||||
//END
|
||||
}
|
||||
|
||||
if (_auto_zmodem()) {
|
||||
on_form_submit();
|
||||
}
|
||||
else {
|
||||
offer_form.onsubmit = on_form_submit;
|
||||
offer_form.style.display = "";
|
||||
}
|
||||
} );
|
||||
|
||||
var promise = new Promise( (res) => {
|
||||
zsession.on("session_end", () => {
|
||||
_hide_file_info();
|
||||
_hide_progress();
|
||||
res();
|
||||
} );
|
||||
} );
|
||||
|
||||
zsession.start();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function _handle_send_session(zsession) {
|
||||
var choose_form = document.getElementById("zm_choose");
|
||||
choose_form.style.display = "";
|
||||
|
||||
var file_el = document.getElementById("zm_files");
|
||||
|
||||
var promise = new Promise( (res) => {
|
||||
file_el.onchange = function(e) {
|
||||
choose_form.style.display = "none";
|
||||
|
||||
var files_obj = file_el.files;
|
||||
|
||||
Zmodem.Browser.send_files(
|
||||
zsession,
|
||||
files_obj,
|
||||
{
|
||||
on_offer_response(obj, xfer) {
|
||||
if (xfer) _show_progress();
|
||||
//console.log("offer", xfer ? "accepted" : "skipped");
|
||||
},
|
||||
on_progress(obj, xfer) {
|
||||
_update_progress(xfer);
|
||||
},
|
||||
on_file_complete(obj) {
|
||||
//console.log("COMPLETE", obj);
|
||||
_hide_progress();
|
||||
},
|
||||
}
|
||||
).then(_hide_progress).then(
|
||||
zsession.close.bind(zsession),
|
||||
console.error.bind(console)
|
||||
).then( () => {
|
||||
_hide_file_info();
|
||||
_hide_progress();
|
||||
res();
|
||||
} );
|
||||
};
|
||||
} );
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
//This is here to allow canceling of an in-progress ZMODEM transfer.
|
||||
var current_receive_xfer;
|
||||
|
||||
//Called from HTML directly.
|
||||
function skip_current_file() {
|
||||
current_receive_xfer.skip();
|
||||
|
||||
skipper_button.disabled = true;
|
||||
skipper_button.textContent = "Waiting for server to acknowledge skip …";
|
||||
}
|
||||
|
||||
function runRealTerminal() {
|
||||
term.attach(socket);
|
||||
|
||||
term._initialized = true;
|
||||
}
|
||||
|
||||
function runFakeTerminal() {
|
||||
if (term._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
term._initialized = true;
|
||||
|
||||
var shellprompt = '$ ';
|
||||
|
||||
term.prompt = function () {
|
||||
term.write('\r\n' + shellprompt);
|
||||
};
|
||||
|
||||
term.writeln('Welcome to xterm.js');
|
||||
term.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
|
||||
term.writeln('Type some keys and commands to play around.');
|
||||
term.writeln('');
|
||||
term.prompt();
|
||||
|
||||
term.on('key', function (key, ev) {
|
||||
var printable = (
|
||||
!ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
|
||||
);
|
||||
|
||||
if (ev.keyCode == 13) {
|
||||
term.prompt();
|
||||
} else if (ev.keyCode == 8) {
|
||||
// Do not delete the prompt
|
||||
if (term.x > 2) {
|
||||
term.write('\b \b');
|
||||
}
|
||||
} else if (printable) {
|
||||
term.write(key);
|
||||
}
|
||||
});
|
||||
|
||||
term.on('paste', function (data, ev) {
|
||||
term.write(data);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
*
|
||||
* Allow xterm.js to handle ZMODEM uploads and downloads.
|
||||
*
|
||||
* This addon is a wrapper around zmodem.js. It adds the following to the
|
||||
* Terminal class:
|
||||
*
|
||||
* - function `zmodemAttach(<WebSocket>, <Object>)` - creates a Zmodem.Sentry
|
||||
* on the passed WebSocket object. The Object passed is optional and
|
||||
* can contain:
|
||||
* - noTerminalWriteOutsideSession: Suppress writes from the Sentry
|
||||
* object to the Terminal while there is no active Session. This
|
||||
* is necessary for compatibility with, for example, the
|
||||
* `attach.js` addon.
|
||||
*
|
||||
* - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback.
|
||||
* Passes the zmodem.js Detection object.
|
||||
*
|
||||
* - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback.
|
||||
*
|
||||
* You’ll need to provide logic to handle uploads and downloads.
|
||||
* See zmodem.js’s documentation for more details.
|
||||
*
|
||||
* **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have
|
||||
* used the `attach` or `terminado` addons, you’ll need to suspend their
|
||||
* operation for the duration of the ZMODEM session. (The demo does this
|
||||
* via `detach()` and a re-`attach()`.)
|
||||
*/
|
||||
(function (addon) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = addon(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], addon);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
addon(window.Terminal);
|
||||
}
|
||||
})(function _zmodemAddon(Terminal) {
|
||||
Object.assign(
|
||||
Terminal.prototype,
|
||||
{
|
||||
zmodemAttach: function zmodemAttach(ws, opts) {
|
||||
var term = this;
|
||||
|
||||
if (!opts) opts = {};
|
||||
|
||||
var senderFunc = function _ws_sender_func(octets) {
|
||||
ws.send( new Uint8Array(octets) );
|
||||
};
|
||||
|
||||
var zsentry;
|
||||
|
||||
function _shouldWrite() {
|
||||
return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession;
|
||||
}
|
||||
|
||||
zsentry = new Zmodem.Sentry( {
|
||||
to_terminal: function _to_terminal(octets) {
|
||||
if (_shouldWrite()) {
|
||||
term.write(
|
||||
String.fromCharCode.apply(String, octets)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
sender: senderFunc,
|
||||
|
||||
on_retract: function _on_retract() {
|
||||
term.emit("zmodemRetract");
|
||||
},
|
||||
|
||||
on_detect: function _on_detect(detection) {
|
||||
term.emit("zmodemDetect", detection);
|
||||
},
|
||||
} );
|
||||
|
||||
function handleWSMessage(evt) {
|
||||
|
||||
//In testing with xterm.js’s demo the first message was
|
||||
//always text even if the rest were binary. While that
|
||||
//may be specific to xterm.js’s demo, ultimately we
|
||||
//should reject anything that isn’t binary.
|
||||
if (typeof evt.data === "string") {
|
||||
if (_shouldWrite()) {
|
||||
term.write(evt.data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zsentry.consume(evt.data);
|
||||
}
|
||||
}
|
||||
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.addEventListener("message", handleWSMessage);
|
||||
},
|
||||
|
||||
zmodemBrowser: Zmodem.Browser,
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).zmodem=e()}}(function(){return function i(f,u,d){function a(n,e){if(!u[n]){if(!f[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(s)return s(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var o=u[n]={exports:{}};f[n][0].call(o.exports,function(e){return a(f[n][1][e]||e)},o,o.exports,i,f,u,d)}return u[n].exports}for(var s="function"==typeof require&&require,e=0;e<d.length;e++)a(d[e]);return a}({1:[function(e,n,t){"use strict";var i;function r(n,e){void 0===e&&(e={});var t,r=this;function o(){return!!t.get_confirmed_session()||!e.noTerminalWriteOutsideSession}t=new i.Sentry({to_terminal:function(e){o()&&r.write(String.fromCharCode.apply(String,e))},sender:function(e){return n.send(new Uint8Array(e))},on_retract:function(){return r.emit("zmodemRetract")},on_detect:function(e){return r.emit("zmodemDetect",e)}}),n.binaryType="arraybuffer",n.addEventListener("message",function(e){"string"==typeof e.data?o()&&r.write(e.data):t.consume(e.data)})}Object.defineProperty(t,"__esModule",{value:!0}),t.apply=function(e){i="object"==typeof window?window.Zmodem:{Browser:null},e.prototype.zmodemAttach=r,e.prototype.zmodemBrowser=i.Browser}},{}]},{},[1])(1)});
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
font-family: courier-new, courier, monospace;
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
/*
|
||||
* HACK: to fix IE's blinking cursor
|
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible.
|
||||
*/
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -10;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #333;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #333;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.xterm canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm .xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
left: -9999em;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm:not(.enable-mouse-events) {
|
||||
cursor: text;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
.xterm{font-feature-settings:"liga" 0;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:0}.xterm .xterm-helpers{position:absolute;top:0;z-index:10}.xterm .xterm-helper-textarea{position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-10;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm{cursor:text}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:100;color:transparent}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:.5}.xterm-underline{text-decoration:underline}
|
||||
/*# sourceMappingURL=xterm.min.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["xterm.css"],"names":[],"mappings":"AAqCA,OACI,sBAAuB,OAAO,EAC9B,SAAU,SACV,YAAa,KACb,gBAAiB,KACjB,oBAAqB,KAGzB,aACA,aACI,QAAS,EAGb,sBACI,SAAU,SACV,IAAK,EAKL,QAAS,GAGb,8BAKI,SAAU,SACV,QAAS,EACT,KAAM,QACN,IAAK,EACL,MAAO,EACP,OAAQ,EACR,QAAS,IAET,YAAa,OACb,SAAU,OACV,OAAQ,KAGZ,yBAEI,WAAY,KACZ,MAAO,KACP,QAAS,KACT,SAAU,SACV,YAAa,OACb,QAAS,EAGb,gCACI,QAAS,MAGb,uBAEI,iBAAkB,KAClB,WAAY,OACZ,OAAQ,QACR,SAAU,SACV,MAAO,EACP,KAAM,EACN,IAAK,EACL,OAAQ,EAGZ,qBACI,SAAU,SAGd,4BACI,SAAU,SACV,KAAM,EACN,IAAK,EAGT,0BACI,WAAY,OAGhB,4BACI,QAAS,aACT,WAAY,OACZ,SAAU,SACV,IAAK,EACL,KAAM,QACN,YAAa,OAGjB,OACI,OAAQ,KAGZ,2BAEI,OAAQ,QAGZ,4BACI,OAAQ,QAGZ,2BAEI,OAAQ,UAGZ,4BACA,sBACI,SAAU,SACV,KAAM,EACN,IAAK,EACL,OAAQ,EACR,MAAO,EACP,QAAS,IACT,MAAO,YAGX,oBACI,SAAU,SACV,KAAM,QACN,MAAO,IACP,OAAQ,IACR,SAAU,OAGd,WACI,QAAS,GAGb,iBACI,gBAAiB"}
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+13
@@ -0,0 +1,13 @@
|
||||
<div>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">目标URL</span><input class="bt-input-text" type="text" name="toUrl" value="http://" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="请填写完整URL,例:http://www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">发送域名</span><input class="bt-input-text" type="text" name="toDomain" value="$host" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="发送到目标服务器的域名,例:www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">内容替换</span><input class="bt-input-text" type="text" name="sub1" value="" style="margin-left: 5px;width: 182px;height: 30px;margin-right:10px;" placeholder="被替换的文本,可留空"><input class="bt-input-text" type="text" name="sub2" value="" style="margin-left: 5px;width: 183px;height: 30px;margin-right:10px;" placeholder="替换为,可留空"></p>
|
||||
<div class="label-input-group ptb10"><label style="font-weight:normal"><input type="checkbox" name="status" onclick="Proxy('w6.hao.com',1)">启用反向代理</label><label style="margin-left: 18px;"><input type="checkbox" name="status" onclick="OpenCache('w6.hao.com',1)">开启缓存</label></div>
|
||||
<ul class="help-info-text c7 ptb10">
|
||||
<li>目标Url必需是可以访问的,否则将直接502</li>
|
||||
<li>默认本站点所有域名访问将被传递到目标服务器,请确保目标服务器已绑定域名</li>
|
||||
<li>若您是被动代理,请在发送域名处填写上目标站点的域名</li>
|
||||
<li>若您不需要内容替换功能,请直接留空</li>
|
||||
<li>可通过purge清理指定URL的缓存,示例:http://test.com/purge/test.png</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -105,7 +105,7 @@ var database = {
|
||||
shadeClose: false,
|
||||
content: '<div class="plr15 mt10">\
|
||||
<div class="db_list">\
|
||||
<span><a style="width: 205px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;display: inline-block;vertical-align: bottom;margin-right: 11px;" title="'+ db_name + '">'+lan.database.db_name+':'+ db_name + '</a>\
|
||||
<span><a style="width: 239px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;display: inline-block;vertical-align: bottom;margin-right: 11px;" title="'+ db_name + '">'+lan.database.db_name+':'+ db_name + '</a>\
|
||||
<a class="tools_size">'+lan.database.size+':'+ rdata.data_size + '</a></span>\
|
||||
<span id="db_tools" style="float: right;"></span>\
|
||||
</div >\
|
||||
|
||||
@@ -773,7 +773,7 @@ function php_file_webshell(file) {
|
||||
}
|
||||
|
||||
function auto_table_width() {
|
||||
var oldTable = $(window).height() - $('#tipTools')[0].getBoundingClientRect().height - $('#filePage')[0].getBoundingClientRect().height - $('.footer')[0].getBoundingClientRect().height - 111;
|
||||
var oldTable = $(window).height() - $('#tipTools')[0].getBoundingClientRect().height - $('#filePage')[0].getBoundingClientRect().height - $('.footer')[0].getBoundingClientRect().height - 121;
|
||||
var oldTable_heigth = $('.oldTable table').height();
|
||||
$('.oldTable thead th').each(function (index, el) {
|
||||
var table_th = $('.oldTable thead th').length;
|
||||
|
||||
@@ -479,7 +479,7 @@ var aceEditor = {
|
||||
var _html = '',
|
||||
_arry = ['White', 'Black'];
|
||||
for (var i = 0; i < _this.themeList.length; i++) {
|
||||
if (_this.themeList[i] != _this.editorTheme) {
|
||||
if (_this.aceConfig.themeList[i] != _this.aceConfig.aceEditor.editorTheme) {
|
||||
_html += '<li data-value="' + _this.themeList[i] + '">' + _this.themeList[i] + '【' + _arry[i] + '】</li>';
|
||||
} else {
|
||||
_html += '<li data-value="' + _this.themeList[i] + '" class="active">' + _this.themeList[i] + '【' + _arry[i] + '】' + _icon + '</li>';
|
||||
@@ -906,6 +906,26 @@ var aceEditor = {
|
||||
this.setEditorView();
|
||||
this.reader_file_dir_menu();
|
||||
},
|
||||
// 设置本地存储,设置类型type:session或local
|
||||
setStorage:function(type,key,val){
|
||||
if(type != "local" && type != "session") val = key,key = type,type = 'session';
|
||||
window[type+'Storage'].setItem(key,val);
|
||||
},
|
||||
//获取指定本地存储,设置类型type:session或local
|
||||
getStorage:function(type,key){
|
||||
if(type != "local" && type != "session") key = type,type = 'session';
|
||||
return window[type+'Storage'].getItem(key);
|
||||
},
|
||||
//删除指定本地存储,设置类型type:session或local
|
||||
removeStorage:function(type,key){
|
||||
if(type != "local" && type != "session") key = type,type = 'session';
|
||||
window[type+'Storage'].removeItem(key);
|
||||
},
|
||||
// 删除指定类型的所有存储信息
|
||||
clearStorage:function(type){
|
||||
if(type != "local" && type != "session") key = type,type = 'session';
|
||||
window[type+'Storage'].clear();
|
||||
},
|
||||
// 新建文件类型
|
||||
newly_file_type: function(that) {
|
||||
var _type = parseInt($(that).attr('data-type')),
|
||||
@@ -1480,7 +1500,7 @@ var aceEditor = {
|
||||
if (this.editor == null) this.editor = {};
|
||||
this.editor['ace_editor_' + obj.id] = {
|
||||
ace: ace.edit("ace_editor_" + obj.id, {
|
||||
theme: "ace/theme/" + _this.editorTheme, //主题
|
||||
theme: "ace/theme/" + _this.aceConfig.aceEditor.editorTheme, //主题
|
||||
mode: "ace/mode/" + (obj.fileName != undefined ? obj.mode : 'text'), // 语言类型
|
||||
wrap: _this.aceConfig.aceEditor.wrap,
|
||||
showInvisibles: _this.aceConfig.aceEditor.showInvisibles,
|
||||
@@ -1717,7 +1737,7 @@ var aceEditor = {
|
||||
tips:true,
|
||||
},function(rdata){
|
||||
layer.close(loadT);
|
||||
setCookie('aceConfig',JSON.stringify(data));
|
||||
_this.setStorage('aceConfig',JSON.stringify(data));
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
@@ -1726,7 +1746,7 @@ var aceEditor = {
|
||||
var loadT = layer.msg(lan.public.get_ace_config,{time: 0,icon: 16,shade: [0.3, '#000']}),_this = this;
|
||||
this.getFileBody({path:'/www/server/panel/BTPanel/static/ace/ace.editor.config.json'},function(rdata){
|
||||
layer.close(loadT);
|
||||
setCookie('aceConfig',JSON.stringify(rdata.data));
|
||||
_this.setStorage('aceConfig',JSON.stringify(rdata.data));
|
||||
if(callback) callback(JSON.parse(rdata.data));
|
||||
});
|
||||
},
|
||||
@@ -1734,7 +1754,7 @@ var aceEditor = {
|
||||
var loadT = layer.msg(lan.public.get_ace_config,{time: 0,icon: 16,shade: [0.3, '#000']}),_this = this;
|
||||
this.getFileBody({path:'/www/server/panel/BTPanel/static/ace/ace.editor.config.json'},function(rdata){
|
||||
layer.close(loadT);
|
||||
setCookie('aceConfig',JSON.stringify(rdata.data));
|
||||
_this.setStorage('aceConfig',JSON.stringify(rdata.data));
|
||||
if(callback) callback(JSON.parse(rdata.data));
|
||||
});
|
||||
},
|
||||
@@ -1818,7 +1838,7 @@ function openEditorView(type, path) {
|
||||
aceEditor.setEditorView();
|
||||
});
|
||||
}
|
||||
var aceConfig = getCookie('aceConfig');
|
||||
var aceConfig = aceEditor.getStorage('aceConfig');
|
||||
if(aceConfig == null){
|
||||
// 获取编辑器配置
|
||||
aceEditor.getAceConfig(function(res){
|
||||
@@ -2905,6 +2925,7 @@ function setSelectChecked(c, d) {
|
||||
GetTaskCount();
|
||||
|
||||
function RecInstall() {
|
||||
$.getScript('jquery.fly.min.js.js');
|
||||
$.post("/ajax?action=GetSoftList", "", function(l) {
|
||||
var c = "";
|
||||
var g = "";
|
||||
|
||||
@@ -1459,12 +1459,11 @@ var site = {
|
||||
},
|
||||
get_rewrite_list: function(web) {
|
||||
var filename = '/www/server/panel/vhost/rewrite/' + web.name + '.conf';
|
||||
|
||||
bt.site.get_rewrite_list(web.name, function(rdata) {
|
||||
if (bt.get_cookie('serverType') == 'apache' || bt.get_cookie('serverType') == 'openlitespeed') filename = rdata.sitePath + '/.htaccess';
|
||||
var arrs = [];
|
||||
var arrs = [], webserver = bt.get_cookie('serverType');
|
||||
if (webserver == 'apache' || webserver == 'openlitespeed') filename = rdata.sitePath + '/.htaccess';
|
||||
if (webserver == 'openlitespeed') webserver = 'apache';
|
||||
for (var i = 0; i < rdata.rewrite.length; i++) arrs.push({ title: rdata.rewrite[i], value: rdata.rewrite[i] });
|
||||
|
||||
var datas = [{
|
||||
name: 'rewrite',
|
||||
type: 'select',
|
||||
@@ -1473,7 +1472,7 @@ var site = {
|
||||
callback: function(obj) {
|
||||
if (bt.os == 'Linux') {
|
||||
var spath = filename;
|
||||
if (obj.val() != lan.site.rewritename) spath = '/www/server/panel/rewrite/' + bt.get_cookie('serverType') + '/' + obj.val() + '.conf';
|
||||
if (obj.val() != lan.site.rewritename) spath = '/www/server/panel/rewrite/' + webserver + '/' + obj.val() + '.conf';
|
||||
bt.files.get_file_body(spath, function(ret) {
|
||||
editor.setValue(ret.data);
|
||||
})
|
||||
|
||||
+30
-11
@@ -561,6 +561,7 @@ class ajax:
|
||||
phplib = json.loads(public.readFile('data/phplib.conf'))
|
||||
libs = []
|
||||
tasks = public.M('tasks').where("status!=?",('1',)).field('status,name').select()
|
||||
phpini_ols = None
|
||||
for lib in phplib:
|
||||
lib['task'] = '1'
|
||||
for task in tasks:
|
||||
@@ -574,9 +575,10 @@ class ajax:
|
||||
if public.get_webserver() == 'openlitespeed':
|
||||
lib['status'] = False
|
||||
get.php_version = "{}.{}".format(get.version[0],get.version[1])
|
||||
phpini = self.php_info(get)['phpinfo']['modules'].lower()
|
||||
phpini = phpini.split()
|
||||
for i in phpini:
|
||||
if not phpini_ols:
|
||||
phpini_ols = self.php_info(get)['phpinfo']['modules'].lower()
|
||||
phpini_ols = phpini_ols.split()
|
||||
for i in phpini_ols:
|
||||
if lib['check'][:-3].lower() == i :
|
||||
lib['status'] = True
|
||||
break
|
||||
@@ -596,20 +598,37 @@ class ajax:
|
||||
|
||||
#获取PHP扩展
|
||||
def getCloudPHPExt(self,get):
|
||||
import json
|
||||
try:
|
||||
self._process_chinese_ext_description()
|
||||
if 'php_ext' in session: return True
|
||||
if not session.get('download_url'): session['download_url'] = 'http://download.bt.cn'
|
||||
download_url = session['download_url'] + '/install/lib/phplib_en.json'
|
||||
tstr = public.httpGet(download_url)
|
||||
data = json.loads(tstr)
|
||||
if not data: return False
|
||||
public.writeFile('data/phplib.conf',json.dumps(data))
|
||||
if not self._get_cloud_phplib():
|
||||
return False
|
||||
session['php_ext'] = True
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
# 处理PHP插件变描述中文
|
||||
def _process_chinese_ext_description(self):
|
||||
chinese = None
|
||||
phplib = json.loads(public.readFile('data/phplib.conf'))
|
||||
for p in phplib:
|
||||
if "缓存器" in p['type']:
|
||||
chinese = True
|
||||
break
|
||||
if chinese:
|
||||
self._get_cloud_phplib()
|
||||
|
||||
# 下载云端php扩展配置
|
||||
def _get_cloud_phplib(self):
|
||||
if not session.get('download_url'): session['download_url'] = 'http://download.bt.cn'
|
||||
download_url = session['download_url'] + '/install/lib/phplib_en.json'
|
||||
tstr = public.httpGet(download_url)
|
||||
data = json.loads(tstr)
|
||||
if not data: return False
|
||||
public.writeFile('data/phplib.conf', json.dumps(data))
|
||||
return True
|
||||
|
||||
#取PHPINFO信息
|
||||
def GetPHPInfo(self,get):
|
||||
if public.get_webserver() == "openlitespeed":
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class panelSetup:
|
||||
ua = ua.lower()
|
||||
if ua.find('spider') != -1 or ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.6.7'
|
||||
g.version = '6.6.9'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
if not os.path.exists('data/debug.pl'):
|
||||
|
||||
+19
-11
@@ -892,6 +892,7 @@ class config:
|
||||
|
||||
# 设置Session缓存方式
|
||||
def SetSessionConf(self, get):
|
||||
import glob
|
||||
g = get.save_handler
|
||||
ip = get.ip
|
||||
port = get.port
|
||||
@@ -910,22 +911,29 @@ class config:
|
||||
if re.search(prep, passwd):
|
||||
return public.returnMsg(False, 'SPECIAL_CHARACTRES', ('" ~ ` / = "'))
|
||||
filename = '/www/server/php/' + get.version + '/etc/php.ini'
|
||||
filename_ols = '/usr/local/lsws/lsphp{}/etc/php/{}.{}/litespeed/php.ini'.format(get.version, get.version[0],
|
||||
get.version[1])
|
||||
if os.path.exists('/etc/redhat-release'):
|
||||
filename_ols = '/usr/local/lsws/lsphp' + get.version + '/etc/php.ini'
|
||||
ols_php_os_path = "/usr/local/lsws/lsphp{}/lib/php/20*/".format(get.version)
|
||||
if os.path.exists("/etc/redhat-release"):
|
||||
ols_php_os_path = '/usr/local/lsws/lsphp{}/lib64/php/modules/'.format(get.version)
|
||||
ols_so_list = os.listdir(ols_php_os_path)
|
||||
filename_ols = None
|
||||
if os.path.exists("/usr/local/lsws"):
|
||||
filename_ols = '/usr/local/lsws/lsphp{}/etc/php/{}.{}/litespeed/php.ini'.format(get.version, get.version[0],
|
||||
get.version[1])
|
||||
if os.path.exists('/etc/redhat-release'):
|
||||
filename_ols = '/usr/local/lsws/lsphp' + get.version + '/etc/php.ini'
|
||||
try:
|
||||
ols_php_os_path = glob.glob("/usr/local/lsws/lsphp{}/lib/php/20*".format(get.version))[0]
|
||||
except:
|
||||
ols_php_os_path = None
|
||||
if os.path.exists("/etc/redhat-release"):
|
||||
ols_php_os_path = '/usr/local/lsws/lsphp{}/lib64/php/modules/'.format(get.version)
|
||||
ols_so_list = os.listdir(ols_php_os_path)
|
||||
for f in [filename,filename_ols]:
|
||||
if not f:
|
||||
continue
|
||||
phpini = public.readFile(f)
|
||||
rep = r'session.save_handler\s*=\s*(.+)\r?\n'
|
||||
val = r'session.save_handler = ' + g + '\n'
|
||||
phpini = re.sub(rep, val, phpini)
|
||||
if g == "memcached":
|
||||
if not re.search("memcached.so", phpini) and "memcached.so" not in ols_so_list:
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g))
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g,))
|
||||
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
|
||||
val = r'\nsession.save_path = "%s:%s" \n' % (ip,port)
|
||||
if re.search(rep, phpini):
|
||||
@@ -934,7 +942,7 @@ class config:
|
||||
phpini = re.sub('\n;session.save_path = "/tmp"', '\n;session.save_path = "/tmp"' + val, phpini)
|
||||
if g == "memcache":
|
||||
if not re.search("memcache.so", phpini) and "memcache.so" not in ols_so_list:
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g))
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g,))
|
||||
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
|
||||
val = r'\nsession.save_path = "tcp://%s:%s"\n' % (ip, port)
|
||||
if re.search(rep, phpini):
|
||||
@@ -943,7 +951,7 @@ class config:
|
||||
phpini = re.sub('\n;session.save_path = "/tmp"', '\n;session.save_path = "/tmp"' + val, phpini)
|
||||
if g == "redis":
|
||||
if not re.search("redis.so", phpini) and "redis.so" not in ols_so_list:
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g))
|
||||
return public.returnMsg(False, 'INSTALL_EXTEND_FIRST', (g,))
|
||||
if passwd:
|
||||
passwd = "?auth=" + passwd
|
||||
else:
|
||||
|
||||
+12
-2
@@ -785,6 +785,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
public.WriteLog('TYPE_FILE', 'FILE_COPY_SUCCESS',
|
||||
(get.sfile, get.dfile))
|
||||
stat = os.stat(get.sfile)
|
||||
os.chmod(get.dfile,stat.st_mode)
|
||||
os.chown(get.dfile, stat.st_uid, stat.st_gid)
|
||||
return public.returnMsg(True, 'FILE_COPY_SUCCESS')
|
||||
except:
|
||||
@@ -807,6 +808,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
try:
|
||||
self.copytree(get.sfile, get.dfile)
|
||||
stat = os.stat(get.sfile)
|
||||
os.chmod(get.dfile,stat.st_mode)
|
||||
os.chown(get.dfile, stat.st_uid, stat.st_gid)
|
||||
public.WriteLog('TYPE_FILE', 'DIR_COPY_SUCCESS',
|
||||
(get.sfile, get.dfile))
|
||||
@@ -825,8 +827,11 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
if get.sfile == '/www/Recycle_bin':
|
||||
return public.returnMsg(False,'You cannot directly operate the recycle bin directory, please press the [Recycle Bin] button in the upper right corner to open')
|
||||
if not os.path.exists(get.sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
return public.returnMsg(False, 'FILE_NOT_EXISTS')
|
||||
|
||||
if get.dfile[-1] == '/':
|
||||
get.dfile = get.dfile[:-1]
|
||||
|
||||
if get.dfile == get.sfile:
|
||||
return public.returnMsg(False,'Meaningless operation')
|
||||
|
||||
@@ -1331,6 +1336,11 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
os.remove(sfile)
|
||||
return True
|
||||
|
||||
|
||||
#创建软链
|
||||
def create_link(self,args):
|
||||
pass
|
||||
|
||||
# 复制目录
|
||||
def copytree(self, sfile, dfile):
|
||||
if sfile == dfile:
|
||||
|
||||
+11
-2
@@ -28,6 +28,7 @@ class backup:
|
||||
_inode_min = 10
|
||||
_db_mysql = None
|
||||
_cloud = None
|
||||
_local_backdir = None
|
||||
_is_save_local = not os.path.exists('data/is_save_local_backup.pl')
|
||||
def __init__(self,cloud_object = None):
|
||||
'''
|
||||
@@ -194,6 +195,7 @@ class backup:
|
||||
self.echo_info('Keep the latest number of backups: {} copies'.format(save))
|
||||
num = len(backups) - int(save)
|
||||
if num > 0:
|
||||
self._get_local_backdir()
|
||||
self.echo_info('-' * 90)
|
||||
for backup in backups:
|
||||
#处理目录备份到远程的情况
|
||||
@@ -203,7 +205,10 @@ class backup:
|
||||
backup['name'] = tmp[-1]
|
||||
#尝试删除本地文件
|
||||
if os.path.exists(backup['filename']):
|
||||
os.remove(backup['filename'])
|
||||
try:
|
||||
os.remove(self._local_backdir + '/'+ data_type +'/' + backup['name'])
|
||||
except:
|
||||
pass
|
||||
self.echo_info("Expired backup files have been cleaned from disk:" + backup['filename'])
|
||||
#尝试删除远程文件
|
||||
if self._cloud:
|
||||
@@ -215,6 +220,10 @@ class backup:
|
||||
num -= 1
|
||||
if num < 1: break
|
||||
|
||||
# 获取本地备份目录
|
||||
def _get_local_backdir(self):
|
||||
self._local_backdir = public.M('config').field('backup_path').find()['backup_path']
|
||||
|
||||
#压缩目录
|
||||
def backup_path_to(self,spath,dfile,exclude = [],siteName = None):
|
||||
if not os.path.exists(spath):
|
||||
@@ -445,7 +454,7 @@ class backup:
|
||||
else:
|
||||
backups = public.M('backup').where('type=? and pid=? and filename=?',('1',pid,filename)).field('id,name,filename').select()
|
||||
|
||||
|
||||
self.echo_info(str(backups))
|
||||
self.delete_old(backups,save,'database')
|
||||
self.echo_end()
|
||||
return dfile
|
||||
|
||||
+1
-1
@@ -75,6 +75,6 @@ function get_info(){
|
||||
return $data;
|
||||
}
|
||||
$result = get_info();
|
||||
exit(json_encode($result,1));
|
||||
exit(json_encode($result));
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
import datetime
|
||||
import subprocess
|
||||
import time
|
||||
subprocess.Popen('echo > ' + logPath, cwd=cwd, stdin=subprocess.PIPE, shell=shell, bufsize=4096)
|
||||
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)
|
||||
|
||||
while sub.poll() is None:
|
||||
|
||||
Reference in New Issue
Block a user