diff --git a/client/angular.json b/client/angular.json index e45d51651..dee0fe99b 100644 --- a/client/angular.json +++ b/client/angular.json @@ -24,7 +24,23 @@ "tsConfig": "src/tsconfig.app.json", "assets": ["src/favicon.ico", "src/assets"], "styles": ["src/styles.scss", "node_modules/material-design-icons/iconfont/material-icons.css"], - "scripts": [] + "scripts": [ + "node_modules/tinymce/tinymce.min.js", + "node_modules/tinymce/themes/modern/theme.js", + "node_modules/tinymce/plugins/autolink/plugin.js", + "node_modules/tinymce/plugins/charmap/plugin.js", + "node_modules/tinymce/plugins/code/plugin.js", + "node_modules/tinymce/plugins/colorpicker/plugin.js", + "node_modules/tinymce/plugins/fullscreen/plugin.js", + "node_modules/tinymce/plugins/image/plugin.js", + "node_modules/tinymce/plugins/imagetools/plugin.js", + "node_modules/tinymce/plugins/lists/plugin.js", + "node_modules/tinymce/plugins/link/plugin.js", + "node_modules/tinymce/plugins/paste/plugin.js", + "node_modules/tinymce/plugins/preview/plugin.js", + "node_modules/tinymce/plugins/searchreplace/plugin.js", + "node_modules/tinymce/plugins/textcolor/plugin.js" + ] }, "configurations": { "production": { @@ -71,7 +87,9 @@ "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": ["src/styles.scss"], - "scripts": [], + "scripts": [ + "node_modules/tinymce/tinymce.min.js" + ], "assets": ["src/favicon.ico", "src/assets"] } }, diff --git a/client/package.json b/client/package.json index 980fc2fb4..d9bf99a33 100644 --- a/client/package.json +++ b/client/package.json @@ -30,6 +30,7 @@ "@ngx-pwa/local-storage": "^7.0.0", "@ngx-translate/core": "^11.0.1", "@ngx-translate/http-loader": "^4.0.0", + "@tinymce/tinymce-angular": "^2.3.1", "core-js": "^2.5.4", "file-saver": "^2.0.0-rc.3", "material-design-icons": "^3.0.1", @@ -38,6 +39,7 @@ "po2json": "^1.0.0-alpha", "roboto-fontface": "^0.10.0", "rxjs": "^6.3.3", + "tinymce": "^4.8.5", "uuid": "^3.3.2", "zone.js": "^0.8.26" }, diff --git a/client/src/app/base.component.ts b/client/src/app/base.component.ts index 6f8746fca..f80f882ed 100644 --- a/client/src/app/base.component.ts +++ b/client/src/app/base.component.ts @@ -17,6 +17,27 @@ export abstract class BaseComponent extends OpenSlidesComponent { */ private titleSuffix = ' - OpenSlides 3'; + /** + * Settings for the TinyMCE editor selector + */ + public tinyMceSettings = { + // TODO: language_url: '/static/tinymce/i18n/' + gettextCatalog.getCurrentLanguage() + '.js', + // TODO: theme_url: '/static/js/openslides-libs.js', + skin_url: '/assets/tinymce/skins/lightgray', + inline: false, + statusbar: false, + browser_spellcheck: true, + image_advtab: true, + height: 320, + // TODO: image_list: images, + plugins: `autolink charmap code colorpicker fullscreen image imagetools + lists link paste preview searchreplace textcolor`, + menubar: '', + toolbar: `undo redo searchreplace | styleselect | bold italic underline strikethrough + | forecolor backcolor removeformat | bullist numlist | outdent indent | + link image charmap table | code preview fullscreen` + }; + /** * Child constructor that implements the titleServices and calls Super from OpenSlidesComponent */ diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 9496526ef..529ad2168 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -23,7 +23,7 @@ import { DateAdapter, MatIconModule, MatButtonToggleModule, - MatBadgeModule, + MatBadgeModule } from '@angular/material'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatChipsModule } from '@angular/material'; @@ -43,6 +43,9 @@ import { TranslateModule } from '@ngx-translate/core'; // ngx-file-drop import { FileDropModule } from 'ngx-file-drop'; +// TinyMCE +import { EditorModule } from '@tinymce/tinymce-angular'; + // directives import { PermsDirective } from './directives/perms.directive'; import { DomChangeDirective } from './directives/dom-change.directive'; @@ -107,7 +110,8 @@ import { SpeakerListComponent } from 'app/site/agenda/components/speaker-list/sp TranslateModule.forChild(), RouterModule, NgxMatSelectSearchModule, - FileDropModule + FileDropModule, + EditorModule ], exports: [ FormsModule, @@ -151,7 +155,8 @@ import { SpeakerListComponent } from 'app/site/agenda/components/speaker-list/sp LegalNoticeContentComponent, PrivacyPolicyContentComponent, PromptDialogComponent, - SortingListComponent + SortingListComponent, + EditorModule ], declarations: [ PermsDirective, diff --git a/client/src/app/site/agenda/components/topic-detail/topic-detail.component.html b/client/src/app/site/agenda/components/topic-detail/topic-detail.component.html index 335a82491..f50589c54 100644 --- a/client/src/app/site/agenda/components/topic-detail/topic-detail.component.html +++ b/client/src/app/site/agenda/components/topic-detail/topic-detail.component.html @@ -32,7 +32,7 @@
- {{ topic.text }} +
No description provided.
@@ -58,11 +58,8 @@ A name is required -
- - - -
+ +
diff --git a/client/src/app/site/agenda/components/topic-detail/topic-detail.component.ts b/client/src/app/site/agenda/components/topic-detail/topic-detail.component.ts index c9c123711..827e37524 100644 --- a/client/src/app/site/agenda/components/topic-detail/topic-detail.component.ts +++ b/client/src/app/site/agenda/components/topic-detail/topic-detail.component.ts @@ -2,9 +2,12 @@ import { Component } from '@angular/core'; import { Location } from '@angular/common'; import { FormGroup, Validators, FormBuilder } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { MatSnackBar } from '@angular/material'; import { TranslateService } from '@ngx-translate/core'; +import { BaseViewComponent } from 'app/site/base/base-view'; import { PromptService } from 'app/core/services/prompt.service'; import { TopicRepositoryService } from '../../services/topic-repository.service'; import { ViewTopic } from '../../models/view-topic'; @@ -17,7 +20,7 @@ import { ViewTopic } from '../../models/view-topic'; templateUrl: './topic-detail.component.html', styleUrls: ['./topic-detail.component.scss'] }) -export class TopicDetailComponent { +export class TopicDetailComponent extends BaseViewComponent { /** * Determine if the topic is in edit mode */ @@ -40,24 +43,28 @@ export class TopicDetailComponent { /** * Constructor for the topic detail page. - * + * @param title Setting the browsers title + * @param matSnackBar display errors and other messages + * @param translate Handles translations * @param route Angulars ActivatedRoute * @param router Angulars Router * @param location Enables to navigate back * @param formBuilder Angulars FormBuilder - * @param translate Handles translations * @param repo The topic repository * @param promptService Allows warning before deletion attempts */ public constructor( + title: Title, + matSnackBar: MatSnackBar, + protected translate: TranslateService, private route: ActivatedRoute, private router: Router, private location: Location, private formBuilder: FormBuilder, - private translate: TranslateService, private repo: TopicRepositoryService, private promptService: PromptService ) { + super(title, translate, matSnackBar); this.getTopicByUrl(); this.createForm(); } diff --git a/client/src/app/site/config/components/config-field/config-field.component.html b/client/src/app/site/config/components/config-field/config-field.component.html index 662b69ebb..2e236996e 100644 --- a/client/src/app/site/config/components/config-field/config-field.component.html +++ b/client/src/app/site/config/components/config-field/config-field.component.html @@ -1,6 +1,7 @@ -
- - + + + + @@ -8,9 +9,6 @@ - - - @@ -28,7 +26,7 @@ - + @@ -41,25 +39,27 @@ - - - - - -
- - {{ configItem.label | translate }} - -
- {{ configItem.helpText | translate }} +
+ +
+ + {{ configItem.label | translate }} + +
{{ configItem.helpText | translate }}
+
{{ error }}
+
+ + +
+

{{ configItem.label | translate }}

+ +
+
-
- {{ error }} -
-
+ diff --git a/client/src/app/site/config/components/config-field/config-field.component.ts b/client/src/app/site/config/components/config-field/config-field.component.ts index 23843964e..e14f84201 100644 --- a/client/src/app/site/config/components/config-field/config-field.component.ts +++ b/client/src/app/site/config/components/config-field/config-field.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit, Input, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core'; import { Title } from '@angular/platform-browser'; +import { distinctUntilChanged } from 'rxjs/operators'; + import { TranslateService } from '@ngx-translate/core'; + import { ViewConfig } from '../../models/view-config'; import { BaseComponent } from '../../../../base.component'; import { FormGroup, FormBuilder } from '@angular/forms'; @@ -95,9 +98,13 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit { this.form.patchValue({ value: this.configItem.value }); - this.form.valueChanges.subscribe(form => { - this.onChange(form.value); - }); + this.form.valueChanges + // The editor fires changes whenever content was changed. Even by AutoUpdate. + // This checks for discting content + .pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))) + .subscribe(form => { + this.onChange(form.value); + }); } /** @@ -156,6 +163,9 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit { /** * Uses the configItem to determine the kind of interation: * input, textarea, choice or date + * + * @param type: the type of a config item + * @returns the template type */ public formType(type: string): string { switch (type) { @@ -167,4 +177,15 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit { return 'text'; } } + + /** + * Checks of the config.type can be part of the form + * + * @param type the config.type of a setting + * @returns wheather it should be excluded or not + */ + public isExcludedType(type: string): boolean { + const excluded = ['boolean', 'markupText']; + return excluded.includes(type); + } } diff --git a/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.html b/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.html index 0212d07fb..e0ca24878 100644 --- a/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.html +++ b/client/src/app/site/motions/components/motion-change-recommendation/motion-change-recommendation.component.html @@ -7,9 +7,12 @@ {{ radio.title }} - - - + +

Change recommendation Text

+ {{ 'Public' | translate }} diff --git a/client/src/app/site/motions/components/motion-comments/motion-comments.component.html b/client/src/app/site/motions/components/motion-comments/motion-comments.component.html index 7d16d76d5..cd98241c6 100644 --- a/client/src/app/site/motions/components/motion-comments/motion-comments.component.html +++ b/client/src/app/site/motions/components/motion-comments/motion-comments.component.html @@ -11,9 +11,12 @@
- - - + +

Comment

+
diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html index 555cff31c..558f6665e 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html @@ -316,19 +316,27 @@ [innerHTML]="getFormattedStatuteAmendment()"> - - - + + -
-
Reason
+
+
Reason
- - - + + + +
diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts index 6a1003182..d503b7833 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts @@ -23,9 +23,9 @@ import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { ViewUnifiedChange } from '../../models/view-unified-change'; import { OperatorService } from '../../../../core/services/operator.service'; import { BaseViewComponent } from '../../../base/base-view'; -import { ViewStatuteParagraph } from "../../models/view-statute-paragraph"; -import { StatuteParagraphRepositoryService } from "../../services/statute-paragraph-repository.service"; -import { ConfigService } from "../../../../core/services/config.service"; +import { ViewStatuteParagraph } from '../../models/view-statute-paragraph'; +import { StatuteParagraphRepositoryService } from '../../services/statute-paragraph-repository.service'; +import { ConfigService } from '../../../../core/services/config.service'; /** * Component for the motion detail view @@ -196,9 +196,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit { this.categoryObserver.next(DS.getAll(Category)); } }); - this.configService.get('motions_statutes_enabled').subscribe((enabled: boolean): void => { - this.statutesEnabled = enabled; - }); + this.configService.get('motions_statutes_enabled').subscribe( + (enabled: boolean): void => { + this.statutesEnabled = enabled; + } + ); } /** @@ -258,7 +260,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit { }); this.metaInfoForm.patchValue(metaInfoPatch); - const contentPatch: {[key: string]: any} = {}; + const contentPatch: { [key: string]: any } = {}; Object.keys(this.contentForm.controls).forEach(ctrl => { contentPatch[ctrl] = formMotion[ctrl]; }); diff --git a/client/src/app/site/motions/components/personal-note/personal-note.component.html b/client/src/app/site/motions/components/personal-note/personal-note.component.html index d80e4ca6e..828fa888f 100644 --- a/client/src/app/site/motions/components/personal-note/personal-note.component.html +++ b/client/src/app/site/motions/components/personal-note/personal-note.component.html @@ -11,9 +11,12 @@
- - - + +

Personal note

+
diff --git a/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.html b/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.html index 13e5bcf13..cce0858c1 100644 --- a/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.html +++ b/client/src/app/site/motions/components/statute-paragraph-list/statute-paragraph-list.component.html @@ -25,15 +25,14 @@

-

- - - - Required - - -

+ + +

Statute paragraph

+ +
@@ -64,15 +63,14 @@

-

- - - - Required - - -

+ + +

Statute paragraph

+ +
@@ -89,7 +87,7 @@