Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
7.2.17-SNAPSHOT (WIP)
==================
* [OLMIS-8191](https://openlmis.atlassian.net/browse/OLMIS-8191) / [OLMIS-8192](https://openlmis.atlassian.net/browse/OLMIS-8192): Add openlmis-long-text class and directive so long free-text in table cells grows with content then wraps — for both the editable textarea and its read-only display.

7.2.16 / 2026-06-09
==================
Expand Down
4 changes: 4 additions & 0 deletions src/common/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ $padding-small: 0.5em;
$padding: (2 * $padding-small);
$padding-large: (2 * $padding);

// openlmis-long-text widen-then-wrap: cap = where wrapping starts, floor = editable typing room.
$openlmis-long-text-max-width: 35em !default;
$openlmis-long-text-min-width: 14em !default;

$margin: 1em;

$padding2px:2px;
Expand Down
19 changes: 16 additions & 3 deletions src/openlmis-table-form/_table-forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,24 @@ td > label.checkbox {
width: 100%;
}

.openlmis-table td > div.input-control > textarea {
min-width: 14em;
max-width: 20em;
// Long free-text in a table column: widens with content, then wraps. Opt-in class on the
// editable textarea (sized by the openlmisLongText directive) and the read-only span.
.openlmis-long-text {
display: inline-block;
max-width: $openlmis-long-text-max-width;
white-space: pre-wrap;
overflow-wrap: break-word;
overflow: hidden;
resize: none;
vertical-align: middle;
}

// Editable: minimum typing width (the directive sets the actual width).
textarea.openlmis-long-text {
min-width: $openlmis-long-text-min-width;
}

// Read-only: size to content up to the cap, so short cells stay narrow and long text wraps.
span.openlmis-long-text {
width: max-content;
}
Binary file not shown.
102 changes: 102 additions & 0 deletions src/openlmis-table-form/openlmis-long-text.directive.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* This program is part of the OpenLMIS logistics management information system platform software.
* Copyright © 2017 VillageReach
*
* This program is free software: you can redistribute it and/or modify it under the terms
* of the GNU Affero General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*  
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
* See the GNU Affero General Public License for more details. You should have received a copy of
* the GNU Affero General Public License along with this program. If not, see
* http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org. 
*/

describe('openlmisLongText directive', function() {

beforeEach(function() {
module('openlmis-table-form');

inject(function($injector) {
this.$compile = $injector.get('$compile');
this.$rootScope = $injector.get('$rootScope');
});

this.$scope = this.$rootScope.$new();

this.compileMarkup = function(markup) {
const element = this.$compile(markup)(this.$scope);
angular.element('body').append(element);
this.$scope.$apply();
return element;
};
});

it('should set an explicit width and height on a textarea with the class', function() {
const textarea = this.compileMarkup('<textarea class="openlmis-long-text">short</textarea>');

expect(Number.parseInt(textarea[0].style.width, 10)).toBeGreaterThan(0);
expect(Number.parseInt(textarea[0].style.height, 10)).toBeGreaterThan(0);
});

it('should grow width when the value becomes longer', function() {
const textarea = this.compileMarkup('<textarea class="openlmis-long-text">short</textarea>');
const previousWidth = Number.parseInt(textarea[0].style.width, 10);

textarea[0].value = 'a value that is clearly longer than the initial one';
this.$scope.$apply();

expect(Number.parseInt(textarea[0].style.width, 10)).toBeGreaterThan(previousWidth);
});

it('should grow height when the value spans multiple lines', function() {
const textarea = this.compileMarkup('<textarea class="openlmis-long-text">short</textarea>');
const previousHeight = Number.parseInt(textarea[0].style.height, 10);

textarea[0].value = 'first line\nsecond line\nthird line\nfourth line';
this.$scope.$apply();

expect(Number.parseInt(textarea[0].style.height, 10)).toBeGreaterThan(previousHeight);
});

it('should not resize a textarea that does not have the class', function() {
const textarea = this.compileMarkup('<textarea>plain</textarea>');

expect(textarea[0].style.width).toEqual('');
expect(textarea[0].style.height).toEqual('');
});

it('should not set an inline size on a read-only span with the class', function() {
const span = this.compileMarkup('<span class="openlmis-long-text">read only</span>');

expect(span[0].style.width).toEqual('');
expect(span[0].style.height).toEqual('');
});

it('should not collapse a textarea that is hidden when linked', function() {
const textarea = this.compileMarkup(
'<textarea class="openlmis-long-text" style="display: none;">hidden</textarea>'
);

// A hidden textarea reports scrollHeight 0; sizing it then would bake height:0 and
// leave it collapsed once shown (e.g. an ng-show free-text comment). It must be skipped.
expect(textarea[0].style.height).not.toEqual('0px');
});

it('should size a pre-filled textarea once it becomes visible after being hidden', function() {
const textarea = this.compileMarkup(
'<textarea class="openlmis-long-text" style="display: none;">a pre-filled value</textarea>'
);

// Hidden at link time -> skipped, no inline height yet.
expect(textarea[0].style.height).toEqual('');

// Shown later without a value change -> the visibility watch must size it.
textarea[0].style.display = '';
this.$scope.$apply();

expect(Number.parseInt(textarea[0].style.height, 10)).toBeGreaterThan(0);
expect(Number.parseInt(textarea[0].style.width, 10)).toBeGreaterThan(0);
});
});
79 changes: 0 additions & 79 deletions src/openlmis-table-form/textarea-auto-resize.directive.spec.js

This file was deleted.

Loading