diff options
author | lutangar <johan.dufour@gmail.com> | 2022-08-30 17:13:26 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2022-09-08 08:41:36 +0200 |
commit | 2873a53efd8913b6b5fbf305320f88731cd07771 (patch) | |
tree | 5063f5b38f222ce27f6923dc4bb8765f713ac4c7 /client | |
parent | 5f016383a4fabf2f296cda6d5e383719ee9d5e27 (diff) | |
download | PeerTube-2873a53efd8913b6b5fbf305320f88731cd07771.tar.gz PeerTube-2873a53efd8913b6b5fbf305320f88731cd07771.tar.zst PeerTube-2873a53efd8913b6b5fbf305320f88731cd07771.zip |
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)
Diffstat (limited to 'client')
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.html | 34 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.scss (renamed from client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.scss) | 0 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.ts (renamed from client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.ts) | 26 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.html | 36 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-edit.component.html | 9 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-edit.component.ts | 14 | ||||
-rw-r--r-- | client/src/app/+videos/+video-edit/shared/video-edit.module.ts | 4 |
7 files changed, 65 insertions, 58 deletions
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 index 000000000..e8079c74e --- /dev/null +++ b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.html | |||
@@ -0,0 +1,34 @@ | |||
1 | <ng-container [formGroup]="form"> | ||
2 | <div class="modal-header"> | ||
3 | <h4 i18n class="modal-title">Edit caption</h4> | ||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
5 | </div> | ||
6 | |||
7 | <div class="modal-body"> | ||
8 | <label i18n for="captionFileContent">Caption</label> | ||
9 | <textarea | ||
10 | id="captionFileContent" | ||
11 | formControlName="captionFileContent" | ||
12 | class="form-control caption-textarea" | ||
13 | [ngClass]="{ 'input-error': formErrors['captionFileContent'] }" | ||
14 | #textarea | ||
15 | > | ||
16 | </textarea> | ||
17 | |||
18 | <div *ngIf="formErrors.captionFileContent" class="form-error"> | ||
19 | {{ formErrors.captionFileContent }} | ||
20 | </div> | ||
21 | </div> | ||
22 | |||
23 | <div class="modal-footer inputs"> | ||
24 | <input | ||
25 | type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button" | ||
26 | (click)="cancel()" (key.enter)="cancel()" | ||
27 | > | ||
28 | |||
29 | <input | ||
30 | type="submit" i18n-value value="Edit this caption" class="peertube-button orange-button" | ||
31 | [disabled]="!form.valid" (click)="updateCaption()" | ||
32 | > | ||
33 | </div> | ||
34 | </ng-container> | ||
diff --git a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.scss b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.scss index bd96f2b7a..bd96f2b7a 100644 --- a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.scss +++ b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.scss | |||
diff --git a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.ts b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.ts index f74f3c5ea..f33353d36 100644 --- a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.ts +++ b/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal-content/video-caption-edit-modal-content.component.ts | |||
@@ -2,28 +2,33 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } | |||
2 | import { VIDEO_CAPTION_FILE_CONTENT_VALIDATOR } from '@app/shared/form-validators/video-captions-validators' | 2 | import { VIDEO_CAPTION_FILE_CONTENT_VALIDATOR } from '@app/shared/form-validators/video-captions-validators' |
3 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 3 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' |
4 | import { VideoCaptionEdit, VideoCaptionService, VideoCaptionWithPathEdit } from '@app/shared/shared-main' | 4 | import { VideoCaptionEdit, VideoCaptionService, VideoCaptionWithPathEdit } from '@app/shared/shared-main' |
5 | import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' | 5 | import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' |
6 | import { HTMLServerConfig, VideoConstant } from '@shared/models' | 6 | import { HTMLServerConfig, VideoConstant } from '@shared/models' |
7 | import { ServerService } from '../../../../core' | 7 | import { ServerService } from '../../../../core' |
8 | 8 | ||
9 | /** | ||
10 | * https://github.com/valor-software/ngx-bootstrap/issues/3825 | ||
11 | * https://stackblitz.com/edit/angular-t5dfp7 | ||
12 | * https://medium.com/@izzatnadiri/how-to-pass-data-to-and-receive-from-ng-bootstrap-modals-916f2ad5d66e | ||
13 | */ | ||
9 | @Component({ | 14 | @Component({ |
10 | selector: 'my-video-caption-edit-modal', | 15 | selector: 'my-video-caption-edit-modal-content', |
11 | styleUrls: [ './video-caption-edit-modal.component.scss' ], | 16 | styleUrls: [ './video-caption-edit-modal-content.component.scss' ], |
12 | templateUrl: './video-caption-edit-modal.component.html' | 17 | templateUrl: './video-caption-edit-modal-content.component.html' |
13 | }) | 18 | }) |
14 | 19 | ||
15 | export class VideoCaptionEditModalComponent extends FormReactive implements OnInit { | 20 | export class VideoCaptionEditModalContentComponent extends FormReactive implements OnInit { |
16 | @Input() videoCaption: VideoCaptionWithPathEdit | 21 | @Input() videoCaption: VideoCaptionWithPathEdit |
17 | @Input() serverConfig: HTMLServerConfig | 22 | @Input() serverConfig: HTMLServerConfig |
18 | 23 | ||
19 | @Output() captionEdited = new EventEmitter<VideoCaptionEdit>() | 24 | @Output() captionEdited = new EventEmitter<VideoCaptionEdit>() |
20 | 25 | ||
21 | @ViewChild('modal', { static: true }) modal: ElementRef | 26 | @ViewChild('textarea', { static: true }) textarea!: ElementRef |
22 | 27 | ||
23 | videoCaptionLanguages: VideoConstant<string>[] = [] | 28 | videoCaptionLanguages: VideoConstant<string>[] = [] |
24 | private openedModal: NgbModalRef | ||
25 | 29 | ||
26 | constructor ( | 30 | constructor ( |
31 | protected openedModal: NgbActiveModal, | ||
27 | protected formValidatorService: FormValidatorService, | 32 | protected formValidatorService: FormValidatorService, |
28 | private modalService: NgbModal, | 33 | private modalService: NgbModal, |
29 | private videoCaptionService: VideoCaptionService, | 34 | private videoCaptionService: VideoCaptionService, |
@@ -49,11 +54,14 @@ export class VideoCaptionEditModalComponent extends FormReactive implements OnIn | |||
49 | this.form.patchValue({ | 54 | this.form.patchValue({ |
50 | captionFileContent: res | 55 | captionFileContent: res |
51 | }) | 56 | }) |
57 | this.resetTextarea() | ||
52 | }) | 58 | }) |
53 | } | 59 | } |
54 | 60 | ||
55 | show () { | 61 | resetTextarea () { |
56 | this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false }) | 62 | this.textarea.nativeElement.scrollTop = 0 |
63 | this.textarea.nativeElement.selectionStart = 0 | ||
64 | this.textarea.nativeElement.selectionEnd = 0 | ||
57 | } | 65 | } |
58 | 66 | ||
59 | hide () { | 67 | 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 index be6f676c2..000000000 --- a/client/src/app/+videos/+video-edit/shared/video-caption-edit-modal/video-caption-edit-modal.component.html +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | <ng-template #modal> | ||
2 | <ng-container [formGroup]="form"> | ||
3 | |||
4 | <div class="modal-header"> | ||
5 | <h4 i18n class="modal-title">Edit caption</h4> | ||
6 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
7 | </div> | ||
8 | |||
9 | <div class="modal-body"> | ||
10 | <label i18n for="captionFileContent">Caption</label> | ||
11 | <textarea | ||
12 | id="captionFileContent" | ||
13 | formControlName="captionFileContent" | ||
14 | class="form-control caption-textarea" | ||
15 | [ngClass]="{ 'input-error': formErrors['captionFileContent'] }" | ||
16 | > | ||
17 | </textarea> | ||
18 | |||
19 | <div *ngIf="formErrors.captionFileContent" class="form-error"> | ||
20 | {{ formErrors.captionFileContent }} | ||
21 | </div> | ||
22 | </div> | ||
23 | |||
24 | <div class="modal-footer inputs"> | ||
25 | <input | ||
26 | type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button" | ||
27 | (click)="cancel()" (key.enter)="cancel()" | ||
28 | > | ||
29 | |||
30 | <input | ||
31 | type="submit" i18n-value value="Edit this caption" class="peertube-button orange-button" | ||
32 | [disabled]="!form.valid" (click)="updateCaption()" | ||
33 | > | ||
34 | </div> | ||
35 | </ng-container> | ||
36 | </ng-template> | ||
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.html b/client/src/app/+videos/+video-edit/shared/video-edit.component.html index de126bdf7..7be5a3736 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.html | |||
@@ -185,7 +185,7 @@ | |||
185 | 185 | ||
186 | <div i18n class="caption-entry-state">Already uploaded on {{ videoCaption.updatedAt | date }} ✔</div> | 186 | <div i18n class="caption-entry-state">Already uploaded on {{ videoCaption.updatedAt | date }} ✔</div> |
187 | 187 | ||
188 | <span i18n class="caption-entry-edit" (click)="videoCaptionEditModal.show()">Edit</span> | 188 | <span i18n class="caption-entry-edit" (click)="openEditCaptionModal(videoCaption)">Edit</span> |
189 | <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span> | 189 | <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span> |
190 | </ng-container> | 190 | </ng-container> |
191 | 191 | ||
@@ -212,13 +212,6 @@ | |||
212 | 212 | ||
213 | <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span> | 213 | <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span> |
214 | </ng-container> | 214 | </ng-container> |
215 | |||
216 | <my-video-caption-edit-modal | ||
217 | #videoCaptionEditModal | ||
218 | [videoCaption]="videoCaption" | ||
219 | [serverConfig]="serverConfig" | ||
220 | (captionEdited)="onCaptionEdited($event)" | ||
221 | ></my-video-caption-edit-modal> | ||
222 | </div> | 215 | </div> |
223 | </div> | 216 | </div> |
224 | 217 | ||
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.ts b/client/src/app/+videos/+video-edit/shared/video-edit.component.ts index 99f8c9034..0275f66f5 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.component.ts +++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.ts | |||
@@ -35,10 +35,11 @@ import { | |||
35 | } from '@shared/models' | 35 | } from '@shared/models' |
36 | import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' | 36 | import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' |
37 | import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' | 37 | import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' |
38 | import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component' | 38 | import { VideoCaptionEditModalContentComponent } from './video-caption-edit-modal-content/video-caption-edit-modal-content.component' |
39 | import { VideoEditType } from './video-edit.type' | 39 | import { VideoEditType } from './video-edit.type' |
40 | import { VideoSource } from '@shared/models/videos/video-source' | 40 | import { VideoSource } from '@shared/models/videos/video-source' |
41 | import { logger } from '@root-helpers/logger' | 41 | import { logger } from '@root-helpers/logger' |
42 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
42 | 43 | ||
43 | type VideoLanguages = VideoConstant<string> & { group?: string } | 44 | type VideoLanguages = VideoConstant<string> & { group?: string } |
44 | type PluginField = { | 45 | type PluginField = { |
@@ -70,7 +71,6 @@ export class VideoEditComponent implements OnInit, OnDestroy { | |||
70 | @Input() liveVideo: LiveVideo | 71 | @Input() liveVideo: LiveVideo |
71 | 72 | ||
72 | @ViewChild('videoCaptionAddModal', { static: true }) videoCaptionAddModal: VideoCaptionAddModalComponent | 73 | @ViewChild('videoCaptionAddModal', { static: true }) videoCaptionAddModal: VideoCaptionAddModalComponent |
73 | @ViewChild('videoCaptionEditModal', { static: true }) editCaptionModal: VideoCaptionEditModalComponent | ||
74 | 74 | ||
75 | @Output() formBuilt = new EventEmitter<void>() | 75 | @Output() formBuilt = new EventEmitter<void>() |
76 | @Output() pluginFieldsAdded = new EventEmitter<void>() | 76 | @Output() pluginFieldsAdded = new EventEmitter<void>() |
@@ -128,7 +128,8 @@ export class VideoEditComponent implements OnInit, OnDestroy { | |||
128 | private i18nPrimengCalendarService: I18nPrimengCalendarService, | 128 | private i18nPrimengCalendarService: I18nPrimengCalendarService, |
129 | private ngZone: NgZone, | 129 | private ngZone: NgZone, |
130 | private hooks: HooksService, | 130 | private hooks: HooksService, |
131 | private cd: ChangeDetectorRef | 131 | private cd: ChangeDetectorRef, |
132 | private modalService: NgbModal | ||
132 | ) { | 133 | ) { |
133 | this.calendarTimezone = this.i18nPrimengCalendarService.getTimezone() | 134 | this.calendarTimezone = this.i18nPrimengCalendarService.getTimezone() |
134 | this.calendarDateFormat = this.i18nPrimengCalendarService.getDateFormat() | 135 | this.calendarDateFormat = this.i18nPrimengCalendarService.getDateFormat() |
@@ -286,6 +287,13 @@ export class VideoEditComponent implements OnInit, OnDestroy { | |||
286 | this.videoCaptionAddModal.show() | 287 | this.videoCaptionAddModal.show() |
287 | } | 288 | } |
288 | 289 | ||
290 | openEditCaptionModal (videoCaption: VideoCaptionWithPathEdit) { | ||
291 | const modalRef = this.modalService.open(VideoCaptionEditModalContentComponent, { centered: true, keyboard: false }) | ||
292 | modalRef.componentInstance.videoCaption = videoCaption | ||
293 | modalRef.componentInstance.serverConfig = this.serverConfig | ||
294 | modalRef.componentInstance.captionEdited.subscribe(this.onCaptionEdited.bind(this)) | ||
295 | } | ||
296 | |||
289 | isSaveReplayEnabled () { | 297 | isSaveReplayEnabled () { |
290 | return this.serverConfig.live.allowReplay | 298 | return this.serverConfig.live.allowReplay |
291 | } | 299 | } |
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.module.ts b/client/src/app/+videos/+video-edit/shared/video-edit.module.ts index 4e8767364..d463bf633 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.module.ts +++ b/client/src/app/+videos/+video-edit/shared/video-edit.module.ts | |||
@@ -6,7 +6,7 @@ import { SharedMainModule } from '@app/shared/shared-main' | |||
6 | import { SharedVideoLiveModule } from '@app/shared/shared-video-live' | 6 | import { SharedVideoLiveModule } from '@app/shared/shared-video-live' |
7 | import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' | 7 | import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' |
8 | import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' | 8 | import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' |
9 | import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component' | 9 | import { VideoCaptionEditModalContentComponent } from './video-caption-edit-modal-content/video-caption-edit-modal-content.component' |
10 | import { VideoEditComponent } from './video-edit.component' | 10 | import { VideoEditComponent } from './video-edit.component' |
11 | 11 | ||
12 | @NgModule({ | 12 | @NgModule({ |
@@ -22,7 +22,7 @@ import { VideoEditComponent } from './video-edit.component' | |||
22 | declarations: [ | 22 | declarations: [ |
23 | VideoEditComponent, | 23 | VideoEditComponent, |
24 | VideoCaptionAddModalComponent, | 24 | VideoCaptionAddModalComponent, |
25 | VideoCaptionEditModalComponent | 25 | VideoCaptionEditModalContentComponent |
26 | ], | 26 | ], |
27 | 27 | ||
28 | exports: [ | 28 | exports: [ |