mirror of
https://github.com/bingohuang/docker-labs.git
synced 2025-07-14 01:57:32 +08:00
Font size and fullscreen (#120)
* Allow to change terminal font size in settings. Allow to enter fullscreen mode with alt+enter. * Fix size issues
This commit is contained in:
parent
453b39d75f
commit
d6c359645c
@ -11,7 +11,7 @@
|
|||||||
}, 500);
|
}, 500);
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'KeyboardShortcutService', 'InstanceService', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, KeyboardShortcutService, InstanceService) {
|
app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'TerminalService', 'KeyboardShortcutService', 'InstanceService', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, TerminalService, KeyboardShortcutService, InstanceService) {
|
||||||
$scope.sessionId = window.location.pathname.replace('/p/', '');
|
$scope.sessionId = window.location.pathname.replace('/p/', '');
|
||||||
$scope.instances = [];
|
$scope.instances = [];
|
||||||
$scope.idx = {};
|
$scope.idx = {};
|
||||||
@ -52,6 +52,8 @@
|
|||||||
$scope.socket.emit('viewport resize', geometry.cols, geometry.rows);
|
$scope.socket.emit('viewport resize', geometry.cols, geometry.rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardShortcutService.setResizeFunc($scope.resize);
|
||||||
|
|
||||||
$scope.closeSession = function() {
|
$scope.closeSession = function() {
|
||||||
$scope.socket.emit('session close');
|
$scope.socket.emit('session close');
|
||||||
}
|
}
|
||||||
@ -195,6 +197,7 @@
|
|||||||
if (!instance.term) {
|
if (!instance.term) {
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
createTerminal(instance);
|
createTerminal(instance);
|
||||||
|
TerminalService.setFontSize(TerminalService.getFontSize());
|
||||||
instance.term.focus();
|
instance.term.focus();
|
||||||
}, 0, false);
|
}, 0, false);
|
||||||
return
|
return
|
||||||
@ -326,14 +329,14 @@
|
|||||||
})
|
})
|
||||||
.component("settingsDialog", {
|
.component("settingsDialog", {
|
||||||
templateUrl : "settings-modal.html",
|
templateUrl : "settings-modal.html",
|
||||||
controller : function($mdDialog, KeyboardShortcutService, $rootScope, InstanceService) {
|
controller : function($mdDialog, KeyboardShortcutService, $rootScope, InstanceService, TerminalService) {
|
||||||
var $ctrl = this;
|
var $ctrl = this;
|
||||||
|
|
||||||
$ctrl.$onInit = function() {
|
$ctrl.$onInit = function() {
|
||||||
$ctrl.keyboardShortcutPresets = KeyboardShortcutService.getAvailablePresets();
|
$ctrl.keyboardShortcutPresets = KeyboardShortcutService.getAvailablePresets();
|
||||||
$ctrl.selectedShortcutPreset = KeyboardShortcutService.getCurrentShortcuts();
|
$ctrl.selectedShortcutPreset = KeyboardShortcutService.getCurrentShortcuts();
|
||||||
$ctrl.instanceImages = InstanceService.getAvailableImages();
|
$ctrl.instanceImages = InstanceService.getAvailableImages();
|
||||||
$ctrl.selectedInstanceImage = InstanceService.getDesiredImage();
|
$ctrl.selectedInstanceImage = InstanceService.getDesiredImage();
|
||||||
|
$ctrl.terminalFontSizes = TerminalService.getFontSizes();
|
||||||
};
|
};
|
||||||
|
|
||||||
$ctrl.currentShortcutConfig = function(value) {
|
$ctrl.currentShortcutConfig = function(value) {
|
||||||
@ -352,6 +355,15 @@
|
|||||||
}
|
}
|
||||||
return InstanceService.getDesiredImage(value);
|
return InstanceService.getDesiredImage(value);
|
||||||
};
|
};
|
||||||
|
$ctrl.currentTerminalFontSize = function(value) {
|
||||||
|
if (value !== undefined) {
|
||||||
|
// set font size
|
||||||
|
TerminalService.setFontSize(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TerminalService.getFontSize();
|
||||||
|
}
|
||||||
|
|
||||||
$ctrl.close = function() {
|
$ctrl.close = function() {
|
||||||
$mdDialog.cancel();
|
$mdDialog.cancel();
|
||||||
@ -396,20 +408,30 @@
|
|||||||
|
|
||||||
})
|
})
|
||||||
.run(function(InstanceService) { /* forcing pre-populating for now */ })
|
.run(function(InstanceService) { /* forcing pre-populating for now */ })
|
||||||
.service("KeyboardShortcutService", function() {
|
.service("KeyboardShortcutService", ['TerminalService', function(TerminalService) {
|
||||||
|
var resizeFunc;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getAvailablePresets : getAvailablePresets,
|
getAvailablePresets : getAvailablePresets,
|
||||||
getCurrentShortcuts : getCurrentShortcuts,
|
getCurrentShortcuts : getCurrentShortcuts,
|
||||||
setCurrentShortcuts : setCurrentShortcuts
|
setCurrentShortcuts : setCurrentShortcuts,
|
||||||
|
setResizeFunc : setResizeFunc
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function setResizeFunc(f) {
|
||||||
|
resizeFunc = f;
|
||||||
|
}
|
||||||
|
|
||||||
function getAvailablePresets() {
|
function getAvailablePresets() {
|
||||||
return [
|
return [
|
||||||
{ name : "None", presets : [] },
|
{ name : "None", presets : [
|
||||||
|
{ description : "Toggle terminal fullscreen", command : "Alt+enter", altKey : true, keyCode : 13, action : function(context) { TerminalService.toggleFullscreen(context.terminal, resizeFunc); }}
|
||||||
|
] },
|
||||||
{
|
{
|
||||||
name : "Mac OSX",
|
name : "Mac OSX",
|
||||||
presets : [
|
presets : [
|
||||||
{ description : "Clear terminal", command : "Cmd+K", metaKey : true, keyCode : 75, action : function(context) { context.terminal.clear(); }}
|
{ description : "Clear terminal", command : "Cmd+K", metaKey : true, keyCode : 75, action : function(context) { context.terminal.clear(); }},
|
||||||
|
{ description : "Toggle terminal fullscreen", command : "Alt+enter", altKey : true, keyCode : 13, action : function(context) { TerminalService.toggleFullscreen(context.terminal, resizeFunc); }}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -440,7 +462,72 @@
|
|||||||
return "Mac OSX";
|
return "Mac OSX";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
}])
|
||||||
|
.service('TerminalService', ['$window', function($window) {
|
||||||
|
var fullscreen;
|
||||||
|
var fontSize = getFontSize();
|
||||||
|
return {
|
||||||
|
getFontSizes : getFontSizes,
|
||||||
|
setFontSize : setFontSize,
|
||||||
|
getFontSize : getFontSize,
|
||||||
|
increaseFontSize : increaseFontSize,
|
||||||
|
decreaseFontSize : decreaseFontSize,
|
||||||
|
toggleFullscreen : toggleFullscreen
|
||||||
|
};
|
||||||
|
function getFontSizes() {
|
||||||
|
var terminalFontSizes = [];
|
||||||
|
for (var i=3; i<40; i++) {
|
||||||
|
terminalFontSizes.push(i+'px');
|
||||||
|
}
|
||||||
|
return terminalFontSizes;
|
||||||
|
};
|
||||||
|
function getFontSize() {
|
||||||
|
if (!fontSize) {
|
||||||
|
return $('.terminal').css('font-size');
|
||||||
|
}
|
||||||
|
return fontSize;
|
||||||
|
}
|
||||||
|
function setFontSize(value) {
|
||||||
|
fontSize = value;
|
||||||
|
var size = parseInt(value);
|
||||||
|
$('.terminal').css('font-size', value).css('line-height', (size + 2)+'px');
|
||||||
|
//.css('line-height', value).css('height', value);
|
||||||
|
angular.element($window).trigger('resize');
|
||||||
|
}
|
||||||
|
function increaseFontSize() {
|
||||||
|
var sizes = getFontSizes();
|
||||||
|
var size = getFontSize();
|
||||||
|
var i = sizes.indexOf(size);
|
||||||
|
if (i == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i+1 > sizes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setFontSize(sizes[i+1]);
|
||||||
|
}
|
||||||
|
function decreaseFontSize() {
|
||||||
|
var sizes = getFontSizes();
|
||||||
|
var size = getFontSize();
|
||||||
|
var i = sizes.indexOf(size);
|
||||||
|
if (i == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i-1 < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setFontSize(sizes[i-1]);
|
||||||
|
}
|
||||||
|
function toggleFullscreen(terminal, resize) {
|
||||||
|
if(fullscreen) {
|
||||||
|
terminal.toggleFullscreen();
|
||||||
|
resize(fullscreen);
|
||||||
|
fullscreen = null;
|
||||||
|
} else {
|
||||||
|
fullscreen = terminal.proposeGeometry();
|
||||||
|
terminal.toggleFullscreen();
|
||||||
|
angular.element($window).trigger('resize');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,20 +10,19 @@
|
|||||||
* @module xterm/addons/fit/fit
|
* @module xterm/addons/fit/fit
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function (fit) {
|
(function (fit) {
|
||||||
if (typeof exports === 'object' && typeof module === 'object') {
|
if (typeof exports === 'object' && typeof module === 'object') {
|
||||||
/*
|
/*
|
||||||
* CommonJS environment
|
* CommonJS environment
|
||||||
*/
|
*/
|
||||||
module.exports = fit(require('../../xterm'));
|
module.exports = fit(require('../../xterm'));
|
||||||
}
|
} else if (typeof define == 'function') {
|
||||||
else if (typeof define == 'function') {
|
|
||||||
/*
|
/*
|
||||||
* Require.js is available
|
* Require.js is available
|
||||||
*/
|
*/
|
||||||
define(['../../xterm'], fit);
|
define(['../../xterm'], fit);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/*
|
/*
|
||||||
* Plain browser environment
|
* Plain browser environment
|
||||||
*/
|
*/
|
||||||
@ -31,29 +30,65 @@
|
|||||||
}
|
}
|
||||||
})(function (Xterm) {
|
})(function (Xterm) {
|
||||||
var exports = {};
|
var exports = {};
|
||||||
|
|
||||||
exports.proposeGeometry = function (term) {
|
exports.proposeGeometry = function (term) {
|
||||||
var parentElementStyle = window.getComputedStyle(term.element.parentElement), parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), elementStyle = window.getComputedStyle(term.element), elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), availableHeight = parentElementHeight - elementPaddingVer, availableWidth = parentElementWidth - elementPaddingHor, container = term.rowContainer, subjectRow = term.rowContainer.firstElementChild, contentBuffer = subjectRow.innerHTML, characterHeight, rows, characterWidth, cols, geometry;
|
if (!term.element.parentElement) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var parentElementStyle = window.getComputedStyle(term.element.parentElement),
|
||||||
|
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')),
|
||||||
|
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17),
|
||||||
|
elementStyle = window.getComputedStyle(term.element),
|
||||||
|
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
|
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')),
|
||||||
|
availableHeight = parentElementHeight - elementPaddingVer,
|
||||||
|
availableWidth = parentElementWidth - elementPaddingHor,
|
||||||
|
container = term.rowContainer,
|
||||||
|
subjectRow = term.rowContainer.firstElementChild,
|
||||||
|
contentBuffer = subjectRow.innerHTML,
|
||||||
|
characterHeight,
|
||||||
|
rows,
|
||||||
|
characterWidth,
|
||||||
|
cols,
|
||||||
|
geometry;
|
||||||
|
|
||||||
|
if (term.element.classList.contains('fullscreen')) {
|
||||||
|
// we are in fullscreen mode and need to use element height and width directly;
|
||||||
|
|
||||||
|
availableHeight = parseInt(elementStyle.getPropertyValue('height'));
|
||||||
|
availableWidth = Math.max(0, parseInt(elementStyle.getPropertyValue('width')) - 17);
|
||||||
|
}
|
||||||
|
|
||||||
subjectRow.style.display = 'inline';
|
subjectRow.style.display = 'inline';
|
||||||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
||||||
characterWidth = subjectRow.getBoundingClientRect().width;
|
characterWidth = subjectRow.getBoundingClientRect().width;
|
||||||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
||||||
characterHeight = parseInt(subjectRow.offsetHeight);
|
//characterHeight = subjectRow.getBoundingClientRect().height;
|
||||||
|
characterHeight = parseInt(window.getComputedStyle(subjectRow).fontSize, 10)+2;
|
||||||
subjectRow.innerHTML = contentBuffer;
|
subjectRow.innerHTML = contentBuffer;
|
||||||
|
|
||||||
rows = parseInt(availableHeight / characterHeight);
|
rows = parseInt(availableHeight / characterHeight);
|
||||||
cols = parseInt(availableWidth / characterWidth);
|
cols = parseInt(availableWidth / characterWidth);
|
||||||
|
|
||||||
geometry = {cols: cols, rows: rows};
|
geometry = {cols: cols, rows: rows};
|
||||||
return geometry;
|
return geometry;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.fit = function (term) {
|
exports.fit = function (term) {
|
||||||
var geometry = exports.proposeGeometry(term);
|
var geometry = exports.proposeGeometry(term);
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
term.resize(geometry.cols, geometry.rows);
|
term.resize(geometry.cols, geometry.rows);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Xterm.prototype.proposeGeometry = function () {
|
Xterm.prototype.proposeGeometry = function () {
|
||||||
return exports.proposeGeometry(this);
|
return exports.proposeGeometry(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Xterm.prototype.fit = function () {
|
Xterm.prototype.fit = function () {
|
||||||
return exports.fit(this);
|
return exports.fit(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
return exports;
|
return exports;
|
||||||
});
|
});
|
||||||
//# sourceMappingURL=fit.js.map
|
|
10
www/assets/xterm-addons/fullscreen.css
Normal file
10
www/assets/xterm-addons/fullscreen.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.xterm.fullscreen {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
z-index: 255;
|
||||||
|
}
|
50
www/assets/xterm-addons/fullscreen.js
Normal file
50
www/assets/xterm-addons/fullscreen.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Fullscreen addon for xterm.js
|
||||||
|
* @module xterm/addons/fullscreen/fullscreen
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
(function (fullscreen) {
|
||||||
|
if (typeof exports === 'object' && typeof module === 'object') {
|
||||||
|
/*
|
||||||
|
* CommonJS environment
|
||||||
|
*/
|
||||||
|
module.exports = fullscreen(require('../../xterm'));
|
||||||
|
} else if (typeof define == 'function') {
|
||||||
|
/*
|
||||||
|
* Require.js is available
|
||||||
|
*/
|
||||||
|
define(['../../xterm'], fullscreen);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Plain browser environment
|
||||||
|
*/
|
||||||
|
fullscreen(window.Terminal);
|
||||||
|
}
|
||||||
|
})(function (Xterm) {
|
||||||
|
var exports = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the given terminal's fullscreen mode.
|
||||||
|
* @param {Xterm} 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');
|
||||||
|
};
|
||||||
|
|
||||||
|
Xterm.prototype.toggleFullscreen = function (fullscreen) {
|
||||||
|
exports.toggleFullScreen(this, fullscreen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
});
|
@ -5,6 +5,7 @@
|
|||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons" />
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons" />
|
||||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
|
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
|
||||||
<link rel="stylesheet" href="/assets/xterm.css" />
|
<link rel="stylesheet" href="/assets/xterm.css" />
|
||||||
|
<link rel="stylesheet" href="/assets/xterm-addons/fullscreen.css" />
|
||||||
<link rel="stylesheet" href="/assets/style.css" />
|
<link rel="stylesheet" href="/assets/style.css" />
|
||||||
<script>
|
<script>
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
@ -161,6 +162,18 @@
|
|||||||
</md-input-container>
|
</md-input-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div layout="row">
|
||||||
|
<div flex="50">
|
||||||
|
<md-input-container class="md-block" flex-gt-sm>
|
||||||
|
<label>Terminal Font Size</label>
|
||||||
|
<md-select ng-model="$ctrl.currentTerminalFontSize" ng-model-options="{getterSetter: true}">
|
||||||
|
<md-option ng-repeat="size in $ctrl.terminalFontSizes" value="{{size}}">
|
||||||
|
{{ size }}
|
||||||
|
</md-option>
|
||||||
|
</md-select>
|
||||||
|
</md-input-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</md-dialog-content>
|
</md-dialog-content>
|
||||||
|
|
||||||
@ -172,6 +185,11 @@
|
|||||||
</md-dialog-actions>
|
</md-dialog-actions>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script
|
||||||
|
src="https://code.jquery.com/jquery-3.2.1.min.js"
|
||||||
|
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
|
||||||
@ -182,6 +200,7 @@
|
|||||||
<script src="/assets/app.js"></script>
|
<script src="/assets/app.js"></script>
|
||||||
<script src="/assets/xterm.js"></script>
|
<script src="/assets/xterm.js"></script>
|
||||||
<script src="/assets/xterm-addons/fit.js"></script>
|
<script src="/assets/xterm-addons/fit.js"></script>
|
||||||
|
<script src="/assets/xterm-addons/fullscreen.js"></script>
|
||||||
<script src="/assets/attach.js"></script>
|
<script src="/assets/attach.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
|
||||||
<script type="text/javascript" charset="utf-8">
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user