export abstract class FormReactive {
protected abstract formValidatorService: FormValidatorService
+ protected formChanged = false
form: FormGroup
formErrors: FormReactiveErrors
this.formErrors[ field ] = ''
const control = this.form.get(field)
+ if (control.dirty) this.formChanged = true
+
// Don't care if dirty on force check
const isDirty = control.dirty || forceCheck === true
if (control && isDirty && !control.valid) {
<input
type="file"
[name]="inputName" [id]="inputName" [accept]="extensions"
- (change)="fileChange($event)"
+ (change)="fileChange($event)" [(ngModel)]="fileInputValue"
/>
</div>
@Output() fileChanged = new EventEmitter<Blob>()
allowedExtensionsMessage = ''
+ fileInputValue: any
private file: File
writeValue (file: any) {
this.file = file
+
+ if (!this.file) this.fileInputValue = null
}
registerOnChange (fn: (_: any) => void) {
<div class="form-group" *ngFor="let videoCaption of videoCaptions">
- <div *ngIf="videoCaption.action !== 'REMOVE'" class="caption-entry">
- <div class="caption-entry-label">{{ videoCaption.language.label }}</div>
+ <div class="caption-entry">
+ <ng-container *ngIf="!videoCaption.action">
+ <a
+ i18n-title title="See the subtitle file" class="caption-entry-label" target="_blank" rel="noopener noreferrer"
+ [href]="videoCaption.captionPath"
+ >{{ videoCaption.language.label }}</a>
- <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
+ <div class="caption-entry-state">Already uploaded ✔</div>
+
+ <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
+ </ng-container>
+
+ <ng-container *ngIf="videoCaption.action === 'CREATE'">
+ <span class="caption-entry-label">{{ videoCaption.language.label }}</span>
+
+ <div class="caption-entry-state caption-entry-state-create">Will be created on update</div>
+
+ <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel create</span>
+ </ng-container>
+
+ <ng-container *ngIf="videoCaption.action === 'REMOVE'">
+ <span class="caption-entry-label">{{ videoCaption.language.label }}</span>
+
+ <div class="caption-entry-state caption-entry-state-delete">Will be deleted on update</div>
+
+ <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span>
+ </ng-container>
</div>
</div>
height: 40px;
align-items: center;
+ a.caption-entry-label {
+ @include disable-default-a-behaviour;
+
+ color: #000;
+
+ &:hover {
+ opacity: 0.8;
+ }
+ }
+
.caption-entry-label {
font-size: 15px;
font-weight: bold;
margin-right: 20px;
+ width: 150px;
+ }
+
+ .caption-entry-state {
+ width: 200px;
+
+ &.caption-entry-state-create {
+ color: #39CC0B;
+ }
+
+ &.caption-entry-state-delete {
+ color: #FF0000;
+ }
}
.caption-entry-delete {
private schedulerInterval
private firstPatchDone = false
+ private initialVideoCaptions: string[] = []
constructor (
private formValidatorService: FormValidatorService,
this.videoLanguages = this.serverService.getVideoLanguages()
this.schedulerInterval = setInterval(() => this.minScheduledDate = new Date(), 1000 * 60) // Update every minute
+
+ this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
}
ngOnDestroy () {
)
}
- deleteCaption (caption: VideoCaptionEdit) {
+ async deleteCaption (caption: VideoCaptionEdit) {
+ // Caption recovers his former state
+ if (caption.action && this.initialVideoCaptions.indexOf(caption.language.id) !== -1) {
+ caption.action = undefined
+ return
+ }
+
// This caption is not on the server, just remove it from our array
if (caption.action === 'CREATE') {
removeElementFromArray(this.videoCaptions, caption)
import { LoginGuard } from '../../core'
import { VideoUpdateComponent } from './video-update.component'
import { VideoUpdateResolver } from '@app/videos/+video-edit/video-update.resolver'
+import { CanDeactivateGuard } from '@app/shared/guards/can-deactivate-guard.service'
const videoUpdateRoutes: Routes = [
{
path: '',
component: VideoUpdateComponent,
canActivate: [ MetaGuard, LoginGuard ],
+ canDeactivate: [ CanDeactivateGuard ],
resolve: {
videoData: VideoUpdateResolver
}
schedulePublicationPossible = false
videoCaptions: VideoCaptionEdit[] = []
+ private updateDone = false
+
constructor (
protected formValidatorService: FormValidatorService,
private route: ActivatedRoute,
this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.PRIVATE
}
- // FIXME: Angular does not detec
+ // FIXME: Angular does not detect the change inside this subscription, so use the patched setTimeout
setTimeout(() => this.hydrateFormFromVideo())
},
)
}
+ canDeactivate () {
+ if (this.updateDone === true) return { canDeactivate: true }
+
+ for (const caption of this.videoCaptions) {
+ if (caption.action) return { canDeactivate: false }
+ }
+
+ return { canDeactivate: this.formChanged === false }
+ }
+
checkForm () {
this.forceCheck()
)
.subscribe(
() => {
+ this.updateDone = true
this.isUpdatingVideo = false
this.loadingBar.complete()
this.notificationsService.success(this.i18n('Success'), this.i18n('Video updated.'))
import { VideoUpdateRoutingModule } from './video-update-routing.module'
import { VideoUpdateComponent } from './video-update.component'
import { VideoUpdateResolver } from '@app/videos/+video-edit/video-update.resolver'
+import { CanDeactivateGuard } from '@app/shared/guards/can-deactivate-guard.service'
@NgModule({
imports: [
],
providers: [
- VideoUpdateResolver
+ VideoUpdateResolver,
+ CanDeactivateGuard
]
})
export class VideoUpdateModule { }