diff --git a/demo-shell/src/app.config.json b/demo-shell/src/app.config.json index a20d590726..63f049cb44 100644 --- a/demo-shell/src/app.config.json +++ b/demo-shell/src/app.config.json @@ -488,5 +488,10 @@ "adf-version-manager": { "allowComments": true, "allowDownload": true + }, + + "sideNav": { + "openedSidenav": true, + "preserveState": true } } diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.html b/demo-shell/src/app/components/app-layout/app-layout.component.html index f2b98c3e29..2b6cde211b 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.html +++ b/demo-shell/src/app/components/app-layout/app-layout.component.html @@ -1,4 +1,4 @@ - + diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts index c1cf9ade45..2745ed0725 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts @@ -15,7 +15,8 @@ * limitations under the License. */ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, ViewEncapsulation, Input } from '@angular/core'; +import { StorageService, AppConfigService } from '@alfresco/adf-core'; @Component({ templateUrl: 'app-layout.component.html', @@ -25,6 +26,7 @@ import { Component, ViewEncapsulation } from '@angular/core'; }, encapsulation: ViewEncapsulation.None }) + export class AppLayoutComponent { links: Array = [ @@ -48,6 +50,18 @@ export class AppLayoutComponent { { href: '/about', icon: 'info_outline', title: 'APP_LAYOUT.ABOUT' } ]; - constructor() { + @Input() expandedSidenav = false; + + constructor(private storage: StorageService, private config: AppConfigService) { + const preserved = this.storage.getItem('openedSidenav'); + if (preserved !== null) { + if (preserved === 'false') { + this.expandedSidenav = false; + } else { + this.expandedSidenav = true; + } + } else { + this.expandedSidenav = this.config.get('sideNav.openedSidenav'); + } } } diff --git a/docs/core/sidenav-layout.component.md b/docs/core/sidenav-layout.component.md index 34e040f03e..01dc1b8057 100644 --- a/docs/core/sidenav-layout.component.md +++ b/docs/core/sidenav-layout.component.md @@ -105,4 +105,24 @@ Beside the template context's **isMenuMinimized** variable, another way to liste Every time the menu state is changed, the following values are emitted: - true, if the menu got into opened state -- false, if the menu git into closed state \ No newline at end of file +- false, if the menu git into closed state + +### Preserving the menu state + +It is possible to preserve the state of the menu between sessions. This require to first set a property in the appConfig.json file. + +``` + "sideNav" : { + "preserveState" : true + } +``` +If this property is set, the collapsed/expanded state will be stored in the local storage, and it will be restored with page reload or the next time the user visits the app. +Beside this, it is also possible to set the default value in the appConfig.json file: + +``` + "sideNav" : { + "openedSidenav" : true + } +``` + +By default the collapsed/exapnded state should be read from the application configuration file, but only if there is no value for the collapsed/expanded state in the local storage. \ No newline at end of file diff --git a/lib/core/pipes/app-config.pipe.ts b/lib/core/pipes/app-config.pipe.ts new file mode 100644 index 0000000000..562710cb51 --- /dev/null +++ b/lib/core/pipes/app-config.pipe.ts @@ -0,0 +1,39 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 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 . + */ + +import { Pipe, PipeTransform } from '@angular/core'; +import { AppConfigService } from './../app-config/app-config.service'; + +@Pipe({ + name: 'appConfig', + pure: true +}) +export class AppConfigPipe implements PipeTransform { + constructor(private config: AppConfigService) {} + + transform(value: string, fallback: any): any { + return this.config.get(value, fallback); + } +} diff --git a/lib/core/pipes/pipe.module.ts b/lib/core/pipes/pipe.module.ts index 2b71703d1a..5cec64ce27 100644 --- a/lib/core/pipes/pipe.module.ts +++ b/lib/core/pipes/pipe.module.ts @@ -24,6 +24,7 @@ import { NodeNameTooltipPipe } from './node-name-tooltip.pipe'; import { HighlightPipe } from './text-highlight.pipe'; import { TimeAgoPipe } from './time-ago.pipe'; import { InitialUsernamePipe } from './user-initial.pipe'; +import { AppConfigPipe } from './app-config.pipe'; @NgModule({ imports: [ @@ -35,7 +36,8 @@ import { InitialUsernamePipe } from './user-initial.pipe'; TimeAgoPipe, MimeTypeIconPipe, InitialUsernamePipe, - NodeNameTooltipPipe + NodeNameTooltipPipe, + AppConfigPipe ], providers: [ FileSizePipe, @@ -43,7 +45,8 @@ import { InitialUsernamePipe } from './user-initial.pipe'; TimeAgoPipe, MimeTypeIconPipe, InitialUsernamePipe, - NodeNameTooltipPipe + NodeNameTooltipPipe, + AppConfigPipe ], exports: [ FileSizePipe, @@ -51,7 +54,8 @@ import { InitialUsernamePipe } from './user-initial.pipe'; TimeAgoPipe, MimeTypeIconPipe, InitialUsernamePipe, - NodeNameTooltipPipe + NodeNameTooltipPipe, + AppConfigPipe ] }) export class PipeModule { diff --git a/lib/core/pipes/public-api.ts b/lib/core/pipes/public-api.ts index 3ff5d5af91..978cfe90d3 100644 --- a/lib/core/pipes/public-api.ts +++ b/lib/core/pipes/public-api.ts @@ -21,5 +21,7 @@ export * from './node-name-tooltip.pipe'; export * from './text-highlight.pipe'; export * from './time-ago.pipe'; export * from './user-initial.pipe'; +export * from './app-config.pipe'; export * from './pipe.module'; + diff --git a/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.html b/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.html index 55ff07fc51..bec4ecc281 100644 --- a/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.html +++ b/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.html @@ -23,4 +23,4 @@ - \ No newline at end of file + diff --git a/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.ts b/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.ts index e831b937f3..ba1cd9464a 100644 --- a/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.ts +++ b/lib/core/sidenav-layout/components/sidenav-layout/sidenav-layout.component.ts @@ -22,6 +22,9 @@ import { SidenavLayoutHeaderDirective } from '../../directives/sidenav-layout-he import { SidenavLayoutNavigationDirective } from '../../directives/sidenav-layout-navigation.directive'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; +import { AppConfigService } from './../../../app-config/app-config.service'; +import { StorageService } from './../../../services/storage.service'; + @Component({ selector: 'adf-sidenav-layout', @@ -56,7 +59,9 @@ export class SidenavLayoutComponent implements OnInit, AfterViewInit, OnDestroy isMenuMinimized: () => this.isMenuMinimized }; - constructor(private mediaMatcher: MediaMatcher) { + constructor(private mediaMatcher: MediaMatcher, private config: AppConfigService, private storage: StorageService) { + + this.onMediaQueryChange = this.onMediaQueryChange.bind(this); } @@ -82,6 +87,8 @@ export class SidenavLayoutComponent implements OnInit, AfterViewInit, OnDestroy } toggleMenu() { + const preserve = this.config.get('sideNav.preserveState'); + if (!this.mediaQueryList.matches) { this.isMenuMinimized = !this.isMenuMinimized; } else { @@ -89,6 +96,10 @@ export class SidenavLayoutComponent implements OnInit, AfterViewInit, OnDestroy } this.container.toggleMenu(); + + if (preserve) { + this.storage.setItem('openedSidenav', !this.isMenuMinimized); + } } get isMenuMinimized() {