Merge pull request #1457 from MayhemYDG/hide

Hiding enhancements
This commit is contained in:
Mayhem 2014-02-22 02:31:06 +01:00
commit d9a1b2844e
22 changed files with 384 additions and 460 deletions

View File

@ -1,3 +1,13 @@
- Thread and post hiding changes:
- The posts' menu now has a label entry listing the reasons why a post got hidden or highlighted.
- `Thread Hiding` and `Reply Hiding` settings are merged into one: `Post Hiding`.
- `Thread Hiding Link` and `Reply Hiding Link` settings are merged into one: `Post Hiding Link`.
- Hiding a thread removes it from the index in `Paged` or `All threads` modes.
<ul>
<li> Hidden threads can be seen by clicking the `[Show]` button the the top of the index.
<li> The `Anchor Hidden Threads` setting has been removed.
</ul>
### 3.18.1 - *2014-02-20* ### 3.18.1 - *2014-02-20*
- Fix the QR breaking after a change with 4chan. - Fix the QR breaking after a change with 4chan.

View File

@ -368,7 +368,6 @@ a[href="javascript:;"] {
:root.index-loading .navLinks, :root.index-loading .navLinks,
:root.index-loading .board, :root.index-loading .board,
:root.index-loading .pagelist, :root.index-loading .pagelist,
:root:not(.catalog-mode) #hidden-toggle,
:root:not(.catalog-mode) #index-size { :root:not(.catalog-mode) #index-size {
display: none; display: none;
} }
@ -706,14 +705,16 @@ a.hide-announcement {
border: 2px solid rgba(255, 0, 0, .5); border: 2px solid rgba(255, 0, 0, .5);
} }
/* Thread & Reply Hiding */ /* Post Hiding */
.hide-thread-button, .hide-post-button,
.hide-reply-button { .show-post-button {
float: left; font-size: 14px;
margin-right: 2px; line-height: 12px; /* Prevent the floating effect from affecting the thumbnail too */
} }
.stub ~ * { .opContainer > .show-post-button,
display: none !important; .hide-post-button {
float: left;
margin-right: 3px;
} }
.stub input { .stub input {
display: inline-block; display: inline-block;

View File

@ -57,7 +57,18 @@ Filter =
top = filter.match(/top:(yes|no)/)?[1] or 'yes' top = filter.match(/top:(yes|no)/)?[1] or 'yes'
top = top is 'yes' # Turn it into a boolean top = top is 'yes' # Turn it into a boolean
@filters[key].push @createFilter regexp, op, stub, hl, top @filters[key].push {
hide: !hl
op: op
stub: stub
class: hl
top: top
match: regexp
test: if typeof regexp is 'string'
Filter.stringTest # MD5 checking
else
Filter.regexpTest
}
# Only execute filter types that contain valid filters. # Only execute filter types that contain valid filters.
unless @filters[key].length unless @filters[key].length
@ -68,25 +79,6 @@ Filter =
name: 'Filter' name: 'Filter'
cb: @node cb: @node
createFilter: (regexp, op, stub, hl, top) ->
test =
if typeof regexp is 'string'
# MD5 checking
(value) -> regexp is value
else
(value) -> regexp.test value
settings =
hide: !hl
stub: stub
class: hl
top: top
(value, isReply) ->
if isReply and op is 'only' or !isReply and op is 'no'
return false
unless test value
return false
settings
node: -> node: ->
return if @isClone return if @isClone
for key of Filter.filters for key of Filter.filters
@ -94,27 +86,29 @@ Filter =
# Continue if there's nothing to filter (no tripcode for example). # Continue if there's nothing to filter (no tripcode for example).
continue if value is false continue if value is false
for filter in Filter.filters[key] for obj in Filter.filters[key]
unless result = filter value, @isReply unless Filter.test obj, value, @isReply
continue continue
# Hide # Hide
if result.hide if obj.hide
if @isReply continue unless @isReply or g.VIEW is 'index'
PostHiding.hide @, result.stub @hide "Hidden by filtering the #{key}: #{obj.match}", obj.stub
else if g.VIEW is 'index'
ThreadHiding.hide @thread, result.stub
else
continue
return return
# Highlight # Highlight
$.addClass @nodes.root, result.class @highlight "Highlighted by filtering the #{key}: #{obj.match}", obj.class, obj.top
unless @highlights and result.class in @highlights
(@highlights or= []).push result.class
if !@isReply and result.top
@thread.isOnTop = true
stringTest: (string, value) ->
string is value
regexpTest: (regexp, value) ->
regexp.test value
test: ({test, match, op}, value, isReply) ->
if isReply and op is 'only' or !isReply and op is 'no'
return false
unless test match, value
return false
true
name: (post) -> name: (post) ->
if 'name' of post.info if 'name' of post.info
return post.info.name return post.info.name

View File

@ -1,186 +1,184 @@
PostHiding = PostHiding =
init: -> init: ->
return if !Conf['Reply Hiding'] and !Conf['Reply Hiding Link']
@db = new DataBoard 'hiddenPosts' @db = new DataBoard 'hiddenPosts'
@hideButton = $.el 'a',
className: 'hide-post-button'
innerHTML: '<i class="fa fa-minus-square-o"></i>'
href: 'javascript:;'
@showButton = $.el 'a',
className: 'show-post-button'
innerHTML: '<i class="fa fa-plus-square-o"></i>'
href: 'javascript:;'
Post.callbacks.push Post.callbacks.push
name: 'Reply Hiding' name: 'Post Hiding'
cb: @node cb: @node
# XXX tmp conversion
$.get 'hiddenThreads', null, ({hiddenThreads}) ->
return unless hiddenThreads
for boardID, board of hiddenThreads.boards
for threadID, val of board
((PostHiding.db.data.boards[boardID] or= {})[threadID] or= {})[threadID] = val
PostHiding.db.save()
$.delete 'hiddenThreads'
node: -> node: ->
return if !@isReply or @isClone return if !@isReply and g.VIEW isnt 'index' or @isClone
if data = PostHiding.db.get {boardID: @board.ID, threadID: @thread.ID, postID: @ID} if data = PostHiding.db.get {boardID: @board.ID, threadID: @thread.ID, postID: @ID}
if data.thisPost if data.thisPost is false
PostHiding.hide @, data.makeStub, data.hideRecursively label = "Recursively hidden for quoting No.#{@}"
Recursive.apply 'hide', @, label, data.makeStub, true
Recursive.add 'hide', @, label, data.makeStub, true
else else
Recursive.apply PostHiding.hide, @, data.makeStub, true @hide 'Manually hidden', data.makeStub, data.hideRecursively
Recursive.add PostHiding.hide, @, data.makeStub, true
return unless Conf['Reply Hiding']
$.replace $('.sideArrows', @nodes.root), PostHiding.makeButton @, 'hide'
menu: return unless Conf['Post Hiding']
init: -> if @isReply
return if !Conf['Menu'] or !Conf['Reply Hiding Link'] a = PostHiding.makeButton true
a.hidden = true if @isHidden
$.replace $('.sideArrows', @nodes.root), a
else
$.prepend @nodes.root, PostHiding.makeButton !@isHidden
# Hide makeButton: (hide) ->
div = $.el 'div', a = (if hide then PostHiding.hideButton else PostHiding.showButton).cloneNode true
className: 'hide-reply-link' $.on a, 'click', PostHiding.onToggleClick
textContent: 'Hide reply'
apply = $.el 'a',
textContent: 'Apply'
href: 'javascript:;'
$.on apply, 'click', PostHiding.menu.hide
thisPost = $.el 'label',
innerHTML: '<input type=checkbox name=thisPost checked> This post'
replies = $.el 'label',
innerHTML: "<input type=checkbox name=replies checked=#{Conf['Recursive Hiding']}> Hide replies"
makeStub = $.el 'label',
innerHTML: "<input type=checkbox name=makeStub checked=#{Conf['Stubs']}> Make stub"
$.event 'AddMenuEntry',
type: 'post'
el: div
order: 20
open: (post) ->
if !post.isReply or post.isClone or post.isHidden
return false
PostHiding.menu.post = post
true
subEntries: [{el: apply}, {el: thisPost}, {el: replies}, {el: makeStub}]
# Show
div = $.el 'div',
className: 'show-reply-link'
textContent: 'Show reply'
apply = $.el 'a',
textContent: 'Apply'
href: 'javascript:;'
$.on apply, 'click', PostHiding.menu.show
thisPost = $.el 'label',
innerHTML: '<input type=checkbox name=thisPost> This post'
replies = $.el 'label',
innerHTML: "<input type=checkbox name=replies> Show replies"
$.event 'AddMenuEntry',
type: 'post'
el: div
order: 20
open: (post) ->
if !post.isReply or post.isClone or !post.isHidden
return false
unless data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
return false
PostHiding.menu.post = post
thisPost.firstChild.checked = post.isHidden
replies.firstChild.checked = if data?.hideRecursively? then data.hideRecursively else Conf['Recursive Hiding']
true
subEntries: [{el: apply}, {el: thisPost}, {el: replies}]
hide: ->
parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked
replies = $('input[name=replies]', parent).checked
makeStub = $('input[name=makeStub]', parent).checked
{post} = PostHiding.menu
if thisPost
PostHiding.hide post, makeStub, replies
else if replies
Recursive.apply PostHiding.hide, post, makeStub, true
Recursive.add PostHiding.hide, post, makeStub, true
else
return
PostHiding.saveHiddenState post, true, thisPost, makeStub, replies
$.event 'CloseMenu'
show: ->
parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked
replies = $('input[name=replies]', parent).checked
{post} = PostHiding.menu
if thisPost
PostHiding.show post, replies
else if replies
Recursive.apply PostHiding.show, post, true
Recursive.rm PostHiding.hide, post, true
else
return
if data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
PostHiding.saveHiddenState post, !(thisPost and replies), !thisPost, data.makeStub, !replies
$.event 'CloseMenu'
makeButton: (post, type) ->
span = $.el 'span',
textContent: "[\u00A0#{if type is 'hide' then '-' else '+'}\u00A0]"
a = $.el 'a',
className: "#{type}-reply-button"
href: 'javascript:;'
$.add a, span
$.on a, 'click', PostHiding.toggle
a a
saveHiddenState: (post, isHiding, thisPost, makeStub, hideRecursively) -> onToggleClick: ->
PostHiding.toggle if $.x 'ancestor::div[contains(@class,"postContainer")][1]', @
Get.postFromNode @
else
Get.threadFromNode(@).OP
toggle: (post) ->
if post.isHidden
post.show()
else
post.hide 'Manually hidden'
PostHiding.saveHiddenState post
return if post.isReply
Index.updateHideLabel()
Index.sort()
Index.buildIndex()
saveHiddenState: (post, val) ->
data = data =
boardID: post.board.ID boardID: post.board.ID
threadID: post.thread.ID threadID: post.thread.ID
postID: post.ID postID: post.ID
if isHiding if post.isHidden or val and !val.thisPost
data.val = data.val = val or {}
thisPost: thisPost isnt false # undefined -> true
makeStub: makeStub
hideRecursively: hideRecursively
PostHiding.db.set data PostHiding.db.set data
else else if PostHiding.db.get data # unhiding a filtered post f.e.
PostHiding.db.delete data PostHiding.db.delete data
toggle: -> menu:
post = Get.postFromNode @ init: ->
if post.isHidden return if !Conf['Menu'] or !Conf['Post Hiding Link']
PostHiding.show post
else
PostHiding.hide post
PostHiding.saveHiddenState post, post.isHidden
hide: (post, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) -> # Hide
return if post.isHidden apply =
post.isHidden = true el: $.el 'a', textContent: 'Apply', href: 'javascript:;'
open: (post) ->
$.off @el, 'click', @cb if @cb
@cb = -> PostHiding.menu.hide post
$.on @el, 'click', @cb
true
thisPost =
el: $.el 'label', innerHTML: '<input type=checkbox name=thisPost checked> This post'
replies =
el: $.el 'label', innerHTML: "<input type=checkbox name=replies checked=#{Conf['Recursive Hiding']}> Hide replies"
makeStub =
el: $.el 'label', innerHTML: "<input type=checkbox name=makeStub checked=#{Conf['Stubs']}> Make stub"
if hideRecursively $.event 'AddMenuEntry',
Recursive.apply PostHiding.hide, post, makeStub, true type: 'post'
Recursive.add PostHiding.hide, post, makeStub, true el: $.el 'div',
textContent: 'Hide post'
className: 'hide-post-link'
order: 20
open: (post) -> !(post.isHidden or !post.isReply or post.isClone)
subEntries: [apply, thisPost, replies, makeStub]
for quotelink in Get.allQuotelinksLinkingTo post # Show
$.addClass quotelink, 'filtered' apply =
el: $.el 'a', textContent: 'Apply', href: 'javascript:;'
open: (post) ->
$.off @el, 'click', @cb if @cb
@cb = -> PostHiding.menu.show post
$.on @el, 'click', @cb
true
thisPost =
el: $.el 'label', innerHTML: '<input type=checkbox name=thisPost> This post'
open: (post) ->
@el.firstChild.checked = post.isHidden
true
replies =
el: $.el 'label', innerHTML: '<input type=checkbox name=replies> Unhide replies'
open: (post) ->
data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
@el.firstChild.checked = if 'hideRecursively' of data then data.hideRecursively else Conf['Recursive Hiding']
true
unless makeStub $.event 'AddMenuEntry',
post.nodes.root.hidden = true type: 'post'
return el: $.el 'div',
textContent: 'Unhide post'
className: 'show-post-link'
order: 20
open: (post) ->
if !post.isHidden or !post.isReply or post.isClone
return false
unless PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
return false
true
subEntries: [apply, thisPost, replies]
a = PostHiding.makeButton post, 'show' return if g.VIEW isnt 'index'
postInfo = $.event 'AddMenuEntry',
if Conf['Anonymize'] type: 'post'
'Anonymous' el: $.el 'a', href: 'javascript:;'
order: 20
open: (post) ->
@el.textContent = if post.isHidden
'Unhide thread'
else
'Hide thread'
$.off @el, 'click', @cb if @cb
@cb = ->
$.event 'CloseMenu'
PostHiding.toggle post
$.on @el, 'click', @cb
true
hide: (post) ->
parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked
replies = $('input[name=replies]', parent).checked
makeStub = $('input[name=makeStub]', parent).checked
label = 'Manually hidden'
if thisPost
post.hide label, makeStub, replies
else if replies
Recursive.apply 'hide', post, label, makeStub, true
Recursive.add 'hide', post, label, makeStub, true
else else
$('.nameBlock', post.nodes.info).textContent return
$.add a, $.tn " #{postInfo}" PostHiding.saveHiddenState post, {thisPost, hideRecursively: replies, makeStub}
post.nodes.stub = $.el 'div', $.event 'CloseMenu'
className: 'stub' show: (post) ->
$.add post.nodes.stub, a parent = @parentNode
if Conf['Menu'] thisPost = $('input[name=thisPost]', parent).checked
$.add post.nodes.stub, Menu.makeButton() replies = $('input[name=replies]', parent).checked
$.prepend post.nodes.root, post.nodes.stub if thisPost
post.show replies
show: (post, showRecursively=Conf['Recursive Hiding']) -> else if replies
if post.nodes.stub Recursive.apply 'show', post, true
$.rm post.nodes.stub Recursive.rm 'hide', post, true
delete post.nodes.stub else
else return
post.nodes.root.hidden = false val = {thisPost: !thisPost, hideRecursively: !replies, makeStub: !!post.nodes.stub}
post.isHidden = false PostHiding.saveHiddenState post, val
if showRecursively $.event 'CloseMenu'
Recursive.apply PostHiding.show, post, true
Recursive.rm PostHiding.hide, post
for quotelink in Get.allQuotelinksLinkingTo post
$.rmClass quotelink, 'filtered'
return

View File

@ -7,10 +7,9 @@ Recursive =
node: -> node: ->
return if @isClone return if @isClone
for quote in @quotes for quote in @quotes when obj = Recursive.recursives[quote]
if obj = Recursive.recursives[quote] for recursive, i in obj.recursives
for recursive, i in obj.recursives @[recursive] obj.args[i]...
recursive @, obj.args[i]...
return return
add: (recursive, post, args...) -> add: (recursive, post, args...) ->
@ -22,15 +21,13 @@ Recursive =
rm: (recursive, post) -> rm: (recursive, post) ->
return unless obj = Recursive.recursives[post.fullID] return unless obj = Recursive.recursives[post.fullID]
for rec, i in obj.recursives for rec, i in obj.recursives when rec is recursive
if rec is recursive obj.recursives.splice i, 1
obj.recursives.splice i, 1 obj.args.splice i, 1
obj.args.splice i, 1
return return
apply: (recursive, post, args...) -> apply: (recursive, post, args...) ->
{fullID} = post {fullID} = post
for ID, post of g.posts for ID, post of g.posts when fullID in post.quotes
if fullID in post.quotes post[recursive] args...
recursive post, args...
return return

View File

@ -1,126 +0,0 @@
ThreadHiding =
init: ->
return if g.VIEW isnt 'index'
@db = new DataBoard 'hiddenThreads'
$.on d, 'IndexRefresh', @onIndexRefresh
Thread.callbacks.push
name: 'Thread Hiding'
cb: @node
node: ->
if data = ThreadHiding.db.get {boardID: @board.ID, threadID: @ID}
ThreadHiding.hide @, data.makeStub
return unless Conf['Thread Hiding']
$.prepend @OP.nodes.root, ThreadHiding.makeButton @, 'hide'
onIndexRefresh: ->
for root, i in Index.nodes by 2
thread = Get.threadFromRoot root
continue unless thread.isHidden
unless thread.stub
Index.nodes[i + 1].hidden = true
else unless root.contains thread.stub
# When we come back to a page, the stub is already there.
ThreadHiding.makeStub thread, root
return
menu:
init: ->
return if g.VIEW isnt 'index' or !Conf['Menu'] or !Conf['Thread Hiding Link']
div = $.el 'div',
className: 'hide-thread-link'
textContent: 'Hide thread'
apply = $.el 'a',
textContent: 'Apply'
href: 'javascript:;'
$.on apply, 'click', ThreadHiding.menu.hide
makeStub = $.el 'label',
innerHTML: "<input type=checkbox checked=#{Conf['Stubs']}> Make stub"
$.event 'AddMenuEntry',
type: 'post'
el: div
order: 20
open: ({thread, isReply}) ->
if isReply or thread.isHidden or Conf['Index Mode'] is 'catalog'
return false
ThreadHiding.menu.thread = thread
true
subEntries: [el: apply; el: makeStub]
hide: ->
makeStub = $('input', @parentNode).checked
{thread} = ThreadHiding.menu
ThreadHiding.hide thread, makeStub
ThreadHiding.saveHiddenState thread, makeStub
$.event 'CloseMenu'
makeButton: (thread, type) ->
a = $.el 'a',
className: "#{type}-thread-button"
innerHTML: "<span>[&nbsp;#{if type is 'hide' then '-' else '+'}&nbsp;]</span>"
href: 'javascript:;'
a.dataset.fullID = thread.fullID
$.on a, 'click', ThreadHiding.toggle
a
makeStub: (thread, root) ->
numReplies = $$('.thread > .replyContainer', root).length
numReplies += +summary.textContent.match /\d+/ if summary = $ '.summary', root
opInfo = if Conf['Anonymize']
'Anonymous'
else
$('.nameBlock', thread.OP.nodes.info).textContent
a = ThreadHiding.makeButton thread, 'show'
$.add a, $.tn " #{opInfo} (#{if numReplies is 1 then '1 reply' else "#{numReplies} replies"})"
thread.stub = $.el 'div',
className: 'stub'
if Conf['Menu']
$.add thread.stub, [a, Menu.makeButton()]
else
$.add thread.stub, a
$.prepend root, thread.stub
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
toggle: (thread) ->
unless thread instanceof Thread
thread = g.threads[@dataset.fullID]
if thread.isHidden
ThreadHiding.show thread
else
ThreadHiding.hide thread
ThreadHiding.saveHiddenState thread
hide: (thread, makeStub=Conf['Stubs']) ->
return if thread.isHidden
threadRoot = thread.OP.nodes.root.parentNode
thread.isHidden = true
Index.updateHideLabel()
unless makeStub
threadRoot.hidden = threadRoot.nextElementSibling.hidden = true # <hr>
return
ThreadHiding.makeStub thread, threadRoot
show: (thread) ->
if thread.stub
$.rm thread.stub
delete thread.stub
threadRoot = thread.OP.nodes.root.parentNode
threadRoot.nextElementSibling.hidden =
threadRoot.hidden = thread.isHidden = false
Index.updateHideLabel()

View File

@ -244,20 +244,20 @@ Build =
if (OP = board.posts[data.no]) and root = OP.nodes.root.parentNode if (OP = board.posts[data.no]) and root = OP.nodes.root.parentNode
$.rmAll root $.rmAll root
$.add root, OP.nodes.root
else else
root = $.el 'div', root = $.el 'div',
className: 'thread' className: 'thread'
id: "t#{data.no}" id: "t#{data.no}"
$.add root, Build.postFromObject data, board.ID
nodes = [if OP then OP.nodes.root else Build.postFromObject data, board.ID]
if data.omitted_posts or !Conf['Show Replies'] and data.replies if data.omitted_posts or !Conf['Show Replies'] and data.replies
[posts, files] = if Conf['Show Replies'] [posts, files] = if Conf['Show Replies']
[data.omitted_posts, data.omitted_images] [data.omitted_posts, data.omitted_images]
else else
[data.replies, data.images] [data.replies, data.images]
nodes.push Build.summary board.ID, data.no, posts, files $.add root, Build.summary board.ID, data.no, posts, files
$.add root, nodes
root root
catalogThread: (thread) -> catalogThread: (thread) ->
{staticPath, gifIcon} = Build {staticPath, gifIcon} = Build
@ -279,7 +279,7 @@ Build =
root.dataset.fullID = thread.fullID root.dataset.fullID = thread.fullID
$.addClass root, 'pinned' if thread.isPinned $.addClass root, 'pinned' if thread.isPinned
$.addClass root, thread.OP.highlights... if thread.OP.highlights $.addClass root, thread.OP.highlights... if thread.OP.highlights.length
thumb = root.firstElementChild thumb = root.firstElementChild
if data.spoiler and !Conf['Reveal Spoilers'] if data.spoiler and !Conf['Reveal Spoilers']

View File

@ -17,10 +17,9 @@ Config =
'Filtering': 'Filtering':
'Anonymize': [false, 'Make everyone Anonymous.'] 'Anonymize': [false, 'Make everyone Anonymous.']
'Filter': [true, 'Self-moderation placebo.'] 'Filter': [true, 'Self-moderation placebo.']
'Post Hiding': [true, 'Add buttons to hide threads and replies.']
'Stubs': [true, 'Show stubs of hidden posts.']
'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.'] 'Recursive Hiding': [true, 'Hide replies of hidden posts, recursively.']
'Thread Hiding': [true, 'Add buttons to hide entire threads.']
'Reply Hiding': [true, 'Add buttons to hide single replies.']
'Stubs': [true, 'Show stubs of hidden threads / replies.']
'Images': 'Images':
'Auto-GIF': [false, 'Animate GIF thumbnails (disabled on /gif/, /wsg/).'] 'Auto-GIF': [false, 'Animate GIF thumbnails (disabled on /gif/, /wsg/).']
'Image Expansion': [true, 'Expand images inline.'] 'Image Expansion': [true, 'Expand images inline.']
@ -31,8 +30,7 @@ Config =
'Menu': 'Menu':
'Menu': [true, 'Add a drop-down menu to posts.'] 'Menu': [true, 'Add a drop-down menu to posts.']
'Report Link': [true, 'Add a report link to the menu.'] 'Report Link': [true, 'Add a report link to the menu.']
'Thread Hiding Link': [true, 'Add a link to hide entire threads.'] 'Post Hiding Link': [true, 'Add a link to hide threads and replies.']
'Reply Hiding Link': [true, 'Add a link to hide single replies.']
'Delete Link': [true, 'Add post and image deletion links to the menu.'] 'Delete Link': [true, 'Add post and image deletion links to the menu.']
<% if (type === 'crx') { %> <% if (type === 'crx') { %>
'Download Link': [true, 'Add a download with original filename link to the menu.'] 'Download Link': [true, 'Add a download with original filename link to the menu.']
@ -143,7 +141,6 @@ Config =
'Threads per Page': 0 'Threads per Page': 0
'Open threads in a new tab': false 'Open threads in a new tab': false
'Show Replies': true 'Show Replies': true
'Anchor Hidden Threads': true
'Refreshed Navigation': false 'Refreshed Navigation': false
Header: Header:
'Header auto-hide': false 'Header auto-hide': false

View File

@ -1,5 +1,5 @@
class DataBoard class DataBoard
@keys = ['pinnedThreads', 'hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads'] @keys = ['pinnedThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads']
constructor: (@key, sync, dontClean) -> constructor: (@key, sync, dontClean) ->
@data = Conf[key] @data = Conf[key]

View File

@ -3,8 +3,7 @@ Get =
{OP} = thread {OP} = thread
excerpt = OP.info.subject?.trim() or excerpt = OP.info.subject?.trim() or
OP.info.comment.replace(/\n+/g, ' // ') or OP.info.comment.replace(/\n+/g, ' // ') or
Conf['Anonymize'] and 'Anonymous' or OP.getNameBlock()
$('.nameBlock', OP.nodes.info).textContent.trim()
if excerpt.length > 70 if excerpt.length > 70
excerpt = "#{excerpt[...67]}..." excerpt = "#{excerpt[...67]}..."
"/#{thread.board}/ - #{excerpt}" "/#{thread.board}/ - #{excerpt}"
@ -233,6 +232,6 @@ Get =
thread = g.threads["#{boardID}.#{threadID}"] or thread = g.threads["#{boardID}.#{threadID}"] or
new Thread threadID, board new Thread threadID, board
post = new Post Build.post(o, true), thread, board, {isArchived: true} post = new Post Build.post(o, true), thread, board, {isArchived: true}
$('.page-num', post.nodes.info).hidden = true $('.page-num', post.nodes.info)?.hidden = true
Main.callbackNodes Post, [post] Main.callbackNodes Post, [post]
Get.insert post, root, context Get.insert post, root, context

View File

@ -38,15 +38,11 @@ Index =
repliesEntry = repliesEntry =
el: $.el 'label', el: $.el 'label',
innerHTML: '<input type=checkbox name="Show Replies"> Show replies' innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
anchorEntry =
el: $.el 'label',
innerHTML: '<input type=checkbox name="Anchor Hidden Threads"> Anchor hidden threads'
title: 'Move hidden threads at the end of the index.'
refNavEntry = refNavEntry =
el: $.el 'label', el: $.el 'label',
innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation' innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation'
title: 'Refresh index when navigating through pages.' title: 'Refresh index when navigating through pages.'
for label in [targetEntry, repliesEntry, anchorEntry, refNavEntry] for label in [targetEntry, repliesEntry, refNavEntry]
input = label.el.firstChild input = label.el.firstChild
{name} = input {name} = input
input.checked = Conf[name] input.checked = Conf[name]
@ -56,15 +52,13 @@ Index =
$.on input, 'change', @cb.target $.on input, 'change', @cb.target
when 'Show Replies' when 'Show Replies'
$.on input, 'change', @cb.replies $.on input, 'change', @cb.replies
when 'Anchor Hidden Threads'
$.on input, 'change', @cb.sort
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'header' type: 'header'
el: $.el 'span', el: $.el 'span',
textContent: 'Index Navigation' textContent: 'Index Navigation'
order: 90 order: 90
subEntries: [threadNumEntry, targetEntry, repliesEntry, anchorEntry, refNavEntry] subEntries: [threadNumEntry, targetEntry, repliesEntry, refNavEntry]
$.addClass doc, 'index-loading' $.addClass doc, 'index-loading'
@update() @update()
@ -124,24 +118,7 @@ Index =
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'post' type: 'post'
el: $.el 'a', href: 'javascript:;' el: $.el 'a', href: 'javascript:;'
order: 5 order: 19
open: ({thread}) ->
return false if Conf['Index Mode'] isnt 'catalog'
@el.textContent = if thread.isHidden
'Unhide thread'
else
'Hide thread'
$.off @el, 'click', @cb if @cb
@cb = ->
$.event 'CloseMenu'
Index.toggleHide thread
$.on @el, 'click', @cb
true
$.event 'AddMenuEntry',
type: 'post'
el: $.el 'a', href: 'javascript:;'
order: 6
open: ({thread}) -> open: ({thread}) ->
return false if Conf['Index Mode'] isnt 'catalog' return false if Conf['Index Mode'] isnt 'catalog'
@el.textContent = if thread.isPinned @el.textContent = if thread.isPinned
@ -166,7 +143,7 @@ Index =
return if e.button isnt 0 return if e.button isnt 0
thread = g.threads[@parentNode.dataset.fullID] thread = g.threads[@parentNode.dataset.fullID]
if e.shiftKey if e.shiftKey
Index.toggleHide thread PostHiding.toggle thread.OP
else if e.altKey else if e.altKey
Index.togglePin thread Index.togglePin thread
else else
@ -194,15 +171,6 @@ Index =
offsetX: 15 offsetX: 15
offsetY: -20 offsetY: -20
setTimeout (-> el.hidden = false if el.parentNode), .25 * $.SECOND setTimeout (-> el.hidden = false if el.parentNode), .25 * $.SECOND
toggleHide: (thread) ->
$.rm thread.catalogView.nodes.root
if Index.showHiddenThreads
ThreadHiding.show thread
return unless ThreadHiding.db.get {boardID: thread.board.ID, threadID: thread.ID}
# Don't save when un-hiding filtered threads.
else
ThreadHiding.hide thread
ThreadHiding.saveHiddenState thread
togglePin: (thread) -> togglePin: (thread) ->
data = data =
boardID: thread.board.ID boardID: thread.board.ID
@ -259,7 +227,10 @@ Index =
else else
'Show' 'Show'
Index.sort() Index.sort()
Index.buildIndex() if Conf['Index Mode'] is 'paged' and Index.getCurrentPage() > 0
Index.pageNav 0
else
Index.buildIndex()
mode: (e) -> mode: (e) ->
Index.cb.toggleCatalogMode() Index.cb.toggleCatalogMode()
Index.togglePagelist() Index.togglePagelist()
@ -289,7 +260,6 @@ Index =
Index.buildIndex() if e Index.buildIndex() if e
threadsNum: -> threadsNum: ->
return unless Conf['Index Mode'] is 'paged' return unless Conf['Index Mode'] is 'paged'
Index.buildPagelist()
Index.buildIndex() Index.buildIndex()
target: -> target: ->
for threadID, thread of g.BOARD.threads when thread.catalogView for threadID, thread of g.BOARD.threads when thread.catalogView
@ -367,7 +337,6 @@ Index =
Index.currentPage = pageNum Index.currentPage = pageNum
return if Conf['Index Mode'] isnt 'paged' return if Conf['Index Mode'] isnt 'paged'
Index.buildIndex() Index.buildIndex()
Index.setPage()
Index.scrollToIndex() Index.scrollToIndex()
getThreadsNumPerPage: -> getThreadsNumPerPage: ->
@ -376,11 +345,7 @@ Index =
else else
Index.threadsNumPerPage Index.threadsNumPerPage
getPagesNum: -> getPagesNum: ->
numThreads = if Index.isSearching Math.ceil Index.sortedThreads.length / Index.getThreadsNumPerPage()
Index.sortedNodes.length / 2
else
Index.liveThreadIDs.length
Math.ceil numThreads / Index.getThreadsNumPerPage()
getMaxPageNum: -> getMaxPageNum: ->
Math.max 0, Index.getPagesNum() - 1 Math.max 0, Index.getPagesNum() - 1
togglePagelist: -> togglePagelist: ->
@ -430,7 +395,7 @@ Index =
Index.cb.toggleHiddenThreads() if Index.showHiddenThreads Index.cb.toggleHiddenThreads() if Index.showHiddenThreads
return return
Index.hideLabel.hidden = false Index.hideLabel.hidden = false
$('#hidden-count', Index.navLinks).textContent = if hiddenCount is 1 $('#hidden-count', Index.hideLabel).textContent = if hiddenCount is 1
'1 hidden thread' '1 hidden thread'
else else
"#{hiddenCount} hidden threads" "#{hiddenCount} hidden threads"
@ -508,12 +473,10 @@ Index =
Index.parseThreadList pages Index.parseThreadList pages
Index.buildThreads() Index.buildThreads()
Index.sort() Index.sort()
Index.buildPagelist()
if pageNum? if pageNum?
Index.pageNav pageNum Index.pageNav pageNum
return return
Index.buildIndex() Index.buildIndex()
Index.setPage()
parseThreadList: (pages) -> parseThreadList: (pages) ->
Index.threadsNumPerPage = pages[0].threads.length Index.threadsNumPerPage = pages[0].threads.length
Index.liveThreadData = pages.reduce ((arr, next) -> arr.concat next.threads), [] Index.liveThreadData = pages.reduce ((arr, next) -> arr.concat next.threads), []
@ -527,7 +490,7 @@ Index =
posts = [] posts = []
for threadData, i in Index.liveThreadData for threadData, i in Index.liveThreadData
threadRoot = Build.thread g.BOARD, threadData threadRoot = Build.thread g.BOARD, threadData
Index.nodes.push threadRoot, $.el 'hr' Index.nodes.push threadRoot
if thread = g.BOARD.threads[threadData.no] if thread = g.BOARD.threads[threadData.no]
thread.setPage i // Index.threadsNumPerPage thread.setPage i // Index.threadsNumPerPage
thread.setCount 'post', threadData.replies + 1, threadData.bumplimit thread.setCount 'post', threadData.replies + 1, threadData.bumplimit
@ -548,16 +511,18 @@ Index =
error: err error: err
Main.handleErrors errors if errors Main.handleErrors errors if errors
# Add the threads and <hr>s in a container to make sure all features work.
$.nodes Index.nodes
Main.callbackNodes Thread, threads Main.callbackNodes Thread, threads
Main.callbackNodes Post, posts Main.callbackNodes Post, posts
Index.updateHideLabel() Index.updateHideLabel()
$.event 'IndexRefresh' $.event 'IndexRefresh'
buildReplies: (threadRoots) -> buildHRs: (threadRoots) ->
for i in [0...threadRoots.length] by 1
threadRoots.splice (i * 2) + 1, 0, $.el 'hr'
return
buildReplies: (threads) ->
return unless Conf['Show Replies']
posts = [] posts = []
for threadRoot in threadRoots by 2 for thread in threads
thread = Get.threadFromRoot threadRoot
i = Index.liveThreadIDs.indexOf thread.ID i = Index.liveThreadIDs.indexOf thread.ID
continue unless lastReplies = Index.liveThreadData[i].last_replies continue unless lastReplies = Index.liveThreadData[i].last_replies
nodes = [] nodes = []
@ -574,20 +539,16 @@ Index =
errors.push errors.push
message: "Parsing of Post No.#{data.no} failed. Post will be skipped." message: "Parsing of Post No.#{data.no} failed. Post will be skipped."
error: err error: err
$.add threadRoot, nodes $.add thread.OP.nodes.root.parentNode, nodes
Main.handleErrors errors if errors Main.handleErrors errors if errors
Main.callbackNodes Post, posts Main.callbackNodes Post, posts
buildCatalogViews: -> buildCatalogViews: ->
threads = Index.sortedNodes
.filter (n, i) -> !(i % 2)
.map (threadRoot) -> Get.threadFromRoot threadRoot
.filter (thread) -> !thread.isHidden isnt Index.showHiddenThreads
catalogThreads = [] catalogThreads = []
for thread in threads when !thread.catalogView for thread in Index.sortedThreads when !thread.catalogView
catalogThreads.push new CatalogThread Build.catalogThread(thread), thread catalogThreads.push new CatalogThread Build.catalogThread(thread), thread
Main.callbackNodes CatalogThread, catalogThreads Main.callbackNodes CatalogThread, catalogThreads
threads.map (thread) -> thread.catalogView.nodes.root Index.sortedThreads.map (thread) -> thread.catalogView.nodes.root
sizeCatalogViews: (nodes) -> sizeCatalogViews: (nodes) ->
# XXX When browsers support CSS3 attr(), use it instead. # XXX When browsers support CSS3 attr(), use it instead.
size = if Conf['Index Size'] is 'small' then 150 else 250 size = if Conf['Index Size'] is 'small' then 150 else 250
@ -615,36 +576,43 @@ Index =
sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no
when 'filecount' when 'filecount'
sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no
Index.sortedNodes = [] Index.sortedThreads = sortedThreadIDs
for threadID in sortedThreadIDs .map (threadID) -> Get.threadFromRoot Index.nodes[Index.liveThreadIDs.indexOf threadID]
i = Index.liveThreadIDs.indexOf(threadID) * 2 .filter (thread) -> thread.isHidden is Index.showHiddenThreads
Index.sortedNodes.push Index.nodes[i], Index.nodes[i + 1]
if Index.isSearching if Index.isSearching
Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes Index.sortedThreads = Index.querySearch(Index.searchInput.value) or Index.sortedThreads
# Sticky threads # Sticky threads
Index.sortOnTop (thread) -> thread.isSticky Index.sortOnTop (thread) -> thread.isSticky
# Highlighted threads # Highlighted threads
Index.sortOnTop (thread) -> thread.isOnTop or thread.isPinned Index.sortOnTop (thread) -> thread.isOnTop or thread.isPinned
# Non-hidden threads
Index.sortOnTop((thread) -> !thread.isHidden) if Conf['Anchor Hidden Threads']
sortOnTop: (match) -> sortOnTop: (match) ->
offset = 0 offset = 0
for threadRoot, i in Index.sortedNodes by 2 when match Get.threadFromRoot threadRoot for thread, i in Index.sortedThreads when match thread
Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... Index.sortedThreads.splice offset++, 0, Index.sortedThreads.splice(i, 1)[0]
return return
buildIndex: -> buildIndex: ->
switch Conf['Index Mode'] switch Conf['Index Mode']
when 'paged' when 'paged'
pageNum = Index.getCurrentPage() pageNum = Index.getCurrentPage()
nodesPerPage = Index.getThreadsNumPerPage() * 2 if pageNum > Index.getMaxPageNum()
nodes = Index.sortedNodes[nodesPerPage * pageNum ... nodesPerPage * (pageNum + 1)] # Go to the last available page if we were past the limit.
Index.pageNav Index.getMaxPageNum()
return
threadsPerPage = Index.getThreadsNumPerPage()
threads = Index.sortedThreads[threadsPerPage * pageNum ... threadsPerPage * (pageNum + 1)]
nodes = threads.map (thread) -> thread.OP.nodes.root.parentNode
Index.buildReplies threads
Index.buildHRs nodes
Index.buildPagelist()
Index.setPage()
when 'catalog' when 'catalog'
nodes = Index.buildCatalogViews() nodes = Index.buildCatalogViews()
Index.sizeCatalogViews nodes Index.sizeCatalogViews nodes
else else
nodes = Index.sortedNodes nodes = Index.sortedThreads.map (thread) -> thread.OP.nodes.root.parentNode
Index.buildReplies Index.sortedThreads
Index.buildHRs nodes
$.rmAll Index.root $.rmAll Index.root
Index.buildReplies nodes if Conf['Show Replies'] and Conf['Index Mode'] isnt 'catalog'
$.add Index.root, nodes $.add Index.root, nodes
$.event 'IndexBuild', nodes $.event 'IndexBuild', nodes
@ -672,23 +640,17 @@ Index =
delete Index.searchInput.dataset.searching delete Index.searchInput.dataset.searching
<% } %> <% } %>
Index.sort() Index.sort()
# Go to the last available page if we were past the limit. if Conf['Index Mode'] is 'paged' and Index.currentPage isnt Math.min pageNum, Index.getMaxPageNum()
pageNum = Math.min pageNum, Index.getMaxPageNum() if Conf['Index Mode'] is 'paged' # Go to the last available page if we were past the limit.
Index.buildPagelist()
if Index.currentPage is pageNum
Index.buildIndex()
Index.setPage()
else
Index.pageNav pageNum Index.pageNav pageNum
else
Index.buildIndex()
querySearch: (query) -> querySearch: (query) ->
return unless keywords = query.toLowerCase().match /\S+/g return unless keywords = query.toLowerCase().match /\S+/g
Index.search keywords Index.search keywords
search: (keywords) -> search: (keywords) ->
found = [] Index.sortedThreads.filter (thread) ->
for threadRoot, i in Index.sortedNodes by 2 Index.searchMatch thread, keywords
if Index.searchMatch Get.threadFromRoot(threadRoot), keywords
found.push Index.sortedNodes[i], Index.sortedNodes[i + 1]
found
searchMatch: (thread, keywords) -> searchMatch: (thread, keywords) ->
{info, file} = thread.OP {info, file} = thread.OP
text = [] text = []

View File

@ -79,19 +79,18 @@ Main =
initFeature 'Redirect', Redirect initFeature 'Redirect', Redirect
initFeature 'Resurrect Quotes', Quotify initFeature 'Resurrect Quotes', Quotify
initFeature 'Filter', Filter initFeature 'Filter', Filter
initFeature 'Thread Hiding', ThreadHiding initFeature 'Post Hiding', PostHiding
initFeature 'Reply Hiding', PostHiding
initFeature 'Recursive', Recursive initFeature 'Recursive', Recursive
initFeature 'Strike-through Quotes', QuoteStrikeThrough initFeature 'Strike-through Quotes', QuoteStrikeThrough
initFeature 'Quick Reply', QR initFeature 'Quick Reply', QR
initFeature 'Menu', Menu initFeature 'Menu', Menu
initFeature 'Index Generator (Menu)', Index.menu initFeature 'Index Generator (Menu)', Index.menu
initFeature 'Report Link', ReportLink initFeature 'Report Link', ReportLink
initFeature 'Thread Hiding (Menu)', ThreadHiding.menu initFeature 'Post Hiding (Menu)', PostHiding.menu
initFeature 'Reply Hiding (Menu)', PostHiding.menu
initFeature 'Delete Link', DeleteLink initFeature 'Delete Link', DeleteLink
initFeature 'Filter (Menu)', Filter.menu initFeature 'Filter (Menu)', Filter.menu
initFeature 'Download Link', DownloadLink initFeature 'Download Link', DownloadLink
initFeature 'Labels list', Labels
initFeature 'Archive Link', ArchiveLink initFeature 'Archive Link', ArchiveLink
initFeature 'Quote Inlining', QuoteInline initFeature 'Quote Inlining', QuoteInline
initFeature 'Quote Previewing', QuotePreview initFeature 'Quote Previewing', QuotePreview

View File

@ -52,6 +52,8 @@ class Post
@parseQuotes() @parseQuotes()
@parseFile that @parseFile that
@labels = []
@highlights = []
@isDead = false @isDead = false
@isHidden = false @isHidden = false
@ -106,7 +108,7 @@ class Post
# ES6 Set when? # ES6 Set when?
fullID = "#{match[1]}.#{match[2]}" fullID = "#{match[1]}.#{match[2]}"
@quotes.push fullID if @quotes.indexOf(fullID) is -1 @quotes.push fullID unless fullID in @quotes
parseFile: (that) -> parseFile: (that) ->
return unless (fileEl = $ '.file', @nodes.post) and thumb = $ 'img[data-md5]', fileEl return unless (fileEl = $ '.file', @nodes.post) and thumb = $ 'img[data-md5]', fileEl
@ -151,6 +153,76 @@ class Post
$.rmClass node, 'desktop' $.rmClass node, 'desktop'
return return
getNameBlock: ->
if Conf['Anonymize']
'Anonymous'
else
$('.nameBlock', @nodes.info).textContent.trim()
hide: (label, makeStub=Conf['Stubs'], hideRecursively=Conf['Recursive Hiding']) ->
@labels.push label unless label in @labels
return if @isHidden
@isHidden = true
for quotelink in Get.allQuotelinksLinkingTo @
$.addClass quotelink, 'filtered'
if hideRecursively
label = "Recursively hidden for quoting No.#{@}"
Recursive.apply 'hide', @, label, makeStub, true
Recursive.add 'hide', @, label, makeStub, true
if !@isReply
@thread.hide()
return
unless makeStub
@nodes.root.hidden = true
return
@nodes.post.hidden = true
@nodes.post.previousElementSibling.hidden = true
@nodes.stub = $.el 'div',
className: 'stub'
$.add @nodes.stub, [
PostHiding.makeButton false
$.tn " #{@getNameBlock()}"
]
$.add @nodes.stub, Menu.makeButton() if Conf['Menu']
$.prepend @nodes.root, @nodes.stub
show: (showRecursively=Conf['Recursive Hiding']) ->
return if !@isHidden
@isHidden = false
@labels = @labels.filter (label) ->
# This is lame.
!/^(Manually hidden|Recursively hidden|Hidden by)/.test label
for quotelink in Get.allQuotelinksLinkingTo @
$.rmClass quotelink, 'filtered'
if showRecursively
Recursive.apply 'show', @, true
Recursive.rm 'hide', @
if !@isReply
@thread.show()
return
unless @nodes.stub
@nodes.root.hidden = false
return
@nodes.post.hidden = false
@nodes.post.previousElementSibling.hidden = false
$.rm @nodes.stub
delete @nodes.stub
highlight: (label, highlight, top) ->
@labels.push label
unless highlight in @highlights
@highlights.push highlight
$.addClass @nodes.root, highlight
if !@isReply and top
@thread.isOnTop = true
kill: (file) -> kill: (file) ->
if file if file
return if @file.isDead return if @file.isDead

View File

@ -123,18 +123,16 @@ Settings =
div = $.el 'div', div = $.el 'div',
innerHTML: "<button></button><span class=description>: Clear manually-hidden threads and posts on all boards. Reload the page to apply." innerHTML: "<button></button><span class=description>: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
button = $ 'button', div button = $ 'button', div
$.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) -> $.get 'hiddenPosts', {}, ({hiddenPosts}) ->
hiddenNum = 0 hiddenNum = 0
for ID, board of hiddenThreads.boards
hiddenNum += Object.keys(board).length
for ID, board of hiddenPosts.boards for ID, board of hiddenPosts.boards
for ID, thread of board for ID, thread of board
hiddenNum += Object.keys(thread).length hiddenNum += Object.keys(thread).length
button.textContent = "Hidden: #{hiddenNum}" button.textContent = "Hidden: #{hiddenNum}"
$.on button, 'click', -> $.on button, 'click', ->
@textContent = 'Hidden: 0' @textContent = 'Hidden: 0'
$.delete ['hiddenThreads', 'hiddenPosts'] $.delete 'hiddenPosts'
$.after $('input[name="Stubs"]', section).parentNode.parentNode, div $.after $('input[name="Recursive Hiding"]', section).parentNode.parentNode, div
export: -> export: ->
# Make sure to export the most recent data. # Make sure to export the most recent data.
$.get Conf, (Conf) -> $.get Conf, (Conf) ->

