mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-10-01 14:41:14 +00:00
[AAE-11496] Move 'content-plugin' to projects folder as 'aca-content' (#2817)
* [AAE-11496] Move content-plugin to projects * Fix unit test
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<ng-container *ngIf="!item.children">
|
||||
<button
|
||||
class="action-button"
|
||||
mat-icon-button
|
||||
acaActiveLink="action-button--active"
|
||||
[action]="item"
|
||||
[id]="item.id"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
[attr.title]="item.description | translate"
|
||||
[attr.data-automation-id]="item.id"
|
||||
>
|
||||
<adf-icon [value]="item.icon"></adf-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.children && item.children.length">
|
||||
<button
|
||||
[matMenuTriggerFor]="menu"
|
||||
[acaMenuPanel]="item"
|
||||
#acaMenuPanel="acaMenuPanel"
|
||||
mat-icon-button
|
||||
[id]="item.id"
|
||||
[attr.data-automation-id]="item.id"
|
||||
[attr.title]="item.description | translate"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
class="action-button"
|
||||
[ngClass]="{
|
||||
'action-button--active': acaMenuPanel.hasActiveLinks()
|
||||
}"
|
||||
>
|
||||
<adf-icon [value]="item.icon"></adf-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu" [overlapTrigger]="false">
|
||||
<button
|
||||
*ngFor="let child of item.children; trackBy: trackById"
|
||||
acaActiveLink="action-button--active"
|
||||
[action]="child"
|
||||
[attr.aria-label]="child.title | translate"
|
||||
[id]="child.id"
|
||||
[attr.title]="child.description | translate"
|
||||
[attr.data-automation-id]="child.id"
|
||||
mat-menu-item
|
||||
class="action-button"
|
||||
>
|
||||
<adf-icon *ngIf="child.icon" [value]="child.icon"></adf-icon>
|
||||
<span class="action-button__label">{{ child.title | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</ng-container>
|
@@ -0,0 +1,103 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ButtonMenuComponent } from './button-menu.component';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { Router } from '@angular/router';
|
||||
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
|
||||
import { AppSidenavModule } from '../sidenav.module';
|
||||
|
||||
describe('ButtonMenuComponent', () => {
|
||||
let component: ButtonMenuComponent;
|
||||
let fixture: ComponentFixture<ButtonMenuComponent>;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
AppTestingModule,
|
||||
AppSidenavModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(ButtonMenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
router = TestBed.inject(Router);
|
||||
|
||||
spyOn(router, 'navigate');
|
||||
});
|
||||
|
||||
it('should render action item', () => {
|
||||
component.item = {
|
||||
id: 'test-action-button',
|
||||
url: 'dummy',
|
||||
icon: null,
|
||||
title: null,
|
||||
route: null
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const actionButton = document.body.querySelector('#test-action-button');
|
||||
expect(actionButton).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should render action item with children', () => {
|
||||
component.item = {
|
||||
id: 'test-action-button',
|
||||
icon: null,
|
||||
title: null,
|
||||
route: null,
|
||||
children: [
|
||||
{
|
||||
id: 'child-1',
|
||||
title: 'child-1',
|
||||
url: 'dummy',
|
||||
icon: null,
|
||||
route: null
|
||||
},
|
||||
{
|
||||
id: 'child-2',
|
||||
title: 'child-2',
|
||||
url: 'dummy',
|
||||
icon: null,
|
||||
route: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const actionButton = document.body.querySelector('[id="test-action-button"]');
|
||||
actionButton.dispatchEvent(new Event('click'));
|
||||
|
||||
expect(document.querySelector('[id="child-1"]')).not.toBeNull();
|
||||
expect(document.querySelector('[id="child-2"]')).not.toBeNull();
|
||||
});
|
||||
});
|
@@ -0,0 +1,51 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, Input, ViewEncapsulation, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import { NavBarLinkRef } from '@alfresco/adf-extensions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-button-menu',
|
||||
templateUrl: './button-menu.component.html',
|
||||
host: { class: 'app-button-menu' },
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ButtonMenuComponent implements OnInit {
|
||||
@Input()
|
||||
item: NavBarLinkRef;
|
||||
|
||||
constructor(private cd: ChangeDetectorRef, private overlayContainer: OverlayContainer) {
|
||||
this.overlayContainer.getContainerElement().classList.add('aca-menu-panel');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
|
||||
trackById(_index: number, obj: NavBarLinkRef) {
|
||||
return obj.id;
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
<ng-container *ngIf="!item.children">
|
||||
<div class="item">
|
||||
<button
|
||||
acaActiveLink="action-button--active"
|
||||
[action]="item"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
[id]="item.id"
|
||||
[attr.data-automation-id]="item.id"
|
||||
[attr.title]="item.description | translate"
|
||||
mat-button
|
||||
class="action-button full-width"
|
||||
>
|
||||
<adf-icon *ngIf="item.icon" [value]="item.icon"></adf-icon>
|
||||
<span class="action-button__label">{{ item.title | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.children && item.children.length">
|
||||
<mat-expansion-panel
|
||||
[expanded]="acaExpansionPanel.hasActiveLinks()"
|
||||
[acaExpansionPanel]="item"
|
||||
#acaExpansionPanel="acaExpansionPanel"
|
||||
[@.disabled]="true"
|
||||
>
|
||||
<mat-expansion-panel-header expandedHeight="48px" collapsedHeight="48px" role="group">
|
||||
<mat-panel-title>
|
||||
<div class="item">
|
||||
<button
|
||||
[ngClass]="{
|
||||
'action-button--active': acaExpansionPanel.hasActiveLinks()
|
||||
}"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
[id]="item.id"
|
||||
[attr.title]="item.description | translate"
|
||||
[attr.data-automation-id]="item.id"
|
||||
mat-button
|
||||
class="action-button full-width"
|
||||
>
|
||||
<adf-icon *ngIf="item.icon" [value]="item.icon"></adf-icon>
|
||||
<span class="action-button__label">{{ item.title | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div *ngFor="let child of item.children; trackBy: trackById" class="item">
|
||||
<button
|
||||
acaActiveLink="action-button--active"
|
||||
[action]="child"
|
||||
[attr.aria-label]="child.title | translate"
|
||||
[id]="child.id"
|
||||
[attr.data-automation-id]="child.id"
|
||||
[attr.title]="child.description | translate"
|
||||
mat-button
|
||||
class="action-button full-width"
|
||||
>
|
||||
<adf-icon *ngIf="child.icon" [value]="child.icon"></adf-icon>
|
||||
<span class="action-button__label">{{ child.title | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
@@ -0,0 +1,103 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ExpandMenuComponent } from './expand-menu.component';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { Router } from '@angular/router';
|
||||
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
|
||||
import { AppSidenavModule } from '../sidenav.module';
|
||||
|
||||
describe('ExpandMenuComponent', () => {
|
||||
let component: ExpandMenuComponent;
|
||||
let fixture: ComponentFixture<ExpandMenuComponent>;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
AppTestingModule,
|
||||
AppSidenavModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(ExpandMenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
router = TestBed.inject(Router);
|
||||
|
||||
spyOn(router, 'navigate');
|
||||
});
|
||||
|
||||
it('should render action item', () => {
|
||||
component.item = {
|
||||
id: 'test-action-button',
|
||||
url: 'dummy',
|
||||
title: null,
|
||||
icon: null,
|
||||
route: null
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const actionButton = document.body.querySelector('#test-action-button');
|
||||
expect(actionButton).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should render action item with children', () => {
|
||||
component.item = {
|
||||
id: 'test-action-button',
|
||||
icon: null,
|
||||
title: null,
|
||||
route: null,
|
||||
children: [
|
||||
{
|
||||
id: 'child-1',
|
||||
title: 'child-1',
|
||||
url: 'dummy',
|
||||
icon: null,
|
||||
route: null
|
||||
},
|
||||
{
|
||||
id: 'child-2',
|
||||
title: 'child-2',
|
||||
url: 'dummy',
|
||||
icon: null,
|
||||
route: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const actionButton = document.body.querySelector('[id="test-action-button"]');
|
||||
actionButton.dispatchEvent(new Event('click'));
|
||||
|
||||
expect(document.querySelector('[id="child-1"]')).not.toBeNull();
|
||||
expect(document.querySelector('[id="child-2"]')).not.toBeNull();
|
||||
});
|
||||
});
|
@@ -0,0 +1,48 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, OnInit, Input, ViewEncapsulation, ChangeDetectorRef } from '@angular/core';
|
||||
import { NavBarLinkRef } from '@alfresco/adf-extensions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-expand-menu',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
templateUrl: './expand-menu.component.html',
|
||||
host: { class: 'app-expand-menu' }
|
||||
})
|
||||
export class ExpandMenuComponent implements OnInit {
|
||||
@Input()
|
||||
item: NavBarLinkRef;
|
||||
|
||||
constructor(private cd: ChangeDetectorRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
|
||||
trackById(_index: number, obj: NavBarLinkRef) {
|
||||
return obj.id;
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ActionDirective } from './action.directive';
|
||||
|
||||
describe('ActionDirective', () => {
|
||||
let directive: ActionDirective;
|
||||
const routeMock: any = {
|
||||
navigate: jasmine.createSpy('navigate'),
|
||||
parseUrl: () => ({
|
||||
root: {
|
||||
children: []
|
||||
}
|
||||
})
|
||||
};
|
||||
const storeMock: any = {
|
||||
dispatch: jasmine.createSpy('dispatch')
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
directive = new ActionDirective(routeMock, storeMock);
|
||||
});
|
||||
|
||||
it('should navigate if action is route', () => {
|
||||
directive.action = { url: 'dummy' };
|
||||
directive.onClick();
|
||||
expect(routeMock.navigate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should dispatch store action', () => {
|
||||
directive.action = { click: {} };
|
||||
directive.onClick();
|
||||
expect(storeMock.dispatch).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@@ -0,0 +1,68 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, Input, HostListener } from '@angular/core';
|
||||
import { PRIMARY_OUTLET, Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from '@alfresco/aca-shared/store';
|
||||
|
||||
@Directive({
|
||||
/* eslint-disable-next-line */
|
||||
selector: '[action]',
|
||||
exportAs: 'action'
|
||||
})
|
||||
export class ActionDirective {
|
||||
@Input() action;
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
if (this.action.url) {
|
||||
this.router.navigate(this.getNavigationCommands(this.action.url));
|
||||
} else if (this.action.click) {
|
||||
this.store.dispatch({
|
||||
type: this.action.click.action,
|
||||
payload: this.getNavigationCommands(this.action.click.payload)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private router: Router, private store: Store<AppStore>) {}
|
||||
|
||||
private getNavigationCommands(url: string): any[] {
|
||||
const urlTree = this.router.parseUrl(url);
|
||||
const urlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
||||
|
||||
if (!urlSegmentGroup) {
|
||||
return [url];
|
||||
}
|
||||
|
||||
const urlSegments = urlSegmentGroup.segments;
|
||||
|
||||
return urlSegments.reduce(function (acc, item) {
|
||||
acc.push(item.path, item.parameters);
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { AppSidenavModule } from '../sidenav.module';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-test-component',
|
||||
template: ` <span id="test-element" acaActiveLink="active-link-class" [action]="item"></span> `
|
||||
})
|
||||
class TestComponent {
|
||||
item = {
|
||||
route: 'dummy'
|
||||
};
|
||||
}
|
||||
|
||||
class MockRouter {
|
||||
private subject = new Subject();
|
||||
events = this.subject.asObservable();
|
||||
url = '';
|
||||
|
||||
navigateByUrl(url: string) {
|
||||
const navigationEnd = new NavigationEnd(0, '', url);
|
||||
this.subject.next(navigationEnd);
|
||||
}
|
||||
}
|
||||
|
||||
describe('ActionDirective', () => {
|
||||
let fixture: ComponentFixture<TestComponent>;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule, AppSidenavModule],
|
||||
declarations: [TestComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: Router,
|
||||
useClass: MockRouter
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(TestComponent);
|
||||
router = TestBed.inject(Router);
|
||||
});
|
||||
|
||||
it('should add active route class name', () => {
|
||||
fixture.detectChanges();
|
||||
router.navigateByUrl('/dummy');
|
||||
// fixture.detectChanges();
|
||||
expect(document.body.querySelector('#test-element').className.includes('active-link-class')).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove class name if route not active', () => {
|
||||
fixture.detectChanges();
|
||||
router.navigateByUrl('/dummy');
|
||||
|
||||
expect(document.body.querySelector('#test-element').className.includes('active-link-class')).toBe(true);
|
||||
|
||||
router.navigateByUrl('/other');
|
||||
|
||||
expect(document.body.querySelector('#test-element').className.includes('active-link-class')).not.toBe(true);
|
||||
});
|
||||
});
|
@@ -0,0 +1,87 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, OnInit, Input, ElementRef, Renderer2, ContentChildren, QueryList, AfterContentInit, Optional } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ActionDirective } from './action.directive';
|
||||
|
||||
@Directive({
|
||||
selector: '[acaActiveLink]',
|
||||
exportAs: 'acaActiveLink'
|
||||
})
|
||||
export class ActiveLinkDirective implements OnInit, AfterContentInit {
|
||||
@Input() acaActiveLink;
|
||||
@ContentChildren(ActionDirective, { descendants: true })
|
||||
links: QueryList<ActionDirective>;
|
||||
isLinkActive = false;
|
||||
|
||||
private onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
constructor(private router: Router, private element: ElementRef, private renderer: Renderer2, @Optional() private action?: ActionDirective) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof NavigationEnd),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe((event: NavigationEnd) => {
|
||||
this.update(event.urlAfterRedirects);
|
||||
});
|
||||
}
|
||||
|
||||
private update(url: string) {
|
||||
if (this.action) {
|
||||
const itemUrl = this.resolveUrl(this.action);
|
||||
this.render(url, itemUrl);
|
||||
}
|
||||
|
||||
this.links.map((item) => {
|
||||
const itemUrl = this.resolveUrl(item);
|
||||
this.render(url, itemUrl);
|
||||
});
|
||||
}
|
||||
|
||||
private render(routerUrl: string, actionUrl: string) {
|
||||
if (routerUrl && routerUrl.substring(1).startsWith(actionUrl)) {
|
||||
this.isLinkActive = true;
|
||||
this.renderer.addClass(this.element.nativeElement, this.acaActiveLink);
|
||||
} else {
|
||||
this.isLinkActive = false;
|
||||
this.renderer.removeClass(this.element.nativeElement, this.acaActiveLink);
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.links.changes.subscribe(() => this.update(this.router.url));
|
||||
this.update(this.router.url);
|
||||
}
|
||||
|
||||
private resolveUrl(item): string {
|
||||
return (item.action && item.action.click && item.action.click.payload) || item.action.route;
|
||||
}
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NavigationEnd } from '@angular/router';
|
||||
import { ExpansionPanelDirective } from './expansion-panel.directive';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
class RouterStub {
|
||||
url;
|
||||
private subject = new Subject();
|
||||
events = this.subject.asObservable();
|
||||
|
||||
constructor(url = 'some-url') {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
parseUrl() {
|
||||
return {
|
||||
root: {
|
||||
children: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
navigate(nextUrl: string) {
|
||||
const navigationEnd = new NavigationEnd(0, this.url, nextUrl);
|
||||
this.subject.next(navigationEnd);
|
||||
}
|
||||
}
|
||||
|
||||
describe('AcaExpansionPanel', () => {
|
||||
const mockStore: any = {
|
||||
dispatch: jasmine.createSpy('dispatch')
|
||||
};
|
||||
const mockMatExpansionPanel: any = {
|
||||
expanded: false,
|
||||
children: []
|
||||
};
|
||||
|
||||
describe('hasActiveLinks()', () => {
|
||||
it('should return true if child is active route', () => {
|
||||
const router: any = new RouterStub('dummy-route-2');
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
const directive = new ExpansionPanelDirective(mockStore, router, mockMatExpansionPanel);
|
||||
|
||||
directive.acaExpansionPanel = item;
|
||||
|
||||
expect(directive.hasActiveLinks()).toBe(true);
|
||||
});
|
||||
it('should return false if no child is active route', () => {
|
||||
const router: any = new RouterStub('other');
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
const directive = new ExpansionPanelDirective(mockStore, router, mockMatExpansionPanel);
|
||||
|
||||
directive.acaExpansionPanel = item;
|
||||
|
||||
expect(directive.hasActiveLinks()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigation', () => {
|
||||
it('should navigate to first child if none is active route', () => {
|
||||
const router: any = new RouterStub('other');
|
||||
spyOn(router, 'navigate').and.callThrough();
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
|
||||
mockMatExpansionPanel.expanded = true;
|
||||
|
||||
const directive = new ExpansionPanelDirective(mockStore, router, mockMatExpansionPanel);
|
||||
|
||||
directive.acaExpansionPanel = item;
|
||||
|
||||
directive.onClick();
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['dummy-route-1']);
|
||||
});
|
||||
|
||||
it('should not navigate to first child if one is active route', () => {
|
||||
const router: any = new RouterStub('dummy-route-2');
|
||||
spyOn(router, 'navigate').and.callThrough();
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
|
||||
const directive = new ExpansionPanelDirective(mockStore, router, mockMatExpansionPanel);
|
||||
|
||||
directive.acaExpansionPanel = item;
|
||||
mockMatExpansionPanel.expanded = true;
|
||||
|
||||
directive.onClick();
|
||||
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,100 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, Input, HostListener, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Router, NavigationEnd, PRIMARY_OUTLET } from '@angular/router';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { MatExpansionPanel } from '@angular/material/expansion';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Directive({
|
||||
selector: '[acaExpansionPanel]',
|
||||
exportAs: 'acaExpansionPanel'
|
||||
})
|
||||
export class ExpansionPanelDirective implements OnInit, OnDestroy {
|
||||
@Input() acaExpansionPanel;
|
||||
public hasActiveChildren = false;
|
||||
|
||||
private onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
if (this.expansionPanel.expanded && !this.hasActiveLinks()) {
|
||||
const firstChild = this.acaExpansionPanel.children[0];
|
||||
if (firstChild.url) {
|
||||
this.router.navigate(this.getNavigationCommands(firstChild.url));
|
||||
} else {
|
||||
this.store.dispatch({
|
||||
type: firstChild.action.action,
|
||||
payload: this.getNavigationCommands(firstChild.action.payload)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private store: Store<any>, private router: Router, private expansionPanel: MatExpansionPanel) {}
|
||||
|
||||
hasActiveLinks() {
|
||||
if (this.acaExpansionPanel && this.acaExpansionPanel.children) {
|
||||
return this.acaExpansionPanel.children.some((child) => this.router.url.startsWith(child.url || child.action.payload));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.hasActiveChildren = this.hasActiveLinks();
|
||||
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof NavigationEnd),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.hasActiveChildren = this.hasActiveLinks();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
private getNavigationCommands(url: string): any[] {
|
||||
const urlTree = this.router.parseUrl(url);
|
||||
const urlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
||||
|
||||
if (!urlSegmentGroup) {
|
||||
return [url];
|
||||
}
|
||||
|
||||
const urlSegments = urlSegmentGroup.segments;
|
||||
|
||||
return urlSegments.reduce(function (acc, item) {
|
||||
acc.push(item.path, item.parameters);
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NavigationEnd } from '@angular/router';
|
||||
import { MenuPanelDirective } from './menu-panel.directive';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
class RouterStub {
|
||||
url;
|
||||
private subject = new Subject();
|
||||
events = this.subject.asObservable();
|
||||
|
||||
constructor(url = 'some-url') {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
parseUrl() {
|
||||
return {
|
||||
root: {
|
||||
children: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
navigate(nextUrl: string) {
|
||||
const navigationEnd = new NavigationEnd(0, this.url, nextUrl);
|
||||
this.subject.next(navigationEnd);
|
||||
}
|
||||
}
|
||||
|
||||
describe('MenuPanelDirective', () => {
|
||||
const mockStore: any = {
|
||||
dispatch: jasmine.createSpy('dispatch')
|
||||
};
|
||||
const mockMatExpansionPanel: any = {
|
||||
expanded: false,
|
||||
children: []
|
||||
};
|
||||
|
||||
describe('hasActiveLinks()', () => {
|
||||
it('should return true if child is active route', () => {
|
||||
const router: any = new RouterStub('dummy-route-2');
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
const directive = new MenuPanelDirective(mockStore, router);
|
||||
|
||||
directive.acaMenuPanel = item;
|
||||
|
||||
expect(directive.hasActiveLinks()).toBe(true);
|
||||
});
|
||||
it('should return false if no child is active route', () => {
|
||||
const router: any = new RouterStub('other');
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
const directive = new MenuPanelDirective(mockStore, router);
|
||||
|
||||
directive.acaMenuPanel = item;
|
||||
|
||||
expect(directive.hasActiveLinks()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigation', () => {
|
||||
it('should navigate to first child if none is active route', () => {
|
||||
const router: any = new RouterStub('other');
|
||||
spyOn(router, 'navigate').and.callThrough();
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
|
||||
mockMatExpansionPanel.expanded = true;
|
||||
|
||||
const directive = new MenuPanelDirective(mockStore, router);
|
||||
|
||||
directive.acaMenuPanel = item;
|
||||
|
||||
directive.menuOpened();
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['dummy-route-1']);
|
||||
});
|
||||
|
||||
it('should not navigate to first child if one is active route', () => {
|
||||
const router: any = new RouterStub('dummy-route-2');
|
||||
spyOn(router, 'navigate').and.callThrough();
|
||||
const item = {
|
||||
children: [{ url: 'dummy-route-1' }, { url: 'dummy-route-2' }]
|
||||
};
|
||||
|
||||
const directive = new MenuPanelDirective(mockStore, router);
|
||||
|
||||
directive.acaMenuPanel = item;
|
||||
mockMatExpansionPanel.expanded = true;
|
||||
|
||||
directive.menuOpened();
|
||||
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,99 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, Input, OnInit, OnDestroy, HostListener } from '@angular/core';
|
||||
import { Router, NavigationEnd, PRIMARY_OUTLET } from '@angular/router';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Directive({
|
||||
selector: '[acaMenuPanel]',
|
||||
exportAs: 'acaMenuPanel'
|
||||
})
|
||||
export class MenuPanelDirective implements OnInit, OnDestroy {
|
||||
@Input() acaMenuPanel;
|
||||
hasActiveChildren = false;
|
||||
|
||||
private onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
|
||||
@HostListener('menuOpened')
|
||||
menuOpened() {
|
||||
if (this.acaMenuPanel.children && !this.hasActiveLinks()) {
|
||||
const firstChild = this.acaMenuPanel.children[0];
|
||||
if (firstChild.url) {
|
||||
this.router.navigate(this.getNavigationCommands(firstChild.url));
|
||||
} else {
|
||||
this.store.dispatch({
|
||||
type: firstChild.action.action,
|
||||
payload: this.getNavigationCommands(firstChild.action.payload)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private store: Store<any>, private router: Router) {}
|
||||
|
||||
hasActiveLinks() {
|
||||
if (this.acaMenuPanel && this.acaMenuPanel.children) {
|
||||
return this.acaMenuPanel.children.some((child) => this.router.url.startsWith(child.url || child.action.payload));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.hasActiveChildren = this.hasActiveLinks();
|
||||
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof NavigationEnd),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.hasActiveChildren = this.hasActiveLinks();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
private getNavigationCommands(url: string): any[] {
|
||||
const urlTree = this.router.parseUrl(url);
|
||||
const urlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
||||
|
||||
if (!urlSegmentGroup) {
|
||||
return [url];
|
||||
}
|
||||
|
||||
const urlSegments = urlSegmentGroup.segments;
|
||||
|
||||
return urlSegments.reduce(function (acc, item) {
|
||||
acc.push(item.path, item.parameters);
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
<app-sidenav
|
||||
[mode]="data.mode"
|
||||
></app-sidenav>
|
@@ -0,0 +1,39 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* This wrapper is designated to be used with 'adf-dynamic-component'.
|
||||
* It forwards the dynamic component inputs to original sidenav.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'aca-sidenav-wrapper',
|
||||
templateUrl: './sidenav-wrapper.component.html'
|
||||
})
|
||||
export class SidenavWrapperComponent {
|
||||
@Input()
|
||||
data: { mode?: 'collapsed' | 'expanded' } = {};
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<div class="sidenav">
|
||||
<ng-container [ngSwitch]="mode">
|
||||
<div class="section action-menu" [ngClass]="'section--' + mode">
|
||||
<app-main-action [expanded]="mode === 'expanded'"></app-main-action>
|
||||
<app-create-menu [expanded]="mode === 'expanded'"></app-create-menu>
|
||||
</div>
|
||||
|
||||
<div class="section-sub-actions">
|
||||
<div *ngFor="let group of groups; trackBy: trackByGroupId" class="section" [ngClass]="'section--' + mode">
|
||||
<ng-container *ngSwitchCase="'expanded'">
|
||||
<mat-list-item *ngFor="let item of group.items; trackBy: trackByLinkId">
|
||||
<ng-container *ngIf="!item.component">
|
||||
<app-expand-menu [item]="item"></app-expand-menu>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.component">
|
||||
<adf-dynamic-component [data]="{ item: item, state: 'expanded' }" [id]="item.component"></adf-dynamic-component>
|
||||
</ng-container>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'collapsed'">
|
||||
<div class="list-item" *ngFor="let item of group.items; trackBy: trackByLinkId">
|
||||
<ng-container *ngIf="!item.component">
|
||||
<app-button-menu [item]="item"></app-button-menu>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.component">
|
||||
<adf-dynamic-component [data]="{ item: item, state: 'collapsed' }" [id]="item.component"> </adf-dynamic-component>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
@@ -0,0 +1,150 @@
|
||||
.app-sidenav {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.aca-menu-panel {
|
||||
.action-button--active {
|
||||
color: var(--theme-accent-color) !important;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
color: var(--theme-primary-color);
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
color: var(--theme-accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background-color: var(--theme-background-color);
|
||||
|
||||
.section:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.action-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.section.action-menu {
|
||||
padding: 8px 14px;
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.section-sub-actions {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 8px 6px;
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
|
||||
.section--collapsed {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action-button--active {
|
||||
color: var(--theme-primary-color) !important;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
color: var(--theme-text-color);
|
||||
}
|
||||
|
||||
.action-button .action-button__label {
|
||||
margin: 0 8px !important;
|
||||
}
|
||||
|
||||
.app-item,
|
||||
.app-item .item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 12px 0;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
height: 24px;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.item:hover .action-button__label {
|
||||
color: var(--theme-primary-color);
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header {
|
||||
padding: 0 8px 0 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.mat-expansion-panel {
|
||||
width: 100%;
|
||||
background-color: unset;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled='true']):hover {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.mat-expansion-indicator {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-body {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
[dir='rtl'] .sidenav {
|
||||
.mat-expansion-panel-header {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { SidenavComponent } from './sidenav.component';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { AppExtensionService } from '@alfresco/aca-shared';
|
||||
|
||||
describe('SidenavComponent', () => {
|
||||
let fixture: ComponentFixture<SidenavComponent>;
|
||||
let component: SidenavComponent;
|
||||
let extensionService: AppExtensionService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule],
|
||||
declarations: [SidenavComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(SidenavComponent);
|
||||
component = fixture.componentInstance;
|
||||
extensionService = TestBed.inject(AppExtensionService);
|
||||
extensionService.navbar = [
|
||||
{
|
||||
id: 'route',
|
||||
items: [
|
||||
{
|
||||
id: 'item-1',
|
||||
icon: 'item',
|
||||
route: 'route',
|
||||
title: 'item-1'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
it('should set the sidenav data', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(component.groups.length).toBe(1);
|
||||
expect(component.groups[0].items.length).toBe(1);
|
||||
expect(component.groups[0].items[0]).toEqual({
|
||||
id: 'item-1',
|
||||
icon: 'item',
|
||||
url: '/route',
|
||||
route: 'route',
|
||||
title: 'item-1'
|
||||
});
|
||||
});
|
||||
});
|
71
projects/aca-content/src/lib/components/sidenav/sidenav.component.ts
Executable file
71
projects/aca-content/src/lib/components/sidenav/sidenav.component.ts
Executable file
@@ -0,0 +1,71 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||
import { NavBarGroupRef, NavBarLinkRef } from '@alfresco/adf-extensions';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore, getSideNavState } from '@alfresco/aca-shared/store';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, distinctUntilChanged, debounceTime } from 'rxjs/operators';
|
||||
import { AppExtensionService } from '@alfresco/aca-shared';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidenav',
|
||||
templateUrl: './sidenav.component.html',
|
||||
styleUrls: ['./sidenav.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'app-sidenav' }
|
||||
})
|
||||
export class SidenavComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
mode: 'collapsed' | 'expanded' = 'expanded';
|
||||
|
||||
groups: Array<NavBarGroupRef> = [];
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private store: Store<AppStore>, private extensions: AppExtensionService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.store
|
||||
.select(getSideNavState)
|
||||
.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.groups = this.extensions.getApplicationNavigation(this.extensions.navbar);
|
||||
});
|
||||
}
|
||||
|
||||
trackByGroupId(_: number, obj: NavBarGroupRef): string {
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
trackByLinkId(_: number, obj: NavBarLinkRef): string {
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AppCreateMenuModule } from '../create-menu/create-menu.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ExtensionsModule } from '@alfresco/adf-extensions';
|
||||
import { CoreExtensionsModule } from '../../extensions/core.extensions.module';
|
||||
import { ExpansionPanelDirective } from './directives/expansion-panel.directive';
|
||||
import { MenuPanelDirective } from './directives/menu-panel.directive';
|
||||
import { SidenavComponent } from './sidenav.component';
|
||||
import { ActiveLinkDirective } from './directives/active-link.directive';
|
||||
import { ExpandMenuComponent } from './components/expand-menu.component';
|
||||
import { ButtonMenuComponent } from './components/button-menu.component';
|
||||
import { ActionDirective } from './directives/action.directive';
|
||||
import { MainActionModule } from '../main-action/main-action.module';
|
||||
import { SidenavWrapperComponent } from './sidenav-wrapper/sidenav-wrapper.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
CoreModule.forChild(),
|
||||
CoreExtensionsModule.forChild(),
|
||||
ExtensionsModule.forChild(),
|
||||
RouterModule,
|
||||
AppCreateMenuModule,
|
||||
MainActionModule
|
||||
],
|
||||
declarations: [
|
||||
MenuPanelDirective,
|
||||
ExpansionPanelDirective,
|
||||
ActiveLinkDirective,
|
||||
ActionDirective,
|
||||
ExpandMenuComponent,
|
||||
ButtonMenuComponent,
|
||||
SidenavComponent,
|
||||
SidenavWrapperComponent
|
||||
],
|
||||
exports: [
|
||||
MenuPanelDirective,
|
||||
ExpansionPanelDirective,
|
||||
ActiveLinkDirective,
|
||||
ActionDirective,
|
||||
ExpandMenuComponent,
|
||||
ButtonMenuComponent,
|
||||
SidenavComponent
|
||||
]
|
||||
})
|
||||
export class AppSidenavModule {}
|
Reference in New Issue
Block a user