Show excerpts of replies in catalog with full reply on hover.
This commit is contained in:
parent
7c7d79e436
commit
9bb9be1f67
@ -87,6 +87,14 @@ Build =
|
||||
.replace(/<[^>]*>/g, '')
|
||||
Build.unescape html
|
||||
|
||||
parseCommentDisplay: (html) ->
|
||||
# Hide spoilers.
|
||||
unless Conf['Remove Spoilers'] or Conf['Reveal Spoilers']
|
||||
while (html2 = html.replace /<s>(?:(?!<\/?s>).)*<\/s>/g, '[spoiler]') isnt html
|
||||
html = html2
|
||||
# Remove preceding and following new lines, trailing spaces.
|
||||
Build.parseComment(html).trim().replace(/\s+$/gm, '')
|
||||
|
||||
postFromObject: (data, boardID, suppressThumb) ->
|
||||
o = Build.parseJSON data, boardID
|
||||
Build.post o, suppressThumb
|
||||
|
||||
@ -37,20 +37,22 @@ Index =
|
||||
|
||||
# Header "Index Navigation" submenu
|
||||
repliesEntry = el: UI.checkbox 'Show Replies', 'Show replies'
|
||||
hoverEntry = el: UI.checkbox 'Catalog Reply Hover', 'Catalog reply hover'
|
||||
sortEntry = el: UI.checkbox 'Per-Board Sort Type', 'Per-board sort type', (typeof Conf['Index Sort'] is 'object')
|
||||
pinEntry = el: UI.checkbox 'Pin Watched Threads', 'Pin watched threads'
|
||||
anchorEntry = el: UI.checkbox 'Anchor Hidden Threads', 'Anchor hidden threads'
|
||||
refNavEntry = el: UI.checkbox 'Refreshed Navigation', 'Refreshed navigation'
|
||||
hoverEntry.el.title = 'Show full replies in catalog on mouseover of excerpts.'
|
||||
sortEntry.el.title = 'Set the sorting order of each board independently.'
|
||||
pinEntry.el.title = 'Move watched threads to the start of the index.'
|
||||
anchorEntry.el.title = 'Move hidden threads to the end of the index.'
|
||||
refNavEntry.el.title = 'Refresh index when navigating through pages.'
|
||||
for label in [repliesEntry, pinEntry, anchorEntry, refNavEntry]
|
||||
for label in [repliesEntry, hoverEntry, pinEntry, anchorEntry, refNavEntry]
|
||||
input = label.el.firstChild
|
||||
{name} = input
|
||||
$.on input, 'change', $.cb.checked
|
||||
switch name
|
||||
when 'Show Replies'
|
||||
when 'Show Replies', 'Catalog Reply Hover'
|
||||
$.on input, 'change', @cb.replies
|
||||
when 'Pin Watched Threads', 'Anchor Hidden Threads'
|
||||
$.on input, 'change', @cb.resort
|
||||
@ -60,7 +62,7 @@ Index =
|
||||
el: $.el 'span',
|
||||
textContent: 'Index Navigation'
|
||||
order: 100
|
||||
subEntries: [repliesEntry, sortEntry, pinEntry, anchorEntry, refNavEntry]
|
||||
subEntries: [repliesEntry, hoverEntry, sortEntry, pinEntry, anchorEntry, refNavEntry]
|
||||
|
||||
# Navigation links at top of index
|
||||
@navLinks = $.el 'div', className: 'navLinks json-index'
|
||||
@ -582,6 +584,9 @@ Index =
|
||||
thread.setCount 'file', threadData.images + !!threadData.ext, threadData.imagelimit
|
||||
thread.setStatus 'Sticky', !!threadData.sticky
|
||||
thread.setStatus 'Closed', !!threadData.closed
|
||||
if thread.catalogView
|
||||
$.rm thread.catalogView.nodes.replies
|
||||
thread.catalogView.nodes.replies = null
|
||||
else
|
||||
thread = new Thread threadData.no, g.BOARD
|
||||
threads.push thread
|
||||
@ -608,7 +613,7 @@ Index =
|
||||
buildReplies: (threads) ->
|
||||
posts = []
|
||||
for thread in threads
|
||||
continue unless lastReplies = Index.liveThreadDict[thread.ID].last_replies
|
||||
continue unless (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
|
||||
nodes = []
|
||||
for data in lastReplies
|
||||
if (post = thread.posts[data.no]) and not post.isFetchedQuote
|
||||
@ -648,6 +653,40 @@ Index =
|
||||
thumb.style.height = height * ratio + 'px'
|
||||
return
|
||||
|
||||
buildCatalogReplies: (threads) ->
|
||||
for thread in threads
|
||||
{nodes} = thread.catalogView
|
||||
continue unless (lastReplies = Index.liveThreadDict[thread.ID].last_replies)
|
||||
|
||||
if nodes.replies
|
||||
# RelativeDates will stop updating elements if they go out of document.
|
||||
RelativeDates.update timeEl for timeEl in $$ 'time', nodes.replies
|
||||
continue
|
||||
|
||||
replies = []
|
||||
for data in lastReplies
|
||||
excerpt = ''
|
||||
if data.com
|
||||
excerpt = Build.parseCommentDisplay(data.com).replace(/>>\d+/g, '').trim().replace(/\n+/g, ' // ')
|
||||
if data.ext
|
||||
excerpt or= "#{data.filename}#{data.ext}"
|
||||
if data.com
|
||||
excerpt or= Build.unescape data.com.replace(/<br\b[^<]*>/gi, ' // ')
|
||||
excerpt or= '\xA0'
|
||||
excerpt = "#{excerpt[...70]}..." if excerpt.length > 73
|
||||
|
||||
link = Build.postURL thread.board.ID, thread.ID, data.no
|
||||
reply = $.el 'div', {className: 'catalog-reply'},
|
||||
<%= html('<span><time data-utc="${data.time * 1000}" data-abbrev="1">...</time>: </span><a href="${link}">${excerpt}</a>') %>
|
||||
RelativeDates.update $('time', reply)
|
||||
$.on $('a', reply), 'mouseover', QuotePreview.mouseover if Conf['Catalog Reply Hover']
|
||||
replies.push reply
|
||||
|
||||
nodes.replies = $.el 'div', className: 'catalog-replies'
|
||||
$.add nodes.replies, replies
|
||||
$.add thread.OP.nodes.post, nodes.replies
|
||||
return
|
||||
|
||||
sort: ->
|
||||
{liveThreadIDs, liveThreadData} = Index
|
||||
return unless liveThreadData
|
||||
@ -729,6 +768,7 @@ Index =
|
||||
buildCatalog: (threads) ->
|
||||
Index.buildCatalogViews threads
|
||||
Index.sizeCatalogViews threads
|
||||
Index.buildCatalogReplies threads if Conf['Show Replies']
|
||||
nodes = []
|
||||
for thread in threads
|
||||
unless thread.nodes.placeholder
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
RelativeDates =
|
||||
INTERVAL: $.MINUTE / 2
|
||||
|
||||
init: ->
|
||||
if (
|
||||
g.VIEW in ['index', 'thread'] and Conf['Relative Post Dates'] and !Conf['Relative Date Title'] or
|
||||
@ -28,7 +29,7 @@ RelativeDates =
|
||||
RelativeDates.update @
|
||||
|
||||
# diff is milliseconds from now.
|
||||
relative: (diff, now, date) ->
|
||||
relative: (diff, now, date, abbrev) ->
|
||||
unit = if (number = (diff / $.DAY)) >= 1
|
||||
years = now.getYear() - date.getYear()
|
||||
months = now.getMonth() - date.getMonth()
|
||||
@ -57,9 +58,13 @@ RelativeDates =
|
||||
'second'
|
||||
|
||||
rounded = Math.round number
|
||||
unit += 's' if rounded isnt 1 # pluralize
|
||||
|
||||
"#{rounded} #{unit} ago"
|
||||
if abbrev
|
||||
unit = if unit is 'month' then 'mo' else unit[0]
|
||||
else
|
||||
unit += 's' if rounded isnt 1 # pluralize
|
||||
|
||||
if abbrev then "#{rounded}#{unit}" else "#{rounded} #{unit} ago"
|
||||
|
||||
# Changing all relative dates as soon as possible incurs many annoying
|
||||
# redraws and scroll stuttering. Thus, sacrifice accuracy for UX/CPU economy,
|
||||
@ -92,19 +97,22 @@ RelativeDates =
|
||||
# and re-calls `setOwnTimeout()` to re-add `data` to the stale list later.
|
||||
update: (data, now) ->
|
||||
isPost = data instanceof Post
|
||||
date = if isPost
|
||||
data.info.date
|
||||
if isPost
|
||||
date = data.info.date
|
||||
abbrev = false
|
||||
else
|
||||
new Date +data.dataset.utc
|
||||
date = new Date +data.dataset.utc
|
||||
abbrev = !!data.dataset.abbrev
|
||||
now or= new Date()
|
||||
diff = now - date
|
||||
relative = RelativeDates.relative diff, now, date
|
||||
relative = RelativeDates.relative diff, now, date, abbrev
|
||||
if isPost
|
||||
for singlePost in [data].concat data.clones
|
||||
singlePost.nodes.date.firstChild.textContent = relative
|
||||
else
|
||||
data.firstChild.textContent = relative
|
||||
RelativeDates.setOwnTimeout diff, data
|
||||
|
||||
setOwnTimeout: (diff, data) ->
|
||||
delay = if diff < $.MINUTE
|
||||
$.SECOND - (diff + $.SECOND / 2) % $.SECOND
|
||||
@ -115,7 +123,9 @@ RelativeDates =
|
||||
else
|
||||
$.DAY - (diff + $.DAY / 2) % $.DAY
|
||||
setTimeout RelativeDates.markStale, delay, data
|
||||
|
||||
markStale: (data) ->
|
||||
return if data in RelativeDates.stale # We can call RelativeDates.update() multiple times.
|
||||
return if data instanceof Post and !g.posts[data.fullID] # collected post.
|
||||
return if data instanceof Element and !doc.contains(data) # removed catalog reply.
|
||||
RelativeDates.stale.push data
|
||||
|
||||
@ -6,10 +6,11 @@ class CatalogThread
|
||||
@board = @thread.board
|
||||
{post} = @thread.OP.nodes
|
||||
@nodes =
|
||||
root: root
|
||||
root: root
|
||||
thumb: $ '.catalog-thumb', post
|
||||
icons: $ '.catalog-icons', post
|
||||
postCount: $ '.post-count', post
|
||||
fileCount: $ '.file-count', post
|
||||
pageCount: $ '.page-count', post
|
||||
replies: null
|
||||
@thread.catalogView = @
|
||||
|
||||
@ -31,6 +31,7 @@ Post.Clone = class extends Post
|
||||
# Remove catalog stuff.
|
||||
$.rm $('.catalog-link', @nodes.post)
|
||||
$.rm $('.catalog-stats', @nodes.post)
|
||||
$.rm $('.catalog-replies', @nodes.post)
|
||||
|
||||
@parseQuotes()
|
||||
@quotes = [@origin.quotes...]
|
||||
|
||||
@ -732,6 +732,7 @@ Config =
|
||||
'Previous Index Mode': 'paged'
|
||||
'Index Size': 'small'
|
||||
'Show Replies': true
|
||||
'Catalog Reply Hover': true
|
||||
'Pin Watched Threads': false
|
||||
'Anchor Hidden Threads': true
|
||||
'Refreshed Navigation': false
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
:root.burichan .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #D6DAF0;
|
||||
}
|
||||
:root.burichan.werkTyme .catalog-thread:not(:hover), :root.burichan .catalog-thread > .postContainer:hover > .post {
|
||||
:root.burichan.werkTyme .catalog-thread:not(:hover),
|
||||
:root.burichan .catalog-thread > .postContainer:hover > .post,
|
||||
:root.burichan .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #B7C5D9;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
:root.futaba .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #F0E0D6;
|
||||
}
|
||||
:root.futaba.werkTyme .catalog-thread:not(:hover), :root.futaba .catalog-thread > .postContainer:hover > .post {
|
||||
:root.futaba.werkTyme .catalog-thread:not(:hover),
|
||||
:root.futaba .catalog-thread > .postContainer:hover > .post,
|
||||
:root.futaba .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #D9BFB7;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
:root.photon .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #DDD;
|
||||
}
|
||||
:root.photon.werkTyme .catalog-thread:not(:hover), :root.photon .catalog-thread > .postContainer:hover > .post {
|
||||
:root.photon.werkTyme .catalog-thread:not(:hover),
|
||||
:root.photon .catalog-thread > .postContainer:hover > .post,
|
||||
:root.photon .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #CCC;
|
||||
}
|
||||
:root.photon .catalog-code {
|
||||
|
||||
@ -760,7 +760,7 @@ div.catalog-thread {
|
||||
margin-left: -61px;
|
||||
margin-right: -61px;
|
||||
}
|
||||
.catalog-thread > .postContainer:hover > .post > * {
|
||||
.catalog-thread > .postContainer:hover > .post > :not(.catalog-replies) {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
@ -811,7 +811,7 @@ div.catalog-thread {
|
||||
}
|
||||
.catalog-thread .postMessage {
|
||||
margin: 0;
|
||||
padding-bottom: 2px;
|
||||
padding-bottom: .3em;
|
||||
}
|
||||
#delform .catalog-thread > .postContainer:not(:hover) .file,
|
||||
#delform .catalog-thread > .postContainer:not(:hover) .postInfo > :not(.subject),
|
||||
@ -821,7 +821,9 @@ div.catalog-thread {
|
||||
#delform .catalog-thread .postInfo > :not(.subject):not(.nameBlock):not(.dateTime),
|
||||
#delform .catalog-thread .posteruid,
|
||||
.thread:not(.catalog-thread) .catalog-link,
|
||||
.thread:not(.catalog-thread) .catalog-stats {
|
||||
.thread:not(.catalog-thread) .catalog-stats,
|
||||
.thread:not(.catalog-thread) .catalog-replies,
|
||||
.catalog-thread > .postContainer:not(:hover) .catalog-replies {
|
||||
display: none;
|
||||
}
|
||||
.catalog-thread .file {
|
||||
@ -860,6 +862,24 @@ div.catalog-thread {
|
||||
.catalog-thread > .postContainer:hover .postMessage:not(:empty) {
|
||||
padding-top: .3em;
|
||||
}
|
||||
.catalog-reply {
|
||||
text-align: left;
|
||||
margin: -1px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.catalog-reply > span {
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
padding: 3px;
|
||||
}
|
||||
.catalog-reply > a {
|
||||
display: block;
|
||||
padding: 3px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.catalog-thread .prettyprinted {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
@ -33,7 +33,9 @@
|
||||
:root.tomorrow .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #282A2E;
|
||||
}
|
||||
:root.tomorrow.werkTyme .catalog-thread:not(:hover), :root.tomorrow .catalog-thread > .postContainer:hover > .post {
|
||||
:root.tomorrow.werkTyme .catalog-thread:not(:hover),
|
||||
:root.tomorrow .catalog-thread > .postContainer:hover > .post,
|
||||
:root.tomorrow .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #111;
|
||||
}
|
||||
:root.tomorrow .catalog-code {
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
:root.yotsuba-b .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #D6DAF0;
|
||||
}
|
||||
:root.yotsuba-b.werkTyme .catalog-thread:not(:hover), :root.yotsuba-b .catalog-thread > .postContainer:hover > .post {
|
||||
:root.yotsuba-b.werkTyme .catalog-thread:not(:hover),
|
||||
:root.yotsuba-b .catalog-thread > .postContainer:hover > .post,
|
||||
:root.yotsuba-b .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #B7C5D9;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
:root.yotsuba .catalog-thread > .postContainer:hover > .post {
|
||||
background-color: #F0E0D6;
|
||||
}
|
||||
:root.yotsuba.werkTyme .catalog-thread:not(:hover), :root.yotsuba .catalog-thread > .postContainer:hover > .post {
|
||||
:root.yotsuba.werkTyme .catalog-thread:not(:hover),
|
||||
:root.yotsuba .catalog-thread > .postContainer:hover > .post,
|
||||
:root.yotsuba .catalog-thread > .postContainer:hover .catalog-reply {
|
||||
border-color: #D9BFB7;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user