mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-26 17:24:56 +00:00
[ACS-4721] tags are not displayed properly when resizing browser (#8424)
* ACS-4721 Partial fix issue with resizing window * ACS-4721 Fixed issue for overlapping view more button with tags, skip calculation if anyone clicked on view more button * ACS-4721 Unit tests * ACS-4721 Fixed lint issues * ACS-4721 Small correction in tests * ACS-4721 Fixed unit tests * ACS-4721 Fixed unit tests * ACS-4721 Resolved issues after opening viewer * ACS-4721 Formatting * ACS-4721 Fixed lint issue
This commit is contained in:
parent
3e2683e06b
commit
431b3db08a
@ -239,6 +239,29 @@ describe('ContentMetadataComponent', () => {
|
||||
expect(tagService.assignTagsToNode).toHaveBeenCalledWith(node.id, [tag1, tag2]);
|
||||
}));
|
||||
|
||||
it('should call getTagsByNodeId on TagService on save click', fakeAsync( () => {
|
||||
component.editable = true;
|
||||
component.displayTags = true;
|
||||
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, name: 'some-modified-value' };
|
||||
spyOn(nodesApiService, 'updateNode').and.returnValue(of(expectedNode));
|
||||
const tagPaging = mockTagPaging();
|
||||
const getTagsByNodeIdSpy = spyOn(tagService, 'getTagsByNodeId').and.returnValue(of(tagPaging));
|
||||
component.ngOnInit();
|
||||
spyOn(tagService, 'removeTag').and.returnValue(of(undefined));
|
||||
spyOn(tagService, 'assignTagsToNode').and.returnValue(of({}));
|
||||
|
||||
updateService.update(property, 'updated-value');
|
||||
tick(600);
|
||||
|
||||
fixture.detectChanges();
|
||||
findTagsCreator().tagsChange.emit([tagPaging.list.entries[0].entry.tag, 'New tag 3']);
|
||||
getTagsByNodeIdSpy.calls.reset();
|
||||
clickOnSave();
|
||||
|
||||
expect(tagService.getTagsByNodeId).toHaveBeenCalledWith(node.id);
|
||||
}));
|
||||
|
||||
it('should throw error on unsuccessful save', fakeAsync((done) => {
|
||||
const logService: LogService = TestBed.inject(LogService);
|
||||
component.editable = true;
|
||||
|
@ -270,6 +270,9 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.revertChanges();
|
||||
Object.assign(this.node, result.updatedNode);
|
||||
this.nodesApiService.nodeUpdated.next(this.node);
|
||||
if (Object.keys(result).length > 1 && this.displayTags) {
|
||||
this.loadTagsForNode(this.node.id);
|
||||
}
|
||||
}
|
||||
this._saving = false;
|
||||
});
|
||||
|
@ -10,7 +10,8 @@
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
<button mat-button
|
||||
*ngIf="limitTagsDisplayed"
|
||||
[hidden]="!limitTagsDisplayed"
|
||||
[style.left.px]="viewMoreButtonLeftOffset"
|
||||
class="adf-view-more-button"
|
||||
[class.adf-hidden-btn]="!calculationsDone"
|
||||
(click)="displayAllTags($event)"
|
||||
|
@ -4,13 +4,22 @@
|
||||
flex-direction: row;
|
||||
width: inherit;
|
||||
|
||||
&.adf-flex-column {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.adf-view-more-button {
|
||||
margin: 4px;
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
position: absolute;
|
||||
|
||||
&[hidden] {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-flex-column {
|
||||
flex-direction: column;
|
||||
|
||||
.adf-view-more-button {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-full-width {
|
||||
|
@ -44,15 +44,19 @@ describe('TagNodeList', () => {
|
||||
},
|
||||
{
|
||||
entry: {tag: 'test3', id: 'fb4213c0-729d-466c-9a6c-ee2e937273bf'}
|
||||
},
|
||||
{
|
||||
entry: {tag: 'test4', id: 'as4213c0-729d-466c-9a6c-ee2e937273as'}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
let component: any;
|
||||
let component: TagNodeListComponent;
|
||||
let fixture: ComponentFixture<TagNodeListComponent>;
|
||||
let element: HTMLElement;
|
||||
let tagService: TagService;
|
||||
let resizeCallback: ResizeObserverCallback;
|
||||
|
||||
function findViewMoreButton(): HTMLButtonElement {
|
||||
return element.querySelector('.adf-view-more-button');
|
||||
@ -70,6 +74,7 @@ describe('TagNodeList', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const resizeObserverSpy = spyOn(window, 'ResizeObserver').and.callThrough();
|
||||
fixture = TestBed.createComponent(TagNodeListComponent);
|
||||
|
||||
tagService = TestBed.inject(TagService);
|
||||
@ -79,6 +84,7 @@ describe('TagNodeList', () => {
|
||||
component = fixture.componentInstance;
|
||||
component.nodeId = 'fake-node-id';
|
||||
fixture.detectChanges();
|
||||
resizeCallback = resizeObserverSpy.calls.mostRecent().args[0];
|
||||
});
|
||||
|
||||
describe('Rendering tests', () => {
|
||||
@ -137,24 +143,29 @@ describe('TagNodeList', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(findViewMoreButton()).toBeNull();
|
||||
expect(findTagChips().length).toBe(3);
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Limit tags display', () => {
|
||||
let initialEntries: TagEntry[];
|
||||
|
||||
async function renderTags(entries?: TagEntry[]): Promise<any> {
|
||||
if (entries) {
|
||||
dataTag.list.entries = entries;
|
||||
}
|
||||
dataTag.list.entries = entries || initialEntries;
|
||||
component.tagsEntries = dataTag.list.entries;
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
initialEntries = dataTag.list.entries;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
component.limitTagsDisplayed = true;
|
||||
element.style.maxWidth = '200px';
|
||||
component.ngOnInit();
|
||||
element.style.maxWidth = '309px';
|
||||
});
|
||||
|
||||
it('should render view more button when limiting is enabled', async () => {
|
||||
@ -162,8 +173,8 @@ describe('TagNodeList', () => {
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(findViewMoreButton()).not.toBeNull();
|
||||
expect(findTagChips().length).toBe(component.tagsEntries.length);
|
||||
expect(findViewMoreButton().hidden).toBeFalse();
|
||||
expect(findTagChips()).toHaveSize(component.tagsEntries.length);
|
||||
});
|
||||
|
||||
it('should not render view more button when limiting is enabled and all tags fits into container', async () => {
|
||||
@ -174,8 +185,8 @@ describe('TagNodeList', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(findViewMoreButton()).toBeNull();
|
||||
expect(findTagChips().length).toBe(3);
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(4);
|
||||
});
|
||||
|
||||
it('should display all tags when view more button is clicked', async () => {
|
||||
@ -190,8 +201,8 @@ describe('TagNodeList', () => {
|
||||
await fixture.whenStable();
|
||||
|
||||
viewMoreButton = findViewMoreButton();
|
||||
expect(viewMoreButton).toBeNull();
|
||||
expect(findTagChips().length).toBe(3);
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(4);
|
||||
});
|
||||
|
||||
it('should not render view more button when tag takes more than one line and there are no more tags', async () => {
|
||||
@ -204,8 +215,8 @@ describe('TagNodeList', () => {
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(findViewMoreButton()).toBeNull();
|
||||
expect(findTagChips().length).toBe(component.tagsEntries.length);
|
||||
expect(findViewMoreButton().hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(component.tagsEntries.length);
|
||||
});
|
||||
|
||||
it('should render view more button when tag takes more than one line and there are more tags', async () => {
|
||||
@ -223,8 +234,53 @@ describe('TagNodeList', () => {
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(findViewMoreButton()).not.toBeNull();
|
||||
expect(findTagChips().length).toBe(component.tagsEntries.length);
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
expect(viewMoreButton.hidden).toBeFalse();
|
||||
expect(viewMoreButton.style.left).toBe('0px');
|
||||
expect(findTagChips()).toHaveSize(component.tagsEntries.length);
|
||||
});
|
||||
|
||||
it('should not render view more button when there is enough space after resizing', async () => {
|
||||
await renderTags();
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
element.style.maxWidth = '800px';
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(4);
|
||||
});
|
||||
|
||||
it('should render view more button when there is not enough space after resizing', async () => {
|
||||
await renderTags();
|
||||
element.style.maxWidth = '800px';
|
||||
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
element.style.maxWidth = '309px';
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(findViewMoreButton().hidden).toBeFalse();
|
||||
expect(findTagChips()).toHaveSize(component.tagsEntries.length);
|
||||
});
|
||||
|
||||
it('should not render view more button again resizing when there is not enough space if user requested to see all tags', async () => {
|
||||
await renderTags();
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const viewMoreButton = findViewMoreButton();
|
||||
viewMoreButton.click();
|
||||
fixture.detectChanges();
|
||||
element.style.maxWidth = '309px';
|
||||
resizeCallback([], null);
|
||||
fixture.detectChanges();
|
||||
expect(viewMoreButton.hidden).toBeTrue();
|
||||
expect(findTagChips()).toHaveSize(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -15,7 +15,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation, OnDestroy, OnInit, ViewChild, ElementRef, ViewChildren, QueryList } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output,
|
||||
ViewEncapsulation,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
ViewChildren,
|
||||
QueryList,
|
||||
ChangeDetectorRef,
|
||||
AfterViewInit
|
||||
} from '@angular/core';
|
||||
import { TagService } from './services/tag.service';
|
||||
import { TagEntry } from '@alfresco/js-api';
|
||||
import { Subject } from 'rxjs';
|
||||
@ -33,7 +48,7 @@ import { MatChip } from '@angular/material/chips';
|
||||
styleUrls: ['./tag-node-list.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
|
||||
export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit, AfterViewInit {
|
||||
/* eslint no-underscore-dangle: ["error", { "allow": ["_elementRef"] }]*/
|
||||
/** The identifier of a node. */
|
||||
@Input()
|
||||
@ -57,19 +72,29 @@ export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
|
||||
calculationsDone = false;
|
||||
columnFlexDirection = false;
|
||||
undisplayedTagsCount = 0;
|
||||
viewMoreButtonLeftOffset: number;
|
||||
|
||||
/** Emitted when a tag is selected. */
|
||||
@Output()
|
||||
results = new EventEmitter();
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
private initialLimitTagsDisplayed: boolean;
|
||||
private initialTagsEntries: TagEntry[] = [];
|
||||
private viewMoreButtonLeftOffsetBeforeFlexDirection: number;
|
||||
private requestedDisplayingAllTags = false;
|
||||
private resizeObserver = new ResizeObserver(() => {
|
||||
this.calculateTagsToDisplay();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param tagService
|
||||
* @param changeDetectorRef
|
||||
*/
|
||||
constructor(private tagService: TagService) {
|
||||
constructor(private tagService: TagService, private changeDetectorRef: ChangeDetectorRef) {
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
@ -77,6 +102,7 @@ export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.initialLimitTagsDisplayed = this.limitTagsDisplayed;
|
||||
this.tagService.refresh
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => this.refreshTag());
|
||||
@ -90,15 +116,21 @@ export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.resizeObserver.observe(this.containerView.nativeElement);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
this.resizeObserver.unobserve(this.containerView.nativeElement);
|
||||
}
|
||||
|
||||
refreshTag() {
|
||||
if (this.nodeId) {
|
||||
this.tagService.getTagsByNodeId(this.nodeId).subscribe((tagPaging) => {
|
||||
this.tagsEntries = tagPaging.list.entries;
|
||||
this.initialTagsEntries = tagPaging.list.entries;
|
||||
this.results.emit(this.tagsEntries);
|
||||
});
|
||||
}
|
||||
@ -114,29 +146,39 @@ export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.limitTagsDisplayed = false;
|
||||
this.requestedDisplayingAllTags = true;
|
||||
this.resizeObserver.unobserve(this.containerView.nativeElement);
|
||||
this.refreshTag();
|
||||
}
|
||||
|
||||
private calculateTagsToDisplay() {
|
||||
let tagsToDisplay = 1;
|
||||
const containerWidth: number = this.containerView.nativeElement.clientWidth;
|
||||
const viewMoreBtnWidth: number = this.containerView.nativeElement.children[1].offsetWidth;
|
||||
const tagChipMargin = this.getTagChipMargin(this.tagChips.get(0));
|
||||
const tagChipsWidth: number = this.tagChips.reduce((acc, val, index) => {
|
||||
if (containerWidth - viewMoreBtnWidth > acc + val._elementRef.nativeElement.offsetWidth) {
|
||||
tagsToDisplay = index + 1;
|
||||
if (!this.requestedDisplayingAllTags) {
|
||||
this.tagsEntries = this.initialTagsEntries;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.undisplayedTagsCount = 0;
|
||||
let tagsToDisplay = 1;
|
||||
const containerWidth: number = this.containerView.nativeElement.clientWidth;
|
||||
const viewMoreBtnWidth: number = this.containerView.nativeElement.children[1].offsetWidth;
|
||||
const firstTag = this.tagChips.get(0);
|
||||
const tagChipMargin = firstTag ? this.getTagChipMargin(this.tagChips.get(0)) : 0;
|
||||
const tagChipsWidth: number = this.tagChips.reduce((width, val, index) => {
|
||||
width += val._elementRef.nativeElement.offsetWidth + tagChipMargin;
|
||||
if (containerWidth - viewMoreBtnWidth > width) {
|
||||
tagsToDisplay = index + 1;
|
||||
this.viewMoreButtonLeftOffset = width;
|
||||
this.viewMoreButtonLeftOffsetBeforeFlexDirection = width;
|
||||
}
|
||||
return width;
|
||||
}, 0);
|
||||
if ((containerWidth - tagChipsWidth) <= 0) {
|
||||
this.columnFlexDirection = tagsToDisplay === 1 && (containerWidth < (this.tagChips.get(0)._elementRef.nativeElement.offsetWidth + viewMoreBtnWidth));
|
||||
this.undisplayedTagsCount = this.tagsEntries.length - tagsToDisplay;
|
||||
this.tagsEntries = this.tagsEntries.slice(0, tagsToDisplay);
|
||||
}
|
||||
return acc + val._elementRef.nativeElement.offsetWidth + tagChipMargin;
|
||||
}, 0);
|
||||
if ((containerWidth - tagChipsWidth) <= 0) {
|
||||
this.columnFlexDirection = tagsToDisplay === 1 && (containerWidth < (this.tagChips.get(0)._elementRef.nativeElement.offsetWidth + viewMoreBtnWidth));
|
||||
this.undisplayedTagsCount = this.tagsEntries.length - tagsToDisplay;
|
||||
this.tagsEntries = this.tagsEntries.slice(0, tagsToDisplay);
|
||||
this.limitTagsDisplayed = this.undisplayedTagsCount ? this.initialLimitTagsDisplayed : false;
|
||||
this.viewMoreButtonLeftOffset = this.columnFlexDirection ? 0 : this.viewMoreButtonLeftOffsetBeforeFlexDirection;
|
||||
this.calculationsDone = true;
|
||||
}
|
||||
if (!this.undisplayedTagsCount) {
|
||||
this.limitTagsDisplayed = false;
|
||||
}
|
||||
this.calculationsDone = true;
|
||||
}
|
||||
|
||||
private getTagChipMargin(chip: MatChip): number {
|
||||
|
Loading…
x
Reference in New Issue
Block a user