mirror of
https://github.com/LalleSX/4chan-XZ.git
synced 2025-10-07 07:22:37 +02:00
types and fixes
This commit is contained in:
parent
55dd58b8c6
commit
543ff3437b
@ -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 }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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++) {
|
||||
|
||||
1
src/css/font-awesome.css
vendored
1
src/css/font-awesome.css
vendored
@ -4,7 +4,6 @@
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-decoration: inherit;
|
||||
speak: none;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
visibility: visible;
|
||||
|
||||
@ -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('')}`
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}`
|
||||
|
||||
1
src/types/globals.d.ts
vendored
1
src/types/globals.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
declare const XPCNativeWrapper: any
|
||||
export interface File {
|
||||
MD5: string
|
||||
name: string
|
||||
isImage: boolean
|
||||
isVideo: boolean
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
//TODO: Flip this to true
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"noEmit": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user