types and fixes

This commit is contained in:
Lalle 2023-05-08 00:25:33 +02:00
parent 55dd58b8c6
commit 543ff3437b
No known key found for this signature in database
GPG Key ID: A6583D207A8F6B0D
16 changed files with 110 additions and 87 deletions

View File

@ -1,11 +1,6 @@
import { Conf, doc } from "../globals/globals"
import $ from "../platform/$"
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
const Anonymize = {
init() {
if (!Conf['Anonymize']) { return }

View File

@ -14,14 +14,6 @@ import QuoteYou from "../Quotelinks/QuoteYou"
import PostHiding from "./PostHiding"
import ThreadHiding from "./ThreadHiding"
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
interface FilterObj {
isstring: boolean;
@ -40,10 +32,6 @@ type FilterType = "postID" | "name" | "uniqueID" | "tripcode" | "capcode" | "pas
| "flag" | "filename" | "dimensions" | "filesize" | "MD5"
const Filter = {
/**
* Uses a Map for string types, with the value to filter for as the key.
* This allows faster lookup than iterating over every filter.
*/
filters: new Map<FilterType, FilterObj[] | Map<string, FilterObj[]>>(),
init(this: typeof Filter) {
@ -295,7 +283,7 @@ const Filter = {
if (!(url = g.SITE.urls.catalogJSON?.(g.BOARD))) { return }
Filter.catalogData = dict()
$.ajax(url,
{ onloadend: Filter.catalogParse })
{ onloadend: Filter.catalogParse }, this)
return Callbacks.CatalogThreadNative.push({
name: 'Filter',
cb: this.catalogNode

View File

@ -21,7 +21,7 @@ const PostHiding = {
$.addClass(doc, "reply-hide")
}
this.db = new DataBoard('hiddenPosts')
this.db = new DataBoard('hiddenPosts', true, false)
return Callbacks.Post.push({
name: 'Reply Hiding',
cb: this.node

View File

@ -14,7 +14,7 @@ import { dict } from "../platform/helpers"
const ThreadHiding = {
init() {
if (!['index', 'catalog'].includes(g.VIEW) || (!Conf['Thread Hiding Buttons'] && !(Conf['Menu'] && Conf['Thread Hiding Link']) && !Conf['JSON Index'])) { return }
this.db = new DataBoard('hiddenThreads')
this.db = new DataBoard('hiddenThreads', true)
if (g.VIEW === 'catalog') { return this.catalogWatch() }
this.catalogSet(g.BOARD)
$.on(d, 'IndexRefreshInternal', this.onIndexRefresh)

View File

@ -8,6 +8,45 @@ import { SECOND } from "../platform/helpers"
import type { File } from "../types/globals"
import ImageCommon from "./ImageCommon"
import Volume from "./Volume"
interface File {
isVideo: boolean;
isExpanding: boolean;
isExpanded: boolean;
url: string;
dimensions: string | null;
}
interface ImageHover {
error(post: Post, file: File): () => void;
}
interface ImageCommon {
cache?: HTMLElement & { dataset: { fileID: string } };
popCache(): HTMLElement;
rewind(el: HTMLElement): void;
pause(el: HTMLElement): void;
pushCache(el: HTMLElement): void;
}
interface Volume {
setup(el: HTMLVideoElement): void;
}
interface UI {
hover(params: {
root: HTMLElement;
el: HTMLElement;
latestEvent: MouseEvent;
endEvents: string;
height: number;
width: number;
noRemove: boolean;
cb: () => void;
}): void;
}
const ImageHover = {
init() {
if (!['index', 'thread'].includes(g.VIEW)) { return }
@ -42,23 +81,27 @@ const ImageHover = {
return $.on(this.nodes.thumb, 'mouseover', hover)
},
mouseover(post: Post, file: File) {
return function (e) {
let el, height, width
if (!doc.contains(this)) { return }
mouseover(post: Post, file: File): (e: MouseEvent) => void {
return function (e: MouseEvent) {
let el: HTMLElement, height: number, width: number
if (!doc.contains(this)) {
return
}
const { isVideo } = file
if (file.isExpanding || file.isExpanded || g.SITE.isThumbExpanded?.(file)) { return }
if (file.isExpanding || file.isExpanded || g.SITE.isThumbExpanded?.(file)) {
return
}
const error = ImageHover.error(this.post, file)
if (ImageCommon.cache?.dataset.fileID === `${post.fullID}.${file.index}`) {
el = ImageCommon.popCache()
$.on(el, 'error', error)
} else {
el = $.el((isVideo ? 'video' : 'img'), {
el = $.el(isVideo ? 'video' : 'img', {
className: 'ihover',
style: {
maxWidth: '100%',
maxHeight: '100%'
}
maxHeight: '100%',
},
})
el.dataset.fileID = `${post.fullID}.${file.index}`
$.on(el, 'error', error)
@ -74,14 +117,16 @@ const ImageHover = {
if (isVideo) {
el.loop = true
el.controls = false
Volume.setup(el)
Volume.setup(el as HTMLVideoElement)
if (Conf['Autoplay']) {
el.play()
if (this.nodeName === 'VIDEO') { this.currentTime = el.currentTime }
(el as HTMLVideoElement).play()
if (this.nodeName === 'VIDEO') {
(this as HTMLVideoElement).currentTime = (el as HTMLVideoElement).currentTime
}
}
}
if (file.dimensions) {
[width, height] = Array.from((file.dimensions.split('x').map((x) => +x)))
[width, height] = Array.from(file.dimensions.split('x').map((x) => +x))
const maxWidth = doc.clientWidth
const maxHeight = doc.clientHeight - UI.hover.padding
const scale = Math.min(1, maxWidth / width, maxHeight / height)
@ -91,7 +136,7 @@ const ImageHover = {
el.style.maxHeight = `${height}px`
}
return UI.hover({
root: this,
root: this as HTMLElement,
el,
latestEvent: e,
endEvents: 'mouseout click',
@ -105,7 +150,7 @@ const ImageHover = {
$.rm(el)
el.removeAttribute('style')
return el.remove()
}
},
})
}
},

View File

@ -8,6 +8,7 @@ import { dict } from "../platform/helpers"
const Banner = {
db: DataBoard,
init() {
if (Conf['Custom Board Titles']) {
this.db = new DataBoard('customTitles', null, true)
@ -89,18 +90,13 @@ const Banner = {
return Banner.db.set({
boardID: g.BOARD.ID,
threadID: this.className,
val: {
title: this.textContent,
orig: Banner.original[this.className].textContent
}
})
title: this.textContent,
orig: Banner.original[this.className].textContent
}, true)
} else {
$.rmAll(this)
$.add(this, [...Array.from(Banner.original[this.className].cloneNode(true).childNodes)])
return Banner.db.delete({
boardID: g.BOARD.ID,
threadID: this.className
})
return Banner.db.delete({ boardID: g.BOARD.ID, threadID: this.className }, true)
}
}
},

View File

@ -149,12 +149,12 @@ export default class Fetcher {
if (post.no !== this.postID) {
// Cached requests can be stale and must be rechecked.
if (isCached) {
const api = g.SITE.urls.threadJSON({ boardID: this.boardID, threadID: this.threadID })
const api = g.SITE.urls.threadJSON({ boardID: this.boardID, threadID: this.threadID }, true)
$.cleanCache(url => url === api)
const that = this
$.cache(api, function () {
return that.fetchedPost(this, false)
})
}, { force: true })
return
}

View File

@ -9,7 +9,7 @@ import Callbacks from "./Callbacks"
import type Thread from "./Thread"
export default class Post {
callbacksExecuted: boolean
declare origin: Post
declare root: HTMLElement
declare thread: Thread
declare board: Board
@ -33,6 +33,7 @@ export default class Post {
declare files: File[]
declare info: {
comment: string,
subject: string,
name: string,
email: string,

View File

@ -25,7 +25,7 @@ export default class Thread {
fileLimit: boolean
ipCount: number
json: JSON
catalogView: Node
catalogView: any
nodes: { root: Post }
constructor(ID: number | string, board: Board) {

View File

@ -42,15 +42,15 @@ import yotsuba from './yotsuba.css'
import yotsubaB from './yotsuba-b.css'
// <%
// var inc = require['style'];
// var faCSS = read('/node_modules/font-awesome/css/font-awesome.css');
// var faWebFont = readBase64('/node_modules/font-awesome/fonts/fontawesome-webfont.woff');
// var mainCSS = ['font-awesome', 'style', 'yotsuba', 'yotsuba-b', 'futaba', 'burichan', 'tomorrow', 'photon', 'spooky'].map(x => read(`${x}.css`)).join('');
// var inc = require['style'];
// var faCSS = read('/node_modules/font-awesome/css/font-awesome.css');
// var faWebFont = readBase64('/node_modules/font-awesome/fonts/fontawesome-webfont.woff');
// var mainCSS = ['font-awesome', 'style', 'yotsuba', 'yotsuba-b', 'futaba', 'burichan', 'tomorrow', 'photon', 'spooky'].map(x => read(`${x}.css`)).join('');
// var iconNames = files.filter(f => /^linkify\.[^.]+\.png$/.test(f));
// var icons = iconNames.map(readBase64);
// %>
const mainCSS = fontAwesome + style + yotsuba +yotsubaB+futaba+burichan+tomorrow + photon + spooky
const mainCSS = fontAwesome + style + yotsuba + yotsubaB + futaba + burichan + tomorrow + photon + spooky
const faIcons: { name: string, data: string }[] = [
{ name: "Audio", data: linkifyAudio },
{ name: "Bitchute", data: linkifyBitchute },
@ -83,11 +83,11 @@ const CSS = {
www,
sub: function(css: string) {
sub: function (css: string) {
const variables = {
site: g.SITE.selectors
}
return css.replace(/\$[\w\$]+/g, function(name) {
return css.replace(/\$[\w\$]+/g, function (name) {
const words = name.slice(1).split('$')
let sel = variables
for (let i = 0; i < words.length; i++) {

View File

@ -4,7 +4,6 @@
font-style: normal;
-webkit-font-smoothing: antialiased;
text-decoration: inherit;
speak: none;
display: inline-block;
font-size: 13px;
visibility: visible;

View File

@ -1,37 +1,26 @@
// == Reprocess Font Awesome CSS == //
export const fa = (css: string, font: string) => (
// Font Awesome CSS attribution and license
css.match(/\/\*\![^]*?\*\//)[0] + '\n' +
// Font Awesome web font
`@font-face {
export const fa = (css: string, font: string) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const [license, classes] = css.match(/(\/\*![^]*?\*\/)[\s\S]*?((\.fa-[^{]*{\s*content:[^}]*}\s*)+)/)!.slice(1)
return `${license}
@font-face {
font-family: FontAwesome;
src: url('data:application/font-woff;base64,${font}') format('woff');
font-weight: 400;
font-style: normal;
}
` +
// fa-[icon name] classes
css
.match(/(\.fa-[^{]*{\s*content:[^}]*}\s*)+/)[0]
.replace(/([,{;])\s+/g, '$1')
.replace(/,/g, ', ')
)
${classes.replace(/([,{;])\s+/g, '$1').replace(/,/g, ', ')}`
}
// == Create CSS for Link Title Favicons == //
export const icons = (data: { name: string, data: string }[]) => (
'/* Link Title Favicons */\n' +
data.map(({ name, data }) =>
`.linkify.${name}::before {
export const icons = (data: { name: string, data: string }[]) => {
return `/* Link Title Favicons */\n${data.map(({ name, data }) => {
return `.linkify.${name}::before {
content: "";
background: transparent url('data:image/png;base64,${data}') center left no-repeat!important;
padding-left: 18px;
}
`
).join('')
)
}).join('')}`
}

View File

@ -6,6 +6,9 @@ import { dict } from "../platform/helpers"
const SWTinyboard = {
sfwBoards() {
return Conf['boardConfig'].config.sfw_boards
},
insertTags() {
const { config } = Conf['boardConfig']
const { markup_tags } = config

View File

@ -24,14 +24,20 @@ const SWYotsuba = {
urls: {
thread({boardID, threadID}) { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/thread/${threadID}` },
post({postID}) { return `#p${postID}` },
index({boardID}) { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/` },
catalog({boardID}) { if (boardID === 'f') { return undefined } else { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/catalog` } },
archive({boardID}) { if (BoardConfig.isArchived(boardID)) { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/archive` } else { return undefined } },
post({postID})
{ return `#p${postID}` },
index({boardID}) { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/` },
catalog({boardID})
{ if (boardID === 'f') { return undefined } else { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/catalog` } },
archive({boardID})
{ if (BoardConfig.isArchived(boardID)) { return `${location.protocol}//${BoardConfig.domain(boardID)}/${boardID}/archive` } else { return undefined } },
threadJSON({boardID, threadID}) { return `${location.protocol}//a.4cdn.org/${boardID}/thread/${threadID}.json` },
threadsListJSON({boardID}) { return `${location.protocol}//a.4cdn.org/${boardID}/threads.json` },
archiveListJSON({boardID}) { if (BoardConfig.isArchived(boardID)) { return `${location.protocol}//a.4cdn.org/${boardID}/archive.json` } else { return '' } },
catalogJSON({boardID}) { return `${location.protocol}//a.4cdn.org/${boardID}/catalog.json` },
threadsListJSON({boardID})
{ return `${location.protocol}//a.4cdn.org/${boardID}/threads.json` },
archiveListJSON({boardID})
{ if (BoardConfig.isArchived(boardID)) { return `${location.protocol}//a.4cdn.org/${boardID}/archive.json` } else { return '' } },
catalogJSON({boardID})
{ return `${location.protocol}//a.4cdn.org/${boardID}/catalog.json` },
file({boardID}, filename) {
const hostname = boardID === 'f' ? ImageHost.flashHost() : ImageHost.host()
return `${location.protocol}//${hostname}/${boardID}/${filename}`

View File

@ -1,5 +1,6 @@
declare const XPCNativeWrapper: any
export interface File {
MD5: string
name: string
isImage: boolean
isVideo: boolean

View File

@ -9,7 +9,7 @@
"allowJs": true,
"checkJs": true,
//TODO: Flip this to true
"strict": true,
"strict": false,
"noEmit": true,
"jsx": "react",
"jsxFactory": "h",