Merge pull request #257 from NicolasConstant/fix_infinity-scroll-spam

Fix infinity scroll spam
This commit is contained in:
Nicolas Constant 2020-04-18 18:42:57 -04:00 committed by GitHub
commit 9c53010ae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 31 additions and 16 deletions

View File

@ -91,6 +91,10 @@ export class SearchComponent implements OnInit {
this.accounts = results.accounts.slice(0, 5);
this.hashtags = results.hashtags;
if(!this.hashtags.map(x => x.toLowerCase()).includes(data.toLowerCase())){
this.hashtags.unshift(data);
}
for (let status of results.statuses) {
let cwPolicy = this.toolsService.checkContentWarning(status);
const statusWrapper = new StatusWrapper(cwPolicy.status, this.lastAccountUsed, cwPolicy.applyCw, cwPolicy.hide);

View File

@ -1,9 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatabindedTextComponent } from './databinded-text.component';
import { By } from '@angular/platform-browser';
import { isGeneratedFile } from '@angular/compiler/src/aot/util';
import { tick } from '@angular/core/src/render3';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
describe('DatabindedTextComponent', () => {
let component: DatabindedTextComponent;
@ -11,7 +9,8 @@ describe('DatabindedTextComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DatabindedTextComponent]
declarations: [DatabindedTextComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
@ -42,6 +41,14 @@ describe('DatabindedTextComponent', () => {
expect(component.processedText).toContain('bla2');
});
it('should parse hashtag - Pleroma 2.0.2', () => {
const sample = `Blabla <a class="hashtag" data-tag="covid19" href="https://url.com/tag/covid19">#covid19</a> Blibli`;
component.text = sample;
expect(component.processedText).toContain('<a href class="hashtag-covid19" title="#covid19">#covid19</a>');
expect(component.processedText).toContain('Blabla');
expect(component.processedText).toContain('Blibli');
});
it('should parse mention', () => {
const mention = 'sengi_app';
const url = 'https://mastodon.social/@sengi_app';

View File

@ -28,11 +28,11 @@ export class DatabindedTextComponent implements OnInit {
@Input('text')
set text(value: string) {
//console.warn(value);
let parser = new DOMParser();
var dom = parser.parseFromString(value, 'text/html')
this.isCollapsed = [...dom.body.textContent].length > 500;
//console.warn(this.isCollapsed);
this.processedText = '';
@ -52,7 +52,7 @@ export class DatabindedTextComponent implements OnInit {
continue;
}
if (section.includes('class="mention hashtag"') || section.includes('target="_blank">#') || section.includes('rel="tag">')) {
if (section.includes('class="mention hashtag"') || section.includes('class="hashtag"') || section.includes('target="_blank">#') || section.includes('rel="tag">')) {
try {
this.processHashtag(section);
}

View File

@ -19,6 +19,7 @@ import { StatusWrapper } from '../../../models/common.model';
})
export class StreamStatusesComponent implements OnInit, OnDestroy {
isLoading = true;
private lastInfinityFetchReturnedNothing = false;
isThread = false;
displayError: string;
hasContentWarnings = false;
@ -255,7 +256,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
}
private scrolledToBottom() {
if (this.isLoading) return;
if (this.isLoading || this.lastInfinityFetchReturnedNothing) return;
this.isLoading = true;
this.isProcessingInfiniteScroll = true;
@ -272,6 +273,10 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
const wrapper = new StatusWrapper(cwPolicy.status, this.account, cwPolicy.applyCw, cwPolicy.hide);
this.statuses.push(wrapper);
}
if(!status || status.length === 0){
this.lastInfinityFetchReturnedNothing = true;
}
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err, this.account);
@ -318,6 +323,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
private checkAndCleanUpStream(): void {
if (this.streamPositionnedAtTop && this.statuses.length > 3 * this.streamingService.nbStatusPerIteration) {
this.statuses.length = 2 * this.streamingService.nbStatusPerIteration;
this.lastInfinityFetchReturnedNothing = false;
}
if (this.bufferStream.length > 3 * this.streamingService.nbStatusPerIteration) {

View File

@ -133,10 +133,9 @@ export class ThreadComponent implements OnInit, OnDestroy {
const sourceAccount = openThreadEvent.sourceAccount;
if (status.visibility === 'public' || status.visibility === 'unlisted') {
var statusPromise: Promise<Status> = Promise.resolve(status);
if (!sourceAccount || sourceAccount.id !== currentAccount.id) {
statusPromise = this.toolsService.getInstanceInfo(currentAccount)
// var statusPromise: Promise<Status> = Promise.resolve(status);
// if (!sourceAccount || sourceAccount.id !== currentAccount.id) {
var statusPromise = this.toolsService.getInstanceInfo(currentAccount)
.then(instance => {
let version: 'v1' | 'v2' = 'v1';
if (instance.major >= 3) version = 'v2';
@ -149,7 +148,7 @@ export class ThreadComponent implements OnInit, OnDestroy {
}
throw new Error('could not find status');
});
}
// }
this.retrieveThread(currentAccount, statusPromise);

View File

@ -215,9 +215,7 @@
</div>
<div *ngIf="statusSection === 'media'" class="status-media">
<div *ngFor="let media of statusWrapper.status.media_attachments">
<a href title="open" (click)="openAttachment(media)">
<img class="status-media__image" src="{{media.preview_url}}" />
</a>
<app-attachement-image *ngIf="media.type === 'image' || media.type === 'gifv'" class="status-media__image" [attachment]="media" (openEvent)="openAttachment(media)"></app-attachement-image>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { Component, OnInit, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { faUser, faHourglassHalf, faUserCheck, faExclamationTriangle } from "@fortawesome/free-solid-svg-icons";
import { faUser, faHourglassHalf, faUserCheck, faExclamationTriangle, faLink } from "@fortawesome/free-solid-svg-icons";
import { faUser as faUserRegular } from "@fortawesome/free-regular-svg-icons";
import { Observable, Subscription } from 'rxjs';
import { Store } from '@ngxs/store';
@ -27,6 +27,7 @@ export class UserProfileComponent implements OnInit {
faHourglassHalf = faHourglassHalf;
faUserCheck = faUserCheck;
faExclamationTriangle = faExclamationTriangle;
faLink = faLink;
displayedAccount: Account;
hasNote: boolean;