mirror of
https://github.com/LalleSX/4chan-XZ.git
synced 2025-10-07 07:22:37 +02:00
341 lines
8.6 KiB
JavaScript
341 lines
8.6 KiB
JavaScript
import Callbacks from '../classes/Callbacks'
|
|
import DataBoard from '../classes/DataBoard'
|
|
import Thread from '../classes/Thread'
|
|
import Index from '../General/Index'
|
|
import UI from '../General/UI'
|
|
import { Conf, d, doc, g } from '../globals/globals'
|
|
import Main from '../main/Main'
|
|
import Menu from '../Menu/Menu'
|
|
import $ from '../platform/$'
|
|
import $$ from '../platform/$$'
|
|
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')
|
|
if (g.VIEW === 'catalog') {
|
|
return this.catalogWatch()
|
|
}
|
|
this.catalogSet(g.BOARD)
|
|
$.on(d, 'IndexRefreshInternal', this.onIndexRefresh)
|
|
if (Conf['Thread Hiding Buttons']) {
|
|
$.addClass(doc, 'thread-hide')
|
|
}
|
|
return Callbacks.Post.push({
|
|
name: 'Thread Hiding',
|
|
cb: this.node,
|
|
})
|
|
},
|
|
|
|
catalogSet(board) {
|
|
if (!$.hasStorage || g.SITE.software !== 'yotsuba') {
|
|
return
|
|
}
|
|
const hiddenThreads = ThreadHiding.db.get({
|
|
boardID: board.ID,
|
|
defaultValue: dict(),
|
|
})
|
|
for (var threadID in hiddenThreads) {
|
|
hiddenThreads[threadID] = true
|
|
}
|
|
return localStorage.setItem(
|
|
`4chan-hide-t-${board}`,
|
|
JSON.stringify(hiddenThreads)
|
|
)
|
|
},
|
|
|
|
catalogWatch() {
|
|
if (!$.hasStorage || g.SITE.software !== 'yotsuba') {
|
|
return
|
|
}
|
|
this.hiddenThreads =
|
|
JSON.parse(localStorage.getItem(`4chan-hide-t-${g.BOARD}`)) || {}
|
|
return Main.ready(() =>
|
|
// 4chan's catalog sets the style to "display: none;" when hiding or unhiding a thread.
|
|
new MutationObserver(ThreadHiding.catalogSave).observe($.id('threads'), {
|
|
attributes: true,
|
|
subtree: true,
|
|
attributeFilter: ['style'],
|
|
})
|
|
)
|
|
},
|
|
|
|
catalogSave() {
|
|
let threadID
|
|
const hiddenThreads2 =
|
|
JSON.parse(localStorage.getItem(`4chan-hide-t-${g.BOARD}`)) || {}
|
|
for (threadID in hiddenThreads2) {
|
|
if (!$.hasOwn(ThreadHiding.hiddenThreads, threadID)) {
|
|
ThreadHiding.db.set({
|
|
boardID: g.BOARD.ID,
|
|
threadID,
|
|
val: { makeStub: Conf['Stubs'] },
|
|
})
|
|
}
|
|
}
|
|
for (threadID in ThreadHiding.hiddenThreads) {
|
|
if (!$.hasOwn(hiddenThreads2, threadID)) {
|
|
ThreadHiding.db.delete({
|
|
boardID: g.BOARD.ID,
|
|
threadID,
|
|
})
|
|
}
|
|
}
|
|
return (ThreadHiding.hiddenThreads = hiddenThreads2)
|
|
},
|
|
|
|
isHidden(boardID, threadID) {
|
|
return !!(ThreadHiding.db && ThreadHiding.db.get({ boardID, threadID }))
|
|
},
|
|
|
|
node() {
|
|
let data
|
|
if (this.isReply || this.isClone || this.isFetchedQuote) {
|
|
return
|
|
}
|
|
|
|
if (Conf['Thread Hiding Buttons']) {
|
|
$.prepend(this.nodes.root, ThreadHiding.makeButton(this.thread, 'hide'))
|
|
}
|
|
|
|
if (
|
|
(data = ThreadHiding.db.get({
|
|
boardID: this.board.ID,
|
|
threadID: this.ID,
|
|
}))
|
|
) {
|
|
return ThreadHiding.hide(this.thread, data.makeStub)
|
|
}
|
|
},
|
|
|
|
onIndexRefresh() {
|
|
return g.BOARD.threads.forEach(function (thread) {
|
|
const { root } = thread.nodes
|
|
if (thread.isHidden && thread.stub && !root.contains(thread.stub)) {
|
|
return ThreadHiding.makeStub(thread, root)
|
|
}
|
|
})
|
|
},
|
|
|
|
menu: {
|
|
init() {
|
|
if (g.VIEW !== 'index' || !Conf['Menu'] || !Conf['Thread Hiding Link']) {
|
|
return
|
|
}
|
|
|
|
let div = $.el('div', {
|
|
className: 'hide-thread-link',
|
|
textContent: 'Hide',
|
|
})
|
|
|
|
const apply = $.el('a', {
|
|
textContent: 'Apply',
|
|
href: 'javascript:;',
|
|
})
|
|
$.on(apply, 'click', ThreadHiding.menu.hide)
|
|
|
|
const makeStub = UI.checkbox('Stubs', 'Make stub')
|
|
|
|
Menu.menu.addEntry({
|
|
el: div,
|
|
order: 20,
|
|
open({ thread, isReply }) {
|
|
if (
|
|
isReply ||
|
|
thread.isHidden ||
|
|
(Conf['JSON Index'] && Conf['Index Mode'] === 'catalog')
|
|
) {
|
|
return false
|
|
}
|
|
ThreadHiding.menu.thread = thread
|
|
return true
|
|
},
|
|
subEntries: [{ el: apply }, { el: makeStub }],
|
|
})
|
|
|
|
div = $.el('a', {
|
|
className: 'show-thread-link',
|
|
textContent: 'Show',
|
|
href: 'javascript:;',
|
|
})
|
|
$.on(div, 'click', ThreadHiding.menu.show)
|
|
|
|
Menu.menu.addEntry({
|
|
el: div,
|
|
order: 20,
|
|
open({ thread, isReply }) {
|
|
if (
|
|
isReply ||
|
|
!thread.isHidden ||
|
|
(Conf['JSON Index'] && Conf['Index Mode'] === 'catalog')
|
|
) {
|
|
return false
|
|
}
|
|
ThreadHiding.menu.thread = thread
|
|
return true
|
|
},
|
|
})
|
|
|
|
const hideStubLink = $.el('a', {
|
|
textContent: 'Hide stub',
|
|
href: 'javascript:;',
|
|
})
|
|
$.on(hideStubLink, 'click', ThreadHiding.menu.hideStub)
|
|
|
|
return Menu.menu.addEntry({
|
|
el: hideStubLink,
|
|
order: 15,
|
|
open({ thread, isReply }) {
|
|
if (
|
|
isReply ||
|
|
!thread.isHidden ||
|
|
(Conf['JSON Index'] && Conf['Index Mode'] === 'catalog')
|
|
) {
|
|
return false
|
|
}
|
|
return (ThreadHiding.menu.thread = thread)
|
|
},
|
|
})
|
|
},
|
|
|
|
hide() {
|
|
const makeStub = $('input', this.parentNode).checked
|
|
const { thread } = ThreadHiding.menu
|
|
ThreadHiding.hide(thread, makeStub)
|
|
ThreadHiding.saveHiddenState(thread, makeStub)
|
|
return $.event('CloseMenu')
|
|
},
|
|
|
|
show() {
|
|
const { thread } = ThreadHiding.menu
|
|
ThreadHiding.show(thread)
|
|
ThreadHiding.saveHiddenState(thread)
|
|
return $.event('CloseMenu')
|
|
},
|
|
|
|
hideStub() {
|
|
const { thread } = ThreadHiding.menu
|
|
ThreadHiding.show(thread)
|
|
ThreadHiding.hide(thread, false)
|
|
ThreadHiding.saveHiddenState(thread, false)
|
|
$.event('CloseMenu')
|
|
},
|
|
},
|
|
|
|
makeButton(thread, type) {
|
|
const a = $.el('a', {
|
|
className: `${type}-thread-button`,
|
|
href: 'javascript:;',
|
|
})
|
|
$.extend(a, {
|
|
innerHTML:
|
|
'<span class="fa fa-' +
|
|
(type === 'hide' ? 'minus' : 'plus') +
|
|
'-square"></span>',
|
|
})
|
|
a.dataset.fullID = thread.fullID
|
|
$.on(a, 'click', ThreadHiding.toggle)
|
|
return a
|
|
},
|
|
|
|
makeStub(thread, root) {
|
|
let summary, threadDivider
|
|
let numReplies = $$(g.SITE.selectors.replyOriginal, root).length
|
|
if ((summary = $(g.SITE.selectors.summary, root))) {
|
|
numReplies += +summary.textContent.match(/\d+/)
|
|
}
|
|
|
|
const a = ThreadHiding.makeButton(thread, 'show')
|
|
$.add(
|
|
a,
|
|
$.tn(
|
|
` ${thread.OP.info.nameBlock} (${
|
|
numReplies === 1 ? '1 reply' : `${numReplies} replies`
|
|
})`
|
|
)
|
|
)
|
|
thread.stub = $.el('div', { className: 'stub' })
|
|
if (Conf['Menu']) {
|
|
$.add(thread.stub, [a, Menu.makeButton(thread.OP)])
|
|
} else {
|
|
$.add(thread.stub, a)
|
|
}
|
|
$.prepend(root, thread.stub)
|
|
|
|
// Prevent hiding of thread divider on sites that put it inside the thread
|
|
if ((threadDivider = $(g.SITE.selectors.threadDivider, root))) {
|
|
return $.addClass(threadDivider, 'threadDivider')
|
|
}
|
|
},
|
|
|
|
saveHiddenState(thread, makeStub) {
|
|
if (thread.isHidden) {
|
|
ThreadHiding.db.set({
|
|
boardID: thread.board.ID,
|
|
threadID: thread.ID,
|
|
val: { makeStub },
|
|
})
|
|
} else {
|
|
ThreadHiding.db.delete({
|
|
boardID: thread.board.ID,
|
|
threadID: thread.ID,
|
|
})
|
|
}
|
|
return ThreadHiding.catalogSet(thread.board)
|
|
},
|
|
|
|
toggle(thread) {
|
|
if (!(thread instanceof Thread)) {
|
|
thread = g.threads.get(this.dataset.fullID)
|
|
}
|
|
if (thread.isHidden) {
|
|
ThreadHiding.show(thread)
|
|
} else {
|
|
ThreadHiding.hide(thread)
|
|
}
|
|
return ThreadHiding.saveHiddenState(thread)
|
|
},
|
|
|
|
hide(thread, makeStub = Conf['Stubs']) {
|
|
if (thread.isHidden) {
|
|
return
|
|
}
|
|
const threadRoot = thread.nodes.root
|
|
thread.isHidden = true
|
|
Index.updateHideLabel()
|
|
if (thread.catalogView && !Index.showHiddenThreads) {
|
|
$.rm(thread.catalogView.nodes.root)
|
|
$.event('PostsRemoved', null, Index.root)
|
|
}
|
|
|
|
if (!makeStub) {
|
|
return (threadRoot.hidden = true)
|
|
}
|
|
|
|
return ThreadHiding.makeStub(thread, threadRoot)
|
|
},
|
|
|
|
show(thread) {
|
|
if (thread.stub) {
|
|
$.rm(thread.stub)
|
|
delete thread.stub
|
|
}
|
|
const threadRoot = thread.nodes.root
|
|
threadRoot.hidden = thread.isHidden = false
|
|
Index.updateHideLabel()
|
|
if (thread.catalogView && Index.showHiddenThreads) {
|
|
$.rm(thread.catalogView.nodes.root)
|
|
return $.event('PostsRemoved', null, Index.root)
|
|
}
|
|
},
|
|
}
|
|
export default ThreadHiding
|