From 1f2007eb28ac76e57184c8ce9d450ad92512dcb4 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 3 Jul 2021 13:58:54 -0700 Subject: [PATCH] GUACAMOLE-724: Replace CSS grid layout with simpler, equialent, and more compatible flex layout. --- .../app/client/directives/guacTiledClients.js | 18 ++--- ...-client-list.css => tiled-client-grid.css} | 63 ++++++++++++---- .../client/templates/guacTiledClients.html | 35 ++++----- .../app/client/types/ManagedClientGroup.js | 71 ++++++++++--------- 4 files changed, 108 insertions(+), 79 deletions(-) rename guacamole/src/main/frontend/src/app/client/styles/{tiled-client-list.css => tiled-client-grid.css} (53%) diff --git a/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js b/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js index 9c3ab8663..efb0d936a 100644 --- a/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js +++ b/guacamole/src/main/frontend/src/app/client/directives/guacTiledClients.js @@ -150,24 +150,14 @@ angular.module('client').directive('guacTiledClients', [function guacTiledClient $scope.hasMultipleClients = ManagedClientGroup.hasMultipleClients; /** - * @borrows ManagedClientGroup.getTileGridCSS + * @borrows ManagedClientGroup.getClientGrid */ - $scope.getTileGridCSS = ManagedClientGroup.getTileGridCSS; + $scope.getClientGrid = ManagedClientGroup.getClientGrid; /** - * Returns whether the given ManagedClient has any associated share - * links. - * - * @param {ManagedClient} client - * The ManagedClient to test. - * - * @returns {Boolean} - * true if the given ManagedClient has at least one associated - * share link, false otherwise. + * @borrows ManagedClient.isShared */ - $scope.isShared = function isShared(client) { - return ManagedClient.isShared(client); - }; + $scope.isShared = ManagedClient.isShared; }]; diff --git a/guacamole/src/main/frontend/src/app/client/styles/tiled-client-list.css b/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css similarity index 53% rename from guacamole/src/main/frontend/src/app/client/styles/tiled-client-list.css rename to guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css index b40ec2896..06bcaf62a 100644 --- a/guacamole/src/main/frontend/src/app/client/styles/tiled-client-list.css +++ b/guacamole/src/main/frontend/src/app/client/styles/tiled-client-grid.css @@ -17,13 +17,50 @@ * under the License. */ -.tiled-client-list { - padding: 0; - margin: 0; - line-height: 0; +/* + * Overall tiled grid layout. + */ + +.tiled-client-grid { + width: 100%; + height: 100%; } -.tiled-client-list li.client-tile { +.tiled-client-grid, +.tiled-client-grid .tiled-client-row, +.tiled-client-grid .tiled-client-cell, +.tiled-client-grid .client-tile { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.tiled-client-grid { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} + +.tiled-client-grid .tiled-client-row { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; +} + +/* + * Rendering of individual clients within tiles. + */ + +.tiled-client-grid .client-tile { position: relative; display: -webkit-box; display: -webkit-flex; @@ -37,7 +74,7 @@ line-height: 1.5; } -.tiled-client-list li.client-tile .client-tile-name { +.tiled-client-grid .client-tile .client-tile-name { margin: 0; background: #444; padding: 0 0.25em; @@ -46,35 +83,35 @@ display: none; } -.tiled-client-list.multiple-clients li.client-tile .client-tile-name { +.tiled-client-grid.multiple-clients .client-tile .client-tile-name { display: block; } -.tiled-client-list.multiple-clients li.client-tile { +.tiled-client-grid.multiple-clients .client-tile { border: 1px solid #444; } -.tiled-client-list li.client-tile.focused { +.tiled-client-grid .client-tile.focused { border-color: #3161a9; } -.tiled-client-list li.client-tile.focused .client-tile-name { +.tiled-client-grid .client-tile.focused .client-tile-name { background-color: #3161a9; } -.tiled-client-list li.client-tile .main { +.tiled-client-grid .client-tile .main { -webkit-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; } -.tiled-client-list .client-tile-shared-indicator { +.tiled-client-grid .client-tile-shared-indicator { display: none; max-height: 1em; height: 100%; } -.tiled-client-list .shared .client-tile-shared-indicator { +.tiled-client-grid .shared .client-tile-shared-indicator { display: inline; } diff --git a/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html b/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html index 5d8d52ff7..3f79153f7 100644 --- a/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html +++ b/guacamole/src/main/frontend/src/app/client/templates/guacTiledClients.html @@ -1,22 +1,23 @@ - \ No newline at end of file + diff --git a/guacamole/src/main/frontend/src/app/client/types/ManagedClientGroup.js b/guacamole/src/main/frontend/src/app/client/types/ManagedClientGroup.js index 8c057c935..289604cd7 100644 --- a/guacamole/src/main/frontend/src/app/client/types/ManagedClientGroup.js +++ b/guacamole/src/main/frontend/src/app/client/types/ManagedClientGroup.js @@ -282,47 +282,48 @@ angular.module('client').factory('ManagedClientGroup', ['$injector', function de }; /** - * Returns the CSS that should used to achieve a proper grid arrangement - * of the client tiles represented by the given ManagedClientGroup. The - * CSS should be assigned to the element displaying the given - * ManagedClientGroup or, if an index is provided, the element representing - * the client having the given index within the group. - * - * NOTE: Much of this is unnecessary if support for IE is dropped. When - * that is eventually unavoidable (migration to Angular), this can be - * simplified. + * Returns a two-dimensional array of all ManagedClients within the given + * group, arranged in the grid defined by {@link ManagedClientGroup#rows} + * and {@link ManagedClientGroup#columns}. If any grid cell lacks a + * corresponding client (because the number of clients does not divide + * evenly into a grid), that cell will be null. + * + * For the sake of AngularJS scope watches, the results of calling this + * function are cached and will always favor modifying an existing array + * over creating a new array, even for nested arrays. * * @param {ManagedClientGroup} group - * The ManagedClientGroup to determine CSS for. + * The ManagedClientGroup defining the tiled grid arrangement of + * ManagedClients. * - * @param {number} [index] - * The index of the relevant client within the group, if not producing - * CSS for the group itself. - * - * @returns {string} - * The CSS that should be assigned to the element representing the - * given group or, if an index is provided, the CSS that should be - * assigned to the element representing the client having the given - * index within the group. + * @returns {ManagedClient[][]} + * A two-dimensional array of all ManagedClients within the given + * group. */ - ManagedClientGroup.getTileGridCSS = function getTileGridCSS(group, index) { + ManagedClientGroup.getClientGrid = function getClientGrid(group) { - // Produce CSS defining a regular grid if no specific client is - // requested - if (arguments.length <= 1) - return 'display: -ms-grid;' - + 'display: grid;' - + '-ms-grid-rows: (1fr)[' + group.rows + '];' - + 'grid-template-rows: repeat(' + group.rows + ', 1fr);' - + '-ms-grid-columns: (1fr)[' + group.columns + '];' - + 'grid-template-columns: repeat(' + group.columns + ', 1fr);'; + var index = 0; - // For IE10+, the row/column coordinates of each child of a grid - // layout must be explicitly defined - var row = Math.floor(index / group.columns); - var column = index - row * group.columns; - return '-ms-grid-row: ' + (row + 1) + ';' - + '-ms-grid-column: ' + (column + 1) + ';'; + // Operate on cached copy of grid + var clientGrid = group._grid || (group._grid = []); + + // Delete any rows in excess of the required size + clientGrid.splice(group.rows); + + for (var row = 0; row < group.rows; row++) { + + // Prefer to use existing column arrays, deleting any columns in + // excess of the required size + var currentRow = clientGrid[row] || (clientGrid[row] = []); + currentRow.splice(group.columns); + + for (var column = 0; column < group.columns; column++) { + currentRow[column] = group.clients[index++] || null; + } + + } + + return clientGrid; };