diff --git a/package.json b/package.json
index b2f1e7760b..f3972c23b5 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,11 @@
"@angularclass/bootloader": "1.0.1",
"@angularclass/idle-preload": "1.0.4",
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.14",
+ "@ngrx/core": "^1.2.0",
+ "@ngrx/effects": "^2.0.0",
+ "@ngrx/router-store": "^1.2.5",
+ "@ngrx/store": "^2.2.1",
+ "@ngrx/store-devtools": "^3.2.2",
"angular2-express-engine": "2.1.0-rc.1",
"angular2-platform-node": "2.1.0-rc.1",
"angular2-universal": "2.1.0-rc.1",
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 83a269739f..a562e0b675 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,21 +1,4 @@
-
+
diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index dc8b94f882..8b13789179 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -1,13 +1 @@
-@import '../styles/variables.scss';
-header nav.navbar {
- border-radius: 0rem;
-}
-
-header nav.navbar .navbar-toggler {
- float: right;
-}
-
-header nav.navbar .navbar-toggler:hover {
- cursor: pointer;
-}
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 5f1726afd0..15485eb6a6 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,7 +1,14 @@
-import { Component, HostListener, Input, ChangeDetectionStrategy, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core';
-import { Event, NavigationEnd, Router } from '@angular/router';
-
-import { TranslateService } from 'ng2-translate';
+import {
+ Component,
+ ChangeDetectionStrategy,
+ ViewEncapsulation,
+ OnDestroy,
+ OnInit, HostListener
+} from "@angular/core";
+import { TranslateService } from "ng2-translate";
+import { HostWindowState } from "./shared/host-window.reducer";
+import { Store } from "@ngrx/store";
+import { HostWindowActions } from "./shared/host-window.actions";
@Component({
changeDetection: ChangeDetectionStrategy.Default,
@@ -11,14 +18,6 @@ import { TranslateService } from 'ng2-translate';
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy, OnInit {
-
- // TODO: move header and all related properties into its own component
-
- private navCollapsed: boolean;
-
- private routerSubscription: any;
-
-
private translateSubscription: any;
example: string;
@@ -26,32 +25,25 @@ export class AppComponent implements OnDestroy, OnInit {
data: any = {
greeting: 'Hello',
recipient: 'World'
- }
+ };
- constructor(public translate: TranslateService, private router: Router) {
+ constructor(
+ private translate: TranslateService,
+ private store: Store
+ ) {
// this language will be used as a fallback when a translation isn't found in the current language
translate.setDefaultLang('en');
// the lang to use, if the lang isn't available, it will use the current loader to get them
translate.use('en');
-
- this.collapse();
}
ngOnInit() {
- this.routerSubscription = this.router.events.subscribe((event: Event) => {
- if (event instanceof NavigationEnd) {
- this.collapse();
- }
- });
this.translateSubscription = this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((translation: string) => {
this.example = translation;
});
}
ngOnDestroy() {
- if (this.routerSubscription) {
- this.routerSubscription.unsubscribe();
- }
if (this.translateSubscription) {
this.translateSubscription.unsubscribe();
}
@@ -59,23 +51,9 @@ export class AppComponent implements OnDestroy, OnInit {
@HostListener('window:resize', ['$event'])
private onResize(event): void {
- this.collapse();
- }
-
- private collapse(): void {
- this.navCollapsed = true;
- }
-
- private expand(): void {
- this.navCollapsed = false;
- }
-
- public toggle(): void {
- this.navCollapsed ? this.expand() : this.collapse();
- }
-
- public isNavBarCollaped(): boolean {
- return this.navCollapsed;
+ this.store.dispatch(
+ HostWindowActions.resize(event.target.innerWidth, event.target.innerHeight)
+ );
}
}
diff --git a/src/app/app.effects.ts b/src/app/app.effects.ts
new file mode 100644
index 0000000000..6f149709f8
--- /dev/null
+++ b/src/app/app.effects.ts
@@ -0,0 +1,6 @@
+import { EffectsModule } from "@ngrx/effects";
+import { HeaderEffects } from "./header/header.effects";
+
+export const effects = [
+ EffectsModule.run(HeaderEffects)
+];
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 8defafd570..ead69d94f0 100755
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -5,14 +5,54 @@ import { SharedModule } from './shared/shared.module';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
+import { HeaderComponent } from './header/header.component';
+import { StoreModule } from "@ngrx/store";
+import { RouterStoreModule } from "@ngrx/router-store";
+import { StoreDevtoolsModule } from "@ngrx/store-devtools";
+
+import { rootReducer } from './app.reducers';
+import { effects } from './app.effects';
@NgModule({
- declarations: [AppComponent],
+ declarations: [
+ AppComponent,
+ HeaderComponent
+ ],
imports: [
SharedModule,
HomeModule,
- AppRoutingModule
+ AppRoutingModule,
+ /**
+ * StoreModule.provideStore is imported once in the root module, accepting a reducer
+ * function or object map of reducer functions. If passed an object of
+ * reducers, combineReducers will be run creating your application
+ * meta-reducer. This returns all providers for an @ngrx/store
+ * based application.
+ */
+ StoreModule.provideStore(rootReducer),
+
+ /**
+ * @ngrx/router-store keeps router state up-to-date in the store and uses
+ * the store as the single source of truth for the router's state.
+ */
+ RouterStoreModule.connectRouter(),
+
+ /**
+ * Store devtools instrument the store retaining past versions of state
+ * and recalculating new states. This enables powerful time-travel
+ * debugging.
+ *
+ * To use the debugger, install the Redux Devtools extension for either
+ * Chrome or Firefox
+ *
+ * See: https://github.com/zalmoxisus/redux-devtools-extension
+ */
+ StoreDevtoolsModule.instrumentOnlyWithExtension(),
+
+ effects
+ ],
+ providers: [
]
})
export class AppModule {
diff --git a/src/app/app.reducers.ts b/src/app/app.reducers.ts
new file mode 100644
index 0000000000..deb75dd06a
--- /dev/null
+++ b/src/app/app.reducers.ts
@@ -0,0 +1,20 @@
+import { combineReducers } from "@ngrx/store";
+import { routerReducer, RouterState } from "@ngrx/router-store";
+import { headerReducer, HeaderState } from './header/header.reducer';
+import { hostWindowReducer, HostWindowState } from "./shared/host-window.reducer";
+
+export interface AppState {
+ router: RouterState;
+ hostWindow: HostWindowState;
+ header: HeaderState;
+}
+
+export const reducers = {
+ router: routerReducer,
+ hostWindow: hostWindowReducer,
+ header: headerReducer
+};
+
+export function rootReducer(state: any, action: any) {
+ return combineReducers(reducers)(state, action);
+}
diff --git a/src/app/header/header.actions.ts b/src/app/header/header.actions.ts
new file mode 100644
index 0000000000..e3f64c1019
--- /dev/null
+++ b/src/app/header/header.actions.ts
@@ -0,0 +1,24 @@
+import { Action } from "@ngrx/store";
+
+export class HeaderActions {
+ static COLLAPSE = 'dspace/header/COLLAPSE';
+ static collapse(): Action {
+ return {
+ type: HeaderActions.COLLAPSE
+ }
+ }
+
+ static EXPAND = 'dspace/header/EXPAND';
+ static expand(): Action {
+ return {
+ type: HeaderActions.EXPAND
+ }
+ }
+
+ static TOGGLE = 'dspace/header/TOGGLE';
+ static toggle(): Action {
+ return {
+ type: HeaderActions.TOGGLE
+ }
+ }
+}
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
new file mode 100644
index 0000000000..a4b7cf117c
--- /dev/null
+++ b/src/app/header/header.component.html
@@ -0,0 +1,18 @@
+
diff --git a/src/app/header/header.component.scss b/src/app/header/header.component.scss
new file mode 100644
index 0000000000..2170e0b905
--- /dev/null
+++ b/src/app/header/header.component.scss
@@ -0,0 +1,13 @@
+@import '../../styles/variables.scss';
+
+header nav.navbar {
+ border-radius: 0rem;
+}
+
+header nav.navbar .navbar-toggler {
+ float: right;
+}
+
+header nav.navbar .navbar-toggler:hover {
+ cursor: pointer;
+}
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
new file mode 100644
index 0000000000..69da1aea68
--- /dev/null
+++ b/src/app/header/header.component.ts
@@ -0,0 +1,39 @@
+import { Component, OnInit } from "@angular/core";
+import { Store } from "@ngrx/store";
+import { HeaderState } from "./header.reducer";
+import { HeaderActions } from "./header.actions";
+import { Observable } from "rxjs";
+import 'rxjs/add/operator/filter';
+
+@Component({
+ selector: 'ds-header',
+ styleUrls: ['header.component.css'],
+ templateUrl: 'header.component.html'
+})
+export class HeaderComponent implements OnInit {
+ public isNavBarCollapsed: Observable;
+
+ constructor(
+ private store: Store
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.isNavBarCollapsed = this.store.select('header')
+ //unwrap navCollapsed
+ .map(({ navCollapsed }: HeaderState) => navCollapsed);
+ }
+
+ private collapse(): void {
+ this.store.dispatch(HeaderActions.collapse());
+ }
+
+ private expand(): void {
+ this.store.dispatch(HeaderActions.expand());
+ }
+
+ public toggle(): void {
+ this.store.dispatch(HeaderActions.toggle());
+ }
+
+}
diff --git a/src/app/header/header.effects.ts b/src/app/header/header.effects.ts
new file mode 100644
index 0000000000..d9ea53adda
--- /dev/null
+++ b/src/app/header/header.effects.ts
@@ -0,0 +1,21 @@
+import { Injectable } from "@angular/core";
+import { Effect, Actions } from '@ngrx/effects'
+import { HeaderActions } from "./header.actions";
+import { HostWindowActions } from "../shared/host-window.actions";
+import { routerActions } from "@ngrx/router-store";
+
+@Injectable()
+export class HeaderEffects {
+
+ constructor(
+ private actions$: Actions
+ ) { }
+
+ @Effect() resize$ = this.actions$
+ .ofType(HostWindowActions.RESIZE)
+ .map(() => HeaderActions.collapse());
+
+ @Effect() routeChange$ = this.actions$
+ .ofType(routerActions.UPDATE_LOCATION)
+ .map(() => HeaderActions.collapse());
+}
diff --git a/src/app/header/header.reducer.ts b/src/app/header/header.reducer.ts
new file mode 100644
index 0000000000..af153fba24
--- /dev/null
+++ b/src/app/header/header.reducer.ts
@@ -0,0 +1,39 @@
+import { Action } from "@ngrx/store";
+import { HeaderActions } from "./header.actions";
+
+export interface HeaderState {
+ navCollapsed: boolean;
+}
+
+const initialState: HeaderState = {
+ navCollapsed: true
+};
+
+export const headerReducer = (state = initialState, action: Action): HeaderState => {
+ switch (action.type) {
+
+ case HeaderActions.COLLAPSE: {
+ return Object.assign({}, state, {
+ navCollapsed: true
+ });
+ }
+
+ case HeaderActions.EXPAND: {
+ return Object.assign({}, state, {
+ navCollapsed: false
+ });
+
+ }
+
+ case HeaderActions.TOGGLE: {
+ return Object.assign({}, state, {
+ navCollapsed: !state.navCollapsed
+ });
+
+ }
+
+ default: {
+ return state;
+ }
+ }
+};
diff --git a/src/app/shared/host-window.actions.ts b/src/app/shared/host-window.actions.ts
new file mode 100644
index 0000000000..de41c69564
--- /dev/null
+++ b/src/app/shared/host-window.actions.ts
@@ -0,0 +1,14 @@
+import { Action } from "@ngrx/store";
+
+export class HostWindowActions {
+ static RESIZE = 'dspace/host-window/RESIZE';
+ static resize(newWidth: number, newHeight: number): Action {
+ return {
+ type: HostWindowActions.RESIZE,
+ payload: {
+ width: newWidth,
+ height: newHeight
+ }
+ }
+ }
+}
diff --git a/src/app/shared/host-window.reducer.ts b/src/app/shared/host-window.reducer.ts
new file mode 100644
index 0000000000..4b8e1d3cb9
--- /dev/null
+++ b/src/app/shared/host-window.reducer.ts
@@ -0,0 +1,25 @@
+import { Action } from "@ngrx/store";
+import { HostWindowActions } from "./host-window.actions";
+
+export interface HostWindowState {
+ width: number;
+ height: number;
+}
+
+const initialState: HostWindowState = {
+ width: null,
+ height: null
+};
+
+export const hostWindowReducer = (state = initialState, action: Action): HostWindowState => {
+ switch (action.type) {
+
+ case HostWindowActions.RESIZE: {
+ return Object.assign({}, state, action.payload);
+ }
+
+ default: {
+ return state;
+ }
+ }
+};