1
Fork 0
mirror of https://github.com/pds-nest/nest.git synced 2024-11-21 20:44:18 +00:00

💥 Refactor even more...

This commit is contained in:
Steffo 2021-05-22 04:32:47 +02:00
parent c9cf2a1142
commit 919cbefd0f
Signed by: steffo
GPG key ID: 6965406171929D01
12 changed files with 244 additions and 239 deletions

View file

@ -2,7 +2,7 @@ import React from "react"
import BoxFull from "../base/BoxFull"
import useRepositoryViewer from "../../hooks/useRepositoryViewer"
import useStrings from "../../hooks/useStrings"
import { ContainsFilter } from "../../utils/Filter"
import { FilterContains } from "../../utils/Filter"
import FormInlineText from "./FormInlineText"
import { faFont } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
@ -13,7 +13,7 @@ export default function BoxFilterContains({ ...props }) {
const { appendFilter } = useRepositoryViewer()
const submit = value => {
appendFilter(new ContainsFilter(false, value))
appendFilter(new FilterContains(false, value))
}
// TODO: add this string

View file

@ -3,7 +3,7 @@ import BoxFull from "../base/BoxFull"
import { faClock, faHashtag } from "@fortawesome/free-solid-svg-icons"
import useRepositoryViewer from "../../hooks/useRepositoryViewer"
import useStrings from "../../hooks/useStrings"
import { AfterDatetimeFilter } from "../../utils/Filter"
import { FilterInsideTimeRay } from "../../utils/Filter"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import FormInlineBADatetime from "./FormInlineBADatetime"
@ -13,7 +13,7 @@ export default function BoxFilterDatetime({ ...props }) {
const { appendFilter } = useRepositoryViewer()
const submit = ({ date, isBefore }) => {
appendFilter(new AfterDatetimeFilter(isBefore, date))
appendFilter(new FilterInsideTimeRay(isBefore, date))
}
return (

View file

@ -5,7 +5,7 @@ import useRepositoryViewer from "../../hooks/useRepositoryViewer"
import useStrings from "../../hooks/useStrings"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faLocationArrow, faPlus } from "@fortawesome/free-solid-svg-icons"
import { HasPlaceFilter } from "../../utils/Filter"
import { FilterWithPlace } from "../../utils/Filter"
import ButtonIconOnly from "../base/ButtonIconOnly"
@ -15,7 +15,7 @@ export default function BoxFilterHasPlace({ ...props }) {
const { appendFilter } = useRepositoryViewer()
const submit = () => {
appendFilter(new HasPlaceFilter(false))
appendFilter(new FilterWithPlace(false))
}
// TODO: translate this

View file

@ -3,7 +3,7 @@ import BoxFull from "../base/BoxFull"
import { faClock } from "@fortawesome/free-solid-svg-icons"
import useRepositoryViewer from "../../hooks/useRepositoryViewer"
import useStrings from "../../hooks/useStrings"
import { HashtagFilter } from "../../utils/Filter"
import { FilterHashtag } from "../../utils/Filter"
import FormInlineHashtag from "./FormInlineHashtag"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
@ -13,7 +13,7 @@ export default function BoxFilterHashtag({ ...props }) {
const { appendFilter } = useRepositoryViewer()
const submit = value => {
appendFilter(new HashtagFilter(false, value))
appendFilter(new FilterHashtag(false, value))
}
return (

View file

@ -6,7 +6,7 @@ import useStrings from "../../hooks/useStrings"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faMapPin } from "@fortawesome/free-solid-svg-icons"
import FormInlineLocation from "./FormInlineLocation"
import { LocationRadiusFilter } from "../../utils/Filter"
import { FilterInsideMapArea } from "../../utils/Filter"
export default function BoxFilterLocation({ ...props }) {
@ -15,7 +15,7 @@ export default function BoxFilterLocation({ ...props }) {
const { appendFilter, mapViewHook } = useRepositoryViewer()
const submit = () => {
appendFilter(new LocationRadiusFilter(false, mapViewHook.center, mapViewHook.radius))
appendFilter(new FilterInsideMapArea(false, mapViewHook.center, mapViewHook.radius))
}
return (

View file

@ -3,7 +3,7 @@ import BoxFull from "../base/BoxFull"
import { faAt } from "@fortawesome/free-solid-svg-icons"
import useRepositoryViewer from "../../hooks/useRepositoryViewer"
import useStrings from "../../hooks/useStrings"
import { UserFilter } from "../../utils/Filter"
import { FilterPoster } from "../../utils/Filter"
import FormInlineUser from "./FormInlineUser"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
@ -16,7 +16,7 @@ export default function BoxFilterUser({ ...props }) {
const { appendFilter } = useRepositoryViewer()
const submit = value => {
appendFilter(new UserFilter(false, value))
appendFilter(new FilterPoster(false, value))
}
return (

View file

@ -4,7 +4,7 @@ import ContextLanguage from "../../contexts/ContextLanguage"
import BoxFull from "../base/BoxFull"
import Empty from "./Empty"
import ContextRepositoryViewer from "../../contexts/ContextRepositoryViewer"
import { ContainsFilter } from "../../utils/Filter"
import { FilterContains } from "../../utils/Filter"
export default function BoxVisualizationWordcloud({ ...props }) {
@ -20,7 +20,7 @@ export default function BoxVisualizationWordcloud({ ...props }) {
}
const onWordClick = word => {
appendFilter(new ContainsFilter(false, word.text))
appendFilter(new FilterContains(false, word.text))
}
return (

View file

@ -0,0 +1,222 @@
import {
faAt,
faClock,
faFilter,
faFont,
faHashtag,
faLocationArrow,
faMapMarkerAlt,
faMapPin,
} from "@fortawesome/free-solid-svg-icons"
/**
* A filter applicable in the Analysis mode.
*/
export class Filter {
negate
/**
* @param negate - If the filter output should be reversed.
*/
constructor(negate = false) {
this.negate = negate
}
/**
* Check if a tweet passed through the filter or not, without applying `negate`.
*
* @param tweet - The tweet to check.
* @returns {boolean}
*/
check(tweet) {
return true
}
/**
* Check if a tweet passed through the filter or not, applying `negate`.
*
* @param tweet - The tweet to check.
* @returns {boolean}
*/
exec(tweet) {
return Boolean(this.check(tweet) ^ this.negate)
}
display() {
return {
color: "Grey",
icon: faFilter,
children: this.negate ? "False" : "True"
}
}
}
/**
* Checks if a tweet contains a string.
*/
export class FilterContains extends Filter {
string
constructor(word, negate = false) {
super(negate)
this.string = word.toLowerCase().trim()
}
check(tweet) {
return tweet.content?.toLowerCase().includes(this.string)
}
display() {
return {
color: "Grey",
icon: faFont,
children: this.string
}
}
}
/**
* Check if a tweet contains an hashtag.
*/
export class FilterHashtag extends FilterContains {
hashtag
constructor(hashtag, negate = false) {
super(negate, `#${hashtag}`)
this.hashtag = hashtag
}
display() {
return {
color: "Grey",
icon: faHashtag,
children: this.hashtag
}
}
}
/**
* Check if a tweet was posted by a certain user.
*/
export class FilterPoster extends Filter {
poster
constructor(poster, negate = false) {
super(negate)
this.poster = poster
}
check(tweet) {
return tweet.poster.toLowerCase() === this.poster.toLowerCase()
}
display() {
return {
color: "Green",
icon: faAt,
children: this.poster
}
}
}
/**
* Check if a tweet contains `location` metadata.
*/
export class FilterWithLocation extends Filter {
constructor(negate = false) {
super(negate)
}
check(tweet) {
return Boolean(tweet["location"])
}
display() {
return {
color: "Red",
icon: faLocationArrow,
children: ""
}
}
}
/**
* Check if a tweet contains `place` metadata.
*/
export class FilterWithPlace extends Filter {
constructor(negate = false) {
super(negate)
}
check(tweet) {
return Boolean(tweet["place"])
}
display() {
return {
color: "Red",
icon: faMapMarkerAlt,
children: ""
}
}
}
/**
* Check if a tweet's `location` is inside a {@link MapArea}.
*/
export class FilterInsideMapArea extends FilterWithLocation {
mapArea
constructor(mapArea, negate = false) {
super(negate)
this.mapArea = mapArea
}
check(tweet) {
if(!super.check(tweet)) {
return false
}
return this.mapArea.includes(tweet.location)
}
display() {
return {
color: "Red",
icon: faLocationArrow,
children: this.mapArea.toHumanString()
}
}
}
/**
* Check if a tweet's `post_time` is inside a {@link TimeRay}.
*/
export class FilterInsideTimeRay extends Filter {
timeRay
constructor(timeRay, negate = false) {
super(negate)
this.timeRay = timeRay
}
check(tweet) {
return this.datetime < new Date(tweet["insert_time"])
}
display() {
return {
color: "Yellow",
icon: faClock,
children: this.timeRay.toString()
}
}
}

View file

@ -36,7 +36,7 @@ export default class MapArea {
* @returns {string}
*/
toString() {
return `${this.radius} ${this.center.toString()}`
return `< ${this.radius} ${this.center.toString()}`
}
/**
@ -47,9 +47,9 @@ export default class MapArea {
toHumanString() {
if(this.radius >= 2000) {
const kmRadius = Math.round(this.radius / 1000)
return `${kmRadius}km ${this.center.toHumanString()}`
return `< ${kmRadius}km ${this.center.toHumanString()}`
}
return `${this.radius}m ${this.center.toHumanString()}`
return `< ${this.radius}m ${this.center.toHumanString()}`
}
/**

View file

@ -9,5 +9,5 @@ test("MapArea can be constructed", () => {
test("MapArea can be rendered to a spec-compatible string", () => {
const mapArea = new MapArea(1000, new Coordinates(0.0, 0.0))
expect(mapArea.toString()).toBe("1000 0.0000000 0.0000000")
expect(mapArea.toString()).toBe("< 1000 0.0000000 0.0000000")
})

View file

@ -21,4 +21,8 @@ export default class TimeRay {
toString() {
return `${this.isBefore ? "<" : ">"} ${this.date.toISOString()}`
}
includes(date) {
return Boolean((this.date > date) ^ this.isBefore)
}
}

View file

@ -1,221 +0,0 @@
import { Location } from "./location"
import {
faAt,
faClock,
faFilter,
faFont,
faHashtag,
faLocationArrow,
faMapMarkerAlt,
faMapPin,
} from "@fortawesome/free-solid-svg-icons"
export class Filter {
negate
constructor(negate) {
this.negate = negate
}
check(tweet) {
return true
}
exec(tweet) {
return this.check(tweet) ^ this.negate
}
color() {
return "Grey"
}
icon() {
return faFilter
}
text() {
return this.negate ? "False" : "True"
}
}
export class ContainsFilter extends Filter {
word
constructor(negate, word) {
super(negate)
this.word = word.toLowerCase().trim()
}
check(tweet) {
return tweet.content?.toLowerCase().includes(this.word)
}
color() {
return "Grey"
}
icon() {
return faFont
}
text() {
return this.word
}
}
export class HashtagFilter extends ContainsFilter {
hashtag
constructor(negate, hashtag) {
super(negate, `#${hashtag}`)
this.hashtag = hashtag
}
icon() {
return faHashtag
}
text() {
return this.hashtag
}
}
export class UserFilter extends Filter {
user
constructor(negate, user) {
super(negate)
this.user = user.toLowerCase().trim().replace(/^@/, "")
}
check(tweet) {
return tweet.poster.toLowerCase() === this.user
}
color() {
return "Green"
}
icon() {
return faAt
}
text() {
return this.user
}
}
export class HasLocationFilter extends Filter {
constructor(negate) {
super(negate)
}
check(tweet) {
return Boolean(tweet["location"])
}
color() {
return "Red"
}
icon() {
return faMapMarkerAlt
}
text() {
return ""
}
}
export class HasPlaceFilter extends Filter {
constructor(negate) {
super(negate)
}
check(tweet) {
return Boolean(tweet["place"])
}
color() {
return "Red"
}
icon() {
return faLocationArrow
}
text() {
return ""
}
}
export class LocationRadiusFilter extends HasLocationFilter {
center
radius
constructor(negate, center, radius) {
super(negate)
this.center = center
this.radius = radius
}
check(tweet) {
if(!super.check(tweet)) {
return false
}
// FIXME: Maths is hard
const location = Location.fromTweet(tweet)
const latDiff = Math.abs(location.lat - this.center.lat)
const lngDiff = Math.abs(location.lng - this.center.lng)
const squaredDistance = Math.pow(latDiff, 2) + Math.pow(lngDiff, 2)
const squaredRadius = Math.pow(this.radius, 2)
return squaredDistance < squaredRadius
}
color() {
return "Red"
}
icon() {
return faMapPin
}
text() {
return `< ${this.radius}m ${this.center.lat.toFixed(3)} ${this.center.lng.toFixed(3)}`
}
}
export class AfterDatetimeFilter extends Filter {
datetime
constructor(negate, datetime) {
super(negate)
this.datetime = datetime
}
check(tweet) {
return this.datetime < new Date(tweet["insert_time"])
}
color() {
return "Yellow"
}
icon() {
return faClock
}
text() {
return `${this.negate ? "<" : ">"} ${this.datetime.toISOString()}`
}
}