68346: Cleanup of bootstrap col classes in item-bitstream components

This commit is contained in:
Kristof De Langhe
2020-02-11 13:06:31 +01:00
parent c38bf3fd0c
commit 87d7bc1a20
15 changed files with 273 additions and 13 deletions

View File

@@ -25,17 +25,18 @@
<div *ngIf="item && bundles?.length > 0" class="container table-bordered mt-4"> <div *ngIf="item && bundles?.length > 0" class="container table-bordered mt-4">
<div class="row header-row font-weight-bold"> <div class="row header-row font-weight-bold">
<div class="col-2 col-md-3 col-lg-4 row-element"> <div class="{{columnSizes.columns[0].buildClasses()}} row-element">
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle> <ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
{{'item.edit.bitstreams.headers.name' | translate}} {{'item.edit.bitstreams.headers.name' | translate}}
</div> </div>
<div class="col-2 col-sm-3 row-element">{{'item.edit.bitstreams.headers.description' | translate}}</div> <div class="{{columnSizes.columns[1].buildClasses()}} row-element">{{'item.edit.bitstreams.headers.description' | translate}}</div>
<div class="col-2 text-center row-element">{{'item.edit.bitstreams.headers.format' | translate}}</div> <div class="{{columnSizes.columns[2].buildClasses()}} text-center row-element">{{'item.edit.bitstreams.headers.format' | translate}}</div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 text-center row-element">{{'item.edit.bitstreams.headers.actions' | translate}}</div> <div class="{{columnSizes.columns[3].buildClasses()}} text-center row-element">{{'item.edit.bitstreams.headers.actions' | translate}}</div>
</div> </div>
<ds-item-edit-bitstream-bundle *ngFor="let bundle of bundles" <ds-item-edit-bitstream-bundle *ngFor="let bundle of bundles"
[bundle]="bundle" [bundle]="bundle"
[item]="item"> [item]="item"
[columnSizes]="columnSizes">
</ds-item-edit-bitstream-bundle> </ds-item-edit-bitstream-bundle>
</div> </div>
<div *ngIf="bundles?.length === 0" <div *ngIf="bundles?.length === 0"

View File