View File

@ -62,6 +62,17 @@ class Thread
@isPinned = false @isPinned = false
$.rmClass @catalogView.nodes.root, 'pinned' if @catalogView $.rmClass @catalogView.nodes.root, 'pinned' if @catalogView
hide: ->
return if @isHidden
@isHidden = true
if button = $ '.hide-post-button', @OP.nodes.root
$.replace button, PostHiding.makeButton false
show: ->
return if !@isHidden
@isHidden = false
if button = $ '.show-post-button', @OP.nodes.root
$.replace button, PostHiding.makeButton true
kill: -> kill: ->
@isDead = true @isDead = true

View File

@ -84,7 +84,9 @@ UI = do ->
insertEntry: (entry, parent, data) -> insertEntry: (entry, parent, data) ->
if typeof entry.open is 'function' if typeof entry.open is 'function'
return unless entry.open data return unless entry.open data, (subEntry) =>
@parseEntry subEntry
entry.subEntries.push subEntry
$.add parent, entry.el $.add parent, entry.el
return unless entry.subEntries return unless entry.subEntries

View File

@ -43,7 +43,7 @@ ImageExpand =
for post in [post].concat post.clones for post in [post].concat post.clones
{file} = post {file} = post
continue unless file and file.isImage and doc.contains post.nodes.root continue unless file and file.isImage and doc.contains post.nodes.root
if ImageExpand.on and if ImageExpand.on and !post.isHidden and
(!Conf['Expand spoilers'] and file.isSpoiler or (!Conf['Expand spoilers'] and file.isSpoiler or
Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0) Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0)
continue continue
@ -76,7 +76,7 @@ ImageExpand =
expand: (post, src) -> expand: (post, src) ->
# Do not expand images of hidden/filtered replies, or already expanded pictures. # Do not expand images of hidden/filtered replies, or already expanded pictures.
{thumb} = post.file {thumb} = post.file
return if post.isHidden or post.file.isExpanded or $.hasClass thumb, 'expanding' return if post.file.isExpanded or $.hasClass thumb, 'expanding'
$.addClass thumb, 'expanding' $.addClass thumb, 'expanding'
if post.file.fullImage if post.file.fullImage
# Expand already-loaded/ing picture. # Expand already-loaded/ing picture.

