More types!

This commit is contained in:
Lalle 2023-04-16 04:30:46 +02:00
parent 12483e97c5
commit fbc329add3
No known key found for this signature in database
GPG Key ID: A6583D207A8F6B0D
6 changed files with 172 additions and 126 deletions

View File

@ -1,16 +1,20 @@
import { Conf, g } from '../globals/globals'
import $ from '../platform/$'
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
var Get = {
import type Thread from '../classes/Thread'
import type Post from '../classes/Post'
interface Get {
url(type: any, IDs: { siteID: string }, ...args: any[]): string | undefined
threadExcerpt(thread: Thread): string
threadFromRoot(root: HTMLElement): Thread | null
threadFromNode(node: HTMLElement): Thread | null
postFromRoot(root: HTMLElement): Post | null
postFromNode(root: HTMLElement): Post | null
allQuotelinksLinkingTo(post: Post): HTMLAnchorElement[]
postDataFromLink(link: HTMLAnchorElement): { boardID: string; postID: number }
}
var Get: Get = {
url(type, IDs, ...args) {
let f, site
let f: ((IDs: { siteID: string }, ...args: any[]) => string) | undefined, site: typeof g.sites[0]
if ((site = g.sites[IDs.siteID]) && (f = $.getOwn(site.urls, type))) {
return f(IDs, ...Array.from(args))
} else {
@ -43,7 +47,7 @@ var Get = {
},
threadFromNode(node) {
return Get.threadFromRoot(
$.x(`ancestor-or-self::${g.SITE.xpath.thread}`, node),
$.x(`ancestor-or-self::${g.SITE.xpath.threadContainer}[1]`, node)[0],
)
},
postFromRoot(root) {
@ -60,20 +64,23 @@ var Get = {
},
postFromNode(root) {
return Get.postFromRoot(
$.x(`ancestor-or-self::${g.SITE.xpath.postContainer}[1]`, root),
$.x(`ancestor-or-self::${g.SITE.xpath.postContainer}`, root)[0],
)
},
postDataFromLink(link) {
let boardID, postID, threadID
if (link.dataset.postID) {
postDataFromLink(link: any) {
let boardID: any, postID: any, threadID: any
if (link.dataset?.postID) {
// resurrected quote
;({ boardID, threadID, postID } = link.dataset)
({ boardID, threadID, postID } = link.dataset)
if (!threadID) {
threadID = 0
threadID = '0'
}
} else {
const match = link.href.match(g.SITE.regexp.quotelink)
;[boardID, threadID, postID] = Array.from(match.slice(1))
const match = link.href.match(g?.SITE?.regexp?.quotelink)
if (!match) {
throw new Error('Invalid link')
}
[boardID, threadID, postID] = match.slice(1)
if (!postID) {
postID = threadID
}
@ -83,7 +90,7 @@ var Get = {
threadID: +threadID,
postID: +postID,
}
},
},
allQuotelinksLinkingTo(post) {
// Get quotelinks & backlinks linking to the given post.
const quotelinks = []

View File

@ -1,37 +0,0 @@
import BoardConfig from '../General/BoardConfig'
import { d, g } from '../globals/globals'
import SimpleDict from './SimpleDict'
export default class Board {
toString() {
return this.ID
}
constructor(ID) {
this.ID = ID
this.boardID = this.ID
this.siteID = g.SITE.ID
this.threads = new SimpleDict()
this.posts = new SimpleDict()
this.config = BoardConfig.boards?.[this.ID] || {}
g.boards[this.ID] = this
}
cooldowns() {
const c2 = (this.config || {}).cooldowns || {}
const c = {
thread: c2.threads || 0,
reply: c2.replies || 0,
image: c2.images || 0,
thread_global: 300, // inter-board thread cooldown
}
// Pass users have reduced cooldowns.
if (d.cookie.indexOf('pass_enabled=1') >= 0) {
for (var key of ['reply', 'image']) {
c[key] = Math.ceil(c[key] / 2)
}
}
return c
}
}

46
src/classes/Board.ts Normal file
View File

@ -0,0 +1,46 @@
import BoardConfig from '../General/BoardConfig';
import { d, g } from '../globals/globals';
import Post from './Post';
import Thread from './Thread';
import SimpleDict from './SimpleDict';
export default class Board {
ID: string;
boardID: string;
siteID: string;
threads: SimpleDict<Thread>;
posts: SimpleDict<Post>;
config: any;
constructor(ID: string) {
this.ID = ID;
this.boardID = this.ID;
this.siteID = g.SITE.ID;
this.threads = new SimpleDict();
this.posts = new SimpleDict();
this.config = BoardConfig.domain(this.ID)
g.boards[this.ID] = this;
}
toString() {
return this.ID;
}
cooldowns() {
const c2 = (this.config || {}).cooldowns || {};
const c = {
thread: c2.threads || 0,
reply: c2.replies || 0,
image: c2.images || 0,
thread_global: 300, // inter-board thread cooldown
};
// Pass users have reduced cooldowns.
if (d.cookie.indexOf('pass_enabled=1') >= 0) {
for (let key of ['reply', 'image']) {
c[key] = Math.ceil(c[key] / 2);
}
}
return c;
}
}

View File

@ -1,59 +0,0 @@
import Main from '../main/Main'
export default class Callbacks {
static initClass() {
this.Post = new Callbacks('Post')
this.Thread = new Callbacks('Thread')
this.CatalogThread = new Callbacks('Catalog Thread')
this.CatalogThreadNative = new Callbacks('Catalog Thread')
}
constructor(type) {
this.type = type
this.keys = []
}
push({ name, cb }) {
if (!this[name]) {
this.keys.push(name)
}
return (this[name] = cb)
}
execute(node, keys = this.keys, force = false) {
let errors
if (node.callbacksExecuted && !force) {
return
}
node.callbacksExecuted = true
for (var name of keys) {
try {
this[name]?.call(node)
} catch (err) {
if (!errors) {
errors = []
}
errors.push({
message: [
'"',
name,
'" crashed on node ',
this.type,
' No.',
node.ID,
' (',
node.board,
').',
].join(''),
error: err,
html: node.nodes?.root?.outerHTML,
})
}
}
if (errors) {
return Main.handleErrors(errors)
}
}
}
Callbacks.initClass()

68
src/classes/Callbacks.ts Normal file
View File

@ -0,0 +1,68 @@
import Main from '../main/Main';
export default class Callbacks {
private type: string;
private keys: string[];
static Post: Callbacks;
static Thread: Callbacks;
static CatalogThread: Callbacks;
static CatalogThreadNative: Callbacks;
static initClass() {
this.Post = new Callbacks('Post');
this.Thread = new Callbacks('Thread');
this.CatalogThread = new Callbacks('Catalog Thread');
this.CatalogThreadNative = new Callbacks('Catalog Thread');
}
constructor(type: string) {
this.type = type;
this.keys = [];
}
push({ name, cb }: { name: string; cb: () => void }) {
if (!this[name]) {
this.keys.push(name);
}
return (this[name] = cb);
}
execute(node: any, keys = this.keys, force = false) {
let errors: any[];
if (node.callbacksExecuted && !force) {
return;
}
node.callbacksExecuted = true;
for (let name of keys) {
try {
this[name]?.call(node);
} catch (err: any) {
if (!errors) {
errors = [];
}
errors.push({
message: [
'"',
name,
'" crashed on node ',
this.type,
' No.',
node.ID,
' (',
node.board,
').',
].join(''),
error: err,
html: node.nodes?.root?.outerHTML,
});
}
}
if (errors) {
return Main.handleErrors(errors);
}
}
}
Callbacks.initClass();

View File

@ -1,6 +1,7 @@
import SimpleDict from './SimpleDict'
import $ from '../platform/$'
import { g } from '../globals/globals'
import Post from './Post'
/*
* decaffeinate suggestions:
@ -8,15 +9,35 @@ import { g } from '../globals/globals'
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
export default class Thread {
board: string
ID: number
threadID: number
boardID: string
siteID: string
fullID: string
posts: SimpleDict<Post>
isDead: boolean
isHidden: boolean
isSticky: boolean
isClosed: boolean
isArchived: boolean
postLimit: boolean
fileLimit: boolean
lastPost: number
ipCount: undefined
json: null | any
OP: null | Post
catalogView: null | any
nodes: { root: null | HTMLElement }
toString() {
return this.ID
}
constructor(ID, board) {
constructor(ID: string, board: string) {
this.board = board
this.ID = +ID
this.threadID = this.ID
this.boardID = this.board.ID
this.boardID = g.BOARD.ID
this.siteID = g.SITE.ID
this.fullID = `${this.board}.${this.ID}`
this.posts = new SimpleDict()
@ -40,8 +61,8 @@ export default class Thread {
g.threads.push(this.fullID, this)
}
setPage(pageNum) {
let icon
setPage(pageNum: number): void {
let icon: HTMLElement | null
const { info, reply } = this.OP.nodes
if (!(icon = $('.page-num', info))) {
icon = $.el('span', { className: 'page-num' })
@ -54,7 +75,7 @@ export default class Thread {
}
}
setCount(type, count, reachedLimit) {
setCount(type: string, count: number, reachedLimit: boolean): void {
if (!this.catalogView) {
return
}
@ -63,7 +84,7 @@ export default class Thread {
return (reachedLimit ? $.addClass : $.rmClass)(el, 'warning')
}
setStatus(type, status) {
setStatus(type: string, status: boolean): void {
const name = `is${type}`
if (this[name] === status) {
return
@ -77,7 +98,7 @@ export default class Thread {
return this.setIcon('Archived', this.isArchived)
}
setIcon(type, status) {
setIcon(type: string, status: boolean): void {
const typeLC = type.toLowerCase()
let icon = $(`.${typeLC}Icon`, this.OP.nodes.info)
if (!!icon === status) {
@ -117,11 +138,11 @@ export default class Thread {
)
}
kill() {
kill(): boolean {
return (this.isDead = true)
}
collect() {
collect(): boolean {
let n = 0
this.posts.forEach(function (post) {
if (post.clones.length) {
@ -132,7 +153,7 @@ export default class Thread {
})
if (!n) {
g.threads.rm(this.fullID)
return this.board.threads.rm(this)
return this.board.threads.rm(this.ID)
}
}
}