Merge pull request #3815 from tsiegleauq/MobileObserveService
ViewportService and new Prefix
This commit is contained in:
commit
cbf8a33b8d
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"/users/login": {
|
"/apps/users/login": {
|
||||||
"target": "http://localhost:8000",
|
"target": "http://localhost:8000",
|
||||||
"secure": false
|
"secure": false
|
||||||
},
|
},
|
||||||
"/users/logout": {
|
"/apps/users/logout": {
|
||||||
"target": "http://localhost:8000",
|
"target": "http://localhost:8000",
|
||||||
"secure": false
|
"secure": false
|
||||||
},
|
},
|
||||||
"/users/whoami": {
|
"/apps/users/whoami": {
|
||||||
"target": "http://localhost:8000",
|
"target": "http://localhost:8000",
|
||||||
"secure": false
|
"secure": false
|
||||||
},
|
},
|
||||||
|
@ -12,6 +12,7 @@ import { OperatorService } from './services/operator.service';
|
|||||||
import { WebsocketService } from './services/websocket.service';
|
import { WebsocketService } from './services/websocket.service';
|
||||||
import { AddHeaderInterceptor } from './http-interceptor';
|
import { AddHeaderInterceptor } from './http-interceptor';
|
||||||
import { DataSendService } from './services/data-send.service';
|
import { DataSendService } from './services/data-send.service';
|
||||||
|
import { ViewportService } from './services/viewport.service';
|
||||||
|
|
||||||
/** Global Core Module. Contains all global (singleton) services
|
/** Global Core Module. Contains all global (singleton) services
|
||||||
*
|
*
|
||||||
@ -26,6 +27,7 @@ import { DataSendService } from './services/data-send.service';
|
|||||||
DataStoreService,
|
DataStoreService,
|
||||||
DataSendService,
|
DataSendService,
|
||||||
OperatorService,
|
OperatorService,
|
||||||
|
ViewportService,
|
||||||
WebsocketService,
|
WebsocketService,
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
@ -5,6 +5,7 @@ import { catchError, tap } from 'rxjs/operators';
|
|||||||
|
|
||||||
import { OperatorService } from 'app/core/services/operator.service';
|
import { OperatorService } from 'app/core/services/operator.service';
|
||||||
import { OpenSlidesComponent } from '../../openslides.component';
|
import { OpenSlidesComponent } from '../../openslides.component';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates an OpenSlides user with username and password
|
* Authenticates an OpenSlides user with username and password
|
||||||
@ -44,7 +45,7 @@ export class AuthService extends OpenSlidesComponent {
|
|||||||
username: username,
|
username: username,
|
||||||
password: password
|
password: password
|
||||||
};
|
};
|
||||||
return this.http.post<any>('/users/login/', user).pipe(
|
return this.http.post<any>(environment.urlPrefix + '/users/login/', user).pipe(
|
||||||
tap(resp => this.operator.storeUser(resp.user)),
|
tap(resp => this.operator.storeUser(resp.user)),
|
||||||
catchError(this.handleError())
|
catchError(this.handleError())
|
||||||
);
|
);
|
||||||
@ -60,6 +61,6 @@ export class AuthService extends OpenSlidesComponent {
|
|||||||
//TODO not yet used
|
//TODO not yet used
|
||||||
logout(): Observable<any> {
|
logout(): Observable<any> {
|
||||||
this.operator.clear();
|
this.operator.clear();
|
||||||
return this.http.post<any>('/users/logout/', {});
|
return this.http.post<any>(environment.urlPrefix + '/users/logout/', {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { tap, catchError, share } from 'rxjs/operators';
|
|||||||
import { OpenSlidesComponent } from 'app/openslides.component';
|
import { OpenSlidesComponent } from 'app/openslides.component';
|
||||||
import { Group } from 'app/shared/models/users/group';
|
import { Group } from 'app/shared/models/users/group';
|
||||||
import { User } from '../../shared/models/users/user';
|
import { User } from '../../shared/models/users/user';
|
||||||
|
import { environment } from 'environments/environment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The operator represents the user who is using OpenSlides.
|
* The operator represents the user who is using OpenSlides.
|
||||||
@ -74,10 +75,10 @@ export class OperatorService extends OpenSlidesComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calls `/users/whoami` to find out the real operator
|
* calls `/apps/users/whoami` to find out the real operator
|
||||||
*/
|
*/
|
||||||
public whoAmI(): Observable<any> {
|
public whoAmI(): Observable<any> {
|
||||||
return this.http.get<any>('/users/whoami/').pipe(
|
return this.http.get<any>(environment.urlPrefix + '/users/whoami/').pipe(
|
||||||
tap(whoami => {
|
tap(whoami => {
|
||||||
if (whoami && whoami.user) {
|
if (whoami && whoami.user) {
|
||||||
this.storeUser(whoami.user as User);
|
this.storeUser(whoami.user as User);
|
||||||
|
15
client/src/app/core/services/viewport.service.spec.ts
Normal file
15
client/src/app/core/services/viewport.service.spec.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ViewportService } from './viewport.service';
|
||||||
|
|
||||||
|
describe('ViewportService', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [ViewportService]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', inject([ViewportService], (service: ViewportService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
30
client/src/app/core/services/viewport.service.ts
Normal file
30
client/src/app/core/services/viewport.service.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ViewportService {
|
||||||
|
/**
|
||||||
|
* True if Viewport equals mobile or small resolution.
|
||||||
|
*/
|
||||||
|
private _isMobile = false;
|
||||||
|
|
||||||
|
constructor(private breakpointObserver: BreakpointObserver) {}
|
||||||
|
|
||||||
|
checkForChange() {
|
||||||
|
this.breakpointObserver
|
||||||
|
.observe([Breakpoints.Small, Breakpoints.HandsetPortrait])
|
||||||
|
.subscribe((state: BreakpointState) => {
|
||||||
|
if (state.matches) {
|
||||||
|
this._isMobile = true;
|
||||||
|
} else {
|
||||||
|
this._isMobile = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get isMobile() {
|
||||||
|
return this._isMobile;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<mat-sidenav-container autosize class='main-container'>
|
<mat-sidenav-container autosize class='main-container'>
|
||||||
<mat-sidenav #sideNav [mode]="isMobile ? 'push' : 'side'" [opened]='!isMobile' disableClose='!isMobile' class="side-panel">
|
<mat-sidenav #sideNav [mode]="vp.isMobile ? 'push' : 'side'" [opened]='!vp.isMobile' disableClose='!vp.isMobile' class="side-panel">
|
||||||
<mat-toolbar class='nav-toolbar'>
|
<mat-toolbar class='nav-toolbar'>
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<mat-toolbar-row class='os-logo-container'>
|
<mat-toolbar-row class='os-logo-container'>
|
||||||
@ -42,39 +42,39 @@
|
|||||||
<!-- navigation -->
|
<!-- navigation -->
|
||||||
<mat-nav-list class='main-nav'>
|
<mat-nav-list class='main-nav'>
|
||||||
<a [@navItemAnim] *appOsPerms="['core.can_see_frontpage']" mat-list-item routerLink='/' routerLinkActive='active' [routerLinkActiveOptions]="{exact: true}"
|
<a [@navItemAnim] *appOsPerms="['core.can_see_frontpage']" mat-list-item routerLink='/' routerLinkActive='active' [routerLinkActiveOptions]="{exact: true}"
|
||||||
(click)='isMobile ? sideNav.toggle() : null'>
|
(click)='toggleSideNav()'>
|
||||||
<fa-icon icon='home'></fa-icon>
|
<fa-icon icon='home'></fa-icon>
|
||||||
<span translate>Home</span>
|
<span translate>Home</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['agenda.can_see']" mat-list-item routerLink='/agenda' routerLinkActive='active' (click)='isMobile ? sideNav.toggle() : null'>
|
<a [@navItemAnim] *appOsPerms="['agenda.can_see']" mat-list-item routerLink='/agenda' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||||
<fa-icon icon='calendar'></fa-icon>
|
<fa-icon icon='calendar'></fa-icon>
|
||||||
<span translate>Agenda</span>
|
<span translate>Agenda</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['motions.can_see']" mat-list-item routerLink='/motions' routerLinkActive='active' (click)='isMobile ? sideNav.toggle() : null'>
|
<a [@navItemAnim] *appOsPerms="['motions.can_see']" mat-list-item routerLink='/motions' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||||
<fa-icon icon='file-alt'></fa-icon>
|
<fa-icon icon='file-alt'></fa-icon>
|
||||||
<span translate>Motions</span>
|
<span translate>Motions</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['assignments.can_see']" mat-list-item routerLink='/assignments' routerLinkActive='active'
|
<a [@navItemAnim] *appOsPerms="['assignments.can_see']" mat-list-item routerLink='/assignments' routerLinkActive='active'
|
||||||
(click)='isMobile ? sideNav.toggle() : null'>
|
(click)='vp.isMobile ? sideNav.toggle() : null'>
|
||||||
<fa-icon icon='chart-pie'></fa-icon>
|
<fa-icon icon='chart-pie'></fa-icon>
|
||||||
<span translate>Assignments</span>
|
<span translate>Assignments</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['users.can_see_name']" mat-list-item routerLink='/users' routerLinkActive='active' (click)='isMobile ? sideNav.toggle() : null'>
|
<a [@navItemAnim] *appOsPerms="['users.can_see_name']" mat-list-item routerLink='/users' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||||
<fa-icon icon='user'></fa-icon>
|
<fa-icon icon='user'></fa-icon>
|
||||||
<span translate>Participants</span>
|
<span translate>Participants</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['mediafiles.can_see']" mat-list-item routerLink='/mediafiles' routerLinkActive='active' (click)='isMobile ? sideNav.toggle() : null'>
|
<a [@navItemAnim] *appOsPerms="['mediafiles.can_see']" mat-list-item routerLink='/mediafiles' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||||
<fa-icon icon='paperclip'></fa-icon>
|
<fa-icon icon='paperclip'></fa-icon>
|
||||||
<span translate>Files</span>
|
<span translate>Files</span>
|
||||||
</a>
|
</a>
|
||||||
<a [@navItemAnim] *appOsPerms="['core.can_manage_config']" mat-list-item routerLink='/settings' routerLinkActive='active'
|
<a [@navItemAnim] *appOsPerms="['core.can_manage_config']" mat-list-item routerLink='/settings' routerLinkActive='active'
|
||||||
(click)='isMobile ? sideNav.toggle() : null'>
|
(click)='toggleSideNav()'>
|
||||||
<fa-icon icon='cog'></fa-icon>
|
<fa-icon icon='cog'></fa-icon>
|
||||||
<span translate>Settings</span>
|
<span translate>Settings</span>
|
||||||
</a>
|
</a>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<a [@navItemAnim] *appOsPerms="['core.can_see_projector']" mat-list-item routerLink='/projector' routerLinkActive='active'
|
<a [@navItemAnim] *appOsPerms="['core.can_see_projector']" mat-list-item routerLink='/projector' routerLinkActive='active'
|
||||||
(click)='isMobile ? sideNav.toggle() : null'>
|
(click)='toggleSideNav()'>
|
||||||
<fa-icon icon='video'></fa-icon>
|
<fa-icon icon='video'></fa-icon>
|
||||||
<span translate>Projector</span>
|
<span translate>Projector</span>
|
||||||
</a>
|
</a>
|
||||||
@ -83,18 +83,15 @@
|
|||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<button mat-button>
|
<button mat-button>
|
||||||
<a routerLink='/legalnotice' (click)='isMobile ? sideNav.toggle() : null'>
|
<a routerLink='/legalnotice' (click)='toggleSideNav()'>
|
||||||
<span translate>Legal Notice</span>
|
<span translate>Legal Notice</span>
|
||||||
</a>
|
</a>
|
||||||
</button>
|
</button>
|
||||||
<button mat-button>
|
<button mat-button>
|
||||||
<a routerLink='/privacypolicy' (click)='isMobile ? sideNav.toggle() : null'>
|
<a routerLink='/privacypolicy' (click)='toggleSideNav()'>
|
||||||
<span translate>Privacy Policy</span>
|
<span translate>Privacy Policy</span>
|
||||||
</a>
|
</a>
|
||||||
</button>
|
</button>
|
||||||
<!-- <button mat-button (click)='openPrivacyPolicy()'>
|
|
||||||
<span translate>Privacy Policy</span>
|
|
||||||
</button> -->
|
|
||||||
<br>
|
<br>
|
||||||
<span align="center">© Copyright by
|
<span align="center">© Copyright by
|
||||||
<a href='https://openslides.org/'>OpenSlides</a>
|
<a href='https://openslides.org/'>OpenSlides</a>
|
||||||
@ -107,7 +104,7 @@
|
|||||||
<mat-toolbar color='primary'>
|
<mat-toolbar color='primary'>
|
||||||
|
|
||||||
<!-- show/hide menu button -->
|
<!-- show/hide menu button -->
|
||||||
<button mat-icon-button *ngIf="isMobile" (click)='sideNav.toggle()'>
|
<button mat-icon-button *ngIf="vp.isMobile" (click)='sideNav.toggle()'>
|
||||||
<fa-icon icon='bars'></fa-icon>
|
<fa-icon icon='bars'></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -122,4 +119,4 @@
|
|||||||
<main [@pageTransition]="o.isActivated ? o.activatedRoute : ''">
|
<main [@pageTransition]="o.isActivated ? o.activatedRoute : ''">
|
||||||
<router-outlet #o="outlet"></router-outlet>
|
<router-outlet #o="outlet"></router-outlet>
|
||||||
</main>
|
</main>
|
||||||
</mat-sidenav-container>
|
</mat-sidenav-container>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit, HostBinding } from '@angular/core';
|
import { Component, OnInit, HostBinding, ViewChild } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
|
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
|
||||||
|
|
||||||
@ -9,7 +9,8 @@ import { OperatorService } from 'app/core/services/operator.service';
|
|||||||
import { TranslateService } from '@ngx-translate/core'; //showcase
|
import { TranslateService } from '@ngx-translate/core'; //showcase
|
||||||
import { BaseComponent } from 'app/base.component';
|
import { BaseComponent } from 'app/base.component';
|
||||||
import { pageTransition, navItemAnim } from 'app/shared/animations';
|
import { pageTransition, navItemAnim } from 'app/shared/animations';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog, MatSidenav } from '@angular/material';
|
||||||
|
import { ViewportService } from '../core/services/viewport.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-site',
|
selector: 'app-site',
|
||||||
@ -18,16 +19,16 @@ import { MatDialog } from '@angular/material';
|
|||||||
styleUrls: ['./site.component.scss']
|
styleUrls: ['./site.component.scss']
|
||||||
})
|
})
|
||||||
export class SiteComponent extends BaseComponent implements OnInit {
|
export class SiteComponent extends BaseComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* HTML element of the side panel
|
||||||
|
*/
|
||||||
|
@ViewChild('sideNav') sideNav: MatSidenav;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the username from the operator (should be known already)
|
* Get the username from the operator (should be known already)
|
||||||
*/
|
*/
|
||||||
username = this.operator.username;
|
username = this.operator.username;
|
||||||
|
|
||||||
/**
|
|
||||||
* True if Viewport equals mobile or small resolution. Set by breakpointObserver.
|
|
||||||
*/
|
|
||||||
isMobile = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -44,7 +45,7 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
|||||||
private autoupdateService: AutoupdateService,
|
private autoupdateService: AutoupdateService,
|
||||||
private operator: OperatorService,
|
private operator: OperatorService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private breakpointObserver: BreakpointObserver,
|
public vp: ViewportService,
|
||||||
public translate: TranslateService,
|
public translate: TranslateService,
|
||||||
public dialog: MatDialog
|
public dialog: MatDialog
|
||||||
) {
|
) {
|
||||||
@ -55,15 +56,7 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
|||||||
* Initialize the site component
|
* Initialize the site component
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.breakpointObserver
|
this.vp.checkForChange();
|
||||||
.observe([Breakpoints.Small, Breakpoints.HandsetPortrait])
|
|
||||||
.subscribe((state: BreakpointState) => {
|
|
||||||
if (state.matches) {
|
|
||||||
this.isMobile = true;
|
|
||||||
} else {
|
|
||||||
this.isMobile = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get a translation via code: use the translation service
|
// get a translation via code: use the translation service
|
||||||
// this.translate.get('Motions').subscribe((res: string) => {
|
// this.translate.get('Motions').subscribe((res: string) => {
|
||||||
@ -82,6 +75,15 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the sidenav in mobile view
|
||||||
|
*/
|
||||||
|
toggleSideNav() {
|
||||||
|
if (this.vp.isMobile) {
|
||||||
|
this.sideNav.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let the user change the language
|
* Let the user change the language
|
||||||
* @param lang the desired language (en, de, fr, ...)
|
* @param lang the desired language (en, de, fr, ...)
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
// The list of file replacements can be found in `angular.json`.
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false,
|
||||||
|
urlPrefix: '/apps'
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user