16
src/Menu/Labels.coffee Normal file
View File

@ -0,0 +1,16 @@
Labels =
init: ->
return if !Conf['Menu']
$.event 'AddMenuEntry',
type: 'post'
el: $.el 'div', textContent: 'Labels'
order: 60
open: (post, addSubEntry) ->
{labels} = post.origin or post
return false unless labels.length
@subEntries.length = 0
for label in labels
addSubEntry el: $.el 'div', textContent: label
true
subEntries: []

View File

@ -120,7 +120,7 @@ Keybinds =
when Conf['Deselect reply'] when Conf['Deselect reply']
Keybinds.hl 0, threadRoot Keybinds.hl 0, threadRoot
when Conf['Hide'] when Conf['Hide']
ThreadHiding.toggle thread if ThreadHiding.db PostHiding.toggle thread.OP
else else
return return
e.preventDefault() e.preventDefault()

View File

@ -38,8 +38,6 @@ Nav =
getThread: -> getThread: ->
for threadRoot in $$ '.thread' for threadRoot in $$ '.thread'
thread = Get.threadFromRoot threadRoot
continue if thread.isHidden and !thread.stub
if Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height # not scrolled past if Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height # not scrolled past
return threadRoot return threadRoot
return $ '.board' return $ '.board'

View File

@ -92,11 +92,7 @@ Unread =
return return
openNotification: (post) -> openNotification: (post) ->
return unless Header.areNotificationsEnabled return unless Header.areNotificationsEnabled
name = if Conf['Anonymize'] notif = new Notification "#{post.getNameBlock()} replied to you",
'Anonymous'
else
$('.nameBlock', post.nodes.info).textContent.trim()
notif = new Notification "#{name} replied to you",
body: post.info.comment body: post.info.comment
icon: Favicon.logo icon: Favicon.logo
notif.onclick = -> notif.onclick = ->

View File

@ -1,6 +1,6 @@
QuoteStrikeThrough = QuoteStrikeThrough =
init: -> init: ->
return if !Conf['Reply Hiding'] and !Conf['Reply Hiding Link'] and !Conf['Filter'] return if !Conf['Post Hiding'] and !Conf['Post Hiding Link'] and !Conf['Filter']
Post.callbacks.push Post.callbacks.push
name: 'Strike-through Quotes' name: 'Strike-through Quotes'