(component).tranformHtmlRepliesToReplies(pleromaMention);
+ expect(result).toBe('test @sengi_app@pleroma.site qsdqds qsd qsd qsd q @test@pleroma.site @no
');
+ });
});
\ No newline at end of file
diff --git a/src/app/components/create-status/create-status.component.ts b/src/app/components/create-status/create-status.component.ts
index 3287c6b8..a926199b 100644
--- a/src/app/components/create-status/create-status.component.ts
+++ b/src/app/components/create-status/create-status.component.ts
@@ -1,5 +1,7 @@
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ElementRef, ViewChild, ViewContainerRef, ComponentRef, HostListener } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
+import { Overlay, OverlayConfig, FullscreenOverlayContainer, OverlayRef } from '@angular/cdk/overlay';
+import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
import { Store } from '@ngxs/store';
import { Subscription, Observable } from 'rxjs';
import { UP_ARROW, DOWN_ARROW, ENTER, ESCAPE } from '@angular/cdk/keycodes';
@@ -17,12 +19,11 @@ import { AccountInfo } from '../../states/accounts.state';
import { InstancesInfoService } from '../../services/instances-info.service';
import { MediaService } from '../../services/media.service';
import { AutosuggestSelection, AutosuggestUserActionEnum } from './autosuggest/autosuggest.component';
-import { Overlay, OverlayConfig, FullscreenOverlayContainer, OverlayRef } from '@angular/cdk/overlay';
-import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
import { EmojiPickerComponent } from './emoji-picker/emoji-picker.component';
import { PollEditorComponent } from './poll-editor/poll-editor.component';
import { StatusSchedulerComponent } from './status-scheduler/status-scheduler.component';
import { ScheduledStatusService } from '../../services/scheduled-status.service';
+import { StatusesStateService } from '../../services/statuses-state.service';
@Component({
selector: 'app-create-status',
@@ -53,6 +54,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
private _status: string = '';
@Input('status')
set status(value: string) {
+ this.statusStateService.setStatusContent(value, this.statusReplyingToWrapper);
this.countStatusChar(value);
this.detectAutosuggestion(value);
this._status = value;
@@ -65,14 +67,38 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
return this._status;
}
+ private trim(s, mask) {
+ while (~mask.indexOf(s[0])) {
+ s = s.slice(1);
+ }
+ while (~mask.indexOf(s[s.length - 1])) {
+ s = s.slice(0, -1);
+ }
+ return s;
+ }
+
@Input('redraftedStatus')
set redraftedStatus(value: StatusWrapper) {
- if (value) {
+ if (value) {
this.statusLoaded = false;
+
+ const newLine = String.fromCharCode(13, 10);
+ let content = value.status.content;
+
+ content = this.tranformHtmlRepliesToReplies(content);
+
+ while (content.includes('') || content.includes('
') || content.includes('
') || content.includes('
') || content.includes('
')) {
+ content = content.replace('', '').replace('
', newLine + newLine).replace('
', newLine).replace('
', newLine).replace('
', newLine);
+ }
+
+ content = this.trim(content, newLine);
+
let parser = new DOMParser();
- var dom = parser.parseFromString(value.status.content, 'text/html')
+ var dom = parser.parseFromString(content, 'text/html')
this.status = dom.body.textContent;
+ this.statusStateService.setStatusContent(this.status, this.statusReplyingToWrapper);
+
this.setVisibilityFromStatus(value.status);
this.title = value.status.spoiler_text;
this.statusLoaded = true;
@@ -83,17 +109,6 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
.then((status: Status) => {
let cwResult = this.toolsService.checkContentWarning(status);
this.statusReplyingToWrapper = new StatusWrapper(cwResult.status, value.provider, cwResult.applyCw, cwResult.hide);
-
- const mentions = this.getMentions(this.statusReplyingToWrapper.status, this.statusReplyingToWrapper.provider);
- for (const mention of mentions) {
- const name = `@${mention.split('@')[0]}`;
- if (this.status.includes(name)) {
- this.status = this.status.replace(name, `@${mention}`);
- } else {
- this.status = `@${mention} ` + this.status;
- }
- }
-
})
.catch(err => {
this.notificationService.notifyHttpError(err, value.provider);
@@ -159,6 +174,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
private selectedAccount: AccountInfo;
constructor(
+ private statusStateService: StatusesStateService,
private readonly scheduledStatusService: ScheduledStatusService,
private readonly contextMenuService: ContextMenuService,
private readonly store: Store,
@@ -169,7 +185,9 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
private readonly mediaService: MediaService,
private readonly overlay: Overlay,
public viewContainerRef: ViewContainerRef) {
+
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
+ this.status = this.statusStateService.getStatusContent(this.statusReplyingToWrapper);
}
ngOnInit() {
@@ -185,9 +203,14 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
this.statusReplyingTo = this.statusReplyingToWrapper.status;
}
- const uniqueMentions = this.getMentions(this.statusReplyingTo, this.statusReplyingToWrapper.provider);
- for (const mention of uniqueMentions) {
- this.status += `@${mention} `;
+ let state = this.statusStateService.getStatusContent(this.statusReplyingToWrapper);
+ if (state && state !== '') {
+ this.status = state;
+ } else {
+ const uniqueMentions = this.getMentions(this.statusReplyingTo, this.statusReplyingToWrapper.provider);
+ for (const mention of uniqueMentions) {
+ this.status += `@${mention} `;
+ }
}
this.setVisibilityFromStatus(this.statusReplyingTo);
@@ -533,6 +556,8 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
if (this.scheduleIsActive) {
this.scheduledStatusService.statusAdded(acc);
}
+
+ this.statusStateService.resetStatusContent(this.statusReplyingToWrapper);
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err, acc);
@@ -810,4 +835,19 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
this.scheduleIsActive = !this.scheduleIsActive;
return false;
}
+
+ private tranformHtmlRepliesToReplies(data: string): string {
+ const mastodonMentionRegex = /@([a-zA-Z0-9_-]{0,255})<\/span><\/a><\/span>/gmi;
+ const pleromaMentionRegex = /@([a-zA-Z0-9_-]{0,255})<\/span><\/a><\/span>/gmi;
+
+ while(data.match(mastodonMentionRegex)){
+ data = data.replace(mastodonMentionRegex, '@$2@$1');
+ }
+
+ while(data.match(pleromaMentionRegex)){
+ data = data.replace(pleromaMentionRegex, '@$2@$1');
+ }
+
+ return data;
+ }
}
diff --git a/src/app/components/floating-column/manage-account/mentions/mentions.component.ts b/src/app/components/floating-column/manage-account/mentions/mentions.component.ts
index 9e81b404..b90a56a2 100644
--- a/src/app/components/floating-column/manage-account/mentions/mentions.component.ts
+++ b/src/app/components/floating-column/manage-account/mentions/mentions.component.ts
@@ -74,11 +74,11 @@ export class MentionsComponent implements OnInit, OnDestroy {
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
this.processNewMentions(userNotifications);
- if(this.statuses.length < 20) this.scrolledToBottom();
+ if (this.statuses.length < 20) this.scrolledToBottom();
});
}
- private processNewMentions(userNotifications: UserNotification[]) {
+ private processNewMentions(userNotifications: UserNotification[]) {
const userNotification = userNotifications.find(x => x.account.id === this.account.info.id);
if (userNotification && userNotification.mentions) {
let orderedMentions = [...userNotification.mentions.map(x => x.status)].reverse();
@@ -120,7 +120,9 @@ export class MentionsComponent implements OnInit, OnDestroy {
for (const s of statuses) {
let cwPolicy = this.toolsService.checkContentWarning(s);
const wrapper = new StatusWrapper(cwPolicy.status, this.account.info, cwPolicy.applyCw, cwPolicy.hide);
- this.statuses.push(wrapper);
+ if (!this.statuses.find(x => x.status.id === s.id)) {
+ this.statuses.push(wrapper);
+ }
}
this.lastId = result[result.length - 1].id;
diff --git a/src/app/components/floating-column/manage-account/notifications/notifications.component.ts b/src/app/components/floating-column/manage-account/notifications/notifications.component.ts
index 03545b1f..35f4fe12 100644
--- a/src/app/components/floating-column/manage-account/notifications/notifications.component.ts
+++ b/src/app/components/floating-column/manage-account/notifications/notifications.component.ts
@@ -31,7 +31,7 @@ export class NotificationsComponent implements OnInit, OnDestroy {
get account(): AccountWrapper {
return this._account;
}
-
+
@ViewChild('statusstream') public statustream: ElementRef;
private maxReached = false;
@@ -39,7 +39,7 @@ export class NotificationsComponent implements OnInit, OnDestroy {
private userNotificationServiceSub: Subscription;
private lastId: string;
- constructor(
+ constructor(
private readonly toolsService: ToolsService,
private readonly notificationService: NotificationService,
private readonly userNotificationService: UserNotificationService,
@@ -49,22 +49,22 @@ export class NotificationsComponent implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
- if(this.userNotificationServiceSub){
+ if (this.userNotificationServiceSub) {
this.userNotificationServiceSub.unsubscribe();
}
}
- private loadNotifications(){
- if(this.userNotificationServiceSub){
+ private loadNotifications() {
+ if (this.userNotificationServiceSub) {
this.userNotificationServiceSub.unsubscribe();
}
this.notifications.length = 0;
- this.userNotificationService.markNotificationAsRead(this.account.info);
+ this.userNotificationService.markNotificationAsRead(this.account.info);
this.userNotificationServiceSub = this.userNotificationService.userNotifications.subscribe((userNotifications: UserNotification[]) => {
this.processNewNotifications(userNotifications);
- if(this.notifications.length < 20) this.scrolledToBottom();
+ if (this.notifications.length < 20) this.scrolledToBottom();
});
}
@@ -75,7 +75,7 @@ export class NotificationsComponent implements OnInit, OnDestroy {
for (let n of orderedNotifications) {
let cwPolicy = this.toolsService.checkContentWarning(n.status);
const notificationWrapper = new NotificationWrapper(n, this.account.info, cwPolicy.applyCw, cwPolicy.hide);
- if (!this.notifications.find(x => x.wrapperId === notificationWrapper.wrapperId)) {
+ if (!this.notifications.find(x => x.wrapperId === notificationWrapper.wrapperId)) {
this.notifications.unshift(notificationWrapper);
}
}
@@ -84,7 +84,7 @@ export class NotificationsComponent implements OnInit, OnDestroy {
this.userNotificationService.markNotificationAsRead(this.account.info);
}
-
+
onScroll() {
var element = this.statustream.nativeElement as HTMLElement;
const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 1000;
@@ -105,11 +105,13 @@ export class NotificationsComponent implements OnInit, OnDestroy {
this.maxReached = true;
return;
}
-
+
for (const s of notifications) {
let cwPolicy = this.toolsService.checkContentWarning(s.status);
const wrapper = new NotificationWrapper(s, this.account.info, cwPolicy.applyCw, cwPolicy.hide);
- this.notifications.push(wrapper);
+ if (!this.notifications.find(x => x.wrapperId === wrapper.wrapperId)) {
+ this.notifications.push(wrapper);
+ }
}
this.lastId = notifications[notifications.length - 1].id;
@@ -136,16 +138,16 @@ export class NotificationsComponent implements OnInit, OnDestroy {
}
export class NotificationWrapper {
- constructor(notification: Notification, provider: AccountInfo, applyCw: boolean, hideStatus: boolean) {
+ constructor(notification: Notification, provider: AccountInfo, applyCw: boolean, hideStatus: boolean) {
this.type = notification.type;
- switch(this.type){
- case 'mention':
- case 'reblog':
+ switch (this.type) {
+ case 'mention':
+ case 'reblog':
case 'favourite':
- case 'poll':
- this.status= new StatusWrapper(notification.status, provider, applyCw, hideStatus);
- break;
- }
+ case 'poll':
+ this.status = new StatusWrapper(notification.status, provider, applyCw, hideStatus);
+ break;
+ }
this.account = notification.account;
this.wrapperId = `${this.type}-${notification.id}`;
this.notification = notification;
diff --git a/src/app/components/tutorial/tutorial.component.html b/src/app/components/tutorial/tutorial.component.html
index 23077932..c6dadcf8 100644
--- a/src/app/components/tutorial/tutorial.component.html
+++ b/src/app/components/tutorial/tutorial.component.html
@@ -16,4 +16,6 @@ Nice!
Now right-click on your avatar to open your account and be able to add some timelines!
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/app/components/tutorial/tutorial.component.scss b/src/app/components/tutorial/tutorial.component.scss
index a5fcd38d..95766808 100644
--- a/src/app/components/tutorial/tutorial.component.scss
+++ b/src/app/components/tutorial/tutorial.component.scss
@@ -25,20 +25,20 @@
&__arrow {
position: fixed;
- top: 15px;
+ top: 20px;
left: 60px;
}
&__title{
position: relative;
top: 30px;
- left: 70px;
+ left: 85px;
}
&__description {
position: relative;
- top: 45px;
- left: 75px;
+ top: 60px;
+ left: 70px;
text-align: center;
@@ -80,4 +80,11 @@
// word-break: break-all;
white-space: normal;
}
+}
+
+.sengi-logo {
+ width: 230px;
+ position: fixed;
+ bottom: 35px;
+ right: 10px;
}
\ No newline at end of file
diff --git a/src/app/services/statuses-state.service.ts b/src/app/services/statuses-state.service.ts
index 7982c7ec..68180bb7 100644
--- a/src/app/services/statuses-state.service.ts
+++ b/src/app/services/statuses-state.service.ts
@@ -1,11 +1,13 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
+import { StatusWrapper } from '../models/common.model';
@Injectable({
providedIn: 'root'
})
export class StatusesStateService {
+ private cachedStatusText: { [statusId: string]: string } = {};
private cachedStatusStates: { [statusId: string]: { [accountId: string]: StatusState } } = {};
public stateNotification = new Subject();
@@ -62,6 +64,34 @@ export class StatusesStateService {
this.stateNotification.next(this.cachedStatusStates[statusId][accountId]);
}
+
+ setStatusContent(data: string, replyingToStatus: StatusWrapper){
+ if(replyingToStatus){
+ this.cachedStatusText[replyingToStatus.status.uri] = data;
+ } else {
+ this.cachedStatusText['none'] = data;
+ }
+ }
+
+ getStatusContent(replyingToStatus: StatusWrapper): string{
+ let data: string;
+ if(replyingToStatus){
+ data = this.cachedStatusText[replyingToStatus.status.uri];
+ } else {
+ data = this.cachedStatusText['none'];
+ }
+
+ if(!data) return '';
+ return data;
+ }
+
+ resetStatusContent(replyingToStatus: StatusWrapper){
+ if(replyingToStatus){
+ this.cachedStatusText[replyingToStatus.status.uri] = '';
+ } else {
+ this.cachedStatusText['none'] = '';
+ }
+ }
}
export class StatusState {
diff --git a/src/assets/img/arrow_1.png b/src/assets/img/arrow_1.png
index f74cd353..3e2615f7 100644
Binary files a/src/assets/img/arrow_1.png and b/src/assets/img/arrow_1.png differ
diff --git a/src/assets/img/arrow_2.png b/src/assets/img/arrow_2.png
index 6946ad86..f949e514 100644
Binary files a/src/assets/img/arrow_2.png and b/src/assets/img/arrow_2.png differ