Show excerpts of replies in catalog with full reply on hover.

This commit is contained in:
ccd0 2016-09-26 21:37:29 -07:00
parent 7c7d79e436
commit 9bb9be1f67
13 changed files with 114 additions and 21 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 = @

View File

@ -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...]

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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;
}

View File

@ -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;
}