refactor subscribe button and comment-add for visitor-interact UX (#1100)
* refactor subscribe button for visitor-subscribe UX * refactor comment-add for visitor-interact UX
This commit is contained in:
parent
ba6a98b8fa
commit
660d11e91e
|
@ -9,7 +9,7 @@
|
||||||
<div class="actor-display-name">{{ videoChannel.displayName }}</div>
|
<div class="actor-display-name">{{ videoChannel.displayName }}</div>
|
||||||
<div class="actor-name">{{ videoChannel.nameWithHost }}</div>
|
<div class="actor-name">{{ videoChannel.nameWithHost }}</div>
|
||||||
|
|
||||||
<my-subscribe-button #subscribeButton *ngIf="isUserLoggedIn()" [videoChannel]="videoChannel"></my-subscribe-button>
|
<my-subscribe-button #subscribeButton [videoChannel]="videoChannel"></my-subscribe-button>
|
||||||
</div>
|
</div>
|
||||||
<div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>
|
<div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<div i18n class="video-channel-followers">{{ result.followersCount }} subscribers</div>
|
<div i18n class="video-channel-followers">{{ result.followersCount }} subscribers</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-subscribe-button *ngIf="isUserLoggedIn()" [videoChannel]="result"></my-subscribe-button>
|
<my-subscribe-button [videoChannel]="result"></my-subscribe-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="isVideo(result)" class="entry video">
|
<div *ngIf="isVideo(result)" class="entry video">
|
||||||
|
|
|
@ -53,7 +53,7 @@ import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.c
|
||||||
import { VideoImportService } from '@app/shared/video-import/video-import.service'
|
import { VideoImportService } from '@app/shared/video-import/video-import.service'
|
||||||
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
|
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
|
||||||
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
import { SubscribeButtonComponent, RemoteSubscribeComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
||||||
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
||||||
import { OverviewService } from '@app/shared/overview'
|
import { OverviewService } from '@app/shared/overview'
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ import { OverviewService } from '@app/shared/overview'
|
||||||
ReactiveFileComponent,
|
ReactiveFileComponent,
|
||||||
PeertubeCheckboxComponent,
|
PeertubeCheckboxComponent,
|
||||||
SubscribeButtonComponent,
|
SubscribeButtonComponent,
|
||||||
|
RemoteSubscribeComponent,
|
||||||
InstanceFeaturesTableComponent
|
InstanceFeaturesTableComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -127,6 +128,7 @@ import { OverviewService } from '@app/shared/overview'
|
||||||
ReactiveFileComponent,
|
ReactiveFileComponent,
|
||||||
PeertubeCheckboxComponent,
|
PeertubeCheckboxComponent,
|
||||||
SubscribeButtonComponent,
|
SubscribeButtonComponent,
|
||||||
|
RemoteSubscribeComponent,
|
||||||
InstanceFeaturesTableComponent,
|
InstanceFeaturesTableComponent,
|
||||||
|
|
||||||
NumberFormatterPipe,
|
NumberFormatterPipe,
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from './user-subscription.service'
|
export * from './user-subscription.service'
|
||||||
export * from './subscribe-button.component'
|
export * from './subscribe-button.component'
|
||||||
|
export * from './remote-subscribe.component'
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<form novalidate [formGroup]="form"
|
||||||
|
(ngSubmit)="formValidated()">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="email"
|
||||||
|
formControlName="text"
|
||||||
|
class="form-control"
|
||||||
|
(keyup.control.enter)="onValidKey()" (keyup.meta.enter)="onValidKey()"
|
||||||
|
placeholder="jane_doe@example.com">
|
||||||
|
</div>
|
||||||
|
<button type="submit"
|
||||||
|
[disabled]="!form.valid"
|
||||||
|
class="btn btn-sm btn-remote-follow"
|
||||||
|
i18n>
|
||||||
|
<span *ngIf="!interact">Remote subscribe</span>
|
||||||
|
<span *ngIf="interact">Remote interact</span>
|
||||||
|
</button>
|
||||||
|
<my-help *ngIf="!interact && showHelp"
|
||||||
|
helpType="custom"
|
||||||
|
i18n-customHtml customHtml="You can subscribe to the channel via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there.">
|
||||||
|
</my-help>
|
||||||
|
<my-help *ngIf="showHelp && interact"
|
||||||
|
helpType="custom"
|
||||||
|
i18n-customHtml customHtml="You can interact with this via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there.">
|
||||||
|
</my-help>
|
||||||
|
</form>
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.btn-remote-follow {
|
||||||
|
@include orange-button;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
|
import { FormReactive } from '@app/shared/forms/form-reactive'
|
||||||
|
import {
|
||||||
|
FormValidatorService,
|
||||||
|
UserValidatorsService
|
||||||
|
} from '@app/shared/forms/form-validators'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-remote-subscribe',
|
||||||
|
templateUrl: './remote-subscribe.component.html',
|
||||||
|
styleUrls: ['./remote-subscribe.component.scss']
|
||||||
|
})
|
||||||
|
export class RemoteSubscribeComponent extends FormReactive implements OnInit {
|
||||||
|
@Input() account: string
|
||||||
|
@Input() interact = false
|
||||||
|
@Input() showHelp = false
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
protected formValidatorService: FormValidatorService,
|
||||||
|
private userValidatorsService: UserValidatorsService
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.buildForm({
|
||||||
|
text: this.userValidatorsService.USER_EMAIL
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onValidKey () {
|
||||||
|
this.onValueChanged()
|
||||||
|
if (!this.form.valid) return
|
||||||
|
|
||||||
|
this.formValidated()
|
||||||
|
}
|
||||||
|
|
||||||
|
formValidated () {
|
||||||
|
const address = this.form.value['text']
|
||||||
|
const [ , hostname ] = address.split('@')
|
||||||
|
window.open(`https://${hostname}/authorize_interaction?acct=${this.account}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,45 @@
|
||||||
<span i18n *ngIf="subscribed === false" class="subscribe-button" [ngClass]="size" role="button" (click)="subscribe()">
|
<div class="btn-group-subscribe btn-group"
|
||||||
<span>Subscribe</span>
|
[ngClass]="{'subscribe-button': subscribed !== true, 'unsubscribe-button': subscribed === true}">
|
||||||
<span *ngIf="displayFollowers && videoChannel.followersCount !== 0" class="followers-count">
|
<button *ngIf="subscribed === false && isUserLoggedIn()" type="button"
|
||||||
{{ videoChannel.followersCount | myNumberFormatter }}
|
class="btn btn-sm" role="button"
|
||||||
</span>
|
(click)="subscribe()" i18n>
|
||||||
</span>
|
<span>
|
||||||
|
Subscribe
|
||||||
|
</span>
|
||||||
|
<span *ngIf="displayFollowers && videoChannel.followersCount !== 0" class="followers-count">
|
||||||
|
{{ videoChannel.followersCount | myNumberFormatter }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="subscribed === true" type="button"
|
||||||
|
class="btn btn-sm" role="button"
|
||||||
|
(click)="unsubscribe()" i18n>Unsubscribe</button>
|
||||||
|
|
||||||
<span *ngIf="subscribed === true" class="unsubscribe-button" [ngClass]="size" role="button" (click)="unsubscribe()">
|
<div class="btn-group" ngbDropdown autoClose="outside"
|
||||||
<span class="subscribed" i18n>Subscribed</span>
|
placement="bottom-right" role="group"
|
||||||
<span class="unsubscribe" i18n>Unsubscribe</span>
|
aria-label="Multiple ways to subscribe to the current channel">
|
||||||
|
<button class="btn btn-sm dropdown-toggle-split" ngbDropdownToggle>
|
||||||
|
<span *ngIf="!isUserLoggedIn()">
|
||||||
|
Subscribe
|
||||||
|
</span>
|
||||||
|
<span *ngIf="displayFollowers && videoChannel.followersCount !== 0" class="followers-count">
|
||||||
|
{{ videoChannel.followersCount | myNumberFormatter }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" ngbDropdownMenu>
|
||||||
|
|
||||||
<span *ngIf="displayFollowers && videoChannel.followersCount !== 0" class="followers-count">
|
<h6 class="dropdown-header" i18n>Using an ActivityPub-compatible account</h6>
|
||||||
{{ videoChannel.followersCount | myNumberFormatter }}
|
<button class="dropdown-item" (click)="subscribe()"
|
||||||
</span>
|
*ngIf="subscribed === false">
|
||||||
</span>
|
<span *ngIf="!isUserLoggedIn()" i18n>Subscribe with an account on {{ videoChannel.host }}</span>
|
||||||
|
<span *ngIf="isUserLoggedIn()" i18n>Subscribe with your local account</span>
|
||||||
|
</button>
|
||||||
|
<button class="dropdown-item" i18n>Subscribe with a remote account:</button>
|
||||||
|
<my-remote-subscribe showHelp="true" account="{{ uriAccount }}"></my-remote-subscribe>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
|
||||||
|
<h6 class="dropdown-header" i18n>Using a syndication feed</h6>
|
||||||
|
<button (click)="rssOpen()" class="dropdown-item" i18n>Subscribe via RSS</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,51 +1,46 @@
|
||||||
@import '_variables';
|
@import '_variables';
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
|
|
||||||
.subscribe-button {
|
.btn-group-subscribe {
|
||||||
@include peertube-button;
|
@include peertube-button;
|
||||||
@include orange-button;
|
@include disable-default-a-behaviour;
|
||||||
}
|
float: right;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
.unsubscribe-button {
|
&.btn-group > .btn:not(.dropdown-toggle) {
|
||||||
@include peertube-button;
|
padding-right: 5px;
|
||||||
@include grey-button
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
&.btn-group > .btn-group:not(:first-child) > .btn {
|
||||||
.subscribe-button,
|
padding-left: 2px;
|
||||||
.unsubscribe-button {
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
&.small {
|
|
||||||
min-width: 75px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 20px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.normal {
|
&.subscribe-button {
|
||||||
min-width: 120px;
|
.btn {
|
||||||
height: 30px;
|
@include orange-button;
|
||||||
line-height: 30px;
|
font-weight: 600;
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.unsubscribe-button {
|
|
||||||
.subscribed {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unsubscribe {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.subscribed {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.unsubscribe {
|
span.followers-count {
|
||||||
display: inline;
|
padding-left:5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
&.unsubscribe-button {
|
||||||
|
.btn {
|
||||||
|
@include grey-button;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ form {
|
||||||
|
padding: 0.25rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@include peertube-input-text(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core'
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
|
import { Router } from '@angular/router'
|
||||||
|
import { AuthService } from '@app/core'
|
||||||
import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service'
|
import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service'
|
||||||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
@ -17,6 +19,8 @@ export class SubscribeButtonComponent implements OnInit {
|
||||||
subscribed: boolean
|
subscribed: boolean
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
private authService: AuthService,
|
||||||
|
private router: Router,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private userSubscriptionService: UserSubscriptionService,
|
private userSubscriptionService: UserSubscriptionService,
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
|
@ -26,16 +30,30 @@ export class SubscribeButtonComponent implements OnInit {
|
||||||
return this.videoChannel.name + '@' + this.videoChannel.host
|
return this.videoChannel.name + '@' + this.videoChannel.host
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
get uriAccount () {
|
||||||
this.userSubscriptionService.isSubscriptionExists(this.uri)
|
return this.videoChannel.ownerAccount.name + '@' + this.videoChannel.host
|
||||||
.subscribe(
|
}
|
||||||
res => this.subscribed = res[this.uri],
|
|
||||||
|
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
ngOnInit () {
|
||||||
)
|
if (this.isUserLoggedIn()) {
|
||||||
|
this.userSubscriptionService.isSubscriptionExists(this.uri)
|
||||||
|
.subscribe(
|
||||||
|
res => this.subscribed = res[this.uri],
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe () {
|
subscribe () {
|
||||||
|
if (this.isUserLoggedIn()) {
|
||||||
|
this.localSubscribe()
|
||||||
|
} else {
|
||||||
|
this.gotoLogin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localSubscribe () {
|
||||||
this.userSubscriptionService.addSubscription(this.uri)
|
this.userSubscriptionService.addSubscription(this.uri)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => {
|
() => {
|
||||||
|
@ -52,6 +70,12 @@ export class SubscribeButtonComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsubscribe () {
|
unsubscribe () {
|
||||||
|
if (this.isUserLoggedIn()) {
|
||||||
|
this.localUnsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localUnsubscribe () {
|
||||||
this.userSubscriptionService.deleteSubscription(this.uri)
|
this.userSubscriptionService.deleteSubscription(this.uri)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => {
|
() => {
|
||||||
|
@ -66,4 +90,16 @@ export class SubscribeButtonComponent implements OnInit {
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isUserLoggedIn () {
|
||||||
|
return this.authService.isLoggedIn()
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoLogin () {
|
||||||
|
this.router.navigate([ '/login' ])
|
||||||
|
}
|
||||||
|
|
||||||
|
rssOpen () {
|
||||||
|
window.open('')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
|
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
|
||||||
<div class="avatar-and-textarea">
|
<div class="avatar-and-textarea">
|
||||||
<img [src]="user.accountAvatarUrl" alt="Avatar" />
|
<img [src]="getAvatarUrl()" alt="Avatar" />
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<textarea i18n-placeholder placeholder="Add comment..." autosize
|
<textarea i18n-placeholder placeholder="Add comment..." autosize
|
||||||
|
[readonly]="(user === null) ? true : false"
|
||||||
|
(click)="openVisitorModal($event)"
|
||||||
formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }"
|
formControlName="text" [ngClass]="{ 'input-error': formErrors['text'] }"
|
||||||
(keyup.control.enter)="onValidKey()" (keyup.meta.enter)="onValidKey()" #textarea>
|
(keyup.control.enter)="onValidKey()" (keyup.meta.enter)="onValidKey()" #textarea>
|
||||||
|
|
||||||
|
@ -20,3 +22,25 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<ng-template #visitorModal let-modal>
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="modal-basic-title" i18n>You are one step away from commenting</h4>
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="hideVisitorModal()"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" i18n>
|
||||||
|
<span i18n>
|
||||||
|
If you have an account on this instance, you can login:
|
||||||
|
</span>
|
||||||
|
<span class="btn btn-sm mx-3" role="button" (click)="gotoLogin()" i18n>login to comment</span>
|
||||||
|
<span i18n>
|
||||||
|
Otherwise you can comment using an account on an ActivityPub-compatible instance:
|
||||||
|
</span>
|
||||||
|
<my-remote-subscribe [interact]="true" account="{{ uri }}"></my-remote-subscribe>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<span i18n class="action-button action-button-cancel" role="button" (click)="hideVisitorModal()">
|
||||||
|
Cancel
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -36,7 +36,7 @@ form {
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@include peertube-button;
|
@include peertube-button;
|
||||||
@include orange-button
|
@include orange-button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,4 +44,16 @@ form {
|
||||||
textarea, .submit-comment button {
|
textarea, .submit-comment button {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
.btn {
|
||||||
|
@include peertube-button;
|
||||||
|
@include orange-button;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
||||||
|
import { Router } from '@angular/router'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import { VideoCommentCreate } from '../../../../../../shared/models/videos/video-comment.model'
|
import { VideoCommentCreate } from '../../../../../../shared/models/videos/video-comment.model'
|
||||||
|
@ -10,6 +11,8 @@ import { VideoCommentService } from './video-comment.service'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { VideoCommentValidatorsService } from '@app/shared/forms/form-validators/video-comment-validators.service'
|
import { VideoCommentValidatorsService } from '@app/shared/forms/form-validators/video-comment-validators.service'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { AuthService } from '@app/core/auth'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-comment-add',
|
selector: 'my-video-comment-add',
|
||||||
|
@ -25,15 +28,20 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
|
|
||||||
@Output() commentCreated = new EventEmitter<VideoCommentCreate>()
|
@Output() commentCreated = new EventEmitter<VideoCommentCreate>()
|
||||||
|
|
||||||
|
@ViewChild('visitorModal') visitorModal: NgbModal
|
||||||
@ViewChild('textarea') private textareaElement: ElementRef
|
@ViewChild('textarea') private textareaElement: ElementRef
|
||||||
|
|
||||||
private addingComment = false
|
private addingComment = false
|
||||||
|
private uri: string
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
protected formValidatorService: FormValidatorService,
|
protected formValidatorService: FormValidatorService,
|
||||||
private videoCommentValidatorsService: VideoCommentValidatorsService,
|
private videoCommentValidatorsService: VideoCommentValidatorsService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private videoCommentService: VideoCommentService,
|
private videoCommentService: VideoCommentService,
|
||||||
|
private authService: AuthService,
|
||||||
|
private modalService: NgbModal,
|
||||||
|
private router: Router,
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
@ -44,19 +52,23 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
text: this.videoCommentValidatorsService.VIDEO_COMMENT_TEXT
|
text: this.videoCommentValidatorsService.VIDEO_COMMENT_TEXT
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.focusOnInit === true) {
|
this.uri = this.router.url
|
||||||
this.textareaElement.nativeElement.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.parentComment) {
|
if (this.user) {
|
||||||
const mentions = this.parentComments
|
if (this.focusOnInit === true) {
|
||||||
.filter(c => c.account.id !== this.user.account.id) // Don't add mention of ourselves
|
this.textareaElement.nativeElement.focus()
|
||||||
.map(c => '@' + c.by)
|
}
|
||||||
|
|
||||||
const mentionsSet = new Set(mentions)
|
if (this.parentComment) {
|
||||||
const mentionsText = Array.from(mentionsSet).join(' ') + ' '
|
const mentions = this.parentComments
|
||||||
|
.filter(c => c.account.id !== this.user.account.id) // Don't add mention of ourselves
|
||||||
|
.map(c => '@' + c.by)
|
||||||
|
|
||||||
this.form.patchValue({ text: mentionsText })
|
const mentionsSet = new Set(mentions)
|
||||||
|
const mentionsText = Array.from(mentionsSet).join(' ') + ' '
|
||||||
|
|
||||||
|
this.form.patchValue({ text: mentionsText })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +79,20 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
this.formValidated()
|
this.formValidated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openVisitorModal (event) {
|
||||||
|
if (this.user === null) { // we only open it for visitors
|
||||||
|
// fixing ng-bootstrap ModalService and the "Expression Changed After It Has Been Checked" Error
|
||||||
|
event.srcElement.blur()
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
this.modalService.open(this.visitorModal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideVisitorModal () {
|
||||||
|
this.modalService.dismissAll()
|
||||||
|
}
|
||||||
|
|
||||||
formValidated () {
|
formValidated () {
|
||||||
// If we validate very quickly the comment form, we might comment twice
|
// If we validate very quickly the comment form, we might comment twice
|
||||||
if (this.addingComment) return
|
if (this.addingComment) return
|
||||||
|
@ -101,6 +127,17 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
return this.form.value['text']
|
return this.form.value['text']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAvatarUrl () {
|
||||||
|
if (this.user) return this.user.accountAvatarUrl
|
||||||
|
return window.location.origin + '/client/assets/images/default-avatar.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoLogin () {
|
||||||
|
this.hideVisitorModal()
|
||||||
|
this.authService.redirectUrl = this.router.url
|
||||||
|
this.router.navigate([ '/login' ])
|
||||||
|
}
|
||||||
|
|
||||||
private addCommentReply (commentCreate: VideoCommentCreate) {
|
private addCommentReply (commentCreate: VideoCommentCreate) {
|
||||||
return this.videoCommentService
|
return this.videoCommentService
|
||||||
.addCommentReply(this.video.id, this.parentComment.id, commentCreate)
|
.addCommentReply(this.video.id, this.parentComment.id, commentCreate)
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
<ng-template [ngIf]="video.commentsEnabled === true">
|
<ng-template [ngIf]="video.commentsEnabled === true">
|
||||||
<my-video-comment-add
|
<my-video-comment-add
|
||||||
*ngIf="isUserLoggedIn()"
|
|
||||||
[video]="video"
|
[video]="video"
|
||||||
[user]="user"
|
[user]="user"
|
||||||
(commentCreated)="onCommentThreadCreated($event)"
|
(commentCreated)="onCommentThreadCreated($event)"
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
<img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" />
|
<img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<my-subscribe-button #subscribeButton *ngIf="isUserLoggedIn()" [videoChannel]="video.channel" size="small"></my-subscribe-button>
|
<my-subscribe-button #subscribeButton [videoChannel]="video.channel" size="small"></my-subscribe-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="video-info-by">
|
<div class="video-info-by">
|
||||||
|
@ -134,8 +134,6 @@
|
||||||
<span i18n>By {{ video.byAccount }}</span>
|
<span i18n>By {{ video.byAccount }}</span>
|
||||||
<img [src]="video.accountAvatarUrl" alt="Account avatar" />
|
<img [src]="video.accountAvatarUrl" alt="Account avatar" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<my-help helpType="custom" i18n-customHtml customHtml="You can subscribe to this account via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box <strong>@{{video.account.name}}@{{video.account.host}}</strong> and subscribe there."></my-help>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -199,9 +199,18 @@ label {
|
||||||
|
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
padding: 3px 15px;
|
padding: 3px 15px;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@include disable-default-a-behaviour;
|
||||||
color: #000 !important;
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ $nav-pills-link-active-color: #000;
|
||||||
@import '~bootstrap/scss/buttons';
|
@import '~bootstrap/scss/buttons';
|
||||||
//@import '~bootstrap/scss/transitions';
|
//@import '~bootstrap/scss/transitions';
|
||||||
@import '~bootstrap/scss/dropdown';
|
@import '~bootstrap/scss/dropdown';
|
||||||
//@import '~bootstrap/scss/button-group';
|
@import '~bootstrap/scss/button-group';
|
||||||
@import '~bootstrap/scss/input-group';
|
@import '~bootstrap/scss/input-group';
|
||||||
//@import '~bootstrap/scss/custom-forms';
|
//@import '~bootstrap/scss/custom-forms';
|
||||||
@import '~bootstrap/scss/nav';
|
@import '~bootstrap/scss/nav';
|
||||||
|
|
Loading…
Reference in New Issue