Add types to Post

This commit is contained in:
Tuxedo Takodachi 2023-03-31 19:02:10 +02:00
parent f1b998bd7c
commit 35eefa3d09

View File

@ -3,15 +3,48 @@ import { g, Conf } from "../globals/globals";
import ImageExpand from "../Images/ImageExpand"; import ImageExpand from "../Images/ImageExpand";
import $ from "../platform/$"; import $ from "../platform/$";
import $$ from "../platform/$$"; import $$ from "../platform/$$";
import type Board from "./Board";
import Callbacks from "./Callbacks"; import Callbacks from "./Callbacks";
import type Thread from "./Thread";
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS206: Consider reworking classes to avoid initClass
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
export default class Post { export default class Post {
declare root: HTMLElement;
declare thread: Thread;
declare board: Board;
declare ID: number;
declare postID: number;
declare threadID: number;
declare boardID: number | string;
declare siteID: number | string;
declare fullID: string;
declare context: Post;
declare isReply: boolean
declare nodes: ReturnType<Post['parseNodes']>;
declare isDead: boolean;
declare isHidden: boolean;
declare clones: any[];
declare isRebuilt?: boolean;
declare isFetchedQuote: boolean;
declare isClone: boolean;
declare quotes: string[];
declare file: ReturnType<Post['parseFile']>;
declare files: ReturnType<Post['parseFile']>[];
declare info: {
subject: string | undefined,
name: string | undefined,
email: string | undefined,
tripcode: string | undefined,
uniqueID: string | undefined,
capcode: string | undefined,
pass: string | undefined,
flagCode: string | undefined,
flagCodeTroll: string | undefined,
flag: string | undefined,
date: Date | undefined,
nameBlock: string,
};
// because of a circular dependency $ might not be initialized, so we can't use $.el // because of a circular dependency $ might not be initialized, so we can't use $.el
static deadMark = (() => { static deadMark = (() => {
const el = document.createElement('span'); const el = document.createElement('span');
@ -23,7 +56,7 @@ export default class Post {
toString() { return this.ID; } toString() { return this.ID; }
constructor(root, thread, board, flags={}) { constructor(root?: HTMLElement, thread?: Thread, board?: Board, flags={}) {
// <% if (readJSON('/.tests_enabled')) { %> // <% if (readJSON('/.tests_enabled')) { %>
// @normalizedOriginal = Test.normalize root // @normalizedOriginal = Test.normalize root
// <% } %> // <% } %>
@ -73,14 +106,10 @@ export default class Post {
flagCode: this.nodes.flag?.className.match(/flag-(\w+)/)?.[1].toUpperCase(), flagCode: this.nodes.flag?.className.match(/flag-(\w+)/)?.[1].toUpperCase(),
flagCodeTroll: this.nodes.flag?.className.match(/bfl-(\w+)/)?.[1].toUpperCase(), flagCodeTroll: this.nodes.flag?.className.match(/bfl-(\w+)/)?.[1].toUpperCase(),
flag: this.nodes.flag?.title, flag: this.nodes.flag?.title,
date: this.nodes.date ? g.SITE.parseDate(this.nodes.date) : undefined date: this.nodes.date ? g.SITE.parseDate(this.nodes.date) : undefined,
nameBlock: Conf['Anonymize'] ? 'Anonymous' : `${this.info.name || ''} ${this.info.tripcode || ''}`.trim(),
}; };
if (Conf['Anonymize']) {
this.info.nameBlock = 'Anonymous';
} else {
this.info.nameBlock = `${this.info.name || ''} ${this.info.tripcode || ''}`.trim();
}
if (this.info.capcode) { this.info.nameBlock += ` ## ${this.info.capcode}`; } if (this.info.capcode) { this.info.nameBlock += ` ## ${this.info.capcode}`; }
if (this.info.uniqueID) { this.info.nameBlock += ` (ID: ${this.info.uniqueID})`; } if (this.info.uniqueID) { this.info.nameBlock += ` (ID: ${this.info.uniqueID})`; }
@ -110,11 +139,26 @@ export default class Post {
this.isClone = false; this.isClone = false;
} }
parseNodes(root) { parseNodes(root: HTMLElement) {
const s = g.SITE.selectors; const s = g.SITE.selectors;
const post = $(s.post, root) || root; const post: HTMLElement = $(s.post, root) || root;
const info = $(s.infoRoot, post); const info: HTMLElement = $(s.infoRoot, post);
const nodes = {
interface Node {
root: HTMLElement,
bottom: false | HTMLElement,
post: HTMLElement,
info: HTMLElement,
comment: HTMLElement;
quotelinks: HTMLAnchorElement[],
archivelinks: HTMLAnchorElement[],
embedlinks: HTMLAnchorElement[],
backlinks: HTMLCollectionOf<HTMLAnchorElement>;
uniqueIDRoot: any,
uniqueID: any,
};
const nodes: Node & Partial<Record<keyof Post['info'], HTMLElement>> = {
root, root,
bottom: this.isReply || !g.SITE.isOPContainerThread ? root : $(s.opBottom, root), bottom: this.isReply || !g.SITE.isOPContainerThread ? root : $(s.opBottom, root),
post, post,
@ -122,7 +166,10 @@ export default class Post {
comment: $(s.comment, post), comment: $(s.comment, post),
quotelinks: [], quotelinks: [],
archivelinks: [], archivelinks: [],
embedlinks: [] embedlinks: [],
backlinks: post.getElementsByClassName('backlink') as HTMLCollectionOf<HTMLAnchorElement>,
uniqueIDRoot: undefined as any,
uniqueID: undefined as any,
}; };
for (var key in s.info) { for (var key in s.info) {
var selector = s.info[key]; var selector = s.info[key];
@ -131,20 +178,7 @@ export default class Post {
g.SITE.parseNodes?.(this, nodes); g.SITE.parseNodes?.(this, nodes);
if (!nodes.uniqueIDRoot) { nodes.uniqueIDRoot = nodes.uniqueID; } if (!nodes.uniqueIDRoot) { nodes.uniqueIDRoot = nodes.uniqueID; }
// XXX Edge invalidates HTMLCollections when an ancestor node is inserted into another node. return nodes as Node & Record<keyof Post['info'], HTMLElement>;
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7560353/
if ($.engine === 'edge') {
Object.defineProperty(nodes, 'backlinks', {
configurable: true,
enumerable: true,
get() { return post.getElementsByClassName('backlink'); }
}
);
} else {
nodes.backlinks = post.getElementsByClassName('backlink');
}
return nodes;
} }
parseComment() { parseComment() {
@ -224,7 +258,7 @@ export default class Post {
// ES6 Set when? // ES6 Set when?
const fullID = `${match[1]}.${match[3]}`; const fullID = `${match[1]}.${match[3]}`;
if (!this.quotes.includes(fullID)) { return this.quotes.push(fullID); } if (!this.quotes.includes(fullID)) this.quotes.push(fullID);
} }
parseFiles() { parseFiles() {
@ -253,13 +287,23 @@ export default class Post {
return [this.nodes.root]; return [this.nodes.root];
} }
parseFile(fileRoot) { parseFile(fileRoot: HTMLElement) {
const file = {}; interface File {
text: string,
link: HTMLAnchorElement,
thumb: HTMLElement,
thumbLink: HTMLElement,
size: string,
sizeInBytes: number,
isDead: boolean,
};
const file: Partial<File> = { isDead: false };
for (var key in g.SITE.selectors.file) { for (var key in g.SITE.selectors.file) {
var selector = g.SITE.selectors.file[key]; var selector = g.SITE.selectors.file[key];
file[key] = $(selector, fileRoot); file[key] = $(selector, fileRoot);
} }
file.thumbLink = file.thumb?.parentNode; file.thumbLink = file.thumb?.parentNode as HTMLElement;
if (!(file.text && file.link)) { return; } if (!(file.text && file.link)) { return; }
if (!g.SITE.parseFile(this, file)) { return; } if (!g.SITE.parseFile(this, file)) { return; }
@ -275,7 +319,7 @@ export default class Post {
while (unit-- > 0) { size *= 1024; } while (unit-- > 0) { size *= 1024; }
file.sizeInBytes = size; file.sizeInBytes = size;
return file; return file as File;
} }
kill(file, index=0) { kill(file, index=0) {
@ -344,7 +388,7 @@ export default class Post {
collect() { collect() {
g.posts.rm(this.fullID); g.posts.rm(this.fullID);
this.thread.posts.rm(this); this.thread.posts.rm(this);
return this.board.posts.rm(this); this.board.posts.rm(this);
} }
addClone(context, contractThumb) { addClone(context, contractThumb) {
@ -365,11 +409,13 @@ export default class Post {
this.nodes.root.classList.toggle('opContainer', !isCatalogOP); this.nodes.root.classList.toggle('opContainer', !isCatalogOP);
this.nodes.post.classList.toggle('catalog-post', isCatalogOP); this.nodes.post.classList.toggle('catalog-post', isCatalogOP);
this.nodes.post.classList.toggle('op', !isCatalogOP); this.nodes.post.classList.toggle('op', !isCatalogOP);
return this.nodes.post.style.left = (this.nodes.post.style.right = null); this.nodes.post.style.left = (this.nodes.post.style.right = null);
} }
}; };
export class PostClone extends Post { export class PostClone extends Post {
declare origin: Post;
static suffix = 0; static suffix = 0;
constructor(origin, context, contractThumb) { constructor(origin, context, contractThumb) {