]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Set scroll position at top of the textarea when opening the subtitle editor.
authorlutangar <johan.dufour@gmail.com>
Tue, 30 Aug 2022 15:13:26 +0000 (17:13 +0200)
committerChocobozzz <chocobozzz@cpy.re>
Thu, 8 Sep 2022 06:41:36 +0000 (08:41 +0200)
## 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)

client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.html [new file with mode: 0644]
client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.scss [moved from client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.scss with 100% similarity]
client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.ts [moved from client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.ts with 70% similarity]
client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.html [deleted file]
client/src/app/+videos/+video-edit/shared/video-edit.component.html
client/src/app/+videos/+video-edit/shared/video-edit.component.ts
client/src/app/+videos/+video-edit/shared/video-edit.module.ts

diff --git a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.html b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.html
new file mode 100644 (file)
index 0000000..e8079c7
--- /dev/null
@@ -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 () {
diff --git a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.html b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.html
deleted file mode 100644 (file)
index be6f676..0000000
+++ /dev/null
@@ -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>
index de126bdf798ec4d500e78ada0060263358968191..7be5a37363cefcfe00cad9e092669d85a41068d7 100644 (file)
 
                 <div i18n class="caption-entry-state">Already uploaded on {{ videoCaption.updatedAt | date }}  &#10004;</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>
 
 
                 <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>
 
index 99f8c9034915c33cb8dcdcc49b2623da55929216..0275f66f5db0d98d02921f092fb86b5e8ff1240f 100644 (file)
@@ -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
   }
index 4e87673643936326e6dd52233b9eaa46b081e052..d463bf63334fdf23660b8893a75d04e14dfae4bd 100644 (file)
@@ -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: [