@@ -27,6 +27,8 @@ import { Operation } from 'fast-json-patch';
import { MoveOperation } from 'fast-json-patch/lib/core'; import { MoveOperation } from 'fast-json-patch/lib/core';
import { BundleDataService } from '../../../core/data/bundle-data.service'; import { BundleDataService } from '../../../core/data/bundle-data.service';
import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model'; import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
import { ResponsiveColumnSizes } from '../../../shared/responsive-table-sizes/responsive-column-sizes';
import { ResponsiveTableSizes } from '../../../shared/responsive-table-sizes/responsive-table-sizes';
@Component({ @Component({
selector: 'ds-item-bitstreams', selector: 'ds-item-bitstreams',
@@ -52,6 +54,20 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
pageSize: 9999 pageSize: 9999
} as any; } as any;
/**
* The bootstrap sizes used for the columns within this table
*/
columnSizes = new ResponsiveTableSizes([
// Name column
new ResponsiveColumnSizes(2, 2, 3, 4, 4),
// Description column
new ResponsiveColumnSizes(2, 3, 3, 3, 3),
// Format column
new ResponsiveColumnSizes(2, 2, 2, 2, 2),
// Actions column
new ResponsiveColumnSizes(6, 5, 4, 3, 3)
]);
/** /**
* Are we currently submitting the changes? * Are we currently submitting the changes?
* Used to disable any action buttons until the submit finishes * Used to disable any action buttons until the submit finishes

View File

@@ -1,12 +1,12 @@
<ng-template #bundleView> <ng-template #bundleView>
<div class="row bundle-row"> <div class="row bundle-row">
<div class="col-6 col-sm-7 col-md-8 col-lg-9 font-weight-bold row-element d-flex"> <div class="{{bundleNameColumn.buildClasses()}} font-weight-bold row-element d-flex">
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle> <ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
<div class="float-left d-flex align-items-center"> <div class="float-left d-flex align-items-center">
{{'item.edit.bitstreams.bundle.name' | translate:{ name: bundle.name } }} {{'item.edit.bitstreams.bundle.name' | translate:{ name: bundle.name } }}
</div> </div>
</div> </div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 text-center row-element"> <div class="{{columnSizes.columns[3].buildClasses()}} text-center row-element">
<div class="btn-group bundle-action-buttons"> <div class="btn-group bundle-action-buttons">
<button [routerLink]="['/items/', item.id, 'bitstreams', 'new']" <button [routerLink]="['/items/', item.id, 'bitstreams', 'new']"
[queryParams]="{bundle: bundle.id}" [queryParams]="{bundle: bundle.id}"
@@ -17,5 +17,5 @@
</div> </div>
</div> </div>
</div> </div>
<ds-paginated-drag-and-drop-bitstream-list [bundle]="bundle"></ds-paginated-drag-and-drop-bitstream-list> <ds-paginated-drag-and-drop-bitstream-list [bundle]="bundle" [columnSizes]="columnSizes"></ds-paginated-drag-and-drop-bitstream-list>
</ng-template> </ng-template>

View File

@@ -4,12 +4,21 @@ import { TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA, ViewContainerRef } from '@angular/core'; import { NO_ERRORS_SCHEMA, ViewContainerRef } from '@angular/core';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { Bundle } from '../../../../core/shared/bundle.model'; import { Bundle } from '../../../../core/shared/bundle.model';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
describe('ItemEditBitstreamBundleComponent', () => { describe('ItemEditBitstreamBundleComponent', () => {
let comp: ItemEditBitstreamBundleComponent; let comp: ItemEditBitstreamBundleComponent;
let fixture: ComponentFixture<ItemEditBitstreamBundleComponent>; let fixture: ComponentFixture<ItemEditBitstreamBundleComponent>;
let viewContainerRef: ViewContainerRef; let viewContainerRef: ViewContainerRef;
const columnSizes = new ResponsiveTableSizes([
new ResponsiveColumnSizes(2, 2, 3, 4, 4),
new ResponsiveColumnSizes(2, 3, 3, 3, 3),
new ResponsiveColumnSizes(2, 2, 2, 2, 2),
new ResponsiveColumnSizes(6, 5, 4, 3, 3)
]);
const item = Object.assign(new Item(), { const item = Object.assign(new Item(), {
id: 'item-1', id: 'item-1',
uuid: 'item-1' uuid: 'item-1'
@@ -35,6 +44,7 @@ describe('ItemEditBitstreamBundleComponent', () => {
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.item = item; comp.item = item;
comp.bundle = bundle; comp.bundle = bundle;
comp.columnSizes = columnSizes;
viewContainerRef = (comp as any).viewContainerRef; viewContainerRef = (comp as any).viewContainerRef;
spyOn(viewContainerRef, 'createEmbeddedView'); spyOn(viewContainerRef, 'createEmbeddedView');
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -16,6 +16,8 @@ import { combineLatest as observableCombineLatest } from 'rxjs';
import { hasNoValue, isEmpty } from '../../../../shared/empty.util'; import { hasNoValue, isEmpty } from '../../../../shared/empty.util';
import { PaginatedSearchOptions } from '../../../../shared/search/paginated-search-options.model'; import { PaginatedSearchOptions } from '../../../../shared/search/paginated-search-options.model';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
@Component({ @Component({
selector: 'ds-item-edit-bitstream-bundle', selector: 'ds-item-edit-bitstream-bundle',
@@ -42,10 +44,22 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
*/ */
@Input() item: Item; @Input() item: Item;
/**
* The bootstrap sizes used for the columns within this table
*/
@Input() columnSizes: ResponsiveTableSizes;
/**
* The bootstrap sizes used for the Bundle Name column
* This column stretches over the first 3 columns and thus is a combination of their sizes processed in ngOnInit
*/
bundleNameColumn: ResponsiveColumnSizes;
constructor(private viewContainerRef: ViewContainerRef) { constructor(private viewContainerRef: ViewContainerRef) {
} }
ngOnInit(): void { ngOnInit(): void {
this.bundleNameColumn = this.columnSizes.combineColumns(0, 2);
this.viewContainerRef.createEmbeddedView(this.bundleView); this.viewContainerRef.createEmbeddedView(this.bundleView);
} }
} }

