Added types and bug fixes

This commit is contained in:
Lalle 2023-04-19 03:33:50 +02:00
parent f65fbc4fed
commit 241ff1eb7a
No known key found for this signature in database
GPG Key ID: A6583D207A8F6B0D
14 changed files with 227 additions and 317 deletions

View File

@ -874,8 +874,9 @@ var Embedding = {
{ {
key: 'YouTube', key: 'YouTube',
regExp: regExp:
/^\w+:\/\/(?:youtu.be\/|[\w.]*youtube[\w.]*\/.*(?:v=|\bembed\/|\bv\/))([\w\-]{11})(.*)/, /^\w+:\/\/(?:www\.)?youtube\.com\/(?:watch\?v=|embed\/|v\/)?(\w+)/,
el(a) { el(a) {
const isShort = a.href.includes('youtube.com/shorts/')
let start = a.dataset.options.match(/\b(?:star)?t\=(\w+)/) let start = a.dataset.options.match(/\b(?:star)?t\=(\w+)/)
if (start) { if (start) {
start = start[1] start = start[1]
@ -888,11 +889,15 @@ var Embedding = {
1 * start.match(/(\d+)s/)[1] 1 * start.match(/(\d+)s/)[1]
} }
const el = $.el('iframe', { const el = $.el('iframe', {
src: `//www.youtube.com/embed/${a.dataset.uid}?rel=0&wmode=opaque${ src: `//www.youtube.com/embed/${a.dataset.uid}${isShort ? '?t=0s&enablejsapi=1&controls=0&loop=1&mute=1&playsinline=1' : `?rel=0&wmode=opaque${start ? '&start=' + start : ''}`}`,
start ? '&start=' + start : ''
}`,
}) })
el.setAttribute('allowfullscreen', 'true') el.setAttribute('allowfullscreen', 'true')
if (isShort) {
el.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share')
el.setAttribute('allowfullscreen', '')
el.setAttribute('loading', 'lazy')
el.setAttribute('class', 'youtube-short')
}
return el return el
}, },
title: { title: {
@ -907,17 +912,18 @@ var Embedding = {
const m = _.error.match(/^(\d*)\s*(.*)/) const m = _.error.match(/^(\d*)\s*(.*)/)
return [+m[1], m[2]] return [+m[1], m[2]]
} else { } else {
return [200, 'OK'] return [200, null]
} }
}, },
}, },
preview: { preview: {
url(uid) { url(uid) {
return `https://img.youtube.com/vi/${uid}/0.jpg` const isShort = uid.includes('shorts')
return `https://img.youtube.com/vi/${uid}${isShort ? '/mqdefault.jpg' : '/0.jpg'}`
}, },
height: 360, height: 360,
}, },
}, },
], ],
} }
export default Embedding export default Embedding

View File

