Set scroll position at top of the textarea when opening the subtitle editor.
## Description This set the position of the scrollbar at the top of the textarea when opening the __subtitle editor__. Previously the textarea scroll position was at the bottom of the textarea which doesn't make much sense when you want to edit a subtitle : you most likely want to edit the beginning of the subtitle first. This also set the caret position on the first character. ## Design decision I had to use a *component approach* instead of an `<ng-template>` for the edition modal because the `@viewChild` directive doesn't work for elements __inside__ an `<ng-template>`. I needed the `viewChild` directive to get an `ElementRef` of the `textarea`. > See the following issue and its workaround : > - https://github.com/valor-software/ngx-bootstrap/issues/3825 > - https://stackblitz.com/edit/angular-t5dfp7 > - https://medium.com/@izzatnadiri/how-to-pass-data-to-and-receive-from-ng-bootstrap-modals-916f2ad5d66e ## Related issues Closes [peertube-plugin-transcription/#39](https://gitlab.com/apps_education/peertube/plugin-transcription/-/issues/39)
This commit is contained in:
parent
5f016383a4
commit
2873a53efd
7 changed files with 65 additions and 58 deletions
|
@ -0,0 +1,34 @@
|
|||
<ng-container [formGroup]="form">
|
||||
<div class="modal-header">
|
||||
<h4 i18n class="modal-title">Edit caption</h4>
|
||||
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<label i18n for="captionFileContent">Caption</label>
|
||||
<textarea
|
||||
id="captionFileContent"
|
||||
formControlName="captionFileContent"
|
||||
class="form-control caption-textarea"
|
||||
[ngClass]="{ 'input-error': formErrors['captionFileContent'] }"
|
||||
#textarea
|
||||
>
|
||||
</textarea>
|
||||
|
||||
<div *ngIf="formErrors.captionFileContent" class="form-error">
|
||||
{{ formErrors.captionFileContent }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer inputs">
|
||||
<input
|
||||
type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button"
|
||||
(click)="cancel()" (key.enter)="cancel()"
|
||||
>
|
||||
|
||||
<input
|
||||
type="submit" i18n-value value="Edit this caption" class="peertube-button orange-button"
|
||||
[disabled]="!form.valid" (click)="updateCaption()"
|
||||
>
|
||||
</div>
|
||||
</ng-container>
|
|
@ -2,28 +2,33 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild }
|
|||
import { VIDEO_CAPTION_FILE_CONTENT_VALIDATOR } from '@app/shared/form-validators/video-captions-validators'
|
||||
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { VideoCaptionEdit, VideoCaptionService, VideoCaptionWithPathEdit } from '@app/shared/shared-main'
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { HTMLServerConfig, VideoConstant } from '@shared/models'
|
||||
import { ServerService } from '../../../../core'
|
||||
|
||||
/**
|
||||
* https://github.com/valor-software/ngx-bootstrap/issues/3825
|
||||
* https://stackblitz.com/edit/angular-t5dfp7
|
||||
* https://medium.com/@izzatnadiri/how-to-pass-data-to-and-receive-from-ng-bootstrap-modals-916f2ad5d66e
|
||||
*/
|
||||
@Component({
|
||||
selector: 'my-video-caption-edit-modal',
|
||||
styleUrls: [ './video-caption-edit-modal.component.scss' ],
|
||||
templateUrl: './video-caption-edit-modal.component.html'
|
||||
selector: 'my-video-caption-edit-modal-content',
|
||||
styleUrls: [ './video-caption-edit-modal-content.component.scss' ],
|
||||
templateUrl: './video-caption-edit-modal-content.component.html'
|
||||
})
|
||||
|
||||
export class VideoCaptionEditModalComponent extends FormReactive implements OnInit {
|
||||
export class VideoCaptionEditModalContentComponent extends FormReactive implements OnInit {
|
||||
@Input() videoCaption: VideoCaptionWithPathEdit
|
||||
@Input() serverConfig: HTMLServerConfig
|
||||
|
||||
@Output() captionEdited = new EventEmitter<VideoCaptionEdit>()
|
||||
|
||||
@ViewChild('modal', { static: true }) modal: ElementRef
|
||||
@ViewChild('textarea', { static: true }) textarea!: ElementRef
|
||||
|
||||
videoCaptionLanguages: VideoConstant<string>[] = []
|
||||
private openedModal: NgbModalRef
|
||||
|
||||
constructor (
|
||||
protected openedModal: NgbActiveModal,
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private modalService: NgbModal,
|
||||
private videoCaptionService: VideoCaptionService,
|
||||
|
@ -49,11 +54,14 @@ export class VideoCaptionEditModalComponent extends FormReactive implements OnIn
|
|||
this.form.patchValue({
|
||||
captionFileContent: res
|
||||
})
|
||||
this.resetTextarea()
|
||||
})
|
||||
}
|
||||
|
||||
show () {
|
||||
this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false })
|
||||
resetTextarea () {
|
||||
this.textarea.nativeElement.scrollTop = 0
|
||||
this.textarea.nativeElement.selectionStart = 0
|
||||
this.textarea.nativeElement.selectionEnd = 0
|
||||
}
|
||||
|
||||
hide () {
|
|
@ -1,36 +0,0 @@
|
|||
<ng-template #modal>
|
||||
<ng-container [formGroup]="form">
|
||||
|
||||
<div class="modal-header">
|
||||
<h4 i18n class="modal-title">Edit caption</h4>
|
||||
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<label i18n for="captionFileContent">Caption</label>
|
||||
<textarea
|
||||
id="captionFileContent"
|
||||
formControlName="captionFileContent"
|
||||
class="form-control caption-textarea"
|
||||
[ngClass]="{ 'input-error': formErrors['captionFileContent'] }"
|
||||
>
|
||||
</textarea>
|
||||
|
||||
<div *ngIf="formErrors.captionFileContent" class="form-error">
|
||||
{{ formErrors.captionFileContent }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer inputs">
|
||||
<input
|
||||
type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button"
|
||||
(click)="cancel()" (key.enter)="cancel()"
|
||||
>
|
||||
|
||||
<input
|
||||
type="submit" i18n-value value="Edit this caption" class="peertube-button orange-button"
|
||||
[disabled]="!form.valid" (click)="updateCaption()"
|
||||
>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
|
@ -185,7 +185,7 @@
|
|||
|
||||
<div i18n class="caption-entry-state">Already uploaded on {{ videoCaption.updatedAt | date }} ✔</div>
|
||||
|
||||
<span i18n class="caption-entry-edit" (click)="videoCaptionEditModal.show()">Edit</span>
|
||||
<span i18n class="caption-entry-edit" (click)="openEditCaptionModal(videoCaption)">Edit</span>
|
||||
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
|
||||
</ng-container>
|
||||
|
||||
|
@ -212,13 +212,6 @@
|
|||
|
||||
<span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span>
|
||||
</ng-container>
|
||||
|
||||
<my-video-caption-edit-modal
|
||||
#videoCaptionEditModal
|
||||
[videoCaption]="videoCaption"
|
||||
[serverConfig]="serverConfig"
|
||||
(captionEdited)="onCaptionEdited($event)"
|
||||
></my-video-caption-edit-modal>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -35,10 +35,11 @@ import {
|
|||
} from '@shared/models'
|
||||
import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
|
||||
import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
|
||||
import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component'
|
||||
import { VideoCaptionEditModalContentComponent } from './video-caption-edit-modal-content/video-caption-edit-modal-content.component'
|
||||
import { VideoEditType } from './video-edit.type'
|
||||
import { VideoSource } from '@shared/models/videos/video-source'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
type VideoLanguages = VideoConstant<string> & { group?: string }
|
||||
type PluginField = {
|
||||
|
@ -70,7 +71,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
@Input() liveVideo: LiveVideo
|
||||
|
||||
@ViewChild('videoCaptionAddModal', { static: true }) videoCaptionAddModal: VideoCaptionAddModalComponent
|
||||
@ViewChild('videoCaptionEditModal', { static: true }) editCaptionModal: VideoCaptionEditModalComponent
|
||||
|
||||
@Output() formBuilt = new EventEmitter<void>()
|
||||
@Output() pluginFieldsAdded = new EventEmitter<void>()
|
||||
|
@ -128,7 +128,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
private i18nPrimengCalendarService: I18nPrimengCalendarService,
|
||||
private ngZone: NgZone,
|
||||
private hooks: HooksService,
|
||||
private cd: ChangeDetectorRef
|
||||
private cd: ChangeDetectorRef,
|
||||
private modalService: NgbModal
|
||||
) {
|
||||
this.calendarTimezone = this.i18nPrimengCalendarService.getTimezone()
|
||||
this.calendarDateFormat = this.i18nPrimengCalendarService.getDateFormat()
|
||||
|
@ -286,6 +287,13 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
this.videoCaptionAddModal.show()
|
||||
}
|
||||
|
||||
openEditCaptionModal (videoCaption: VideoCaptionWithPathEdit) {
|
||||
const modalRef = this.modalService.open(VideoCaptionEditModalContentComponent, { centered: true, keyboard: false })
|
||||
modalRef.componentInstance.videoCaption = videoCaption
|
||||
modalRef.componentInstance.serverConfig = this.serverConfig
|
||||
modalRef.componentInstance.captionEdited.subscribe(this.onCaptionEdited.bind(this))
|
||||
}
|
||||
|
||||
isSaveReplayEnabled () {
|
||||
return this.serverConfig.live.allowReplay
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { SharedMainModule } from '@app/shared/shared-main'
|
|||
import { SharedVideoLiveModule } from '@app/shared/shared-video-live'
|
||||
import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
|
||||
import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
|
||||
import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component'
|
||||
import { VideoCaptionEditModalContentComponent } from './video-caption-edit-modal-content/video-caption-edit-modal-content.component'
|
||||
import { VideoEditComponent } from './video-edit.component'
|
||||
|
||||
@NgModule({
|
||||
|
@ -22,7 +22,7 @@ import { VideoEditComponent } from './video-edit.component'
|
|||
declarations: [
|
||||
VideoEditComponent,
|
||||
VideoCaptionAddModalComponent,
|
||||
VideoCaptionEditModalComponent
|
||||
VideoCaptionEditModalContentComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
|
Loading…
Reference in a new issue