diff --git a/src/General/Get.js b/src/General/Get.ts similarity index 69% rename from src/General/Get.js rename to src/General/Get.ts index 23e37d4..66a5de1 100644 --- a/src/General/Get.js +++ b/src/General/Get.ts @@ -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 = [] diff --git a/src/classes/Board.js b/src/classes/Board.js deleted file mode 100644 index e2add5c..0000000 --- a/src/classes/Board.js +++ /dev/null @@ -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 - } -} diff --git a/src/classes/Board.ts b/src/classes/Board.ts new file mode 100644 index 0000000..e95b5ab --- /dev/null +++ b/src/classes/Board.ts @@ -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; + posts: SimpleDict; + 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; + } +} diff --git a/src/classes/Callbacks.js b/src/classes/Callbacks.js deleted file mode 100644 index 9aa4463..0000000 --- a/src/classes/Callbacks.js +++ /dev/null @@ -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() diff --git a/src/classes/Callbacks.ts b/src/classes/Callbacks.ts new file mode 100644 index 0000000..1f8dc1f --- /dev/null +++ b/src/classes/Callbacks.ts @@ -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(); diff --git a/src/classes/Thread.js b/src/classes/Thread.ts similarity index 79% rename from src/classes/Thread.js rename to src/classes/Thread.ts index f730c69..09b19cb 100644 --- a/src/classes/Thread.js +++ b/src/classes/Thread.ts @@ -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 + 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) } } }