Merge pull request #5086 from GabrielInTheWorld/editStart

Adds the 'edit-mode' to start, legal-notice and privacy-policy
This commit is contained in:
Sean 2019-10-30 12:04:51 +01:00 committed by GitHub
commit 9ae4472b0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 402 additions and 44 deletions

View File

@ -1,9 +1,18 @@
<mat-card class="os-card">
<div>
<ng-container *ngIf="!isEditing">
<div *ngIf="legalNotice" class="legal-notice-text" [innerHtml]="legalNotice | trust: 'html'"></div>
<div *ngIf="!legalNotice" translate>
The event manager hasn't set up a legal notice yet.
</div>
</ng-container>
<ng-container *ngIf="isEditing">
<div>
<form [formGroup]="formGroup">
<editor formControlName="legalNotice" [init]="tinyMceSettings"></editor>
</form>
</div>
</ng-container>
<mat-divider></mat-divider>
<div *ngIf="versionInfo" class="version-text">
<a [attr.href]="versionInfo.openslides_url" target="_blank">

View File

@ -1,9 +1,14 @@
import { Component, OnInit } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { environment } from 'environments/environment';
import { HttpService } from 'app/core/core-services/http.service';
import { LoginDataService } from 'app/core/ui-services/login-data.service';
import { BaseViewComponent } from 'app/site/base/base-view';
/**
* Characterize a plugin. This data is retrieved from the server
@ -64,7 +69,50 @@ interface VersionResponse {
templateUrl: './legal-notice-content.component.html',
styleUrls: ['./legal-notice-content.component.scss']
})
export class LegalNoticeContentComponent implements OnInit {
export class LegalNoticeContentComponent extends BaseViewComponent implements OnInit {
/**
* Decides, whether the component can be edited at all.
* Defaults to `false`.
*/
@Input()
public canBeEdited = false;
/**
* Sets the editing-state and updates the FormGroup with the current value.
*
* @param isEditing whether the component is currently in editing-mode.
*/
@Input()
public set isEditing(isEditing: boolean) {
this.formGroup.patchValue({ legalNotice: this.legalNotice });
this._isEditing = isEditing;
}
/**
* Gets the editing-state.
*
* @returns `isEditing`.
*/
public get isEditing(): boolean {
return this._isEditing;
}
/**
* Emitter to send updated value to the parent-component.
*/
@Output()
public update = new EventEmitter<string>();
/**
* FormGroup for editing value.
*/
public formGroup: FormGroup;
/**
* State, whether this is in editing-mode.
*/
private _isEditing = false;
/**
* The legal notive text for the ui.
*/
@ -81,7 +129,19 @@ export class LegalNoticeContentComponent implements OnInit {
* @param translate
* @param http
*/
public constructor(private loginDataService: LoginDataService, private http: HttpService) {}
public constructor(
title: Title,
translate: TranslateService,
matSnackbar: MatSnackBar,
private loginDataService: LoginDataService,
private http: HttpService,
fb: FormBuilder
) {
super(title, translate, matSnackbar);
this.formGroup = fb.group({
legalNotice: ''
});
}
/**
* Subscribes for the legal notice text.
@ -100,5 +160,11 @@ export class LegalNoticeContentComponent implements OnInit {
// TODO: error handling if the version info could not be loaded
}
);
if (this.canBeEdited) {
this.subscriptions.push(
this.formGroup.get('legalNotice').valueChanges.subscribe(value => this.update.emit(value))
);
}
}
}

View File

@ -1,6 +1,13 @@
<mat-card class="os-card">
<mat-card [ngClass]="isEditing ? 'os-form-card' : 'os-card'">
<ng-container *ngIf="!isEditing">
<div *ngIf="privacyPolicy" [innerHtml]="privacyPolicy | trust: 'html'"></div>
<div *ngIf="!privacyPolicy" translate>
The event manager hasn't set up a privacy policy yet.
</div>
</ng-container>
<ng-container *ngIf="isEditing">
<form [formGroup]="formGroup">
<editor formControlName="privacyPolicy" [init]="tinyMceSettings"></editor>
</form>
</ng-container>
</mat-card>

View File

@ -1,6 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { LoginDataService } from 'app/core/ui-services/login-data.service';
import { BaseViewComponent } from 'app/site/base/base-view';
/**
* Shared component to hold the content of the Privacy Policy.
@ -11,18 +17,76 @@ import { LoginDataService } from 'app/core/ui-services/login-data.service';
templateUrl: './privacy-policy-content.component.html',
styleUrls: ['./privacy-policy-content.component.scss']
})
export class PrivacyPolicyContentComponent implements OnInit {
export class PrivacyPolicyContentComponent extends BaseViewComponent implements OnInit {
/**
* Decides, whether the component can be edited at all.
* Defaults to `false`.
*/
@Input()
public canBeEdited = false;
/**
* Sets the editing-state and updates the FormGroup with the current value.
*
* @param isEditing whether the component is currently in editing-mode.
*/
@Input()
public set isEditing(isEditing: boolean) {
this.formGroup.patchValue({ privacyPolicy: this.privacyPolicy });
this._isEditing = isEditing;
}
/**
* Gets the editing-state.
*
* @returns `isEditing`.
*/
public get isEditing(): boolean {
return this._isEditing;
}
/**
* Emitter to send updated value to the parent-component.
*/
@Output()
public update = new EventEmitter<{ [key: string]: string }>();
/**
* FormGroup for editing value.
*/
public formGroup: FormGroup;
/**
* State, whether this is in editing-mode.
*/
private _isEditing = false;
/**
* The actual privacy policy as string
*/
public privacyPolicy: string;
/**
* Imports the loginDataService and the translation service
* @param loginDataService Login Data
* @param translate for the translation
* Constructor.
*
* @param title
* @param translate
* @param matSnackbar
* @param loginDataService
* @param fb
*/
public constructor(private loginDataService: LoginDataService) {}
public constructor(
title: Title,
protected translate: TranslateService,
matSnackbar: MatSnackBar,
private loginDataService: LoginDataService,
fb: FormBuilder
) {
super(title, translate, matSnackbar);
this.formGroup = fb.group({
privacyPolicy: ''
});
}
/**
* Subscribes for the privacy policy text
@ -31,5 +95,10 @@ export class PrivacyPolicyContentComponent implements OnInit {
this.loginDataService.privacyPolicy.subscribe(privacyPolicy => {
this.privacyPolicy = privacyPolicy;
});
if (this.canBeEdited) {
this.subscriptions.push(
this.formGroup.get('privacyPolicy').valueChanges.subscribe(value => this.update.emit(value))
);
}
}
}

View File

@ -1,10 +1,24 @@
<os-head-bar [nav]="false" [goBack]="true">
<os-head-bar
[nav]="false"
[goBack]="true"
[editMode]="isEditing"
[hasMainButton]="canManage()"
[mainButtonIcon]="'edit'"
[mainActionTooltip]="'Edit' | translate"
(cancelEditEvent)="isEditing = !isEditing"
(mainEvent)="isEditing = !isEditing"
(saveEvent)="saveChanges()"
>
<div class="title-slot">
<h2 translate>Legal notice</h2>
</div>
</os-head-bar>
<os-legal-notice-content></os-legal-notice-content>
<os-legal-notice-content
[canBeEdited]="true"
[isEditing]="isEditing"
(update)="legalNotice = $event"
></os-legal-notice-content>
<mat-card class="os-card">
<div>

View File

@ -1,25 +1,47 @@
import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { OpenSlidesService } from 'app/core/core-services/openslides.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ConfigRepositoryService } from 'app/core/repositories/config/config-repository.service';
import { UpdateService } from 'app/core/ui-services/update.service';
import { BaseViewComponent } from 'app/site/base/base-view';
@Component({
selector: 'os-legal-notice',
templateUrl: './legal-notice.component.html'
})
export class LegalNoticeComponent implements OnInit {
export class LegalNoticeComponent extends BaseViewComponent implements OnInit {
/**
* Whether this component is in editing-mode.
*/
public isEditing = false;
/**
* Holds the current legal-notice.
*/
public legalNotice = '';
/**
* Constructor.
*/
public constructor(
title: Title,
protected translate: TranslateService,
matSnackbar: MatSnackBar,
private openSlidesService: OpenSlidesService,
private update: UpdateService,
private titleService: Title,
private translate: TranslateService
) {}
private configRepo: ConfigRepositoryService,
private operator: OperatorService
) {
super(title, translate, matSnackbar);
}
public ngOnInit(): void {
this.titleService.setTitle(this.translate.instant('Legal notice'));
super.setTitle(this.translate.instant('Legal notice'));
}
public resetCache(): void {
@ -33,4 +55,20 @@ export class LegalNoticeComponent implements OnInit {
public initiateUpdateCheckForAllClients(): void {
this.update.initiateUpdateCheckForAllClients();
}
/**
* Saves changes.
*/
public saveChanges(): void {
this.configRepo
.bulkUpdate([{ key: 'general_event_legal_notice', value: this.legalNotice }])
.then(() => (this.isEditing = !this.isEditing), this.raiseError);
}
/**
* Returns, if the current user has the necessary permissions.
*/
public canManage(): boolean {
return this.operator.hasPerms('core.can_manage_config');
}
}

View File

@ -1,7 +1,21 @@
<os-head-bar [nav]=false [goBack]=true>
<os-head-bar
[nav]="false"
[goBack]="true"
[editMode]="isEditing"
[hasMainButton]="canManage()"
[mainButtonIcon]="'edit'"
[mainActionTooltip]="'Edit' | translate"
(cancelEditEvent)="isEditing = !isEditing"
(mainEvent)="isEditing = !isEditing"
(saveEvent)="saveChanges()"
>
<div class="title-slot">
<h2 translate>Privacy Policy</h2>
</div>
</os-head-bar>
<os-privacy-policy-content></os-privacy-policy-content>
<os-privacy-policy-content
[canBeEdited]="true"
[isEditing]="isEditing"
(update)="privacyProlicy = $event"
></os-privacy-policy-content>

View File

@ -1,17 +1,63 @@
import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ConfigRepositoryService } from 'app/core/repositories/config/config-repository.service';
import { BaseViewComponent } from 'app/site/base/base-view';
@Component({
selector: 'os-privacy-policy',
templateUrl: './privacy-policy.component.html',
styleUrls: ['./privacy-policy.component.scss']
})
export class PrivacyPolicyComponent implements OnInit {
public constructor(private titleService: Title, private translate: TranslateService) {}
export class PrivacyPolicyComponent extends BaseViewComponent implements OnInit {
/**
* Whether the component is in editing-mode.
*/
public isEditing = false;
/**
* Holds the current privacy-policy.
*/
public privacyProlicy = '';
/**
* Constructor.
*
* @param titleService
* @param translate
* @param configRepo
*/
public constructor(
title: Title,
protected translate: TranslateService,
matSnackbar: MatSnackBar,
private configRepo: ConfigRepositoryService,
private operator: OperatorService
) {
super(title, translate, matSnackbar);
}
public ngOnInit(): void {
this.titleService.setTitle(this.translate.instant('Privacy policy'));
super.setTitle(this.translate.instant('Privacy policy'));
}
/**
* Saves changes.
*/
public saveChanges(): void {
this.configRepo
.bulkUpdate([{ key: 'general_event_privacy_policy', value: this.privacyProlicy }])
.then(() => (this.isEditing = !this.isEditing), this.raiseError);
}
/**
* Returns, if the current user has the necessary permissions.
*/
public canManage(): boolean {
return this.operator.hasPerms('core.can_manage_config');
}
}

View File

@ -1,13 +1,38 @@
<os-head-bar>
<os-head-bar
[hasMainButton]="canManage()"
[editMode]="isEditing"
[mainButtonIcon]="'edit'"
[isSaveButtonEnabled]="startForm.valid"
(mainEvent)="editStartPage()"
(saveEvent)="saveChanges()"
(cancelEditEvent)="isEditing = !isEditing"
>
<div class="title-slot">
<h2 translate>Home</h2>
</div>
</os-head-bar>
<mat-card class="os-card">
<mat-card [ngClass]="isEditing ? 'os-form-card' : 'os-card'">
<ng-container *ngIf="!isEditing">
<div class="app-content">
<h1>{{ welcomeTitle | translate }}</h1>
<h1>{{ startContent.general_event_welcome_title | translate }}</h1>
<div [innerHTML]="welcomeText | trust: 'html'"></div>
<div [innerHTML]="startContent.general_event_welcome_text | trust: 'html'"></div>
</div>
</ng-container>
<ng-container *ngIf="isEditing">
<form [formGroup]="startForm">
<mat-form-field>
<input
matInput
formControlName="general_event_welcome_title"
required
placeholder="{{ 'Front page title' | translate }}"
/>
<mat-error translate>The title is required</mat-error>
</mat-form-field>
<editor formControlName="general_event_welcome_text" [init]="tinyMceSettings"></editor>
</form>
</ng-container>
</mat-card>

View File

@ -1,10 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; // showcase
import { BaseComponent } from 'app/base.component';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ConfigRepositoryService } from 'app/core/repositories/config/config-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { BaseViewComponent } from 'app/site/base/base-view';
/**
* Interface describes the keys for the fields at start-component.
*/
interface IStartContent {
general_event_welcome_title: string;
general_event_welcome_text: string;
}
/**
* The start component. Greeting page for OpenSlides
@ -14,9 +26,24 @@ import { ConfigService } from 'app/core/ui-services/config.service';
templateUrl: './start.component.html',
styleUrls: ['./start.component.scss']
})
export class StartComponent extends BaseComponent implements OnInit {
public welcomeTitle: string;
public welcomeText: string;
export class StartComponent extends BaseViewComponent implements OnInit {
/**
* Whether the user is editing the content.
*/
public isEditing = false;
/**
* Formular for the content.
*/
public startForm: FormGroup;
/**
* Holding the values for the content.
*/
public startContent: IStartContent = {
general_event_welcome_title: '',
general_event_welcome_text: ''
};
/**
* Constructor of the StartComponent
@ -25,8 +52,20 @@ export class StartComponent extends BaseComponent implements OnInit {
* @param translate to translation module
* @param configService read out config values
*/
public constructor(titleService: Title, translate: TranslateService, private configService: ConfigService) {
super(titleService, translate);
public constructor(
titleService: Title,
translate: TranslateService,
matSnackbar: MatSnackBar,
private configService: ConfigService,
private configRepo: ConfigRepositoryService,
private fb: FormBuilder,
private operator: OperatorService
) {
super(titleService, translate, matSnackbar);
this.startForm = this.fb.group({
general_event_welcome_title: ['', Validators.required],
general_event_welcome_text: ''
});
}
/**
@ -40,11 +79,42 @@ export class StartComponent extends BaseComponent implements OnInit {
// set the welcome title
this.configService
.get<string>('general_event_welcome_title')
.subscribe(welcomeTitle => (this.welcomeTitle = welcomeTitle));
.subscribe(welcomeTitle => (this.startContent.general_event_welcome_title = welcomeTitle));
// set the welcome text
this.configService.get<string>('general_event_welcome_text').subscribe(welcomeText => {
this.welcomeText = this.translate.instant(welcomeText);
this.startContent.general_event_welcome_text = this.translate.instant(welcomeText);
});
}
/**
* Changes to editing mode.
*/
public editStartPage(): void {
Object.keys(this.startForm.controls).forEach(control => {
this.startForm.patchValue({ [control]: this.startContent[control] });
});
this.isEditing = true;
}
/**
* Saves changes and updates the content.
*/
public saveChanges(): void {
this.configRepo
.bulkUpdate(
Object.keys(this.startForm.controls).map(control => ({
key: control,
value: this.startForm.value[control]
}))
)
.then(() => (this.isEditing = !this.isEditing), this.raiseError);
}
/**
* Returns, if the current user has the necessary permissions.
*/
public canManage(): boolean {
return this.operator.hasPerms('core.can_manage_config');
}
}