From c6684f5ba2dc0b94b81a81b24a47adb431281ec7 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Thu, 18 Jul 2019 15:15:05 -0700 Subject: [PATCH] Add option `Filter in Native Catalog` to apply 4chan X filters on native catalog. Also works on vichan sites. #2351 --- src/Filtering/Filter.coffee | 47 +++++++++++++++++++++++--- src/General/Settings.coffee | 3 ++ src/General/Settings/Filter-guide.html | 4 --- src/classes/Callbacks.coffee | 1 + src/classes/CatalogThreadNative.coffee | 12 +++++++ src/config/Config.coffee | 5 +++ src/css/style.css | 3 +- src/main/Main.coffee | 47 +++++++++++++++++++++++++- src/site/SW.tinyboard.coffee | 8 +++++ src/site/SW.yotsuba.coffee | 5 +++ 10 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/classes/CatalogThreadNative.coffee diff --git a/src/Filtering/Filter.coffee b/src/Filtering/Filter.coffee index 0075c907e..f5790e148 100644 --- a/src/Filtering/Filter.coffee +++ b/src/Filtering/Filter.coffee @@ -2,7 +2,8 @@ Filter = filters: {} results: {} init: -> - return unless g.VIEW in ['index', 'thread'] and Conf['Filter'] + return unless g.VIEW in ['index', 'thread', 'catalog'] and Conf['Filter'] + return if g.VIEW is 'catalog' and not Conf['Filter in Native Catalog'] unless Conf['Filtered Backlinks'] $.addClass doc, 'hide-backlinks' @@ -89,9 +90,12 @@ Filter = (@filters[key] or= []).push filter return unless Object.keys(@filters).length - Callbacks.Post.push - name: 'Filter' - cb: @node + if g.VIEW is 'catalog' + Filter.catalog() + else + Callbacks.Post.push + name: 'Filter' + cb: @node # Parse comma-separated list of boards. # Sites can be specified by a beginning part of the site domain followed by a colon. @@ -166,6 +170,41 @@ Filter = if noti and Unread.posts and (@ID > Unread.lastReadPost) and not QuoteYou.isYou(@) Unread.openNotification @, ' triggered a notification filter' + catalog: -> + return unless (url = g.SITE.urls.catalogJSON?(g.BOARD)) + Filter.catalogData = {} + $.ajax url, + onloadend: Filter.catalogParse + Callbacks.CatalogThreadNative.push + name: 'Filter' + cb: @catalogNode + + catalogParse: -> + if @status not in [200, 404] + new Notice 'warning', "Failed to fetch catalog JSON data. #{if @status then "Error #{@statusText} (#{@status})" else 'Connection Error'}", 1 + return + for page in @response + for item in page.threads + Filter.catalogData[item.no] = item + g.BOARD.threads.forEach (thread) -> + if thread.catalogViewNative + Filter.catalogNode.call thread.catalogViewNative + return + + catalogNode: -> + return unless @boardID is g.BOARD.ID and Filter.catalogData[@ID] + return if QuoteYou.db?.get {siteID: g.SITE.ID, boardID: @boardID, threadID: @ID, postID: @ID} + {hide, hl, top} = Filter.test(g.SITE.Build.parseJSON Filter.catalogData[@ID], @) + if hide + @nodes.root.hidden = true + else + if hl + @highlights = hl + $.addClass @nodes.root, hl... + if top + $.prepend @nodes.root.parentNode, @nodes.root + g.SITE.catalogPin? @nodes.root + isHidden: (post) -> !!Filter.test(post).hide diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index bd639ab02..133164d82 100644 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -492,6 +492,9 @@ Settings = if compareString < '00001.00014.00009.00001' if data['Use Faster Image Host']? and not data['fourchanImageHost']? set 'fourchanImageHost', (if data['Use Faster Image Host'] then 'i.4cdn.org' else '') + if compareString < '00001.00014.00010.00001' + unless data['Filter in Native Catalog']? + set 'Filter in Native Catalog', false changes loadSettings: (data, cb) -> diff --git a/src/General/Settings/Filter-guide.html b/src/General/Settings/Filter-guide.html index 8a6a3ea84..02bba5805 100644 --- a/src/General/Settings/Filter-guide.html +++ b/src/General/Settings/Filter-guide.html @@ -51,7 +51,3 @@ For example: type:filename+filesize+dimensions;.
-

- Note: If you're using the native catalog rather than <%= meta.name %>'s catalog, <%= meta.name %>'s filters do not apply there.
- The native catalog has its own separate filter list. -

