Add custom modal to plugin helpers (#2631)
* Add custom modal component * Add custom modal to app and plugins helpers * Fixes custom modal component * Add doc for custom modal * Fix newline end of file html and scss files * Move my-custom-modal component outside component for UserLoggedIn modals * Move initializeCustomModal to ngAfterViewInit() * Wrap events and conditionnals * Replace ng-show with ngIf* * Add modalRef to open only one modal + onCloseClick * Refacto + Fix access methods of custom modal * Fix methods names custom-modal.component * Fix implement AfterViewInit & no default boolean Co-authored-by: kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
parent
45c14ae1b2
commit
437e8e06eb
|
@ -54,3 +54,5 @@
|
||||||
<my-welcome-modal #welcomeModal></my-welcome-modal>
|
<my-welcome-modal #welcomeModal></my-welcome-modal>
|
||||||
<my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
|
<my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<my-custom-modal #customModal></my-custom-modal>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core'
|
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
|
||||||
import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular/router'
|
import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular/router'
|
||||||
import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core'
|
import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core'
|
||||||
|
@ -14,6 +14,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants'
|
import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants'
|
||||||
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
|
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
|
||||||
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
|
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
|
||||||
|
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
||||||
import { ServerConfig, UserRole } from '@shared/models'
|
import { ServerConfig, UserRole } from '@shared/models'
|
||||||
import { User } from '@app/shared'
|
import { User } from '@app/shared'
|
||||||
import { InstanceService } from '@app/shared/instance/instance.service'
|
import { InstanceService } from '@app/shared/instance/instance.service'
|
||||||
|
@ -24,9 +25,10 @@ import { MenuService } from './core/menu/menu.service'
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: [ './app.component.scss' ]
|
styleUrls: [ './app.component.scss' ]
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit, AfterViewInit {
|
||||||
@ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
|
@ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
|
||||||
@ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
|
@ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
|
||||||
|
@ViewChild('customModal') customModal: CustomModalComponent
|
||||||
|
|
||||||
customCSS: SafeHtml
|
customCSS: SafeHtml
|
||||||
|
|
||||||
|
@ -87,6 +89,10 @@ export class AppComponent implements OnInit {
|
||||||
this.openModalsIfNeeded()
|
this.openModalsIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit () {
|
||||||
|
this.pluginService.initializeCustomModal(this.customModal)
|
||||||
|
}
|
||||||
|
|
||||||
isUserLoggedIn () {
|
isUserLoggedIn () {
|
||||||
return this.authService.isLoggedIn()
|
return this.authService.isLoggedIn()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-
|
||||||
import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '@shared/models'
|
import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '@shared/models'
|
||||||
import { APP_BASE_HREF } from '@angular/common'
|
import { APP_BASE_HREF } from '@angular/common'
|
||||||
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
|
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
|
||||||
|
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
||||||
|
|
||||||
export function metaFactory (serverService: ServerService): MetaLoader {
|
export function metaFactory (serverService: ServerService): MetaLoader {
|
||||||
return new MetaStaticLoader({
|
return new MetaStaticLoader({
|
||||||
|
@ -47,6 +48,7 @@ export function metaFactory (serverService: ServerService): MetaLoader {
|
||||||
SuggestionsComponent,
|
SuggestionsComponent,
|
||||||
SuggestionComponent,
|
SuggestionComponent,
|
||||||
|
|
||||||
|
CustomModalComponent,
|
||||||
WelcomeModalComponent,
|
WelcomeModalComponent,
|
||||||
InstanceConfigWarningModalComponent
|
InstanceConfigWarningModalComponent
|
||||||
],
|
],
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
|
||||||
import { RegisterClientHelpers } from '../../../types/register-client-option.model'
|
import { RegisterClientHelpers } from '../../../types/register-client-option.model'
|
||||||
import { PluginTranslation } from '@shared/models/plugins/plugin-translation.model'
|
import { PluginTranslation } from '@shared/models/plugins/plugin-translation.model'
|
||||||
import { importModule } from '@app/shared/misc/utils'
|
import { importModule } from '@app/shared/misc/utils'
|
||||||
|
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
||||||
|
|
||||||
interface HookStructValue extends RegisterClientHookOptions {
|
interface HookStructValue extends RegisterClientHookOptions {
|
||||||
plugin: ServerConfigPlugin
|
plugin: ServerConfigPlugin
|
||||||
|
@ -49,6 +50,8 @@ export class PluginService implements ClientHook {
|
||||||
|
|
||||||
translationsObservable: Observable<PluginTranslation>
|
translationsObservable: Observable<PluginTranslation>
|
||||||
|
|
||||||
|
customModal: CustomModalComponent
|
||||||
|
|
||||||
private plugins: ServerConfigPlugin[] = []
|
private plugins: ServerConfigPlugin[] = []
|
||||||
private scopes: { [ scopeName: string ]: PluginInfo[] } = {}
|
private scopes: { [ scopeName: string ]: PluginInfo[] } = {}
|
||||||
private loadedScripts: { [ script: string ]: boolean } = {}
|
private loadedScripts: { [ script: string ]: boolean } = {}
|
||||||
|
@ -81,6 +84,10 @@ export class PluginService implements ClientHook {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeCustomModal (customModal: CustomModalComponent) {
|
||||||
|
this.customModal = customModal
|
||||||
|
}
|
||||||
|
|
||||||
ensurePluginsAreBuilt () {
|
ensurePluginsAreBuilt () {
|
||||||
return this.pluginsBuilt.asObservable()
|
return this.pluginsBuilt.asObservable()
|
||||||
.pipe(first(), shareReplay())
|
.pipe(first(), shareReplay())
|
||||||
|
@ -279,6 +286,16 @@ export class PluginService implements ClientHook {
|
||||||
success: (text: string, title?: string, timeout?: number) => this.notifier.success(text, title, timeout)
|
success: (text: string, title?: string, timeout?: number) => this.notifier.success(text, title, timeout)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showModal: (input: {
|
||||||
|
title: string,
|
||||||
|
content: string,
|
||||||
|
close?: boolean,
|
||||||
|
cancel?: { value: string, action?: () => void },
|
||||||
|
confirm?: { value: string, action?: () => void }
|
||||||
|
}) => {
|
||||||
|
this.customModal.show(input)
|
||||||
|
},
|
||||||
|
|
||||||
translate: (value: string) => {
|
translate: (value: string) => {
|
||||||
return this.translationsObservable
|
return this.translationsObservable
|
||||||
.pipe(map(allTranslations => allTranslations[npmName]))
|
.pipe(map(allTranslations => allTranslations[npmName]))
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<ng-template #modal let-hide="close">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">{{title}}</h4>
|
||||||
|
<my-global-icon *ngIf="close" iconName="cross" aria-label="Close" role="button" (click)="onCloseClick()"></my-global-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body" [innerHTML]="content"></div>
|
||||||
|
|
||||||
|
<div *ngIf="hasCancel() || hasConfirm()" class="modal-footer inputs">
|
||||||
|
<input
|
||||||
|
*ngIf="hasCancel()" type="button" role="button" value="{{cancel.value}}" class="action-button action-button-cancel"
|
||||||
|
(click)="onCancelClick()" (key.enter)="onCancelClick()"
|
||||||
|
>
|
||||||
|
|
||||||
|
<input
|
||||||
|
*ngIf="hasConfirm()" type="button" role="button" value="{{confirm.value}}" class="action-button action-button-confirm"
|
||||||
|
(click)="onConfirmClick()" (key.enter)="onConfirmClick()"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
|
@ -0,0 +1,20 @@
|
||||||
|
@import '_mixins';
|
||||||
|
@import '_variables';
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button-cancel {
|
||||||
|
@include peertube-button;
|
||||||
|
@include grey-button;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button-confirm {
|
||||||
|
@include peertube-button;
|
||||||
|
@include orange-button;
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
import { Component, ElementRef, ViewChild, Input } from '@angular/core'
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-custom-modal',
|
||||||
|
templateUrl: './custom-modal.component.html',
|
||||||
|
styleUrls: [ './custom-modal.component.scss' ]
|
||||||
|
})
|
||||||
|
export class CustomModalComponent {
|
||||||
|
@ViewChild('modal', { static: true }) modal: ElementRef
|
||||||
|
|
||||||
|
@Input() title: string
|
||||||
|
@Input() content: string
|
||||||
|
@Input() close?: boolean
|
||||||
|
@Input() cancel?: { value: string, action?: () => void }
|
||||||
|
@Input() confirm?: { value: string, action?: () => void }
|
||||||
|
|
||||||
|
private modalRef: NgbModalRef
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private modalService: NgbModal
|
||||||
|
) { }
|
||||||
|
|
||||||
|
show (input: {
|
||||||
|
title: string,
|
||||||
|
content: string,
|
||||||
|
close?: boolean,
|
||||||
|
cancel?: { value: string, action?: () => void },
|
||||||
|
confirm?: { value: string, action?: () => void }
|
||||||
|
}) {
|
||||||
|
if (this.modalRef instanceof NgbModalRef && this.modalService.hasOpenModals()) {
|
||||||
|
console.error('Cannot open another custom modal, one is already opened.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title, content, close, cancel, confirm } = input
|
||||||
|
|
||||||
|
this.title = title
|
||||||
|
this.content = content
|
||||||
|
this.close = close
|
||||||
|
this.cancel = cancel
|
||||||
|
this.confirm = confirm
|
||||||
|
|
||||||
|
this.modalRef = this.modalService.open(this.modal, {
|
||||||
|
centered: true,
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false,
|
||||||
|
size: 'lg'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick () {
|
||||||
|
this.modalRef.close()
|
||||||
|
|
||||||
|
if (typeof this.cancel.action === 'function') {
|
||||||
|
this.cancel.action()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseClick () {
|
||||||
|
this.modalRef.close()
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
onConfirmClick () {
|
||||||
|
this.modalRef.close()
|
||||||
|
|
||||||
|
if (typeof this.confirm.action === 'function') {
|
||||||
|
this.confirm.action()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCancel () {
|
||||||
|
return typeof this.cancel !== 'undefined'
|
||||||
|
}
|
||||||
|
|
||||||
|
hasConfirm () {
|
||||||
|
return typeof this.confirm !== 'undefined'
|
||||||
|
}
|
||||||
|
|
||||||
|
private destroy () {
|
||||||
|
delete this.modalRef
|
||||||
|
delete this.title
|
||||||
|
delete this.content
|
||||||
|
delete this.close
|
||||||
|
delete this.cancel
|
||||||
|
delete this.confirm
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,5 +19,13 @@ export type RegisterClientHelpers = {
|
||||||
success: (text: string, title?: string, timeout?: number) => void
|
success: (text: string, title?: string, timeout?: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showModal: (input: {
|
||||||
|
title: string,
|
||||||
|
content: string,
|
||||||
|
close?: boolean,
|
||||||
|
cancel?: { value: string, action?: () => void },
|
||||||
|
confirm?: { value: string, action?: () => void }
|
||||||
|
}) => void
|
||||||
|
|
||||||
translate: (toTranslate: string) => Promise<string>
|
translate: (toTranslate: string) => Promise<string>
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,24 @@ notifier.success('Success message content.')
|
||||||
notifier.error('Error message content.')
|
notifier.error('Error message content.')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Custom Modal
|
||||||
|
|
||||||
|
To show a custom modal:
|
||||||
|
|
||||||
|
```js
|
||||||
|
peertubeHelpers.showModal({
|
||||||
|
title: 'My custom modal title',
|
||||||
|
content: '<p>My custom modal content</p>',
|
||||||
|
// Optionals parameters :
|
||||||
|
// show close icon
|
||||||
|
close: true,
|
||||||
|
// show cancel button and call action() after hiding modal
|
||||||
|
cancel: { value: 'cancel', action: () => {} },
|
||||||
|
// show confirm button and call action() after hiding modal
|
||||||
|
confirm: { value: 'confirm', action: () => {} },
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
#### Translate
|
#### Translate
|
||||||
|
|
||||||
You can translate some strings of your plugin (PeerTube will use your `translations` object of your `package.json` file):
|
You can translate some strings of your plugin (PeerTube will use your `translations` object of your `package.json` file):
|
||||||
|
|
Loading…
Reference in New Issue