Merge pull request #1329 from MayhemYDG/index
Index navigation improvements - EP02
This commit is contained in:
commit
aa5bfce32f
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,3 +1,22 @@
|
||||
- More index navigation improvements:
|
||||
- Searching in the index is now possible and will show matched OPs by:
|
||||
<ul>
|
||||
<li> comment
|
||||
<li> subject
|
||||
<li> filename
|
||||
<li> name
|
||||
<li> tripcode
|
||||
<li> e-mail
|
||||
</ul>
|
||||
- The page number on which threads are will now be displayed in OPs, to easily identify where threads are located when:
|
||||
<ul>
|
||||
<li> searching through the index.
|
||||
<li> using different index sorting types.
|
||||
<li> threads highlighted by the filter are moved to the top and move other threads down.
|
||||
<ul>
|
||||
- The elapsed time since the last index refresh is now indicated at the top of the index.
|
||||
- New setting: `Show replies`, enabled by default. Disable it to only show OPs in the index.
|
||||
|
||||
### 3.12.1 - *2013-11-04*
|
||||
|
||||
- The index refreshing notification will now only appear on initial page load with slow connections.
|
||||
|
||||
@ -32,6 +32,9 @@
|
||||
background-color: #F2F2F2;
|
||||
color: #888;
|
||||
}
|
||||
.field::-webkit-search-decoration {
|
||||
display: none;
|
||||
}
|
||||
.move {
|
||||
cursor: move;
|
||||
}
|
||||
@ -220,7 +223,7 @@ a[href="javascript:;"] {
|
||||
color: white;
|
||||
}
|
||||
.notification > .close {
|
||||
padding: 6px;
|
||||
padding: 7px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
@ -270,7 +273,7 @@ a[href="javascript:;"] {
|
||||
}
|
||||
#fourchanx-settings > nav a.close {
|
||||
text-decoration: none;
|
||||
padding: 2px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.sections-list {
|
||||
flex: 1;
|
||||
@ -363,10 +366,37 @@ a[href="javascript:;"] {
|
||||
}
|
||||
|
||||
/* Index */
|
||||
:root.index-loading .navLinks,
|
||||
:root.index-loading .board,
|
||||
:root.index-loading .pagelist {
|
||||
display: none;
|
||||
}
|
||||
#index-search {
|
||||
padding-right: 1.5em;
|
||||
width: 100px;
|
||||
transition: color .25s, border-color .25s, width .25s;
|
||||
}
|
||||
#index-search:focus,
|
||||
#index-search[data-searching] {
|
||||
width: 200px;
|
||||
}
|
||||
#index-search-clear {
|
||||
color: gray;
|
||||
margin-left: -1.25em;
|
||||
}
|
||||
<% if (type === 'crx') { %>
|
||||
/* ``::-webkit-*'' selectors break selector lists on Firefox. */
|
||||
#index-search::-webkit-search-cancel-button,
|
||||
<% } %>
|
||||
#index-search:not([data-searching]) + #index-search-clear {
|
||||
display: none;
|
||||
}
|
||||
.page-num {
|
||||
font-family: inherit;
|
||||
}
|
||||
.page-num::before {
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
.summary {
|
||||
text-decoration: none;
|
||||
}
|
||||
@ -720,13 +750,13 @@ a.hide-announcement {
|
||||
border-style: dashed;
|
||||
opacity: 1;
|
||||
}
|
||||
.remove {
|
||||
a.remove {
|
||||
color: #E00 !important;
|
||||
font-weight: 700;
|
||||
padding: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
.remove:hover::after {
|
||||
content: ' Remove';
|
||||
font-weight: 700;
|
||||
}
|
||||
.qr-preview > label {
|
||||
background: rgba(0, 0, 0, .5);
|
||||
@ -741,11 +771,9 @@ a.hide-announcement {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
#add-post {
|
||||
display: inline-block;
|
||||
font-size: 30px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
line-height: 1;
|
||||
font-size: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@ -818,7 +846,6 @@ a.hide-announcement {
|
||||
#qr-no-file,
|
||||
#qr-filename,
|
||||
#qr-filesize,
|
||||
#qr-filerm,
|
||||
#qr-file-spoiler {
|
||||
margin: 0 2px !important;
|
||||
}
|
||||
|
||||
4
html/General/Index-navlinks.html
Normal file
4
html/General/Index-navlinks.html
Normal file
@ -0,0 +1,4 @@
|
||||
[<a href="./catalog">Catalog</a>]
|
||||
[<time id="index-last-refresh" title="Last index refresh" data-init="1">...</time>]
|
||||
<input type="search" id="index-search" class="field" placeholder="Search">
|
||||
<a id="index-search-clear" class="fa fa-times-circle" href="javascript:;"></a>
|
||||
@ -2,10 +2,13 @@
|
||||
<nav>
|
||||
<div class="sections-list"></div>
|
||||
<div class="credits">
|
||||
<a href="<%= meta.page %>" target="_blank"><%= meta.name %></a> |
|
||||
<a href="<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md" target="_blank">#{g.VERSION}</a> |
|
||||
<a href="<%= meta.repo %>blob/<%= meta.mainBranch %>/CONTRIBUTING.md#reporting-bugs-and-suggestions" target="_blank">Issues</a> |
|
||||
<a href="javascript:;" class="close" title="Close">×</a>
|
||||
<a href="<%= meta.page %>" target="_blank"><%= meta.name %></a>
|
||||
|
|
||||
<a href="<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md" target="_blank">#{g.VERSION}</a>
|
||||
|
|
||||
<a href="<%= meta.repo %>blob/<%= meta.mainBranch %>/CONTRIBUTING.md#reporting-bugs-and-suggestions" target="_blank">Issues</a>
|
||||
|
|
||||
<a href="javascript:;" class="close fa fa-times" title="Close"></a>
|
||||
</div>
|
||||
</nav>
|
||||
<hr>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<option value="new">New thread</option>
|
||||
</select>
|
||||
<span class="move"></span>
|
||||
<a href="javascript:;" class="close" title="Close">×</a>
|
||||
<a href="javascript:;" class="close fa fa-times" title="Close"></a>
|
||||
</div>
|
||||
<form>
|
||||
<div class="persona">
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div id="dump-list-container">
|
||||
<div id="dump-list"></div>
|
||||
<a id="add-post" href="javascript:;" title="Add a post">+</a>
|
||||
<a href="javascript:;" id="add-post" class="fa fa-plus" title="Add a post"></a>
|
||||
</div>
|
||||
<div class="textarea">
|
||||
<textarea data-name="com" placeholder="Comment" class="field"></textarea>
|
||||
@ -29,7 +29,7 @@
|
||||
<span id="qr-no-file">No selected file</span>
|
||||
<input id="qr-filename" data-name="filename" spellcheck="false">
|
||||
<span id="qr-filesize"></span>
|
||||
<a id="qr-filerm" href="javascript:;" title="Remove file">×</a>
|
||||
<a href="javascript:;" id="qr-filerm" class="fa fa-times" title="Remove file"></a>
|
||||
<input type="checkbox" id="qr-file-spoiler" title="Spoiler image">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -190,10 +190,12 @@ Build =
|
||||
else
|
||||
''
|
||||
|
||||
replyLink = if isOP and g.VIEW is 'index'
|
||||
" <span>[<a href='/#{boardID}/res/#{threadID}' class=replylink>Reply</a>]</span>"
|
||||
if isOP and g.VIEW is 'index'
|
||||
pageNum = Math.floor Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage
|
||||
pageIcon = "<i class='page-num fa fa-file-o' title='This thread is on page #{pageNum} in the original index.'> #{pageNum}</i> "
|
||||
replyLink = " <span>[<a href='/#{boardID}/res/#{threadID}' class=replylink>Reply</a>]</span>"
|
||||
else
|
||||
''
|
||||
pageIcon = replyLink = ''
|
||||
|
||||
container = $.el 'div',
|
||||
id: "pc#{postID}"
|
||||
@ -226,6 +228,7 @@ Build =
|
||||
(if isOP then fileHTML else '') +
|
||||
|
||||
"<div class='postInfo desktop' id=pi#{postID}>" +
|
||||
pageIcon +
|
||||
"<input type=checkbox name=#{postID} value=delete> " +
|
||||
"#{subject} " +
|
||||
"<span class='nameBlock#{capcodeClass}'>" +
|
||||
@ -279,8 +282,13 @@ Build =
|
||||
id: "t#{data.no}"
|
||||
|
||||
nodes = [if OP then OP.nodes.root else Build.postFromObject data, board.ID]
|
||||
if data.omitted_posts
|
||||
nodes.push Build.summary board.ID, data.no, data.omitted_posts, data.omitted_images
|
||||
if data.omitted_posts or !Conf['Show Replies'] and data.replies
|
||||
[posts, files] = if Conf['Show Replies']
|
||||
[data.omitted_posts, data.omitted_images]
|
||||
else
|
||||
# XXX data.images is not accurate.
|
||||
[data.replies, data.omitted_images + data.last_replies.filter((data) -> !!data.ext).length]
|
||||
nodes.push Build.summary board.ID, data.no, posts, files
|
||||
|
||||
$.add root, nodes
|
||||
root
|
||||
|
||||
@ -142,6 +142,7 @@ Config =
|
||||
Index:
|
||||
'Index Mode': 'paged'
|
||||
'Index Sort': 'bump'
|
||||
'Show Replies': true
|
||||
Header:
|
||||
'Header auto-hide': false
|
||||
'Bottom header': false
|
||||
@ -162,39 +163,39 @@ Config =
|
||||
usercss: ''
|
||||
hotkeys:
|
||||
# Header, QR & Options
|
||||
'Toggle board list': ['Ctrl+b', 'Toggle the full board list.']
|
||||
'Open empty QR': ['q', 'Open QR without post number inserted.']
|
||||
'Open QR': ['Shift+q', 'Open QR with post number inserted.']
|
||||
'Open settings': ['Alt+o', 'Open Settings.']
|
||||
'Close': ['Esc', 'Close Settings, Notifications or QR.']
|
||||
'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.']
|
||||
'Code tags': ['Alt+c', 'Insert code tags.']
|
||||
'Eqn tags': ['Alt+e', 'Insert eqn tags.']
|
||||
'Math tags': ['Alt+m', 'Insert math tags.']
|
||||
'Submit QR': ['Alt+s', 'Submit post.']
|
||||
'Toggle board list': ['Ctrl+b', 'Toggle the full board list.']
|
||||
'Open empty QR': ['q', 'Open QR without post number inserted.']
|
||||
'Open QR': ['Shift+q', 'Open QR with post number inserted.']
|
||||
'Open settings': ['Alt+o', 'Open Settings.']
|
||||
'Close': ['Esc', 'Close Settings, Notifications or QR.']
|
||||
'Spoiler tags': ['Ctrl+s', 'Insert spoiler tags.']
|
||||
'Code tags': ['Alt+c', 'Insert code tags.']
|
||||
'Eqn tags': ['Alt+e', 'Insert eqn tags.']
|
||||
'Math tags': ['Alt+m', 'Insert math tags.']
|
||||
'Submit QR': ['Alt+s', 'Submit post.']
|
||||
# Index/Thread related
|
||||
'Update': ['r', 'Refresh the index/thread.']
|
||||
'Watch': ['w', 'Watch thread.']
|
||||
'Update': ['r', 'Refresh the index/thread.']
|
||||
'Watch': ['w', 'Watch thread.']
|
||||
# Images
|
||||
'Expand image': ['Shift+e', 'Expand selected image.']
|
||||
'Expand images': ['e', 'Expand all images.']
|
||||
'Expand image': ['Shift+e', 'Expand selected image.']
|
||||
'Expand images': ['e', 'Expand all images.']
|
||||
# Board Navigation
|
||||
'Front page': ['0', 'Jump to page 0.']
|
||||
'Open front page': ['Shift+0', 'Open page 0 in a new tab.']
|
||||
'Next page': ['Right', 'Jump to the next page.']
|
||||
'Previous page': ['Left', 'Jump to the previous page.']
|
||||
'Search form': ['Ctrl+Alt+s', 'Open the search field on the board index.']
|
||||
'Front page': ['0', 'Jump to page 0.']
|
||||
'Open front page': ['Shift+0', 'Open page 0 in a new tab.']
|
||||
'Next page': ['Right', 'Jump to the next page.']
|
||||
'Previous page': ['Left', 'Jump to the previous page.']
|
||||
'Search form': ['Ctrl+Alt+s', 'Focus the search field on the board index.']
|
||||
# Thread Navigation
|
||||
'Next thread': ['Down', 'See next thread.']
|
||||
'Previous thread': ['Up', 'See previous thread.']
|
||||
'Expand thread': ['Ctrl+e', 'Expand thread.']
|
||||
'Open thread': ['o', 'Open thread in current tab.']
|
||||
'Open thread tab': ['Shift+o', 'Open thread in new tab.']
|
||||
'Next thread': ['Down', 'See next thread.']
|
||||
'Previous thread': ['Up', 'See previous thread.']
|
||||
'Expand thread': ['Ctrl+e', 'Expand thread.']
|
||||
'Open thread': ['o', 'Open thread in current tab.']
|
||||
'Open thread tab': ['Shift+o', 'Open thread in new tab.']
|
||||
# Reply Navigation
|
||||
'Next reply': ['j', 'Select next reply.']
|
||||
'Previous reply': ['k', 'Select previous reply.']
|
||||
'Deselect reply': ['Shift+d', 'Deselect reply.']
|
||||
'Hide': ['x', 'Hide thread.']
|
||||
'Next reply': ['j', 'Select next reply.']
|
||||
'Previous reply': ['k', 'Select previous reply.']
|
||||
'Deselect reply': ['Shift+d', 'Deselect reply.']
|
||||
'Hide': ['x', 'Hide thread.']
|
||||
updater:
|
||||
checkbox:
|
||||
'Beep': [false, 'Beep on new post to completely read thread.']
|
||||
|
||||
@ -36,12 +36,19 @@ Index =
|
||||
$.on input, 'change', $.cb.value
|
||||
$.on input, 'change', @cb.sort
|
||||
|
||||
repliesEntry =
|
||||
el: $.el 'label', innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
|
||||
input = repliesEntry.el.firstChild
|
||||
input.checked = Conf['Show Replies']
|
||||
$.on input, 'change', $.cb.checked
|
||||
$.on input, 'change', @cb.replies
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'header'
|
||||
el: $.el 'span',
|
||||
textContent: 'Index Navigation'
|
||||
order: 90
|
||||
subEntries: [modeEntry, sortEntry]
|
||||
subEntries: [modeEntry, sortEntry, repliesEntry]
|
||||
|
||||
$.addClass doc, 'index-loading'
|
||||
@update()
|
||||
@ -50,13 +57,33 @@ Index =
|
||||
className: 'pagelist'
|
||||
hidden: true
|
||||
innerHTML: <%= importHTML('General/Index-pagelist') %>
|
||||
@navLinks = $.el 'div',
|
||||
className: 'navLinks'
|
||||
innerHTML: <%= importHTML('General/Index-navlinks') %>
|
||||
@searchInput = $ '#index-search', @navLinks
|
||||
@currentPage = @getCurrentPage()
|
||||
$.on window, 'popstate', @cb.popstate
|
||||
$.on @pagelist, 'click', @cb.pageNav
|
||||
$.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), ->
|
||||
$.replace $('.board'), Index.root
|
||||
$.replace $('.pagelist'), Index.pagelist
|
||||
$.on @searchInput, 'input', @onSearchInput
|
||||
$.on $('#index-search-clear', @navLinks), 'click', @clearSearch
|
||||
$.asap (-> $('.board', doc) or d.readyState isnt 'loading'), ->
|
||||
board = $ '.board'
|
||||
$.replace board, Index.root
|
||||
# Hacks:
|
||||
# - When removing an element from the document during page load,
|
||||
# its ancestors will still be correctly created inside of it.
|
||||
# - Creating loadable elements inside of an origin-less document
|
||||
# will not download them.
|
||||
# - Combine the two and you get a download canceller!
|
||||
# Does not work on Firefox unfortunately.
|
||||
d.implementation.createDocument(null, null, null).appendChild board
|
||||
|
||||
for navLink in $$ '.navLinks'
|
||||
$.rm navLink
|
||||
$.after $.x('child::form/preceding-sibling::hr[1]'), Index.navLinks
|
||||
$.rmClass doc, 'index-loading'
|
||||
$.asap (-> $('.pagelist') or d.readyState isnt 'loading'), ->
|
||||
$.replace $('.pagelist'), Index.pagelist
|
||||
|
||||
cb:
|
||||
mode: ->
|
||||
@ -65,6 +92,10 @@ Index =
|
||||
sort: ->
|
||||
Index.sort()
|
||||
Index.buildIndex()
|
||||
replies: ->
|
||||
Index.buildThreads()
|
||||
Index.sort()
|
||||
Index.buildIndex()
|
||||
popstate: (e) ->
|
||||
pageNum = Index.getCurrentPage()
|
||||
Index.pageLoad pageNum if Index.currentPage isnt pageNum
|
||||
@ -97,31 +128,39 @@ Index =
|
||||
Index.setPage()
|
||||
Index.scrollToIndex()
|
||||
|
||||
getPagesNum: ->
|
||||
if Index.isSearching
|
||||
Math.ceil (Index.sortedNodes.length / 2) / Index.threadsNumPerPage
|
||||
else
|
||||
Index.pagesNum
|
||||
getMaxPageNum: ->
|
||||
Math.max 0, Index.getPagesNum() - 1
|
||||
togglePagelist: ->
|
||||
Index.pagelist.hidden = Conf['Index Mode'] isnt 'paged'
|
||||
buildPagelist: ->
|
||||
pagesRoot = $ '.pages', Index.pagelist
|
||||
if pagesRoot.childElementCount isnt Index.pagesNum
|
||||
maxPageNum = Index.getMaxPageNum()
|
||||
if pagesRoot.childElementCount isnt maxPageNum + 1
|
||||
nodes = []
|
||||
for i in [0..Index.pagesNum - 1]
|
||||
for i in [0..maxPageNum] by 1
|
||||
a = $.el 'a',
|
||||
textContent: i
|
||||
href: if i then i else './'
|
||||
nodes.push $.tn('['), a, $.tn '] '
|
||||
$.rmAll pagesRoot
|
||||
$.add pagesRoot, nodes
|
||||
Index.setPage()
|
||||
Index.togglePagelist()
|
||||
setPage: ->
|
||||
pageNum = Index.getCurrentPage()
|
||||
pagesRoot = $ '.pages', Index.pagelist
|
||||
pageNum = Index.getCurrentPage()
|
||||
maxPageNum = Index.getMaxPageNum()
|
||||
pagesRoot = $ '.pages', Index.pagelist
|
||||
# Previous/Next buttons
|
||||
prev = pagesRoot.previousSibling.firstChild
|
||||
next = pagesRoot.nextSibling.firstChild
|
||||
href = Math.max pageNum - 1, 0
|
||||
prev.href = if href is 0 then './' else href
|
||||
prev.firstChild.disabled = href is pageNum
|
||||
href = Math.min pageNum + 1, Index.pagesNum - 1
|
||||
href = Math.min pageNum + 1, maxPageNum
|
||||
next.href = if href is 0 then './' else href
|
||||
next.firstChild.disabled = href is pageNum
|
||||
# <strong> current page
|
||||
@ -184,6 +223,18 @@ Index =
|
||||
notice.el.lastElementChild.textContent = 'Index refreshed!'
|
||||
setTimeout notice.close, $.SECOND
|
||||
|
||||
timeEl = $ '#index-last-refresh', Index.navLinks
|
||||
timeEl.dataset.utc = e.timeStamp <% if (type === 'userscript') { %>/ 1000<% } %>
|
||||
if timeEl.dataset.init
|
||||
RelativeDates.setUpdate el: timeEl
|
||||
<% if (type === 'userscript') { %>
|
||||
# XXX https://github.com/greasemonkey/greasemonkey/issues/1571
|
||||
timeEl.removeAttribute 'data-init'
|
||||
<% } else { %>
|
||||
delete timeEl.dataset.init
|
||||
<% } %>
|
||||
else
|
||||
RelativeDates.flush()
|
||||
Index.scrollToIndex()
|
||||
parse: (pages) ->
|
||||
Index.parseThreadList pages
|
||||
@ -191,6 +242,7 @@ Index =
|
||||
Index.sort()
|
||||
Index.buildIndex()
|
||||
Index.buildPagelist()
|
||||
Index.setPage()
|
||||
parseThreadList: (pages) ->
|
||||
Index.pagesNum = pages.length
|
||||
Index.threadsNumPerPage = pages[0].threads.length
|
||||
@ -203,10 +255,11 @@ Index =
|
||||
Index.nodes = []
|
||||
threads = []
|
||||
posts = []
|
||||
for threadData in Index.liveThreadData
|
||||
for threadData, i in Index.liveThreadData
|
||||
threadRoot = Build.thread g.BOARD, threadData
|
||||
Index.nodes.push threadRoot, $.el 'hr'
|
||||
if thread = g.BOARD.threads[threadData.no]
|
||||
thread.setPage Math.floor i / Index.threadsNumPerPage
|
||||
thread.setStatus 'Sticky', !!threadData.sticky
|
||||
thread.setStatus 'Closed', !!threadData.closed
|
||||
else
|
||||
@ -276,13 +329,14 @@ Index =
|
||||
offset = 0
|
||||
for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isSticky
|
||||
Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)...
|
||||
return unless Conf['Filter']
|
||||
# Put the highlighted thread & <hr> on top of the index
|
||||
# while keeping the original order they appear in.
|
||||
offset = 0
|
||||
for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop
|
||||
Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)...
|
||||
return
|
||||
if Conf['Filter']
|
||||
# Put the highlighted thread & <hr> on top of the index
|
||||
# while keeping the original order they appear in.
|
||||
offset = 0
|
||||
for threadRoot, i in Index.sortedNodes by 2 when Get.threadFromRoot(threadRoot).isOnTop
|
||||
Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)...
|
||||
if Index.isSearching
|
||||
Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes
|
||||
buildIndex: ->
|
||||
if Conf['Index Mode'] is 'paged'
|
||||
pageNum = Index.getCurrentPage()
|
||||
@ -291,6 +345,57 @@ Index =
|
||||
else
|
||||
nodes = Index.sortedNodes
|
||||
$.rmAll Index.root
|
||||
Index.buildReplies nodes
|
||||
Index.buildReplies nodes if Conf['Show Replies']
|
||||
$.event 'IndexBuild', nodes
|
||||
$.add Index.root, nodes
|
||||
|
||||
isSearching: false
|
||||
clearSearch: ->
|
||||
Index.searchInput.value = null
|
||||
Index.onSearchInput()
|
||||
Index.searchInput.focus()
|
||||
onSearchInput: ->
|
||||
if Index.isSearching = !!Index.searchInput.value.trim()
|
||||
unless Index.searchInput.dataset.searching
|
||||
Index.searchInput.dataset.searching = 1
|
||||
Index.pageBeforeSearch = Index.getCurrentPage()
|
||||
pageNum = 0
|
||||
else
|
||||
pageNum = Index.getCurrentPage()
|
||||
else
|
||||
pageNum = Index.pageBeforeSearch
|
||||
delete Index.pageBeforeSearch
|
||||
<% if (type === 'userscript') { %>
|
||||
# XXX https://github.com/greasemonkey/greasemonkey/issues/1571
|
||||
Index.searchInput.removeAttribute 'data-searching'
|
||||
<% } else { %>
|
||||
delete Index.searchInput.dataset.searching
|
||||
<% } %>
|
||||
Index.sort()
|
||||
# Go to the last available page if we were past the limit.
|
||||
pageNum = Math.min pageNum, Index.getMaxPageNum() if Conf['Index Mode'] is 'paged'
|
||||
Index.buildPagelist()
|
||||
if Index.currentPage is pageNum
|
||||
Index.buildIndex()
|
||||
Index.setPage()
|
||||
else
|
||||
Index.pageNav pageNum
|
||||
querySearch: (query) ->
|
||||
return unless keywords = query.toLowerCase().match /\S+/g
|
||||
Index.search keywords
|
||||
search: (keywords) ->
|
||||
found = []
|
||||
for threadRoot, i in Index.sortedNodes by 2
|
||||
if Index.searchMatch Get.threadFromRoot(threadRoot), keywords
|
||||
found.push Index.sortedNodes[i], Index.sortedNodes[i + 1]
|
||||
found
|
||||
searchMatch: (thread, keywords) ->
|
||||
{info, file} = thread.OP
|
||||
text = []
|
||||
for key in ['comment', 'subject', 'name', 'tripcode', 'email']
|
||||
text.push info[key] if key of info
|
||||
text.push file.name if file
|
||||
text = text.join(' ').toLowerCase()
|
||||
for keyword in keywords
|
||||
return false if -1 is text.indexOf keyword
|
||||
return true
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
class Notice
|
||||
constructor: (type, content, @timeout) ->
|
||||
@el = $.el 'div',
|
||||
innerHTML: '<a href=javascript:; class=close title=Close>×</a><div class=message></div>'
|
||||
innerHTML: '<a href=javascript:; class="close fa fa-times" title=Close></a><div class=message></div>'
|
||||
@el.style.opacity = 0
|
||||
@setType type
|
||||
$.on @el.firstElementChild, 'click', @close
|
||||
|
||||
@ -49,7 +49,7 @@ class Post
|
||||
|
||||
@parseComment()
|
||||
@parseQuotes()
|
||||
@parseFile(that)
|
||||
@parseFile that
|
||||
|
||||
@clones = []
|
||||
g.posts[@fullID] = thread.posts[@] = board.posts[@] = @
|
||||
|
||||
@ -12,6 +12,11 @@ class Thread
|
||||
|
||||
g.threads[@fullID] = board.threads[@] = @
|
||||
|
||||
setPage: (pageNum) ->
|
||||
icon = $ '.page-num', @OP.nodes.post
|
||||
for key in ['title', 'textContent']
|
||||
icon[key] = icon[key].replace /\d+/, pageNum
|
||||
return
|
||||
setStatus: (type, status) ->
|
||||
name = "is#{type}"
|
||||
return if @[name] is status
|
||||
|
||||
@ -50,16 +50,19 @@ ExpandThread =
|
||||
a.textContent = ExpandThread.text '+', a.textContent.match(/\d+/g)... if a
|
||||
return
|
||||
|
||||
num = if thread.isSticky
|
||||
1
|
||||
else switch g.BOARD.ID
|
||||
# XXX boards config
|
||||
when 'b', 'vg' then 3
|
||||
when 't' then 1
|
||||
else 5
|
||||
replies = $$ '.thread > .replyContainer', threadRoot
|
||||
if Conf['Show Replies']
|
||||
num = if thread.isSticky
|
||||
1
|
||||
else switch g.BOARD.ID
|
||||
# XXX boards config
|
||||
when 'b', 'vg' then 3
|
||||
when 't' then 1
|
||||
else 5
|
||||
replies = replies[...-num]
|
||||
postsCount = 0
|
||||
filesCount = 0
|
||||
for reply in $$('.thread > .replyContainer', threadRoot)[...-num]
|
||||
for reply in replies
|
||||
# rm clones
|
||||
inlined.click() while inlined = $ '.inlined', reply if Conf['Quote Inlining']
|
||||
postsCount++
|
||||
|
||||
@ -87,7 +87,7 @@ Keybinds =
|
||||
return unless g.VIEW is 'index' and Conf['Index Mode'] is 'paged'
|
||||
$('.prev button', Index.pagelist).click()
|
||||
when Conf['Search form']
|
||||
$.id('search-btn').click()
|
||||
Index.searchInput.focus()
|
||||
# Thread Navigation
|
||||
when Conf['Next thread']
|
||||
return if g.VIEW isnt 'index'
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
RelativeDates =
|
||||
INTERVAL: $.MINUTE / 2
|
||||
init: ->
|
||||
return if g.VIEW is 'catalog' or !Conf['Relative Post Dates']
|
||||
|
||||
# Flush when page becomes visible again or when the thread updates.
|
||||
$.on d, 'visibilitychange ThreadUpdate', @flush
|
||||
|
||||
# Start the timeout.
|
||||
@flush()
|
||||
switch g.VIEW
|
||||
when 'index'
|
||||
@flush()
|
||||
$.on d, 'visibilitychange', @flush
|
||||
return unless Conf['Relative Post Dates']
|
||||
when 'thread'
|
||||
return unless Conf['Relative Post Dates']
|
||||
@flush()
|
||||
$.on d, 'visibilitychange ThreadUpdate', @flush if g.VIEW is 'thread'
|
||||
else
|
||||
return
|
||||
|
||||
Post.callbacks.push
|
||||
name: 'Relative Post Dates'
|
||||
@ -21,7 +25,7 @@ RelativeDates =
|
||||
dateEl = @nodes.date
|
||||
dateEl.title = dateEl.textContent
|
||||
|
||||
RelativeDates.setUpdate @
|
||||
RelativeDates.setUpdate post: @
|
||||
|
||||
# diff is milliseconds from now.
|
||||
relative: (diff, now, date) ->
|
||||
@ -81,7 +85,7 @@ RelativeDates =
|
||||
# Create function `update()`, closed over post, that, when called
|
||||
# from `flush()`, updates the elements, and re-calls `setOwnTimeout()` to
|
||||
# re-add `update()` to the stale list later.
|
||||
setUpdate: (post) ->
|
||||
setUpdate: ({post, el}) ->
|
||||
setOwnTimeout = (diff) ->
|
||||
delay = if diff < $.MINUTE
|
||||
$.SECOND - (diff + $.SECOND / 2) % $.SECOND
|
||||
@ -94,11 +98,17 @@ RelativeDates =
|
||||
setTimeout markStale, delay
|
||||
|
||||
update = (now) ->
|
||||
{date} = post.info
|
||||
date = if post
|
||||
post.info.date
|
||||
else
|
||||
new Date +el.dataset.utc
|
||||
diff = now - date
|
||||
relative = RelativeDates.relative diff, now, date
|
||||
for singlePost in [post].concat post.clones
|
||||
singlePost.nodes.date.firstChild.textContent = relative
|
||||
if post
|
||||
for singlePost in [post].concat post.clones
|
||||
singlePost.nodes.date.firstChild.textContent = relative
|
||||
else
|
||||
el.firstChild.textContent = RelativeDates.relative diff, now, date
|
||||
setOwnTimeout diff
|
||||
|
||||
markStale = -> RelativeDates.stale.push update
|
||||
|
||||
@ -131,7 +131,7 @@ ThreadWatcher =
|
||||
|
||||
makeLine: (boardID, threadID, data) ->
|
||||
x = $.el 'a',
|
||||
textContent: '×'
|
||||
className: 'fa fa-times'
|
||||
href: 'javascript:;'
|
||||
$.on x, 'click', ThreadWatcher.cb.rm
|
||||
|
||||
|
||||
@ -438,7 +438,7 @@ QR =
|
||||
className: 'qr-preview'
|
||||
draggable: true
|
||||
href: 'javascript:;'
|
||||
innerHTML: '<a class=remove>×</a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
||||
innerHTML: '<a class="remove fa fa-times"></a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
||||
|
||||
@nodes =
|
||||
el: el
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user