View File

@@ -19,7 +19,8 @@
'bg-white': updateValue.changeType === undefined 'bg-white': updateValue.changeType === undefined
}"> }">
<ds-item-edit-bitstream [fieldUpdate]="updateValue" <ds-item-edit-bitstream [fieldUpdate]="updateValue"
[bundleUrl]="bundle.self"> [bundleUrl]="bundle.self"
[columnSizes]="columnSizes">
<div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle> <div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle>
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle> <ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
</div> </div>

View File

@@ -13,6 +13,8 @@ import { BitstreamFormat } from '../../../../../core/shared/bitstream-format.mod
import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
import { of as observableOf } from 'rxjs/internal/observable/of'; import { of as observableOf } from 'rxjs/internal/observable/of';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { ResponsiveColumnSizes } from '../../../../../shared/responsive-table-sizes/responsive-column-sizes';
describe('PaginatedDragAndDropBitstreamListComponent', () => { describe('PaginatedDragAndDropBitstreamListComponent', () => {
let comp: PaginatedDragAndDropBitstreamListComponent; let comp: PaginatedDragAndDropBitstreamListComponent;
@@ -20,6 +22,13 @@ describe('PaginatedDragAndDropBitstreamListComponent', () => {
let objectUpdatesService: ObjectUpdatesService; let objectUpdatesService: ObjectUpdatesService;
let bundleService: BundleDataService; let bundleService: BundleDataService;
const columnSizes = new ResponsiveTableSizes([
new ResponsiveColumnSizes(2, 2, 3, 4, 4),
new ResponsiveColumnSizes(2, 3, 3, 3, 3),
new ResponsiveColumnSizes(2, 2, 2, 2, 2),
new ResponsiveColumnSizes(6, 5, 4, 3, 3)
]);
const bundle = Object.assign(new Bundle(), { const bundle = Object.assign(new Bundle(), {
id: 'bundle-1', id: 'bundle-1',
uuid: 'bundle-1', uuid: 'bundle-1',
@@ -104,6 +113,7 @@ describe('PaginatedDragAndDropBitstreamListComponent', () => {
fixture = TestBed.createComponent(PaginatedDragAndDropBitstreamListComponent); fixture = TestBed.createComponent(PaginatedDragAndDropBitstreamListComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.bundle = bundle; comp.bundle = bundle;
comp.columnSizes = columnSizes;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -6,6 +6,7 @@ import { ObjectUpdatesService } from '../../../../../core/data/object-updates/ob
import { BundleDataService } from '../../../../../core/data/bundle-data.service'; import { BundleDataService } from '../../../../../core/data/bundle-data.service';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model'; import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model';
import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-sizes/responsive-table-sizes';
@Component({ @Component({
selector: 'ds-paginated-drag-and-drop-bitstream-list', selector: 'ds-paginated-drag-and-drop-bitstream-list',
@@ -24,6 +25,11 @@ export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginate
*/ */
@Input() bundle: Bundle; @Input() bundle: Bundle;
/**
* The bootstrap sizes used for the columns within this table
*/
@Input() columnSizes: ResponsiveTableSizes;
constructor(protected objectUpdatesService: ObjectUpdatesService, constructor(protected objectUpdatesService: ObjectUpdatesService,
protected elRef: ElementRef, protected elRef: ElementRef,
protected bundleService: BundleDataService) { protected bundleService: BundleDataService) {

View File

@@ -1,21 +1,21 @@
<ng-template #bitstreamView> <ng-template #bitstreamView>
<div class="col-2 col-md-3 col-lg-4 row-element d-flex"> <div class="{{columnSizes.columns[0].buildClasses()}} row-element d-flex">
<ng-content select="[slot=drag-handle]"></ng-content> <ng-content select="[slot=drag-handle]"></ng-content>
<div class="float-left d-flex align-items-center"> <div class="float-left d-flex align-items-center">
{{ bitstream.name }} {{ bitstream.name }}
</div> </div>
</div> </div>
<div class="col-2 col-sm-3 row-element d-flex align-items-center"> <div class="{{columnSizes.columns[1].buildClasses()}} row-element d-flex align-items-center">
<div class="w-100"> <div class="w-100">
{{ bitstream.description }} {{ bitstream.description }}
</div> </div>
</div> </div>
<div class="col-2 row-element d-flex align-items-center"> <div class="{{columnSizes.columns[2].buildClasses()}} row-element d-flex align-items-center">
<div class="text-center w-100"> <div class="text-center w-100">
{{ (format$ | async).shortDescription }} {{ (format$ | async).shortDescription }}
</div> </div>
</div> </div>
<div class="col-6 col-sm-5 col-md-4 col-lg-3 row-element d-flex align-items-center"> <div class="{{columnSizes.columns[3].buildClasses()}} row-element d-flex align-items-center">
<div class="text-center w-100"> <div class="text-center w-100">
<div class="btn-group relationship-action-buttons"> <div class="btn-group relationship-action-buttons">
<a [href]="bitstream?.content" <a [href]="bitstream?.content"

View File

@@ -8,10 +8,19 @@ import { VarDirective } from '../../../../shared/utils/var.directive';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { createMockRDObs } from '../item-bitstreams.component.spec'; import { createMockRDObs } from '../item-bitstreams.component.spec';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model'; import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
let comp: ItemEditBitstreamComponent; let comp: ItemEditBitstreamComponent;
let fixture: ComponentFixture<ItemEditBitstreamComponent>; let fixture: ComponentFixture<ItemEditBitstreamComponent>;
const columnSizes = new ResponsiveTableSizes([
new ResponsiveColumnSizes(2, 2, 3, 4, 4),
new ResponsiveColumnSizes(2, 3, 3, 3, 3),
new ResponsiveColumnSizes(2, 2, 2, 2, 2),
new ResponsiveColumnSizes(6, 5, 4, 3, 3)
]);
const format = Object.assign(new BitstreamFormat(), { const format = Object.assign(new BitstreamFormat(), {
shortDescription: 'PDF' shortDescription: 'PDF'
}); });
@@ -71,6 +80,7 @@ describe('ItemEditBitstreamComponent', () => {
comp = fixture.componentInstance; comp = fixture.componentInstance;
comp.fieldUpdate = fieldUpdate; comp.fieldUpdate = fieldUpdate;
comp.bundleUrl = url; comp.bundleUrl = url;
comp.columnSizes = columnSizes;
comp.ngOnChanges(undefined); comp.ngOnChanges(undefined);
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -7,6 +7,7 @@ import { FieldChangeType } from '../../../../core/data/object-updates/object-upd
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model'; import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
@Component({ @Component({
selector: 'ds-item-edit-bitstream', selector: 'ds-item-edit-bitstream',
@@ -33,6 +34,11 @@ export class ItemEditBitstreamComponent implements OnChanges, OnInit {
*/ */
@Input() bundleUrl: string; @Input() bundleUrl: string;
/**
* The bootstrap sizes used for the columns within this table
*/
@Input() columnSizes: ResponsiveTableSizes;
/** /**
* The bitstream of this field * The bitstream of this field
*/ */

View File

@@ -0,0 +1,22 @@
import { ResponsiveColumnSizes } from './responsive-column-sizes';
describe('ResponsiveColumnSizes', () => {
const xs = 2;
const sm = 3;
const md = 4;
const lg = 6;
const xl = 8;
const column = new ResponsiveColumnSizes(xs, sm, md, lg, xl);
describe('buildClasses', () => {
let classes: string;
beforeEach(() => {
classes = column.buildClasses();
});
it('should return the correct bootstrap classes', () => {
expect(classes).toEqual(`col-${xs} col-sm-${sm} col-md-${md} col-lg-${lg} col-xl-${xl}`);
});
});
});

View File

@@ -0,0 +1,46 @@
/**
* A helper class storing the sizes in which to render a single column
* The values in this class are expected to be between 1 and 12
* There are used to be added to bootstrap classes such as col-xs-{this.xs}
*/
export class ResponsiveColumnSizes {
/**
* The extra small bootstrap size
*/
xs: number;
/**
* The small bootstrap size
*/
sm: number;
/**
* The medium bootstrap size
*/
md: number;
/**
* The large bootstrap size
*/
lg: number;
/**
* The extra large bootstrap size
*/
xl: number;
constructor(xs: number, sm: number, md: number, lg: number, xl: number) {
this.xs = xs;
this.sm = sm;
this.md = md;
this.lg = lg;
this.xl = xl;
}
/**
* Build the bootstrap responsive column classes matching the values of this object
*/
buildClasses(): string {
return `col-${this.xs} col-sm-${this.sm} col-md-${this.md} col-lg-${this.lg} col-xl-${this.xl}`
}
}

View File

@@ -0,0 +1,76 @@
import { ResponsiveColumnSizes } from './responsive-column-sizes';
import { ResponsiveTableSizes } from './responsive-table-sizes';
describe('ResponsiveColumnSizes', () => {
const column0 = new ResponsiveColumnSizes(2, 3, 4, 6, 8);
const column1 = new ResponsiveColumnSizes(8, 7, 4, 2, 1);
const column2 = new ResponsiveColumnSizes(1, 1, 4, 2, 1);
const column3 = new ResponsiveColumnSizes(1, 1, 4, 2, 2);
const table = new ResponsiveTableSizes([column0, column1, column2, column3]);
describe('combineColumns', () => {
describe('when start value is out of bounds', () => {
let combined: ResponsiveColumnSizes;
beforeEach(() => {
combined = table.combineColumns(-1, 2);
});
it('should return undefined', () => {
expect(combined).toBeUndefined();
});
});
describe('when end value is out of bounds', () => {
let combined: ResponsiveColumnSizes;
beforeEach(() => {
combined = table.combineColumns(0, 5);
});
it('should return undefined', () => {
expect(combined).toBeUndefined();
});
});
describe('when start value is greater than end value', () => {
let combined: ResponsiveColumnSizes;
beforeEach(() => {
combined = table.combineColumns(2, 0);
});
it('should return undefined', () => {
expect(combined).toBeUndefined();
});
});
describe('when start value is equal to end value', () => {
let combined: ResponsiveColumnSizes;
beforeEach(() => {
combined = table.combineColumns(0, 0);
});
it('should return undefined', () => {
expect(combined).toBeUndefined();
});
});
describe('when provided with valid values', () => {
let combined: ResponsiveColumnSizes;
beforeEach(() => {
combined = table.combineColumns(0, 2);
});
it('should combine the sizes of each column within the range into one', () => {
expect(combined.xs).toEqual(column0.xs + column1.xs + column2.xs);
expect(combined.sm).toEqual(column0.sm + column1.sm + column2.sm);
expect(combined.md).toEqual(column0.md + column1.md + column2.md);
expect(combined.lg).toEqual(column0.lg + column1.lg + column2.lg);
expect(combined.xl).toEqual(column0.xl + column1.xl + column2.xl);
});
});
});
});

View File

@@ -0,0 +1,42 @@
import { ResponsiveColumnSizes } from './responsive-column-sizes';
import { hasValue } from '../empty.util';
/**
* A helper class storing the sizes in which to render a table
* It stores a list of columns, which in turn store their own bootstrap column sizes
*/
export class ResponsiveTableSizes {
/**
* A list of all the columns and their responsive sizes within this table
*/
columns: ResponsiveColumnSizes[];
constructor(columns: ResponsiveColumnSizes[]) {
this.columns = columns;
}
/**
* Combine the values of multiple columns into a single ResponsiveColumnSizes
* Useful when a row element stretches over multiple columns
* @param start Index of the first column
* @param end Index of the last column (inclusive)
*/
combineColumns(start: number, end: number): ResponsiveColumnSizes {
if (start < end && hasValue(this.columns[start]) && hasValue(this.columns[end])) {
let xs = this.columns[start].xs;
let sm = this.columns[start].sm;
let md = this.columns[start].md;
let lg = this.columns[start].lg;
let xl = this.columns[start].xl;
for (let i = start + 1; i < end + 1; i++) {
xs += this.columns[i].xs;
sm += this.columns[i].sm;
md += this.columns[i].md;
lg += this.columns[i].lg;
xl += this.columns[i].xl;
}
return new ResponsiveColumnSizes(xs, sm, md, lg, xl);
}
return undefined;
}
}