diff --git a/src/classes/Callbacks.coffee b/src/classes/Callbacks.coffee index f35629d9b..31aee94f5 100644 --- a/src/classes/Callbacks.coffee +++ b/src/classes/Callbacks.coffee @@ -2,6 +2,7 @@ class Callbacks @Post = new Callbacks 'Post' @Thread = new Callbacks 'Thread' @CatalogThread = new Callbacks 'Catalog Thread' + @CatalogThreadNative = new Callbacks 'Catalog Thread' constructor: (@type) -> @keys = [] diff --git a/src/classes/CatalogThreadNative.coffee b/src/classes/CatalogThreadNative.coffee new file mode 100644 index 000000000..f66bb1ab9 --- /dev/null +++ b/src/classes/CatalogThreadNative.coffee @@ -0,0 +1,12 @@ +class CatalogThreadNative + toString: -> @ID + + constructor: (root) -> + @nodes = + root: root + thumb: $(g.SITE.selectors.catalog.thumb, root) + @siteID = g.SITE.ID + @boardID = @nodes.thumb.parentNode.pathname.split(/\/+/)[1] + @board = g.boards[@boardID] or new Board(@boardID) + @ID = @threadID = +(root.dataset.id or root.id).match(/\d*$/)[0] + @thread = @board.threads[@ID] or new Thread(@ID, @board) diff --git a/src/config/Config.coffee b/src/config/Config.coffee index 2e538533a..c3032bfae 100644 --- a/src/config/Config.coffee +++ b/src/config/Config.coffee @@ -187,6 +187,11 @@ Config = 'When enabled, shows backlinks to filtered posts with a line-through decoration. Otherwise, hides the backlinks.' 1 ] + 'Filter in Native Catalog': [ + true + 'Apply 4chan X filters in native catalog.' + 1 + ] 'Recursive Hiding': [ true 'Hide replies of hidden posts, recursively.' diff --git a/src/css/style.css b/src/css/style.css index 12d309922..0be891aea 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1462,7 +1462,8 @@ input[name="Default Volume"] { :root:not(.werkTyme) .catalog-thread.filter-highlight .catalog-thumb, :root.werkTyme .catalog-thread.filter-highlight:not(:hover), :root.werkTyme:not(.catalog-hover-expand) .catalog-thread.filter-highlight, -:root.werkTyme.catalog-hover-expand .catalog-thread.filter-highlight > .catalog-container:hover > .catalog-post { +:root.werkTyme.catalog-hover-expand .catalog-thread.filter-highlight > .catalog-container:hover > .catalog-post, +:root.catalog $site$catalog$thread.filter-highlight$site$relative$catalogHighlight { box-shadow: 0 0 3px 3px rgba(255, 0, 0, .5); } :root:not(.werkTyme) .catalog-thread.watched .catalog-thumb, diff --git a/src/main/Main.coffee b/src/main/Main.coffee index 8fd3ce8ba..812513430 100644 --- a/src/main/Main.coffee +++ b/src/main/Main.coffee @@ -325,7 +325,9 @@ Main = new Notice 'warning', msg # Parse HTML or skip it and start building from JSON. - unless Index.enabled + if g.VIEW is 'catalog' + Main.initCatalog() + else if !Index.enabled Main.initThread() else Main.expectInitFinished = true @@ -431,6 +433,49 @@ Main = $.event 'PostsRemoved', null, thread.nodes.root return + initCatalog: -> + s = g.SITE.selectors.catalog + if s and (board = $ s.board) + threads = [] + errors = [] + + Main.addCatalogThreadsObserver = new MutationObserver Main.addCatalogThreads + Main.addCatalogThreadsObserver.observe board, {childList: true} + + Main.parseCatalogThreads $$(s.thread, board), threads, errors + Main.handleErrors errors if errors.length + + Main.callbackNodes 'CatalogThreadNative', threads + + Main.expectInitFinished = true + $.event '4chanXInitFinished' + + parseCatalogThreads: (threadRoots, threads, errors) -> + for threadRoot in threadRoots + try + thread = new CatalogThreadNative threadRoot + if thread.thread.catalogViewNative?.nodes.root isnt threadRoot + thread.thread.catalogViewNative = thread + threads.push thread + catch err + # Skip threads that we failed to parse. + errors.push + message: "Parsing of Catalog Thread No.#{(threadRoot.dataset.id or threadRoot.id).match(/\d+/)} failed. Thread will be skipped." + error: err + return + + addCatalogThreads: (records) -> + threadRoots = [] + for record in records + for node in record.addedNodes when node.nodeType is Node.ELEMENT_NODE and node.matches(g.SITE.selectors.catalog.thread) + threadRoots.push node + return unless threadRoots.length + threads = [] + errors = [] + Main.parseCatalogThreads threadRoots, threads, errors + Main.handleErrors errors if errors.length + Main.callbackNodes 'CatalogThreadNative', threads + callbackNodes: (klass, nodes) -> i = 0 cb = Callbacks[klass] diff --git a/src/site/SW.tinyboard.coffee b/src/site/SW.tinyboard.coffee index 2ab00499f..cc78ec912 100644 --- a/src/site/SW.tinyboard.coffee +++ b/src/site/SW.tinyboard.coffee @@ -94,9 +94,14 @@ SW.tinyboard = opHighlight: ' > .op' replyPost: '.reply' replyOriginal: 'div[id^="reply_"]:not(.hidden)' + catalogHighlight: ' > .thread' comment: '.body' spoiler: '.spoiler' quotelink: 'a[onclick^="highlightReply("]' + catalog: + board: '#Grid' + thread: '.mix' + thumb: '.thread-image' boardList: '.boardlist' boardListBottom: '.boardlist.bottom' styleSheet: '#stylesheet' @@ -186,3 +191,6 @@ SW.tinyboard = isLinkified: (link) -> /\bnofollow\b/.test(link.rel) + + catalogPin: (threadRoot) -> + threadRoot.dataset.sticky = 'true' diff --git a/src/site/SW.yotsuba.coffee b/src/site/SW.yotsuba.coffee index fcd2e12fa..38a74994c 100644 --- a/src/site/SW.yotsuba.coffee +++ b/src/site/SW.yotsuba.coffee @@ -54,9 +54,14 @@ SW.yotsuba = opHighlight: '.opContainer' replyPost: ' > .reply' replyOriginal: '.replyContainer:not([data-clone])' + catalogHighlight: '' comment: '.postMessage' spoiler: 's' quotelink: ':not(pre) > .quotelink' # XXX https://github.com/4chan/4chan-JS/issues/77: 4chan currently creates quote links inside [code] tags; ignore them + catalog: + board: '#threads' + thread: '.thread' + thumb: '.thumb' boardList: '#boardNavDesktop > .boardList' boardListBottom: '#boardNavDesktopFoot > .boardList' styleSheet: 'link[title=switch]'