@ -4,11 +4,6 @@ import Filter from '../Filtering/Filter'
import { g, Conf } from '../globals/globals' import { g, Conf } from '../globals/globals'
import Menu from './Menu' import Menu from './Menu'
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
const ArchiveLink = { const ArchiveLink = {
init() { init() {
if ( if (

View File

@ -2,12 +2,14 @@ import { g, Conf, d } from '../globals/globals'
import $ from '../platform/$' import $ from '../platform/$'
import Menu from './Menu' import Menu from './Menu'
/* interface CopyTextLink {
* decaffeinate suggestions: text: string
* DS102: Remove unnecessary code created because of implicit returns init(): VoidFunction
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md copy(): VoidFunction
*/ }
var CopyTextLink = {
const CopyTextLink: CopyTextLink = {
text: '',
init() { init() {
if ( if (
!['index', 'thread'].includes(g.VIEW) || !['index', 'thread'].includes(g.VIEW) ||

View File

@ -3,13 +3,9 @@ import ImageCommon from '../Images/ImageCommon'
import $ from '../platform/$' import $ from '../platform/$'
import Menu from './Menu' import Menu from './Menu'
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
const DownloadLink = { const DownloadLink = {
init() { init(): VoidFunction {
if ( if (
!['index', 'thread'].includes(g.VIEW) || !['index', 'thread'].includes(g.VIEW) ||
!Conf['Menu'] || !Conf['Menu'] ||
@ -18,7 +14,7 @@ const DownloadLink = {
return return
} }
const a = $.el('a', { const a: HTMLAnchorElement = $.el('a', {
className: 'download-link', className: 'download-link',
textContent: 'Download file', textContent: 'Download file',
}) })
@ -37,7 +33,7 @@ const DownloadLink = {
a.download = file.name a.download = file.name
return true return true
}, },
}) }) as VoidFunction
}, },
} }
export default DownloadLink export default DownloadLink

View File

@ -2,14 +2,10 @@ import Callbacks from '../classes/Callbacks'
import UI from '../General/UI' import UI from '../General/UI'
import { g, Conf } from '../globals/globals' import { g, Conf } from '../globals/globals'
import $ from '../platform/$' import $ from '../platform/$'
import Post from '../classes/Post'
/* var Menu: any = {
* decaffeinate suggestions: init(): VoidFunction {
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
var Menu = {
init() {
if (!['index', 'thread'].includes(g.VIEW) || !Conf['Menu']) { if (!['index', 'thread'].includes(g.VIEW) || !Conf['Menu']) {
return return
} }
@ -33,7 +29,7 @@ var Menu = {
}) })
}, },
node() { node(): HTMLElement {
if (this.isClone) { if (this.isClone) {
const button = $('.menu-button', this.nodes.info) const button = $('.menu-button', this.nodes.info)
$.rmClass(button, 'active') $.rmClass(button, 'active')
@ -44,15 +40,15 @@ var Menu = {
return $.add(this.nodes.info, Menu.makeButton(this)) return $.add(this.nodes.info, Menu.makeButton(this))
}, },
catalogNode() { catalogNode(): HTMLElement {
return $.after(this.nodes.icons, Menu.makeButton(this.thread.OP)) return $.after(this.nodes.icons, Menu.makeButton(this.thread.OP))
}, },
makeButton(post, button) { makeButton(post: Post, button?: HTMLElement): HTMLElement {
if (!button) { if (!button) {
button = Menu.button.cloneNode(true) button = Menu.button.cloneNode(true)
} }
$.on(button, 'click', function (e) { $.on(button, 'click', (e: Event) => {
return Menu.menu.toggle(e, this, post) return Menu.menu.toggle(e, this, post)
}) })
return button return button

View File

@ -1,23 +1,24 @@
import { g, Conf, d } from '../globals/globals' import { g, Conf, d } from '../globals/globals'
import $ from '../platform/$' import $ from '../platform/$'
import Menu from './Menu' import Menu from './Menu'
import Post from '../classes/Post'
/* type ReportLinkType = {
* decaffeinate suggestions: init: () => void
* DS102: Remove unnecessary code created because of implicit returns report: () => void
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md url: string
*/ dims: string
var ReportLink = { }
const ReportLink: ReportLinkType = {
init() { init() {
if ( if (!['index', 'thread'].includes(g.VIEW) ||
!['index', 'thread'].includes(g.VIEW) ||
!Conf['Menu'] || !Conf['Menu'] ||
!Conf['Report Link'] !Conf['Report Link']) {
) {
return return
} }
const a = $.el('a', { const a: HTMLAnchorElement = $.el('a', {
className: 'report-link', className: 'report-link',
href: 'javascript:;', href: 'javascript:;',
textContent: 'Report', textContent: 'Report',
@ -27,10 +28,8 @@ var ReportLink = {
return Menu.menu.addEntry({ return Menu.menu.addEntry({
el: a, el: a,
order: 10, order: 10,
open(post) { open(post: Post) {
ReportLink.url = `//sys.${location.hostname.split('.')[1]}.org/${ ReportLink.url = `//sys.${location.hostname.split('.')[1]}.org/${post.board}/imgboard.php?mode=report&no=${post}`
post.board
}/imgboard.php?mode=report&no=${post}`
if (d.cookie.indexOf('pass_enabled=1') >= 0) { if (d.cookie.indexOf('pass_enabled=1') >= 0) {
ReportLink.dims = 'width=350,height=275' ReportLink.dims = 'width=350,height=275'
} else { } else {
@ -47,5 +46,7 @@ var ReportLink = {
const set = `toolbar=0,scrollbars=1,location=0,status=1,menubar=0,resizable=1,${dims}` const set = `toolbar=0,scrollbars=1,location=0,status=1,menubar=0,resizable=1,${dims}`
return window.open(url, `report${id}`, set) return window.open(url, `report${id}`, set)
}, },
url: '',
dims: ''
} }
export default ReportLink export default ReportLink

View File

@ -2,20 +2,16 @@ import $ from '../platform/$'
import CSS from '../css/CSS' import CSS from '../css/CSS'
import { Conf } from '../globals/globals' import { Conf } from '../globals/globals'
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
const CustomCSS = { const CustomCSS = {
init() { init(): void {
if (!Conf['Custom CSS']) { if (!Conf['Custom CSS']) {
return return
} }
return this.addStyle() return this.addStyle()
}, },
addStyle() { addStyle(): HTMLStyleElement {
return (this.style = $.addStyle( return (this.style = $.addStyle(
CSS.sub(Conf['usercss']), CSS.sub(Conf['usercss']),
'custom-css', 'custom-css',
@ -23,18 +19,18 @@ const CustomCSS = {
)) ))
}, },
rmStyle() { rmStyle(): boolean {
if (this.style) { if (this.style) {
$.rm(this.style) $.rm(this.style)
return delete this.style return delete this.style
} }
}, },
update() { update(): void {
if (!this.style) { if (this.style) {
return this.addStyle() this.rmStyle()
this.addStyle()
} }
return (this.style.textContent = CSS.sub(Conf['usercss'])) }
},
} }
export default CustomCSS export default CustomCSS

View File

@ -1,10 +1,10 @@
import Callbacks from '../classes/Callbacks' import Callbacks from "../classes/Callbacks";
import BoardConfig from '../General/BoardConfig' import BoardConfig from "../General/BoardConfig";
import { d, doc, g } from '../globals/globals' import { d, doc, g } from "../globals/globals";
import Main from '../main/Main' import Main from "../main/Main";
import $ from '../platform/$' import $ from "../platform/$";
import $$ from '../platform/$$' import $$ from "../platform/$$";
import ExpandComment from './ExpandComment' import ExpandComment from "./ExpandComment";
/* /*
* decaffeinate suggestions: * decaffeinate suggestions:
@ -13,161 +13,110 @@ import ExpandComment from './ExpandComment'
*/ */
var Fourchan = { var Fourchan = {
init() { init() {
if ( if ((g.SITE.software !== 'yotsuba') || !['index', 'thread', 'archive'].includes(g.VIEW)) { return; }
g.SITE.software !== 'yotsuba' || BoardConfig.ready(this.initBoard);
!['index', 'thread', 'archive'].includes(g.VIEW) return Main.ready(this.initReady);
) {
return
}
BoardConfig.ready(this.initBoard)
return Main.ready(this.initReady)
}, },
initBoard() { initBoard() {
if (g.BOARD.config.code_tags) { if (g.BOARD.config.code_tags) {
$.on(window, 'prettyprint:cb', function (e) { $.on(window, 'prettyprint:cb', function (e) {
let post, pre let post, pre;
if (!(post = g.posts.get(e.detail.ID))) { if (!(post = g.posts.get(e.detail.ID))) { return; }
return if (!(pre = $$('.prettyprint', post.nodes.comment)[+e.detail.i])) { return; }
}
if (!(pre = $$('.prettyprint', post.nodes.comment)[+e.detail.i])) {
return
}
if (!$.hasClass(pre, 'prettyprinted')) { if (!$.hasClass(pre, 'prettyprinted')) {
pre.innerHTML = e.detail.html pre.innerHTML = e.detail.html;
return $.addClass(pre, 'prettyprinted') return $.addClass(pre, 'prettyprinted');
} }
}) });
$.global(() => $.global(() => window.addEventListener('prettyprint', e => window.dispatchEvent(new CustomEvent('prettyprint:cb', {
window.addEventListener( detail: {
'prettyprint', ID: e.detail.ID,
(e) => i: e.detail.i,
window.dispatchEvent( html: window.prettyPrintOne(e.detail.html)
new CustomEvent('prettyprint:cb', { }
detail: { }))
ID: e.detail.ID, , false));
i: e.detail.i,
html: window.prettyPrintOne(e.detail.html),
},
}),
),
false,
),
)
Callbacks.Post.push({ Callbacks.Post.push({
name: 'Parse [code] tags', name: 'Parse [code] tags',
cb: Fourchan.code, cb: Fourchan.code
}) });
g.posts.forEach(function (post) { g.posts.forEach(function (post) {
if (post.callbacksExecuted) { if (post.callbacksExecuted) {
return Callbacks.Post.execute(post, ['Parse [code] tags'], true) return Callbacks.Post.execute(post, ['Parse [code] tags'], true);
} }
}) });
ExpandComment.callbacks.push(Fourchan.code) ExpandComment.callbacks.push(Fourchan.code);
} }
if (g.BOARD.config.math_tags) { if (g.BOARD.config.math_tags) {
$.global(() => $.global(() => window.addEventListener('mathjax', function (e) {
window.addEventListener( if (window.MathJax) {
'mathjax', return window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target]);
function (e) { } else {
if (window.MathJax) { if (!document.querySelector('script[src^="//cdn.mathjax.org/"]')) { // don't load MathJax if already loading
return window.MathJax.Hub.Queue([ window.loadMathJax();
'Typeset', window.loadMathJax = function () { };
window.MathJax.Hub, }
e.target, // 4chan only handles post comments on MathJax load; anything else (e.g. the QR preview) must be queued explicitly.
]) if (!e.target.classList.contains('postMessage')) {
} else { return document.querySelector('script[src^="//cdn.mathjax.org/"]').addEventListener('load', () => window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, e.target])
if ( , false);
!document.querySelector('script[src^="//cdn.mathjax.org/"]') }
) { }
// don't load MathJax if already loading }
window.loadMathJax() , false));
window.loadMathJax = function () {}
}
// 4chan only handles post comments on MathJax load; anything else (e.g. the QR preview) must be queued explicitly.
if (!e.target.classList.contains('postMessage')) {
return document
.querySelector('script[src^="//cdn.mathjax.org/"]')
.addEventListener(
'load',
() =>
window.MathJax.Hub.Queue([
'Typeset',
window.MathJax.Hub,
e.target,
]),
false,
)
}
}
},
false,
),
)
Callbacks.Post.push({ Callbacks.Post.push({
name: 'Parse [math] tags', name: 'Parse [math] tags',
cb: Fourchan.math, cb: Fourchan.math
}) });
g.posts.forEach(function (post) { g.posts.forEach(function (post) {
if (post.callbacksExecuted) { if (post.callbacksExecuted) {
return Callbacks.Post.execute(post, ['Parse [math] tags'], true) return Callbacks.Post.execute(post, ['Parse [math] tags'], true);
} }
}) });
return ExpandComment.callbacks.push(Fourchan.math) return ExpandComment.callbacks.push(Fourchan.math);
} }
}, },
// Disable 4chan's ID highlighting (replaced by IDHighlight) and reported post hiding. // Disable 4chan's ID highlighting (replaced by IDHighlight) and reported post hiding.
initReady() { initReady() {
return $.global(function () { return $.global(function () {
window.clickable_ids = false window.clickable_ids = false;
for (var node of document.querySelectorAll('.posteruid, .capcode')) { for (var node of document.querySelectorAll('.posteruid, .capcode')) {
node.removeEventListener('click', window.idClick, false) node.removeEventListener('click', window.idClick, false);
} }
}) });
}, },
code() { code() {
if (this.isClone) { if (this.isClone) { return; }
return
}
return $.ready(() => { return $.ready(() => {
const iterable = $$('.prettyprint', this.nodes.comment) const iterable = $$('.prettyprint', this.nodes.comment);
for (let i = 0; i < iterable.length; i++) { for (let i = 0; i < iterable.length; i++) {
var pre = iterable[i] var pre = iterable[i];
if (!$.hasClass(pre, 'prettyprinted')) { if (!$.hasClass(pre, 'prettyprinted')) {
$.event( $.event('prettyprint', { ID: this.fullID, i, html: pre.innerHTML }, window);
'prettyprint',
{ ID: this.fullID, i, html: pre.innerHTML },
window,
)
} }
} }
}) });
}, },
math() { math() {
let wbrs let wbrs;
if (!/\[(math|eqn)\]/.test(this.nodes.comment.textContent)) { if (!/\[(math|eqn)\]/.test(this.nodes.comment.textContent)) { return; }
return
}
// XXX <wbr> tags frequently break MathJax; remove them. // XXX <wbr> tags frequently break MathJax; remove them.
if ((wbrs = $$('wbr', this.nodes.comment)).length) { if ((wbrs = $$('wbr', this.nodes.comment)).length) {
for (var wbr of wbrs) { for (var wbr of wbrs) { $.rm(wbr); }
$.rm(wbr) this.nodes.comment.normalize();
}
this.nodes.comment.normalize()
} }
var cb = () => { var cb = () => {
if (!doc.contains(this.nodes.comment)) { if (!doc.contains(this.nodes.comment)) { return; }
return $.off(d, 'PostsInserted', cb);
} return $.event('mathjax', null, this.nodes.comment);
$.off(d, 'PostsInserted', cb) };
return $.event('mathjax', null, this.nodes.comment) $.on(d, 'PostsInserted', cb);
} return cb();
$.on(d, 'PostsInserted', cb) }
return cb() };
}, export default Fourchan;
}
export default Fourchan

View File

@ -1,70 +1,55 @@
import Callbacks from '../classes/Callbacks' import Callbacks from "../classes/Callbacks";
import { g, Conf } from '../globals/globals' import { g, Conf } from "../globals/globals";
import $ from '../platform/$' import $ from "../platform/$";
import { dict } from '../platform/helpers' import { dict } from "../platform/helpers";
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
var IDColor = { var IDColor = {
init() { init() {
if (!['index', 'thread'].includes(g.VIEW) || !Conf['Color User IDs']) { if (!['index', 'thread'].includes(g.VIEW) || !Conf['Color User IDs']) { return; }
return this.ids = dict();
} this.ids['Heaven'] = [0, 0, 0, '#fff'];
this.ids = dict()
this.ids['Heaven'] = [0, 0, 0, '#fff']
return Callbacks.Post.push({ return Callbacks.Post.push({
name: 'Color User IDs', name: 'Color User IDs',
cb: this.node, cb: this.node
}) });
}, },
node() { node() {
let span, uid let span, uid;
if ( if (this.isClone || !((uid = this.info.uniqueID) && (span = this.nodes.uniqueID))) { return; }
this.isClone ||
!((uid = this.info.uniqueID) && (span = this.nodes.uniqueID))
) {
return
}
const rgb = IDColor.ids[uid] || IDColor.compute(uid) const rgb = IDColor.ids[uid] || IDColor.compute(uid);
// Style the damn node. // Style the damn node.
const { style } = span const { style } = span;
style.color = rgb[3] style.color = rgb[3];
style.backgroundColor = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})` style.backgroundColor = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
return $.addClass(span, 'painted') return $.addClass(span, 'painted');
}, },
compute(uid) { compute(uid) {
// Convert chars to integers, bitshift and math to create a larger integer // Convert chars to integers, bitshift and math to create a larger integer
// Create a nice string of binary // Create a nice string of binary
let hash; const hash = g.SITE.uidColor ? g.SITE.uidColor(uid) : parseInt(uid, 16);
if (typeof g !== 'undefined' && g.SITE && g.SITE.uidColor) {
hash = g.SITE.uidColor(uid);
} else {
hash = parseInt(uid, 16);
}
// Convert binary string to numerical values with bitshift and '&' truncation. // Convert binary string to numerical values with bitshift and '&' truncation.
const rgb = [(hash >> 16) & 0xff, (hash >> 8) & 0xff, hash & 0xff]; const rgb = [
(hash >> 16) & 0xFF,
// Weight color luminance values, assign a font color that should be readable. (hash >> 8) & 0xFF,
const fontColor = $.luma ? ($.luma(rgb) > 125 ? '#000' : '#fff') : '#000'; hash & 0xFF
];
// Cache color and font color.
const colorCode = `rgb(${rgb.join(',')})`; // Weight color luminance values, assign a font color that should be readable.
this.ids[uid] = { rgb.push($.luma(rgb) > 125 ?
color: colorCode, '#000'
fontColor: fontColor :
}; '#fff'
);
// Return only the color.
return colorCode; // Cache.
}, return this.ids[uid] = rgb;
} }
export default IDColor };
export default IDColor;

View File

@ -1,50 +1,37 @@
import Callbacks from '../classes/Callbacks' import Callbacks from "../classes/Callbacks";
import { g } from '../globals/globals' import { g } from "../globals/globals";
import $ from '../platform/$' 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
*/
var IDHighlight = { var IDHighlight = {
init() { init() {
if (!['index', 'thread'].includes(g.VIEW)) { if (!['index', 'thread'].includes(g.VIEW)) { return; }
return
}
return Callbacks.Post.push({ return Callbacks.Post.push({
name: 'Highlight by User ID', name: 'Highlight by User ID',
cb: this.node, cb: this.node
}) });
}, },
uniqueID: null, uniqueID: null,
node() { node() {
if (this.nodes.uniqueIDRoot) { if (this.nodes.uniqueIDRoot) { $.on(this.nodes.uniqueIDRoot, 'click', IDHighlight.click(this)); }
$.on(this.nodes.uniqueIDRoot, 'click', IDHighlight.click(this)) if (this.nodes.capcode) { $.on(this.nodes.capcode, 'click', IDHighlight.click(this)); }
} if (!this.isClone) { return IDHighlight.set(this); }
if (this.nodes.capcode) {
$.on(this.nodes.capcode, 'click', IDHighlight.click(this))
}
if (!this.isClone) {
return IDHighlight.set(this)
}
}, },
set(post) { set(post) {
const match = const match = (post.info.uniqueID || post.info.capcode) === IDHighlight.uniqueID;
(post.info.uniqueID || post.info.capcode) === IDHighlight.uniqueID return $[match ? 'addClass' : 'rmClass'](post.nodes.post, 'highlight');
return $[match ? 'addClass' : 'rmClass'](post.nodes.post, 'highlight')
}, },
click(post) { click(post) {
return function () { return function () {
const uniqueID = post.info.uniqueID || post.info.capcode const uniqueID = post.info.uniqueID || post.info.capcode;
IDHighlight.uniqueID = IDHighlight.uniqueID === uniqueID ? null : uniqueID IDHighlight.uniqueID = IDHighlight.uniqueID === uniqueID ? null : uniqueID;
return g.posts.forEach(IDHighlight.set) return g.posts.forEach(IDHighlight.set);
} };
}, }
} };
export default IDHighlight export default IDHighlight;

View File

@ -4,15 +4,15 @@ import Main from '../main/Main'
import $ from '../platform/$' import $ from '../platform/$'
const PSA = { const PSA = {
init() { init(): void {
let el let el: HTMLElement
if (g.SITE.software === 'yotsuba' && g.BOARD.ID === 'qa') { if (g.SITE.software === 'yotsuba' && g.BOARD.ID === 'qa') {
const announcement = { const announcement = {
innerHTML: innerHTML:
'Stay in touch with your <a href="https://www.4chan-x.net/qa_friends.html" target="_blank" rel="noopener">/qa/ friends</a>!', 'Stay in touch with your <a href="https://www.4chan-x.net/qa_friends.html" target="_blank" rel="noopener">/qa/ friends</a>!',
} }
el = $.el('div', { className: 'fcx-announcement' }, announcement) el = $.el('span', announcement) as HTMLElement
$.onExists(doc, '.boardBanner', (banner) => $.after(banner, el)) $.onExists(doc, '.boardBanner', (banner: HTMLElement) => $.after(banner, el))
} }
if ( if (
'samachan.org' in Conf['siteProperties'] && 'samachan.org' in Conf['siteProperties'] &&

View File

@ -8,7 +8,7 @@ import { g, Conf } from '../globals/globals'
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/ */
var Time = { var Time = {
init() { init(): VoidFunction {
if ( if (
!['index', 'thread', 'archive'].includes(g.VIEW) || !['index', 'thread', 'archive'].includes(g.VIEW) ||
!Conf['Time Formatting'] !Conf['Time Formatting']
@ -22,18 +22,15 @@ var Time = {
}) })
}, },
node() { node(): any {
if (!this.info.date || this.isClone) { if (!this.info.date || this.isClone) {
return return;
} }
const { textContent } = this.nodes.date const { textContent } = this.nodes.date;
return (this.nodes.date.textContent = return this.nodes.date.textContent = textContent.match(/^\s*/)[0] + Time.format(Conf['time'], this.info.date) + textContent.match(/\s*$/)[0];
textContent.match(/^\s*/)[0] +
Time.format(Conf['time'], this.info.date) +
textContent.match(/\s*$/)[0])
}, },
format(formatString, date) { format(formatString: string, date: Date): string {
return formatString.replace(/%(.)/g, function (s, c) { return formatString.replace(/%(.)/g, function (s, c) {
if ($.hasOwn(Time.formatters, c)) { if ($.hasOwn(Time.formatters, c)) {
return Time.formatters[c].call(date) return Time.formatters[c].call(date)
@ -68,16 +65,16 @@ var Time = {
'December', 'December',
], ],
localeFormat(date, options, defaultValue) { localeFormat(date: Date, options: any, defaultValue: string): string {
if (Conf['timeLocale']) { if (Conf['timeLocale']) {
try { try {
return Intl.DateTimeFormat(Conf['timeLocale'], options).format(date) return Intl.DateTimeFormat(Conf['timeLocale'], options).format(date)
} catch (error) {} } catch (error) { }
} }
return defaultValue return defaultValue
}, },
localeFormatPart(date, options, part, defaultValue) { localeFormatPart(date: Date, options: any, part: string, defaultValue: string): string {
if (Conf['timeLocale']) { if (Conf['timeLocale']) {
try { try {
const parts = Intl.DateTimeFormat( const parts = Intl.DateTimeFormat(
@ -93,12 +90,12 @@ var Time = {
} }
}) })
.join('') .join('')
} catch (error) {} } catch (error) { }
} }
return defaultValue return defaultValue
}, },
zeroPad(n) { zeroPad(n: number): number | string {
if (n < 10) { if (n < 10) {
return `0${n}` return `0${n}`
} else { } else {
@ -107,59 +104,59 @@ var Time = {
}, },
formatters: { formatters: {
a() { a(): string {
return Time.localeFormat( return Time.localeFormat(
this, this,
{ weekday: 'short' }, { weekday: 'short' },
Time.day[this.getDay()].slice(0, 3), Time.day[this.getDay()].slice(0, 3),
) )
}, },
A() { A(): string {
return Time.localeFormat( return Time.localeFormat(
this, this,
{ weekday: 'long' }, { weekday: 'long' },
Time.day[this.getDay()], Time.day[this.getDay()],
) )
}, },
b() { b(): string {
return Time.localeFormat( return Time.localeFormat(
this, this,
{ month: 'short' }, { month: 'short' },
Time.month[this.getMonth()].slice(0, 3), Time.month[this.getMonth()].slice(0, 3),
) )
}, },
B() { B(): string {
return Time.localeFormat( return Time.localeFormat(
this, this,
{ month: 'long' }, { month: 'long' },
Time.month[this.getMonth()], Time.month[this.getMonth()],
) )
}, },
d() { d(): string | number {
return Time.zeroPad(this.getDate()) return Time.zeroPad(this.getDate())
}, },
e() { e(): number {
return this.getDate() return this.getDate()
}, },
H() { H(): string | number {
return Time.zeroPad(this.getHours()) return Time.zeroPad(this.getHours())
}, },
I() { I(): string | number {
return Time.zeroPad(this.getHours() % 12 || 12) return Time.zeroPad(this.getHours() % 12 || 12)
}, },
k() { k(): number {
return this.getHours() return this.getHours()
}, },
l() { l(): number {
return this.getHours() % 12 || 12 return this.getHours() % 12 || 12
}, },
m() { m(): string | number {
return Time.zeroPad(this.getMonth() + 1) return Time.zeroPad(this.getMonth() + 1)
}, },
M() { M(): string | number {
return Time.zeroPad(this.getMinutes()) return Time.zeroPad(this.getMinutes())
}, },
p() { p(): string {
return Time.localeFormatPart( return Time.localeFormatPart(
this, this,
{ hour: 'numeric', hour12: true }, { hour: 'numeric', hour12: true },
@ -167,19 +164,19 @@ var Time = {
this.getHours() < 12 ? 'AM' : 'PM', this.getHours() < 12 ? 'AM' : 'PM',
) )
}, },
P() { P(): string {
return Time.formatters.p.call(this).toLowerCase() return Time.formatters.p.call(this).toLowerCase()
}, },
S() { S(): string | number {
return Time.zeroPad(this.getSeconds()) return Time.zeroPad(this.getSeconds())
}, },
y() { y(): string {
return this.getFullYear().toString().slice(2) return this.getFullYear().toString().slice(2)
}, },
Y() { Y(): number {
return this.getFullYear() return this.getFullYear()
}, },
'%'() { '%'(): string {
return '%' return '%'
}, },
}, },

View File

@ -1,5 +1,5 @@
import SWTinyboard from './SW.tinyboard' import SWTinyboard from './SW.tinyboard'
import SWYotsuba from './SW.yotsuba' import SWYotsuba from './SW.yotsuba'
const SW = { tinyboard: SWTinyboard, yotsuba: SWYotsuba } const SW = { tinyboard: SWTinyboard, yotsuba: SWYotsuba } as const
export default SW export default SW

View File

@ -19,7 +19,7 @@ var Site = {
'smug.nepu.moe': { canonical: 'smuglo.li' }, 'smug.nepu.moe': { canonical: 'smuglo.li' },
}, },
init(cb) { init(cb: () => void): void {
$.extend(Conf['siteProperties'], Site.defaultProperties) $.extend(Conf['siteProperties'], Site.defaultProperties)
let hostname = Site.resolve() let hostname = Site.resolve()
if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) { if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) {
@ -28,7 +28,7 @@ var Site = {
} }
return $.onExists(doc, 'body', () => { return $.onExists(doc, 'body', () => {
for (var software in SW) { for (var software in SW) {
var changes var changes: { [key: string]: string }
if ((changes = SW[software].detect?.())) { if ((changes = SW[software].detect?.())) {
changes.software = software changes.software = software
hostname = location.hostname.replace(/^www\./, '') hostname = location.hostname.replace(/^www\./, '')
@ -55,7 +55,7 @@ var Site = {
}) })
}, },
resolve(url = location) { resolve(url = location): string {
let { hostname } = url let { hostname } = url
while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) { while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) {
hostname = hostname.replace(/^[^.]*\.?/, '') hostname = hostname.replace(/^[^.]*\.?/, '')
@ -69,14 +69,14 @@ var Site = {
return hostname return hostname
}, },
parseURL(url) { parseURL(url: Location): ReturnType<typeof Main.parseURL> {
const siteID = Site.resolve(url) var siteID = Site.resolve(url)
return Main.parseURL(g.sites[siteID], url) return siteID ? g.sites[siteID].parseURL(url) : null
}, },
set(hostname) { set(hostname: string): typeof g.SITE {
for (var ID in Conf['siteProperties']) { for (var ID in Conf['siteProperties']) {
var site var site: typeof g.SITE
var properties = Conf['siteProperties'][ID] var properties = Conf['siteProperties'][ID]
if (properties.canonical) { if (properties.canonical) {
continue continue