mirror of
https://github.com/LalleSX/4chan-XZ.git
synced 2025-10-07 07:22:37 +02:00
types and bug fixes
This commit is contained in:
parent
a1e1a2c6b1
commit
e4dda4dbf8
31
.vscode/settings.json
vendored
31
.vscode/settings.json
vendored
@ -1,16 +1,17 @@
|
||||
{
|
||||
"search.exclude": {
|
||||
"*.jst": true,
|
||||
"*.md": true,
|
||||
"*.yaml": true,
|
||||
"*.yml": true,
|
||||
"*.css": true,
|
||||
"package*.json": true
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.fixAll": true
|
||||
}
|
||||
}
|
||||
"search.exclude": {
|
||||
"*.jst": true,
|
||||
"*.md": true,
|
||||
"*.yaml": true,
|
||||
"*.yml": true,
|
||||
"*.css": true,
|
||||
"non-property-errors-logs.txt": true,
|
||||
"package*.json": true
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.fixAll": true
|
||||
}
|
||||
}
|
||||
@ -125,7 +125,7 @@ const Redirect = {
|
||||
$.set(items)
|
||||
$.extend(Conf, items)
|
||||
Redirect.selectArchives()
|
||||
return cb?.()
|
||||
return cb
|
||||
},
|
||||
|
||||
to(dest, data) {
|
||||
|
||||
@ -378,7 +378,7 @@ const Filter = {
|
||||
}
|
||||
},
|
||||
|
||||
addFilter(type: FilterType, re: string, cb?: () => void) {
|
||||
addFilter(type: FilterType, re: string, cb?: Callbacks) {
|
||||
if (!$.hasOwn(Config.filter, type)) { return }
|
||||
return $.get(type, Conf[type], function (item) {
|
||||
let save = item[type]
|
||||
@ -392,7 +392,7 @@ const Filter = {
|
||||
})
|
||||
},
|
||||
|
||||
removeFilters(type: FilterType, res: FilterObj[] | Map<string, FilterObj[]>, cb?: () => void) {
|
||||
removeFilters(type: FilterType, res: FilterObj[] | Map<string, FilterObj[]>, cb?: Callbacks) {
|
||||
return $.get(type, Conf[type], function (item) {
|
||||
let save = item[type]
|
||||
const filterArray = Array.isArray(res) ? res : [...res.values()].flat()
|
||||
|
||||
@ -3,13 +3,7 @@ import { Conf, g } from "../globals/globals"
|
||||
import $ from "../platform/$"
|
||||
import { dict, HOUR } from "../platform/helpers"
|
||||
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS104: Avoid inline assignments
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
|
||||
const BoardConfig = {
|
||||
cbs: [],
|
||||
|
||||
@ -19,7 +13,7 @@ const BoardConfig = {
|
||||
const now = Date.now()
|
||||
if (now - (2 * HOUR) >= ((middle = Conf['boardConfig'].lastChecked || 0)) || middle > now) {
|
||||
return $.ajax(`${location.protocol}//a.4cdn.org/boards.json`,
|
||||
{ onloadend: this.load })
|
||||
{ onloadend: this.load }, dict())
|
||||
} else {
|
||||
const { boards } = Conf['boardConfig']
|
||||
return this.set(boards)
|
||||
|
||||
@ -1,13 +1,7 @@
|
||||
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
|
||||
*/
|
||||
|
||||
const Get = {
|
||||
url(type, IDs, ...args) {
|
||||
let f, site
|
||||
|
||||
@ -12,13 +12,7 @@ import Get from "./Get"
|
||||
import Settings from "./Settings"
|
||||
import UI from "./UI"
|
||||
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS104: Avoid inline assignments
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
|
||||
const Header = {
|
||||
init() {
|
||||
$.onExists(doc, 'body', () => {
|
||||
@ -404,7 +398,7 @@ const Header = {
|
||||
Header.setBarFixed(this.checked)
|
||||
|
||||
Conf['Fixed Header'] = this.checked
|
||||
return $.set('Fixed Header', this.checked)
|
||||
return $.set('Fixed Header', this.checked, true)
|
||||
},
|
||||
|
||||
setShortcutIcons(show) {
|
||||
|
||||
@ -71,9 +71,9 @@ const Settings = {
|
||||
return localStorage.setItem('4chan-settings', JSON.stringify(settings))
|
||||
} catch (error) {
|
||||
return Object.defineProperty(window, 'Config', {value: {disableAll: true}})
|
||||
}})
|
||||
}}, true)
|
||||
} else {
|
||||
return $.global(() => Object.defineProperty(window, 'Config', {value: {disableAll: true}}))
|
||||
return $.global(() => Object.defineProperty(window, 'Config', {value: {disableAll: true}}), true)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -81,7 +81,7 @@ const Settings = {
|
||||
open(openSection) {
|
||||
let dialog, sectionToOpen
|
||||
if (Settings.dialog) { return }
|
||||
$.event('CloseMenu')
|
||||
$.event('CloseMenu', null)
|
||||
|
||||
Settings.dialog = (dialog = $.el('div',
|
||||
{ id: 'overlay' }
|
||||
@ -258,7 +258,7 @@ Enable it on boards.${location.hostname.split('.')[1]}.org in your browser's pri
|
||||
inputs[key].checked = val
|
||||
inputs[key].parentNode.parentNode.dataset.checked = val
|
||||
}
|
||||
})
|
||||
}, 'Settings')
|
||||
|
||||
const div = $.el('div',
|
||||
{innerHTML: '<button></button><span class="description">: Clear manually-hidden threads and posts on all boards. Reload the page to apply.'})
|
||||
@ -299,6 +299,8 @@ Enable it on boards.${location.hostname.split('.')[1]}.org in your browser's pri
|
||||
}
|
||||
}
|
||||
return button.textContent = `Hidden: ${hiddenNum}`
|
||||
}, function() {
|
||||
return button.textContent = 'Hidden: 0'
|
||||
})
|
||||
$.on(button, 'click', function() {
|
||||
this.textContent = 'Hidden: 0'
|
||||
@ -312,7 +314,7 @@ Enable it on boards.${location.hostname.split('.')[1]}.org in your browser's pri
|
||||
localStorage.removeItem(`4chan-hide-t-${boardID}`)
|
||||
}
|
||||
}
|
||||
return ($.delete(['hiddenThreads', 'hiddenPosts']))
|
||||
return ($.delete(['hiddenThreads', 'hiddenPosts'], dict())
|
||||
})
|
||||
})
|
||||
return $.after($('input[name="Stubs"]', section).parentNode.parentNode, div)
|
||||
@ -326,7 +328,7 @@ Enable it on boards.${location.hostname.split('.')[1]}.org in your browser's pri
|
||||
// Don't export cached JSON data.
|
||||
delete Conf2['boardConfig']
|
||||
return (Settings.downloadExport({version: g.VERSION, date: Date.now(), Conf: Conf2}))
|
||||
})
|
||||
}, 'Settings')
|
||||
},
|
||||
|
||||
downloadExport(data) {
|
||||
@ -918,6 +920,9 @@ vp-replace
|
||||
Settings[key].call(input)
|
||||
}
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) { return }
|
||||
return $.id('lastarchivecheck').textContent = new Date(Conf['lastarchivecheck']).toLocaleString()
|
||||
})
|
||||
|
||||
const listImageHost = $.id('list-fourchanImageHost')
|
||||
@ -944,6 +949,9 @@ vp-replace
|
||||
$.extend(Conf, itemsArchive)
|
||||
Redirect.selectArchives()
|
||||
return Settings.addArchiveTable(section)
|
||||
}, function(err) {
|
||||
if (err) { return }
|
||||
return $.id('lastarchivecheck').textContent = new Date(Conf['lastarchivecheck']).toLocaleString()
|
||||
})
|
||||
|
||||
const boardSelect = $('#archive-board-select', section)
|
||||
@ -1069,7 +1077,7 @@ vp-replace
|
||||
saveSelectedArchive() {
|
||||
return $.get('selectedArchives', Conf['selectedArchives'], ({selectedArchives}) => {
|
||||
(selectedArchives[this.dataset.boardid] || (selectedArchives[this.dataset.boardid] = dict()))[this.dataset.type] = JSON.parse(this.value)
|
||||
$.set('selectedArchives', selectedArchives)
|
||||
$.set('selectedArchives', selectedArchives, () => Conf['selectedArchives'] = selectedArchives)
|
||||
Conf['selectedArchives'] = selectedArchives
|
||||
return Redirect.selectArchives()
|
||||
})
|
||||
@ -1157,7 +1165,7 @@ vp-replace
|
||||
const val = items[key]
|
||||
inputs[key].value = val
|
||||
}
|
||||
})
|
||||
}, true)
|
||||
},
|
||||
|
||||
keybind(e) {
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
import Callbacks from "../classes/Callbacks"
|
||||
import Post from "../classes/Post"
|
||||
import Thread from "../classes/Thread"
|
||||
import Get from "../General/Get"
|
||||
import { Conf, g } 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 IDPostCount = {
|
||||
init() {
|
||||
if ((g.VIEW !== 'thread') || !Conf['Count Posts by ID']) { return }
|
||||
@ -21,19 +18,19 @@ const IDPostCount = {
|
||||
})
|
||||
},
|
||||
|
||||
node() {
|
||||
node(): void {
|
||||
if (this.nodes.uniqueID && (this.thread === IDPostCount.thread)) {
|
||||
return $.on(this.nodes.uniqueID, 'mouseover', IDPostCount.count)
|
||||
}
|
||||
},
|
||||
|
||||
count() {
|
||||
count(): string {
|
||||
const { uniqueID } = Get.postFromNode(this).info
|
||||
let n = 0
|
||||
IDPostCount.thread.posts.forEach(function (post) {
|
||||
IDPostCount.thread.posts.forEach((post: Post) => {
|
||||
if (post.info.uniqueID === uniqueID) { return n++ }
|
||||
})
|
||||
return this.title = `${n} post${n === 1 ? '' : 's'} by this ID`
|
||||
}
|
||||
}
|
||||
export default IDPostCount
|
||||
export default IDPostCount
|
||||
@ -1,18 +1,22 @@
|
||||
import Callbacks from "../classes/Callbacks"
|
||||
import { Conf,g } from "../globals/globals"
|
||||
import type Post from "../classes/Post"
|
||||
import { Conf, g } from "../globals/globals"
|
||||
|
||||
const ThreadLinks = {
|
||||
init(): void {
|
||||
if ((g.VIEW !== 'index') || !Conf['Open Threads in New Tab']) { return }
|
||||
|
||||
Callbacks.Post.push({
|
||||
const postCallback: Post = {
|
||||
name: 'Thread Links',
|
||||
cb: this.node.bind(this)
|
||||
})
|
||||
Callbacks.CatalogThread.push({
|
||||
cb: this.node.bind(this)
|
||||
}
|
||||
const catalogThreadCallback: Post = {
|
||||
name: 'Thread Links',
|
||||
cb: this.catalogNode.bind(this)
|
||||
})
|
||||
cb: this.catalogNode.bind(this)
|
||||
}
|
||||
|
||||
Callbacks.Post.push(postCallback)
|
||||
Callbacks.CatalogThread.push(catalogThreadCallback)
|
||||
},
|
||||
|
||||
node(): void {
|
||||
@ -29,4 +33,4 @@ const ThreadLinks = {
|
||||
}
|
||||
}
|
||||
|
||||
export default ThreadLinks
|
||||
export default ThreadLinks
|
||||
@ -2,31 +2,54 @@ import Callbacks from "../classes/Callbacks"
|
||||
import { Conf, g } 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 Time = {
|
||||
init() {
|
||||
if (!['index', 'thread', 'archive'].includes(g.VIEW) || !Conf['Time Formatting']) { return }
|
||||
interface TimeFormatters {
|
||||
a(): string;
|
||||
A(): string;
|
||||
b(): string;
|
||||
B(): string;
|
||||
d(): string;
|
||||
e(): number;
|
||||
H(): string;
|
||||
I(): string;
|
||||
k(): number;
|
||||
l(): number;
|
||||
m(): string;
|
||||
M(): string;
|
||||
p(): string;
|
||||
P(): string;
|
||||
S(): string;
|
||||
y(): string;
|
||||
Y(): number;
|
||||
'%'(): string;
|
||||
}
|
||||
|
||||
return Callbacks.Post.push({
|
||||
const Time = {
|
||||
init(): void {
|
||||
if (!['index', 'thread', 'archive'].includes(g.VIEW) || !Conf['Time Formatting']) {
|
||||
return
|
||||
}
|
||||
|
||||
Callbacks.Post.push({
|
||||
name: 'Time Formatting',
|
||||
cb: this.node
|
||||
cb: this.node,
|
||||
})
|
||||
},
|
||||
|
||||
node() {
|
||||
if (!this.info.date || this.isClone) { return }
|
||||
node(): void {
|
||||
if (!this.info.date || this.isClone) {
|
||||
return
|
||||
}
|
||||
const { textContent } = this.nodes.date
|
||||
return this.nodes.date.textContent = textContent.match(/^\s*/)[0] + Time.format(Conf['time'], this.info.date) + textContent.match(/\s*$/)[0]
|
||||
this.nodes.date.textContent =
|
||||
textContent.match(/^\s*/)[0] +
|
||||
Time.format(Conf['time'], this.info.date) +
|
||||
textContent.match(/\s*$/)[0]
|
||||
},
|
||||
|
||||
format(formatString, date) {
|
||||
return formatString.replace(/%(.)/g, function (s, c) {
|
||||
format(formatString: string, date: Date): string {
|
||||
return formatString.replace(/%(.)/g, (s: string, c: string): string => {
|
||||
if ($.hasOwn(Time.formatters, c)) {
|
||||
return Time.formatters[c].call(date)
|
||||
return (Time.formatters as TimeFormatters)[c].call(date)
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
@ -40,7 +63,7 @@ const Time = {
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday',
|
||||
'Saturday'
|
||||
'Saturday',
|
||||
],
|
||||
|
||||
month: [
|
||||
@ -55,49 +78,95 @@ const Time = {
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
'December',
|
||||
],
|
||||
|
||||
localeFormat(date, options, defaultValue) {
|
||||
localeFormat(date: Date, options: Intl.DateTimeFormatOptions, defaultValue: string): string {
|
||||
if (Conf['timeLocale']) {
|
||||
try {
|
||||
return Intl.DateTimeFormat(Conf['timeLocale'], options).format(date)
|
||||
} catch (error) { }
|
||||
} catch (error) {/* empty */ }
|
||||
}
|
||||
return defaultValue
|
||||
},
|
||||
|
||||
localeFormatPart(date, options, part, defaultValue) {
|
||||
localeFormatPart(
|
||||
date: Date,
|
||||
options: Intl.DateTimeFormatOptions,
|
||||
part: string,
|
||||
defaultValue: string,
|
||||
): string {
|
||||
if (Conf['timeLocale']) {
|
||||
try {
|
||||
const parts = Intl.DateTimeFormat(Conf['timeLocale'], options).formatToParts(date)
|
||||
return parts.map(function (x) { if (x.type === part) { return x.value } else { return '' } }).join('')
|
||||
} catch (error) { }
|
||||
return parts
|
||||
.map((x) => (x.type === part ? x.value : ''))
|
||||
.join('')
|
||||
} catch (error) { /* empty */ }
|
||||
}
|
||||
return defaultValue
|
||||
},
|
||||
|
||||
zeroPad(n) { if (n < 10) { return `0${n}` } else { return n } },
|
||||
zeroPad(n: number): string | number {
|
||||
return n < 10 ? `0${n}` : n
|
||||
},
|
||||
|
||||
formatters: {
|
||||
a() { return Time.localeFormat(this, { weekday: 'short' }, Time.day[this.getDay()].slice(0, 3)) },
|
||||
A() { return Time.localeFormat(this, { weekday: 'long' }, Time.day[this.getDay()]) },
|
||||
b() { return Time.localeFormat(this, { month: 'short' }, Time.month[this.getMonth()].slice(0, 3)) },
|
||||
B() { return Time.localeFormat(this, { month: 'long' }, Time.month[this.getMonth()]) },
|
||||
d() { return Time.zeroPad(this.getDate()) },
|
||||
e() { return this.getDate() },
|
||||
H() { return Time.zeroPad(this.getHours()) },
|
||||
I() { return Time.zeroPad((this.getHours() % 12) || 12) },
|
||||
k() { return this.getHours() },
|
||||
l() { return (this.getHours() % 12) || 12 },
|
||||
m() { return Time.zeroPad(this.getMonth() + 1) },
|
||||
M() { return Time.zeroPad(this.getMinutes()) },
|
||||
p() { return Time.localeFormatPart(this, { hour: 'numeric', hour12: true }, 'dayperiod', (this.getHours() < 12 ? 'AM' : 'PM')) },
|
||||
P() { return Time.formatters.p.call(this).toLowerCase() },
|
||||
S() { return Time.zeroPad(this.getSeconds()) },
|
||||
y() { return this.getFullYear().toString().slice(2) },
|
||||
Y() { return this.getFullYear() },
|
||||
'%'() { return '%' }
|
||||
}
|
||||
a(): string {
|
||||
return Time.localeFormat(this, { weekday: 'short' }, Time.day[this.getDay()].slice(0, 3))
|
||||
},
|
||||
A(): string {
|
||||
return Time.localeFormat(this, { weekday: 'long' }, Time.day[this.getDay()])
|
||||
},
|
||||
b(): string {
|
||||
return Time.localeFormat(this, { month: 'short' }, Time.month[this.getMonth()].slice(0, 3))
|
||||
},
|
||||
B(): string {
|
||||
return Time.localeFormat(this, { month: 'long' }, Time.month[this.getMonth()])
|
||||
},
|
||||
d(): string | number {
|
||||
return Time.zeroPad(this.getDate())
|
||||
},
|
||||
e(): number {
|
||||
return this.getDate()
|
||||
},
|
||||
H(): string | number {
|
||||
return Time.zeroPad(this.getHours())
|
||||
},
|
||||
I(): string | number {
|
||||
return Time.zeroPad((this.getHours() % 12) || 12)
|
||||
},
|
||||
k(): number {
|
||||
return this.getHours()
|
||||
},
|
||||
l(): number {
|
||||
return (this.getHours() % 12) || 12
|
||||
},
|
||||
m(): string | number {
|
||||
return Time.zeroPad(this.getMonth() + 1)
|
||||
},
|
||||
M(): string | number {
|
||||
return Time.zeroPad(this.getMinutes())
|
||||
},
|
||||
p(): string {
|
||||
return Time.localeFormatPart(this, { hour: 'numeric', hour12: true }, 'dayperiod', this.getHours() < 12 ? 'AM' : 'PM')
|
||||
},
|
||||
P(): string {
|
||||
return Time.formatters.p.call(this).toLowerCase()
|
||||
},
|
||||
S(): string | number {
|
||||
return Time.zeroPad(this.getSeconds())
|
||||
},
|
||||
y(): string {
|
||||
return this.getFullYear().toString().slice(2)
|
||||
},
|
||||
Y(): number {
|
||||
return this.getFullYear()
|
||||
},
|
||||
'%'(): string {
|
||||
return '%'
|
||||
},
|
||||
},
|
||||
}
|
||||
export default Time
|
||||
|
||||
export default Time
|
||||
@ -10,12 +10,11 @@ interface QRPostDetail {
|
||||
}
|
||||
|
||||
const Tinyboard = {
|
||||
init() {
|
||||
init(): void {
|
||||
if (g.SITE.software !== 'tinyboard') { return }
|
||||
if (g.VIEW === 'thread') {
|
||||
return Main.ready(() => $.global(function() {
|
||||
let base
|
||||
const { boardID, threadID } = document.currentScript.dataset
|
||||
return Main.ready(() => $.global(function (data: { boardID: string, threadID: number }) {
|
||||
const { boardID, threadID } = data
|
||||
const threadIdNum = +threadID
|
||||
const form = document.querySelector('form[name="post"]') as HTMLFormElement
|
||||
window.$(document).ajaxComplete((event, request, settings) => {
|
||||
@ -29,16 +28,15 @@ const Tinyboard = {
|
||||
if (redirect && (originalNoko != null) && !originalNoko && !noko) {
|
||||
detail.redirect = redirect
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
event = new CustomEvent('QRPostSuccessful', { bubbles: true, detail })
|
||||
return document.dispatchEvent(event)
|
||||
})
|
||||
const originalNoko = window.tb_settings?.ajax?.always_noko_replies;
|
||||
((base = window.tb_settings || (window.tb_settings = {})).ajax || (base.ajax = {})).always_noko_replies = true
|
||||
}
|
||||
, { boardID: g.BOARD.ID, threadID: g.THREADID }))
|
||||
((window.tb_settings || (window.tb_settings = {})).ajax || (window.tb_settings.ajax = {})).always_noko_replies = true
|
||||
}, { boardID: g.BOARD.ID, threadID: g.THREADID }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Tinyboard
|
||||
export default Tinyboard
|
||||
@ -2,25 +2,22 @@ import { d, g } from "../globals/globals"
|
||||
import $ from "../platform/$"
|
||||
import QR from "./QR"
|
||||
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
const CaptchaT = {
|
||||
init() {
|
||||
if (d.cookie.indexOf('pass_enabled=1') >= 0) { return }
|
||||
if (!(this.isEnabled = !!$('#t-root') || !$.id('postForm'))) { return }
|
||||
|
||||
const root = $.el('div', {className: 'captcha-root'})
|
||||
this.nodes = {root}
|
||||
const root = $.el('div', { className: 'captcha-root' })
|
||||
this.nodes = { root }
|
||||
|
||||
$.addClass(QR.nodes.el, 'has-captcha', 'captcha-t')
|
||||
return $.after(QR.nodes.com.parentNode, root)
|
||||
},
|
||||
|
||||
moreNeeded() {
|
||||
return this.isEnabled && !this.nodes.container
|
||||
},
|
||||
currentThread: null,
|
||||
|
||||
getThread() {
|
||||
let threadID
|
||||
@ -30,26 +27,28 @@ const CaptchaT = {
|
||||
} else {
|
||||
threadID = '' + QR.posts[0].thread
|
||||
}
|
||||
return {boardID, threadID}
|
||||
return { boardID, threadID }
|
||||
},
|
||||
|
||||
setup(focus) {
|
||||
setup(focus?: boolean) {
|
||||
if (!this.isEnabled) { return }
|
||||
|
||||
if (!this.nodes.container) {
|
||||
this.nodes.container = $.el('div', {className: 'captcha-container'})
|
||||
this.nodes.container = $.el('div', { className: 'captcha-container' })
|
||||
$.prepend(this.nodes.root, this.nodes.container)
|
||||
CaptchaT.currentThread = CaptchaT.getThread()
|
||||
$.global(function() {
|
||||
$.global(function () {
|
||||
const el = document.querySelector('#qr .captcha-container')
|
||||
window.TCaptcha.init(el, this.boardID, +this.threadID)
|
||||
return window.TCaptcha.setErrorCb(err => window.dispatchEvent(new CustomEvent('CreateNotification', {detail: {
|
||||
type: 'warning',
|
||||
content: '' + err
|
||||
}})
|
||||
return window.TCaptcha.setErrorCb(err => window.dispatchEvent(new CustomEvent('CreateNotification', {
|
||||
detail: {
|
||||
type: 'warning',
|
||||
content: '' + err
|
||||
}
|
||||
})
|
||||
))
|
||||
}
|
||||
, CaptchaT.currentThread)
|
||||
, CaptchaT.currentThread)
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
@ -59,14 +58,14 @@ const CaptchaT = {
|
||||
|
||||
destroy() {
|
||||
if (!this.isEnabled || !this.nodes.container) { return }
|
||||
$.global(() => window.TCaptcha.destroy())
|
||||
$.global(() => window.TCaptcha.destroy(), CaptchaT.currentThread)
|
||||
$.rm(this.nodes.container)
|
||||
return delete this.nodes.container
|
||||
},
|
||||
|
||||
updateThread() {
|
||||
if (!this.isEnabled) { return }
|
||||
const {boardID, threadID} = (CaptchaT.currentThread || {})
|
||||
const { boardID, threadID } = (CaptchaT.currentThread || {})
|
||||
const newThread = CaptchaT.getThread()
|
||||
if ((newThread.boardID !== boardID) || (newThread.threadID !== threadID)) {
|
||||
CaptchaT.destroy()
|
||||
@ -91,7 +90,7 @@ const CaptchaT = {
|
||||
setUsed() {
|
||||
if (!this.isEnabled) { return }
|
||||
if (this.nodes.container) {
|
||||
return $.global(() => window.TCaptcha.clearChallenge())
|
||||
return $.global(() => window.TCaptcha.clearChallenge(), CaptchaT.currentThread)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ export default class DataBoard {
|
||||
this.data.version = (this.data.version || 0) + 1
|
||||
return $.set(this.key, this.data, () => {
|
||||
if (needSync) { this.sync?.() }
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -77,7 +77,7 @@ export default class DataBoard {
|
||||
for (const change of DataBoard.changes) { change() }
|
||||
this.sync?.()
|
||||
}
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@ import { d } from "../globals/globals"
|
||||
import $ from "../platform/$"
|
||||
import { SECOND } from "../platform/helpers"
|
||||
|
||||
type NoticeType = "success" | "warning" | "error"
|
||||
|
||||
export default class Notice {
|
||||
private el: HTMLDivElement
|
||||
private timeout?: number
|
||||
@ -10,7 +12,7 @@ export default class Notice {
|
||||
private closed = false
|
||||
|
||||
constructor(
|
||||
private type: string,
|
||||
private type: NoticeType,
|
||||
private content: string | Node,
|
||||
timeout?: number,
|
||||
onclose?: () => void
|
||||
@ -36,7 +38,7 @@ export default class Notice {
|
||||
this.onclose = onclose
|
||||
}
|
||||
|
||||
private setType(type: string) {
|
||||
private setType(type: NoticeType) {
|
||||
this.el.className = `notification ${type}`
|
||||
}
|
||||
|
||||
@ -69,4 +71,4 @@ export default class Notice {
|
||||
$.rm(this.el)
|
||||
this.onclose?.()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,6 @@ import Board from "./Board"
|
||||
import Post from "./Post"
|
||||
import SimpleDict from "./SimpleDict"
|
||||
|
||||
|
||||
export default class Thread {
|
||||
ID: number | string
|
||||
OP: Post
|
||||
@ -26,7 +25,6 @@ export default class Thread {
|
||||
json: JSON
|
||||
catalogView: Node
|
||||
nodes: { root: Post }
|
||||
toString() { return this.ID }
|
||||
|
||||
constructor(ID: number | string, board: Board) {
|
||||
this.board = board
|
||||
@ -50,8 +48,7 @@ export default class Thread {
|
||||
this.OP = null
|
||||
this.catalogView = null
|
||||
|
||||
this.nodes =
|
||||
{ root: null }
|
||||
this.nodes = { root: null }
|
||||
|
||||
this.board.threads.push(this.ID, this)
|
||||
g.threads.push(this.fullID, this)
|
||||
@ -66,14 +63,18 @@ export default class Thread {
|
||||
}
|
||||
icon.title = `This thread is on page ${pageNum} in the original index.`
|
||||
icon.textContent = `[${pageNum}]`
|
||||
if (this.catalogView) { return this.catalogView.nodes.pageCount.textContent = pageNum }
|
||||
if (this.catalogView) { this.catalogView.nodes.pageCount.textContent = pageNum }
|
||||
}
|
||||
|
||||
setCount(type: string, count: number, reachedLimit: boolean) {
|
||||
if (!this.catalogView) { return }
|
||||
const el = this.catalogView.nodes[`${type}Count`]
|
||||
el.textContent = count
|
||||
return (reachedLimit ? $.addClass : $.rmClass)(el, 'warning')
|
||||
if (reachedLimit) {
|
||||
$.addClass(el, 'warning')
|
||||
} else {
|
||||
$.rmClass(el, 'warning')
|
||||
}
|
||||
}
|
||||
|
||||
setStatus(type: string, status: boolean) {
|
||||
@ -83,7 +84,7 @@ export default class Thread {
|
||||
if (!this.OP) { return }
|
||||
this.setIcon('Sticky', this.isSticky)
|
||||
this.setIcon('Closed', this.isClosed && !this.isArchived)
|
||||
return this.setIcon('Archived', this.isArchived)
|
||||
this.setIcon('Archived', this.isArchived)
|
||||
}
|
||||
|
||||
setIcon(type: string, status: boolean) {
|
||||
@ -118,21 +119,25 @@ export default class Thread {
|
||||
}
|
||||
|
||||
kill() {
|
||||
return this.isDead = true
|
||||
this.isDead = true
|
||||
}
|
||||
|
||||
collect() {
|
||||
let n = 0
|
||||
this.posts.forEach(function (post) {
|
||||
this.posts.forEach(post => {
|
||||
if (post.clones.length) {
|
||||
return n++
|
||||
n++
|
||||
} else {
|
||||
return post.collect()
|
||||
post.collect()
|
||||
}
|
||||
})
|
||||
if (!n) {
|
||||
g.threads.rm(this.fullID)
|
||||
return this.board.threads.rm(this)
|
||||
this.board.threads.rm(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.ID
|
||||
}
|
||||
}
|
||||
@ -93,7 +93,6 @@ $.ajaxPage = function (url: string, options: AjaxPageOptions) {
|
||||
xhr.send(form)
|
||||
return xhr
|
||||
}
|
||||
$.cache = dict()
|
||||
|
||||
$.ready = function (fc: () => void) {
|
||||
if (d.readyState !== 'loading') {
|
||||
@ -293,7 +292,7 @@ $.ajax = (function () {
|
||||
// With the `If-Modified-Since` header we only receive the HTTP headers and no body for 304 responses.
|
||||
// This saves a lot of bandwidth and CPU time for both the users and the servers.
|
||||
$.lastModified = dict()
|
||||
$.whenModified = function (url, bucket, cb, options) {
|
||||
$.whenModified = function (url, bucket, cb, options = {}) {
|
||||
let t: string
|
||||
const { timeout, ajax } = options
|
||||
const params = []
|
||||
@ -315,42 +314,43 @@ $.whenModified = function (url, bucket, cb, options) {
|
||||
headers
|
||||
})
|
||||
return r
|
||||
};
|
||||
}
|
||||
|
||||
(function () {
|
||||
$.cache = function (url, cb, options = {}) {
|
||||
const reqs = dict()
|
||||
$.cache = function (url, cb, options) {
|
||||
let req
|
||||
const { ajax } = options
|
||||
if (req = reqs[url]) {
|
||||
if (req.callbacks) {
|
||||
req.callbacks.push(cb)
|
||||
} else {
|
||||
$.queueTask(() => cb.call(req, { isCached: true }))
|
||||
}
|
||||
return req
|
||||
let req
|
||||
const { ajax } = options
|
||||
if (req = reqs[url]) {
|
||||
if (req.callbacks) {
|
||||
req.callbacks.push(cb)
|
||||
} else {
|
||||
$.queueTask(() => cb.call(req, { isCached: true }))
|
||||
}
|
||||
const onloadend = function () {
|
||||
if (!this.status) {
|
||||
delete reqs[url]
|
||||
}
|
||||
for (cb of this.callbacks) {
|
||||
(cb => $.queueTask(() => cb.call(this, { isCached: false })))(cb)
|
||||
}
|
||||
return delete this.callbacks
|
||||
}
|
||||
req = (ajax || $.ajax)(url, { onloadend })
|
||||
req.callbacks = [cb]
|
||||
return reqs[url] = req
|
||||
return req
|
||||
}
|
||||
return $.cleanCache = function (testf) {
|
||||
for (const url in reqs) {
|
||||
if (testf(url)) {
|
||||
delete reqs[url]
|
||||
}
|
||||
const onloadend = function () {
|
||||
if (!this.status) {
|
||||
delete reqs[url]
|
||||
}
|
||||
for (cb of this.callbacks) {
|
||||
(cb => $.queueTask(() => cb.call(this, { isCached: false })))(cb)
|
||||
}
|
||||
return delete this.callbacks
|
||||
}
|
||||
req = (ajax || $.ajax)(url, { onloadend })
|
||||
req.callbacks = [cb]
|
||||
return reqs[url] = req
|
||||
}
|
||||
|
||||
$.cleanCache = function (testf) {
|
||||
const reqs = dict()
|
||||
for (const url in reqs) {
|
||||
if (testf(url)) {
|
||||
delete reqs[url]
|
||||
}
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
|
||||
$.cb = {
|
||||
checked() {
|
||||
@ -788,7 +788,7 @@ if (platform === 'crx') {
|
||||
c.error(err.message)
|
||||
setTimeout(setArea, MINUTE, area)
|
||||
timeout[area] = Date.now() + MINUTE
|
||||
return cb?.(err)
|
||||
return cb
|
||||
}
|
||||
|
||||
delete timeout[area]
|
||||
@ -807,7 +807,7 @@ if (platform === 'crx') {
|
||||
return result
|
||||
})()))
|
||||
}
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
}
|
||||
|
||||
@ -831,7 +831,7 @@ if (platform === 'crx') {
|
||||
c.error(chrome.runtime.lastError.message)
|
||||
}
|
||||
if (err == null) { err = chrome.runtime.lastError }
|
||||
if (!--count) { return cb?.(err) }
|
||||
if (!--count) { return cb }
|
||||
}
|
||||
chrome.storage.local.clear(done)
|
||||
return chrome.storage.sync.clear(done)
|
||||
@ -862,7 +862,7 @@ if (platform === 'crx') {
|
||||
|
||||
$.forceSync = function () { }
|
||||
|
||||
$.delete = function (keys, cb) {
|
||||
$.delete = function (keys: string | string[], cb: Callbacks) {
|
||||
let key
|
||||
if (!(keys instanceof Array)) {
|
||||
keys = [keys]
|
||||
@ -877,7 +877,7 @@ if (platform === 'crx') {
|
||||
const items = dict()
|
||||
for (key of keys) { items[key] = undefined }
|
||||
$.syncChannel.postMessage(items)
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
}
|
||||
|
||||
@ -905,7 +905,7 @@ if (platform === 'crx') {
|
||||
return result
|
||||
})()).then(function () {
|
||||
$.syncChannel.postMessage(items)
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
})
|
||||
|
||||
@ -1044,7 +1044,7 @@ if (platform === 'crx') {
|
||||
const value = items[key]
|
||||
$.setValue(g.NAMESPACE + key, JSON.stringify(value), cb)
|
||||
}
|
||||
return cb?.()
|
||||
return cb
|
||||
})
|
||||
})
|
||||
|
||||
@ -1056,7 +1056,7 @@ if (platform === 'crx') {
|
||||
try {
|
||||
$.delete($.listValues().map(key => key.replace(g.NAMESPACE, '')), cb)
|
||||
} catch (error) { }
|
||||
return cb?.()
|
||||
return cb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user