Skip to content

Commit

Permalink
Merge pull request #267 from NicolasConstant/develop
Browse files Browse the repository at this point in the history
0.27.0 PR
  • Loading branch information
NicolasConstant authored Apr 27, 2020
2 parents 11c6ef9 + 7dab421 commit 9eb6fc6
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 46 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sengi",
"version": "0.26.1",
"version": "0.27.0",
"license": "AGPL-3.0-or-later",
"main": "main-electron.js",
"description": "A multi-account desktop client for Mastodon and Pleroma",
Expand Down
28 changes: 28 additions & 0 deletions src/app/components/create-status/create-status.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,32 @@ describe('CreateStatusComponent', () => {
expect(result[1].length).toBeLessThanOrEqual(527);
expect(result[1]).toBe('http://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/');
});

it('should tranform external mentions properly - mastodon', () => {
let mastodonMention = '<p>test <span class="h-card"><a href="https://mastodon.social/@sengi_app" class="u-url mention">@<span>sengi_app</span></a></span> qsdqds qsd qsd qsd q <span class="h-card"><a href="https://mastodon.social/@test" class="u-url mention">@<span>test</span></a></span> <span class="h-card"><a href="https://mastodon.social/@no" class="u-url">@<span>no</span></a></span></p>';

const result = <string>(<any>component).tranformHtmlRepliesToReplies(mastodonMention);
expect(result).toBe('<p>test @[email protected] qsdqds qsd qsd qsd q @[email protected] <span class="h-card"><a href="https://mastodon.social/@no" class="u-url">@<span>no</span></a></span></p>');
});

it('should tranform external mentions properly - mastodon 2', () => {
let mastodonMention = '<p>test <span class="h-card"><a href="https://pleroma.site/users/sengi_app" class="u-url mention">@<span>sengi_app</span></a></span> qsdqds qsd qsd qsd q <span class="h-card"><a href="https://pleroma.site/users/test" class="u-url mention">@<span>test</span></a></span> <span class="h-card"><a href="https://pleroma.site/users/no" class="u-url">@<span>no</span></a></span></p>';

const result = <string>(<any>component).tranformHtmlRepliesToReplies(mastodonMention);
expect(result).toBe('<p>test @[email protected] qsdqds qsd qsd qsd q @[email protected] <span class="h-card"><a href="https://pleroma.site/users/no" class="u-url">@<span>no</span></a></span></p>');
});

it('should tranform external mentions properly - pleroma', () => {
let pleromaMention = '<p>test <span class="h-card"><a data-user="50504" class="u-url mention" href="https://mastodon.social/@sengi_app" rel="ugc">@<span>sengi_app</span></a></span> qsdqds qsd qsd qsd q <span class="h-card"><a data-user="50504" class="u-url mention" href="https://mastodon.social/@test" rel="ugc">@<span>test</span></a></span> <span class="h-card"><a href="https://mastodon.social/@no" class="u-url">@<span>no</span></a></span></p>';

const result = <string>(<any>component).tranformHtmlRepliesToReplies(pleromaMention);
expect(result).toBe('<p>test @[email protected] qsdqds qsd qsd qsd q @[email protected] <span class="h-card"><a href="https://mastodon.social/@no" class="u-url">@<span>no</span></a></span></p>');
});

it('should tranform external mentions properly - pleroma 2', () => {
let pleromaMention = '<p>test <span class="h-card"><a data-user="50504" class="u-url mention" href="https://pleroma.site/users/sengi_app" rel="ugc">@<span>sengi_app</span></a></span> qsdqds qsd qsd qsd q <span class="h-card"><a data-user="50504" class="u-url mention" href="https://pleroma.site/users/test" rel="ugc">@<span>test</span></a></span> <span class="h-card"><a href="https://pleroma.site/users/no" class="u-url">@<span>no</span></a></span></p>';

const result = <string>(<any>component).tranformHtmlRepliesToReplies(pleromaMention);
expect(result).toBe('<p>test @[email protected] qsdqds qsd qsd qsd q @[email protected] <span class="h-card"><a href="https://pleroma.site/users/no" class="u-url">@<span>no</span></a></span></p>');
});
});
76 changes: 58 additions & 18 deletions src/app/components/create-status/create-status.component.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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',
Expand Down Expand Up @@ -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;
Expand All @@ -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('<p>') || content.includes('</p>') || content.includes('<br>') || content.includes('<br/>') || content.includes('<br />')) {
content = content.replace('<p>', '').replace('</p>', newLine + newLine).replace('<br />', newLine).replace('<br/>', newLine).replace('<br>', 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;
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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() {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -810,4 +835,19 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
this.scheduleIsActive = !this.scheduleIsActive;
return false;
}

private tranformHtmlRepliesToReplies(data: string): string {
const mastodonMentionRegex = /<span class="h-card"><a href="https:\/\/([a-zA-Z0-9.]{0,255})\/[a-zA-Z0-9_@/-]{0,255}" class="u-url mention">@<span>([a-zA-Z0-9_-]{0,255})<\/span><\/a><\/span>/gmi;
const pleromaMentionRegex = /<span class="h-card"><a data-user="[a-zA-Z0-9]{0,255}" class="u-url mention" href="https:\/\/([a-zA-Z0-9.]{0,255})\/[a-zA-Z0-9_@/-]{0,255}" rel="ugc">@<span>([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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ export class NotificationsComponent implements OnInit, OnDestroy {
get account(): AccountWrapper {
return this._account;
}

@ViewChild('statusstream') public statustream: ElementRef;

private maxReached = false;
private _account: AccountWrapper;
private userNotificationServiceSub: Subscription;
private lastId: string;

constructor(
constructor(
private readonly toolsService: ToolsService,
private readonly notificationService: NotificationService,
private readonly userNotificationService: UserNotificationService,
Expand All @@ -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();
});
}

Expand All @@ -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);
}
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/tutorial/tutorial.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ <h3 class="open-account__title">Nice!</h3>
Now <span class="underline">right-click</span> on your avatar to open your account and be able to add some timelines!
</p>
</div>
<!-- </div> -->
<!-- </div> -->

<img class="sengi-logo" src="assets/icons/icon-384x384.png" />
15 changes: 11 additions & 4 deletions src/app/components/tutorial/tutorial.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -80,4 +80,11 @@
// word-break: break-all;
white-space: normal;
}
}

.sengi-logo {
width: 230px;
position: fixed;
bottom: 35px;
right: 10px;
}
Loading

0 comments on commit 9eb6fc6

Please sign in to comment.