aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/app.component.html2
-rw-r--r--client/src/app/app.component.ts10
-rw-r--r--client/src/app/app.module.ts2
-rw-r--r--client/src/app/core/plugins/plugin.service.ts17
-rw-r--r--client/src/app/modal/custom-modal.component.html20
-rw-r--r--client/src/app/modal/custom-modal.component.scss20
-rw-r--r--client/src/app/modal/custom-modal.component.ts93
-rw-r--r--client/src/types/register-client-option.model.ts8
-rw-r--r--support/doc/plugins/guide.md18
9 files changed, 188 insertions, 2 deletions
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index d1eb1646f..84cff4812 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -54,3 +54,5 @@
54 <my-welcome-modal #welcomeModal></my-welcome-modal> 54 <my-welcome-modal #welcomeModal></my-welcome-modal>
55 <my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal> 55 <my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
56</ng-template> 56</ng-template>
57
58<my-custom-modal #customModal></my-custom-modal>
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index 1d077646c..12c0efd8a 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -1,4 +1,4 @@
1import { Component, OnInit, ViewChild } from '@angular/core' 1import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'
2import { DomSanitizer, SafeHtml } from '@angular/platform-browser' 2import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
3import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular/router' 3import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular/router'
4import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core' 4import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core'
@@ -14,6 +14,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
14import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants' 14import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants'
15import { WelcomeModalComponent } from '@app/modal/welcome-modal.component' 15import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
16import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component' 16import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
17import { CustomModalComponent } from '@app/modal/custom-modal.component'
17import { ServerConfig, UserRole } from '@shared/models' 18import { ServerConfig, UserRole } from '@shared/models'
18import { User } from '@app/shared' 19import { User } from '@app/shared'
19import { InstanceService } from '@app/shared/instance/instance.service' 20import { InstanceService } from '@app/shared/instance/instance.service'
@@ -24,9 +25,10 @@ import { MenuService } from './core/menu/menu.service'
24 templateUrl: './app.component.html', 25 templateUrl: './app.component.html',
25 styleUrls: [ './app.component.scss' ] 26 styleUrls: [ './app.component.scss' ]
26}) 27})
27export class AppComponent implements OnInit { 28export class AppComponent implements OnInit, AfterViewInit {
28 @ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent 29 @ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
29 @ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent 30 @ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
31 @ViewChild('customModal') customModal: CustomModalComponent
30 32
31 customCSS: SafeHtml 33 customCSS: SafeHtml
32 34
@@ -87,6 +89,10 @@ export class AppComponent implements OnInit {
87 this.openModalsIfNeeded() 89 this.openModalsIfNeeded()
88 } 90 }
89 91
92 ngAfterViewInit () {
93 this.pluginService.initializeCustomModal(this.customModal)
94 }
95
90 isUserLoggedIn () { 96 isUserLoggedIn () {
91 return this.authService.isLoggedIn() 97 return this.authService.isLoggedIn()
92 } 98 }
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index ef23c9655..5a3b109da 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -20,6 +20,7 @@ import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-
20import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '@shared/models' 20import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '@shared/models'
21import { APP_BASE_HREF } from '@angular/common' 21import { APP_BASE_HREF } from '@angular/common'
22import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component' 22import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
23import { CustomModalComponent } from '@app/modal/custom-modal.component'
23 24
24export function metaFactory (serverService: ServerService): MetaLoader { 25export function metaFactory (serverService: ServerService): MetaLoader {
25 return new MetaStaticLoader({ 26 return new MetaStaticLoader({
@@ -47,6 +48,7 @@ export function metaFactory (serverService: ServerService): MetaLoader {
47 SuggestionsComponent, 48 SuggestionsComponent,
48 SuggestionComponent, 49 SuggestionComponent,
49 50
51 CustomModalComponent,
50 WelcomeModalComponent, 52 WelcomeModalComponent,
51 InstanceConfigWarningModalComponent 53 InstanceConfigWarningModalComponent
52 ], 54 ],
diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts
index aa6823060..b4ed56cbe 100644
--- a/client/src/app/core/plugins/plugin.service.ts
+++ b/client/src/app/core/plugins/plugin.service.ts
@@ -20,6 +20,7 @@ import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
20import { RegisterClientHelpers } from '../../../types/register-client-option.model' 20import { RegisterClientHelpers } from '../../../types/register-client-option.model'
21import { PluginTranslation } from '@shared/models/plugins/plugin-translation.model' 21import { PluginTranslation } from '@shared/models/plugins/plugin-translation.model'
22import { importModule } from '@app/shared/misc/utils' 22import { importModule } from '@app/shared/misc/utils'
23import { CustomModalComponent } from '@app/modal/custom-modal.component'
23 24
24interface HookStructValue extends RegisterClientHookOptions { 25interface HookStructValue extends RegisterClientHookOptions {
25 plugin: ServerConfigPlugin 26 plugin: ServerConfigPlugin
@@ -49,6 +50,8 @@ export class PluginService implements ClientHook {
49 50
50 translationsObservable: Observable<PluginTranslation> 51 translationsObservable: Observable<PluginTranslation>
51 52
53 customModal: CustomModalComponent
54
52 private plugins: ServerConfigPlugin[] = [] 55 private plugins: ServerConfigPlugin[] = []
53 private scopes: { [ scopeName: string ]: PluginInfo[] } = {} 56 private scopes: { [ scopeName: string ]: PluginInfo[] } = {}
54 private loadedScripts: { [ script: string ]: boolean } = {} 57 private loadedScripts: { [ script: string ]: boolean } = {}
@@ -81,6 +84,10 @@ export class PluginService implements ClientHook {
81 }) 84 })
82 } 85 }
83 86
87 initializeCustomModal (customModal: CustomModalComponent) {
88 this.customModal = customModal
89 }
90
84 ensurePluginsAreBuilt () { 91 ensurePluginsAreBuilt () {
85 return this.pluginsBuilt.asObservable() 92 return this.pluginsBuilt.asObservable()
86 .pipe(first(), shareReplay()) 93 .pipe(first(), shareReplay())
@@ -279,6 +286,16 @@ export class PluginService implements ClientHook {
279 success: (text: string, title?: string, timeout?: number) => this.notifier.success(text, title, timeout) 286 success: (text: string, title?: string, timeout?: number) => this.notifier.success(text, title, timeout)
280 }, 287 },
281 288
289 showModal: (input: {
290 title: string,
291 content: string,
292 close?: boolean,
293 cancel?: { value: string, action?: () => void },
294 confirm?: { value: string, action?: () => void }
295 }) => {
296 this.customModal.show(input)
297 },
298
282 translate: (value: string) => { 299 translate: (value: string) => {
283 return this.translationsObservable 300 return this.translationsObservable
284 .pipe(map(allTranslations => allTranslations[npmName])) 301 .pipe(map(allTranslations => allTranslations[npmName]))
diff --git a/client/src/app/modal/custom-modal.component.html b/client/src/app/modal/custom-modal.component.html
new file mode 100644
index 000000000..06ecc2743
--- /dev/null
+++ b/client/src/app/modal/custom-modal.component.html
@@ -0,0 +1,20 @@
1<ng-template #modal let-hide="close">
2 <div class="modal-header">
3 <h4 class="modal-title">{{title}}</h4>
4 <my-global-icon *ngIf="close" iconName="cross" aria-label="Close" role="button" (click)="onCloseClick()"></my-global-icon>
5 </div>
6
7 <div class="modal-body" [innerHTML]="content"></div>
8
9 <div *ngIf="hasCancel() || hasConfirm()" class="modal-footer inputs">
10 <input
11 *ngIf="hasCancel()" type="button" role="button" value="{{cancel.value}}" class="action-button action-button-cancel"
12 (click)="onCancelClick()" (key.enter)="onCancelClick()"
13 >
14
15 <input
16 *ngIf="hasConfirm()" type="button" role="button" value="{{confirm.value}}" class="action-button action-button-confirm"
17 (click)="onConfirmClick()" (key.enter)="onConfirmClick()"
18 >
19 </div>
20</ng-template>
diff --git a/client/src/app/modal/custom-modal.component.scss b/client/src/app/modal/custom-modal.component.scss
new file mode 100644
index 000000000..a7fa30cf5
--- /dev/null
+++ b/client/src/app/modal/custom-modal.component.scss
@@ -0,0 +1,20 @@
1@import '_mixins';
2@import '_variables';
3
4.modal-body {
5 font-size: 15px;
6}
7
8li {
9 margin-bottom: 10px;
10}
11
12.action-button-cancel {
13 @include peertube-button;
14 @include grey-button;
15}
16
17.action-button-confirm {
18 @include peertube-button;
19 @include orange-button;
20}
diff --git a/client/src/app/modal/custom-modal.component.ts b/client/src/app/modal/custom-modal.component.ts
new file mode 100644
index 000000000..a98579085
--- /dev/null
+++ b/client/src/app/modal/custom-modal.component.ts
@@ -0,0 +1,93 @@
1import { Component, ElementRef, ViewChild, Input } from '@angular/core'
2import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
3
4@Component({
5 selector: 'my-custom-modal',
6 templateUrl: './custom-modal.component.html',
7 styleUrls: [ './custom-modal.component.scss' ]
8})
9export class CustomModalComponent {
10 @ViewChild('modal', { static: true }) modal: ElementRef
11
12 @Input() title: string
13 @Input() content: string
14 @Input() close?: boolean
15 @Input() cancel?: { value: string, action?: () => void }
16 @Input() confirm?: { value: string, action?: () => void }
17
18 private modalRef: NgbModalRef
19
20 constructor (
21 private modalService: NgbModal
22 ) { }
23
24 show (input: {
25 title: string,
26 content: string,
27 close?: boolean,
28 cancel?: { value: string, action?: () => void },
29 confirm?: { value: string, action?: () => void }
30 }) {
31 if (this.modalRef instanceof NgbModalRef && this.modalService.hasOpenModals()) {
32 console.error('Cannot open another custom modal, one is already opened.')
33 return
34 }
35
36 const { title, content, close, cancel, confirm } = input
37
38 this.title = title
39 this.content = content
40 this.close = close
41 this.cancel = cancel
42 this.confirm = confirm
43
44 this.modalRef = this.modalService.open(this.modal, {
45 centered: true,
46 backdrop: 'static',
47 keyboard: false,
48 size: 'lg'
49 })
50 }
51
52 onCancelClick () {
53 this.modalRef.close()
54
55 if (typeof this.cancel.action === 'function') {
56 this.cancel.action()
57 }
58
59 this.destroy()
60 }
61
62 onCloseClick () {
63 this.modalRef.close()
64 this.destroy()
65 }
66
67 onConfirmClick () {
68 this.modalRef.close()
69
70 if (typeof this.confirm.action === 'function') {
71 this.confirm.action()
72 }
73
74 this.destroy()
75 }
76
77 hasCancel () {
78 return typeof this.cancel !== 'undefined'
79 }
80
81 hasConfirm () {
82 return typeof this.confirm !== 'undefined'
83 }
84
85 private destroy () {
86 delete this.modalRef
87 delete this.title
88 delete this.content
89 delete this.close
90 delete this.cancel
91 delete this.confirm
92 }
93}
diff --git a/client/src/types/register-client-option.model.ts b/client/src/types/register-client-option.model.ts
index b64652a0f..1c235107a 100644
--- a/client/src/types/register-client-option.model.ts
+++ b/client/src/types/register-client-option.model.ts
@@ -19,5 +19,13 @@ export type RegisterClientHelpers = {
19 success: (text: string, title?: string, timeout?: number) => void 19 success: (text: string, title?: string, timeout?: number) => void
20 } 20 }
21 21
22 showModal: (input: {
23 title: string,
24 content: string,
25 close?: boolean,
26 cancel?: { value: string, action?: () => void },
27 confirm?: { value: string, action?: () => void }
28 }) => void
29
22 translate: (toTranslate: string) => Promise<string> 30 translate: (toTranslate: string) => Promise<string>
23} 31}
diff --git a/support/doc/plugins/guide.md b/support/doc/plugins/guide.md
index 5251ce48a..e6870ce17 100644
--- a/support/doc/plugins/guide.md
+++ b/support/doc/plugins/guide.md
@@ -216,6 +216,24 @@ notifier.success('Success message content.')
216notifier.error('Error message content.') 216notifier.error('Error message content.')
217``` 217```
218 218
219#### Custom Modal
220
221To show a custom modal:
222
223```js
224 peertubeHelpers.showModal({
225 title: 'My custom modal title',
226 content: '<p>My custom modal content</p>',
227 // Optionals parameters :
228 // show close icon
229 close: true,
230 // show cancel button and call action() after hiding modal
231 cancel: { value: 'cancel', action: () => {} },
232 // show confirm button and call action() after hiding modal
233 confirm: { value: 'confirm', action: () => {} },
234 })
235```
236
219#### Translate 237#### Translate
220 238
221You can translate some strings of your plugin (PeerTube will use your `translations` object of your `package.json` file): 239You can translate some strings of your plugin (PeerTube will use your `translations` object of your `package.json` file):