Add Custom Board Navigation. Close #926
This commit is contained in:
parent
4f0029cfe2
commit
03c422216d
130
4chan_x.user.js
130
4chan_x.user.js
File diff suppressed because one or more lines are too long
@ -109,11 +109,18 @@ a[href="javascript:;"] {
|
|||||||
}
|
}
|
||||||
#header-bar {
|
#header-bar {
|
||||||
border-width: 0 0 1px;
|
border-width: 0 0 1px;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
position: relative;
|
position: relative;
|
||||||
-webkit-transition: all .1s ease-in-out;
|
-webkit-transition: all .1s ease-in-out;
|
||||||
transition: all .1s ease-in-out;
|
transition: all .1s ease-in-out;
|
||||||
}
|
}
|
||||||
|
#board-list {
|
||||||
|
-webkit-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
#header-bar.autohide:not(:hover) {
|
#header-bar.autohide:not(:hover) {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
margin-bottom: -1em;
|
margin-bottom: -1em;
|
||||||
@ -281,6 +288,9 @@ a[href="javascript:;"] {
|
|||||||
.section-sauce textarea {
|
.section-sauce textarea {
|
||||||
height: 350px;
|
height: 350px;
|
||||||
}
|
}
|
||||||
|
.section-rice .field[name="boardnav"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
.section-rice textarea {
|
.section-rice textarea {
|
||||||
height: 150px;
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ Config =
|
|||||||
main:
|
main:
|
||||||
'Miscellaneous':
|
'Miscellaneous':
|
||||||
'Enable 4chan\'s Extension': [false, 'Compatibility between <%= meta.name %> and 4chan\'s inline extension is NOT guaranteed.']
|
'Enable 4chan\'s Extension': [false, 'Compatibility between <%= meta.name %> and 4chan\'s inline extension is NOT guaranteed.']
|
||||||
|
'Custom Board Navigation': [true, 'Disable this to always display the full board list.']
|
||||||
'404 Redirect': [true, 'Redirect dead threads and images.']
|
'404 Redirect': [true, 'Redirect dead threads and images.']
|
||||||
'Keybinds': [true, 'Bind actions to keyboard shortcuts.']
|
'Keybinds': [true, 'Bind actions to keyboard shortcuts.']
|
||||||
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.']
|
'Time Formatting': [true, 'Localize and format timestamps arbitrarily.']
|
||||||
@ -128,6 +129,7 @@ Config =
|
|||||||
].join '\n'
|
].join '\n'
|
||||||
'Header auto-hide': false
|
'Header auto-hide': false
|
||||||
'Header catalog links': false
|
'Header catalog links': false
|
||||||
|
boardnav: '[current-title / toggle-all]'
|
||||||
time: '%m/%d/%y(%a)%H:%M:%S'
|
time: '%m/%d/%y(%a)%H:%M:%S'
|
||||||
backlink: '>>%id'
|
backlink: '>>%id'
|
||||||
fileInfo: '%l (%p%s, %r)'
|
fileInfo: '%l (%p%s, %r)'
|
||||||
|
|||||||
@ -1,30 +1,37 @@
|
|||||||
Header =
|
Header =
|
||||||
init: ->
|
init: ->
|
||||||
headerEl = $.el 'div',
|
headerEl = $.el 'div',
|
||||||
id: 'header'
|
id: 'header'
|
||||||
innerHTML: """
|
innerHTML: """
|
||||||
<div id=header-bar class=dialog>
|
<div id=header-bar class=dialog>
|
||||||
<span class='menu-button brackets-wrap'><a href=javascript:;><i></i></a></span>
|
<span class='menu-button brackets-wrap'><a href=javascript:;><i></i></a></span>
|
||||||
<span class=brackets-wrap hidden>top secret</span>
|
<span class=brackets-wrap hidden>top secret</span>
|
||||||
<span id=board-list hidden>next-gen board-list</span>
|
|
||||||
|
<span id=board-list>
|
||||||
|
<span id=custom-board-list></span>
|
||||||
|
<span id=full-board-list hidden></span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!--
|
||||||
<span class='show-board-list-button brackets-wrap' title="Toggle the board list."><a href=javascript:;>+</a></span>
|
<span class='show-board-list-button brackets-wrap' title="Toggle the board list."><a href=javascript:;>+</a></span>
|
||||||
<a class=board-name href="/#{g.BOARD}/">
|
<a class=board-name href="/#{g.BOARD}/">
|
||||||
<span class=board-path>/#{g.BOARD}/</span> - <span class=board-title>...</span>
|
<span class=board-path>/#{g.BOARD}/</span> - <span class=board-title>...</span>
|
||||||
</a>
|
</a>
|
||||||
<span class=board-list hidden></span>
|
<span class=board-list hidden></span>
|
||||||
|
-->
|
||||||
|
|
||||||
<div id=toggle-header-bar title="Toggle the header auto-hiding."></div>
|
<div id=toggle-header-bar title="Toggle the header auto-hiding."></div>
|
||||||
</div>
|
</div>
|
||||||
<div id=notifications></div>
|
<div id=notifications></div>
|
||||||
""".replace />\s+</g, '><' # get rid of spaces between elements
|
""".replace />\s+</g, '><' # get rid of spaces between elements
|
||||||
|
|
||||||
@headerBar = $ '#header-bar', headerEl
|
@headerBar = $ '#header-bar', headerEl
|
||||||
Header.setBarVisibility Conf['Header auto-hide']
|
@setBarVisibility Conf['Header auto-hide']
|
||||||
$.sync 'Header auto-hide', Header.setBarVisibility
|
$.sync 'Header auto-hide', @setBarVisibility
|
||||||
|
|
||||||
@menu = new UI.Menu 'header'
|
@menu = new UI.Menu 'header'
|
||||||
$.on $('.menu-button', @headerBar), 'click', @menuToggle
|
$.on $('.menu-button', @headerBar), 'click', @menuToggle
|
||||||
$.on $('.show-board-list-button', @headerBar), 'click', @toggleBoardList
|
$.on $('#toggle-header-bar', @headerBar), 'click', @toggleBarVisibility
|
||||||
$.on $('#toggle-header-bar', @headerBar), 'click', @toggleBar
|
|
||||||
|
|
||||||
catalogToggler = $.el 'label',
|
catalogToggler = $.el 'label',
|
||||||
innerHTML: "<input type=checkbox #{if Conf['Header catalog links'] then 'checked' else ''}> Use catalog board links"
|
innerHTML: "<input type=checkbox #{if Conf['Header catalog links'] then 'checked' else ''}> Use catalog board links"
|
||||||
@ -36,38 +43,75 @@ Header =
|
|||||||
order: 105
|
order: 105
|
||||||
|
|
||||||
$.asap (-> d.body), ->
|
$.asap (-> d.body), ->
|
||||||
if Main.isThisPageLegit()
|
return unless Main.isThisPageLegit()
|
||||||
$.prepend d.body, headerEl
|
$.asap (-> $.id 'boardNavDesktop'), Header.setBoardList
|
||||||
$.asap (-> $.id 'boardNavDesktop'), @setBoardList
|
$.prepend d.body, headerEl
|
||||||
|
|
||||||
setBoardList: ->
|
setBoardList: ->
|
||||||
if nav = $.id 'boardNavDesktop'
|
nav = $.id 'boardNavDesktop'
|
||||||
if a = $ "a[href*='/#{g.BOARD}/']", nav
|
if a = $ "a[href*='/#{g.BOARD}/']", nav
|
||||||
a.className = 'current'
|
a.className = 'current'
|
||||||
$('.board-title', Header.headerBar).textContent = a.title
|
fullBoardList = $ '#full-board-list', Header.headerBar
|
||||||
$.add $('.board-list', Header.headerBar), [nav.childNodes...]
|
$.add fullBoardList, [nav.childNodes...]
|
||||||
Header.setCatalogLinks Conf['Header catalog links']
|
|
||||||
|
if Conf['Custom Board Navigation']
|
||||||
|
Header.generateBoardList Conf['boardnav']
|
||||||
|
$.sync 'boardnav', Header.generateBoardList
|
||||||
|
btn = $.el 'span',
|
||||||
|
className: 'hide-board-list-button brackets-wrap'
|
||||||
|
innerHTML: '<a href=javascript:;> - </a>'
|
||||||
|
$.on btn, 'click', Header.toggleBoardList
|
||||||
|
$.prepend fullBoardList, btn
|
||||||
|
else
|
||||||
|
$.rm $ '#custom-board-list', Header.headerBar
|
||||||
|
fullBoardList.hidden = false
|
||||||
|
|
||||||
|
Header.setCatalogLinks Conf['Header catalog links']
|
||||||
|
|
||||||
|
generateBoardList: (text) ->
|
||||||
|
as = $$('#full-board-list a', Header.headerBar)[0...-2] # ignore the Settings and Home links
|
||||||
|
nodes = text.match(/[\w@]+(-(all|title|full|text:"[^"]+"))?|[^\w@]+/g).map (t) ->
|
||||||
|
if /^[^\w@]/.test t
|
||||||
|
return $.tn t
|
||||||
|
if t is 'toggle-all'
|
||||||
|
a = $.el 'a',
|
||||||
|
className: 'show-board-list-button'
|
||||||
|
textContent: '+'
|
||||||
|
href: 'javascript:;'
|
||||||
|
$.on a, 'click', Header.toggleBoardList
|
||||||
|
return a
|
||||||
|
board = if /^current/.test t
|
||||||
|
g.BOARD.ID
|
||||||
|
else
|
||||||
|
t.match(/^[^-]+/)[0]
|
||||||
|
for a in as
|
||||||
|
if a.textContent is board
|
||||||
|
a = a.cloneNode true
|
||||||
|
if /-title$/.test t
|
||||||
|
a.textContent = a.title
|
||||||
|
else if /-full$/.test t
|
||||||
|
a.textContent = "/#{board}/ - #{a.title}"
|
||||||
|
else if m = t.match /-text:"(.+)"$/
|
||||||
|
a.textContent = m[1]
|
||||||
|
if board is 'v'
|
||||||
|
$.log t, t.match /-text:"(.+)"$/
|
||||||
|
return a
|
||||||
|
$.tn t
|
||||||
|
list = $ '#custom-board-list', Header.headerBar
|
||||||
|
list.innerHTML = null
|
||||||
|
$.add list, nodes
|
||||||
|
|
||||||
toggleBoardList: ->
|
toggleBoardList: ->
|
||||||
node = @firstElementChild.firstChild
|
showBoardList = $.hasClass @, 'show-board-list-button'
|
||||||
if showBoardList = $.hasClass @, 'show-board-list-button'
|
|
||||||
$.rmClass @, 'show-board-list-button'
|
|
||||||
$.addClass @, 'hide-board-list-button'
|
|
||||||
node.data = node.data.replace '+', '-'
|
|
||||||
else
|
|
||||||
$.rmClass @, 'hide-board-list-button'
|
|
||||||
$.addClass @, 'show-board-list-button'
|
|
||||||
node.data = node.data.replace '-', '+'
|
|
||||||
{headerBar} = Header
|
{headerBar} = Header
|
||||||
$('.board-name', headerBar).hidden = showBoardList
|
$('#custom-board-list', headerBar).hidden = showBoardList
|
||||||
$('.board-list', headerBar).hidden = !showBoardList
|
$('#full-board-list', headerBar).hidden = !showBoardList
|
||||||
|
|
||||||
setCatalogLinks: (useCatalog) ->
|
setCatalogLinks: (useCatalog) ->
|
||||||
root = $ '.board-list', Header.headerBar
|
as = $$ '#board-list a[href*="boards.4chan.org"]', Header.headerBar
|
||||||
as = $$ 'a[href*="boards.4chan.org"]', root
|
str = if useCatalog then 'catalog' else ''
|
||||||
as.push $ '.board-name', Header.headerBar
|
|
||||||
for a in as
|
for a in as
|
||||||
a.pathname = "/#{a.pathname.split('/')[1]}/#{if useCatalog then 'catalog' else ''}"
|
a.pathname = "/#{a.pathname.split('/')[1]}/#{str}"
|
||||||
return
|
return
|
||||||
toggleCatalogLinks: ->
|
toggleCatalogLinks: ->
|
||||||
Header.setCatalogLinks @checked
|
Header.setCatalogLinks @checked
|
||||||
@ -75,7 +119,7 @@ Header =
|
|||||||
|
|
||||||
setBarVisibility: (hide) ->
|
setBarVisibility: (hide) ->
|
||||||
(if hide then $.addClass else $.rmClass) Header.headerBar, 'autohide'
|
(if hide then $.addClass else $.rmClass) Header.headerBar, 'autohide'
|
||||||
toggleBar: ->
|
toggleBarVisibility: ->
|
||||||
hide = !$.hasClass Header.headerBar, 'autohide'
|
hide = !$.hasClass Header.headerBar, 'autohide'
|
||||||
Header.setBarVisibility hide
|
Header.setBarVisibility hide
|
||||||
message = if hide
|
message = if hide
|
||||||
@ -466,6 +510,17 @@ Settings =
|
|||||||
|
|
||||||
rice: (section) ->
|
rice: (section) ->
|
||||||
section.innerHTML = """
|
section.innerHTML = """
|
||||||
|
<fieldset>
|
||||||
|
<legend>Custom Board Navigation <span class=warning #{if Conf['Custom Board Navigation'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
|
<div><input name=boardnav class=field></div>
|
||||||
|
<div>In the following, <code>board</code> can translate to a board ID (<code>a</code>, <code>b</code>, etc...), the current board (<code>current</code>), or the Status/Twitter link (<code>status</code>, <code>@</code>).</div>
|
||||||
|
<div>Board link: <code>board</code></div>
|
||||||
|
<div>Title link: <code>board-title</code></div>
|
||||||
|
<div>Full text link: <code>board-full</code></div>
|
||||||
|
<div>Custom text link: <code>board-text:"VIP Board"</code></div>
|
||||||
|
<div>Full board list toggle: <code>toggle-all</code></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Time Formatting <span class=warning #{if Conf['Time Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
<legend>Time Formatting <span class=warning #{if Conf['Time Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
<div><input name=time class=field>: <span class=time-preview></span></div>
|
<div><input name=time class=field>: <span class=time-preview></span></div>
|
||||||
@ -486,7 +541,7 @@ Settings =
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>File Info Formatting <span class=warning #{if Conf['File Info Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
<legend>File Info Formatting <span class=warning #{if Conf['File Info Formatting'] then 'hidden' else ''}>is disabled.</span></legend>
|
||||||
<div><input name=fileInfo class=field>: <span class='fileText file-info-preview'></span></div>
|
<div><input name=fileInfo class=field>: <span class='fileText file-info-preview'></span></div>
|
||||||
<div>divnk: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>
|
<div>Link: <code>%l</code> (truncated), <code>%L</code> (untruncated), <code>%T</code> (Unix timestamp)</div>
|
||||||
<div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>
|
<div>Original file name: <code>%n</code> (truncated), <code>%N</code> (untruncated), <code>%t</code> (Unix timestamp)</div>
|
||||||
<div>Spoiler indicator: <code>%p</code></div>
|
<div>Spoiler indicator: <code>%p</code></div>
|
||||||
<div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>
|
<div>Size: <code>%B</code> (Bytes), <code>%K</code> (KB), <code>%M</code> (MB), <code>%s</code> (4chan default)</div>
|
||||||
@ -510,7 +565,7 @@ Settings =
|
|||||||
<textarea name=usercss class=field></textarea>
|
<textarea name=usercss class=field></textarea>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
"""
|
"""
|
||||||
for name in ['time', 'backlink', 'fileInfo', 'favicon', 'usercss']
|
for name in ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss']
|
||||||
input = $ "[name=#{name}]", section
|
input = $ "[name=#{name}]", section
|
||||||
input.value = $.get name, Conf[name]
|
input.value = $.get name, Conf[name]
|
||||||
event = if name in ['favicon', 'usercss']
|
event = if name in ['favicon', 'usercss']
|
||||||
@ -522,6 +577,8 @@ Settings =
|
|||||||
$.on input, event, Settings[name]
|
$.on input, event, Settings[name]
|
||||||
Settings[name].call input
|
Settings[name].call input
|
||||||
$.on $.id('apply-css'), 'click', Settings.usercss
|
$.on $.id('apply-css'), 'click', Settings.usercss
|
||||||
|
boardnav: ->
|
||||||
|
Header.generateBoardList @value
|
||||||
time: ->
|
time: ->
|
||||||
funk = Time.createFunc @value
|
funk = Time.createFunc @value
|
||||||
@nextElementSibling.textContent = funk Time, new Date()
|
@nextElementSibling.textContent = funk Time, new Date()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user