mirror of
https://github.com/bingohuang/docker-labs.git
synced 2025-07-13 09:12:43 +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);
|
||||
}]);
|
||||
|
||||
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.instances = [];
|
||||
$scope.idx = {};
|
||||
@ -52,6 +52,8 @@
|
||||
$scope.socket.emit('viewport resize', geometry.cols, geometry.rows);
|
||||
}
|
||||
|
||||
KeyboardShortcutService.setResizeFunc($scope.resize);
|
||||
|
||||
$scope.closeSession = function() {
|
||||
$scope.socket.emit('session close');
|
||||
}
|
||||
@ -195,6 +197,7 @@
|
||||
if (!instance.term) {
|
||||
$timeout(function() {
|
||||
createTerminal(instance);
|
||||
TerminalService.setFontSize(TerminalService.getFontSize());
|
||||
instance.term.focus();
|
||||
}, 0, false);
|
||||
return
|
||||
@ -326,14 +329,14 @@
|
||||
})
|
||||
.component("settingsDialog", {
|
||||
templateUrl : "settings-modal.html",
|
||||
controller : function($mdDialog, KeyboardShortcutService, $rootScope, InstanceService) {
|
||||
controller : function($mdDialog, KeyboardShortcutService, $rootScope, InstanceService, TerminalService) {
|
||||
var $ctrl = this;
|
||||
|
||||
$ctrl.$onInit = function() {
|
||||
$ctrl.keyboardShortcutPresets = KeyboardShortcutService.getAvailablePresets();
|
||||
$ctrl.selectedShortcutPreset = KeyboardShortcutService.getCurrentShortcuts();
|
||||
$ctrl.instanceImages = InstanceService.getAvailableImages();
|
||||
$ctrl.selectedInstanceImage = InstanceService.getDesiredImage();
|
||||
$ctrl.terminalFontSizes = TerminalService.getFontSizes();
|
||||
};
|
||||
|
||||
$ctrl.currentShortcutConfig = function(value) {
|
||||
@ -352,6 +355,15 @@
|
||||
}
|
||||
return InstanceService.getDesiredImage(value);
|
||||
};
|
||||
$ctrl.currentTerminalFontSize = function(value) {
|
||||
if (value !== undefined) {
|
||||
// set font size
|
||||
TerminalService.setFontSize(value);
|
||||
return;
|
||||
}
|
||||
|
||||
return TerminalService.getFontSize();
|
||||
}
|
||||
|
||||
$ctrl.close = function() {
|
||||
$mdDialog.cancel();
|
||||
@ -396,20 +408,30 @@
|
||||
|
||||
})
|
||||
.run(function(InstanceService) { /* forcing pre-populating for now */ })
|
||||
.service("KeyboardShortcutService", function() {
|
||||
.service("KeyboardShortcutService", ['TerminalService', function(TerminalService) {
|
||||
var resizeFunc;
|
||||
|
||||
return {
|
||||
getAvailablePresets : getAvailablePresets,
|
||||
getCurrentShortcuts : getCurrentShortcuts,
|
||||
setCurrentShortcuts : setCurrentShortcuts
|
||||
setCurrentShortcuts : setCurrentShortcuts,
|
||||
setResizeFunc : setResizeFunc
|
||||
};
|
||||
|
||||
function setResizeFunc(f) {
|
||||
resizeFunc = f;
|
||||
}
|
||||
|
||||
function getAvailablePresets() {
|
||||
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",
|
||||
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 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,50 +10,85 @@
|
||||
* @module xterm/addons/fit/fit
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (fit) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fit(require('../../xterm'));
|
||||
}
|
||||
else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fit);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fit(window.Terminal);
|
||||
}
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fit(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fit);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fit(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
var exports = {};
|
||||
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;
|
||||
subjectRow.style.display = 'inline';
|
||||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
||||
characterWidth = subjectRow.getBoundingClientRect().width;
|
||||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
||||
characterHeight = parseInt(subjectRow.offsetHeight);
|
||||
subjectRow.innerHTML = contentBuffer;
|
||||
rows = parseInt(availableHeight / characterHeight);
|
||||
cols = parseInt(availableWidth / characterWidth);
|
||||
geometry = { cols: cols, rows: rows };
|
||||
return geometry;
|
||||
};
|
||||
exports.fit = function (term) {
|
||||
var geometry = exports.proposeGeometry(term);
|
||||
term.resize(geometry.cols, geometry.rows);
|
||||
};
|
||||
Xterm.prototype.proposeGeometry = function () {
|
||||
return exports.proposeGeometry(this);
|
||||
};
|
||||
Xterm.prototype.fit = function () {
|
||||
return exports.fit(this);
|
||||
};
|
||||
return exports;
|
||||
var exports = {};
|
||||
|
||||
exports.proposeGeometry = function (term) {
|
||||
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.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
||||
characterWidth = subjectRow.getBoundingClientRect().width;
|
||||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
||||
//characterHeight = subjectRow.getBoundingClientRect().height;
|
||||
characterHeight = parseInt(window.getComputedStyle(subjectRow).fontSize, 10)+2;
|
||||
subjectRow.innerHTML = contentBuffer;
|
||||
|
||||
rows = parseInt(availableHeight / characterHeight);
|
||||
cols = parseInt(availableWidth / characterWidth);
|
||||
|
||||
geometry = {cols: cols, rows: rows};
|
||||
return geometry;
|
||||
};
|
||||
|
||||
exports.fit = function (term) {
|
||||
var geometry = exports.proposeGeometry(term);
|
||||
|
||||
if (geometry) {
|
||||
term.resize(geometry.cols, geometry.rows);
|
||||
}
|
||||
};
|
||||
|
||||
Xterm.prototype.proposeGeometry = function () {
|
||||
return exports.proposeGeometry(this);
|
||||
};
|
||||
|
||||
Xterm.prototype.fit = function () {
|
||||
return exports.fit(this);
|
||||
};
|
||||
|
||||
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://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-addons/fullscreen.css" />
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
@ -161,6 +162,18 @@
|
||||
</md-input-container>
|
||||
</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>
|
||||
</md-dialog-content>
|
||||
|
||||
@ -172,6 +185,11 @@
|
||||
</md-dialog-actions>
|
||||
</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-animate.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/xterm.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="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
Loading…
x
Reference in New Issue
Block a user