1
0
mirror of https://github.com/bingohuang/docker-labs.git synced 2025-07-13 17:42:53 +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:
Jonathan Leibiusky 2017-04-16 17:47:18 -05:00 committed by Marcos Nils
parent 453b39d75f
commit d6c359645c
5 changed files with 255 additions and 54 deletions

View File

@ -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');
}
}
}]);
})();

View File

@ -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

View File

@ -0,0 +1,10 @@
.xterm.fullscreen {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: auto;
height: auto;
z-index: 255;
}

View 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;
});

View File

@ -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">