No more having to hack the contents of the coffee-generated JS.
This commit is contained in:
parent
f51ca57f2f
commit
64bb62a075
2
Makefile
2
Makefile
@ -131,7 +131,7 @@ tmp/declaration.js : .events/declare
|
||||
$(if $(wildcard $@),,node tools/declare.js && echo -> $^)
|
||||
|
||||
define force_compile
|
||||
$$(call dests_of,$1) : $1 $$(call imports,$$(call part_of,$1)) $$(template_deps) $$(coffee_deps) tools/globalize.js tools/chain.js
|
||||
$$(call dests_of,$1) : $1 $$(call imports,$$(call part_of,$1)) $$(template_deps) $$(coffee_deps) tools/chain.js
|
||||
$(RM) $$(subst $$$$,$$(ESC_DOLLAR),$$@)
|
||||
endef
|
||||
|
||||
|
||||
@ -114,3 +114,5 @@ Redirect =
|
||||
location.replace url
|
||||
else if alternative
|
||||
location.replace alternative
|
||||
|
||||
return Redirect
|
||||
|
||||
@ -24,3 +24,5 @@ Anonymize =
|
||||
name.textContent = 'Anonymous' for name in $$ '.name'
|
||||
$.rm trip for trip in $$ '.postertrip'
|
||||
return
|
||||
|
||||
return Anonymize
|
||||
|
||||
@ -247,3 +247,5 @@ Filter =
|
||||
tl = ta.textLength
|
||||
ta.setSelectionRange tl, tl
|
||||
ta.focus()
|
||||
|
||||
return Filter
|
||||
|
||||
@ -215,3 +215,5 @@ PostHiding =
|
||||
for quotelink in Get.allQuotelinksLinkingTo post
|
||||
$.rmClass quotelink, 'filtered'
|
||||
return
|
||||
|
||||
return PostHiding
|
||||
|
||||
@ -32,3 +32,5 @@ Recursive =
|
||||
g.posts.forEach (post) ->
|
||||
if fullID in post.quotes
|
||||
recursive post, args...
|
||||
|
||||
return Recursive
|
||||
|
||||
@ -189,3 +189,5 @@ ThreadHiding =
|
||||
threadRoot = thread.OP.nodes.root.parentNode
|
||||
threadRoot.hidden = thread.isHidden = false
|
||||
Index.updateHideLabel() if Conf['JSON Index']
|
||||
|
||||
return ThreadHiding
|
||||
|
||||
@ -260,3 +260,5 @@ Build =
|
||||
$.addClass $('.file-count', root), 'warning'
|
||||
|
||||
root
|
||||
|
||||
return Build
|
||||
|
||||
@ -67,3 +67,5 @@ Get =
|
||||
for script in $$ 'script:not([src])', d.head
|
||||
return script.textContent if /\bcooldowns *=/.test script.textContent
|
||||
''
|
||||
|
||||
return Get
|
||||
|
||||
@ -539,3 +539,5 @@ Header =
|
||||
$.set 'Desktop Notifications', false
|
||||
notice.close()
|
||||
notice = new Notice 'info', el
|
||||
|
||||
return Header
|
||||
|
||||
@ -773,3 +773,5 @@ Index =
|
||||
for keyword in keywords
|
||||
return false if -1 is text.indexOf keyword
|
||||
return true
|
||||
|
||||
return Index
|
||||
|
||||
@ -13,3 +13,5 @@ Polyfill =
|
||||
ui8a[i] = data.charCodeAt i
|
||||
cb new Blob [ui8a], {type}
|
||||
$.globalEval "HTMLCanvasElement.prototype.toBlob = (#{HTMLCanvasElement::toBlob});"
|
||||
|
||||
return Polyfill
|
||||
|
||||
@ -613,3 +613,5 @@ Settings =
|
||||
return unless (key = Keybinds.keyCode e)?
|
||||
@value = key
|
||||
$.cb.value.call @
|
||||
|
||||
return Settings
|
||||
|
||||
@ -1,390 +1,389 @@
|
||||
UI = do ->
|
||||
dialog = (id, position, properties) ->
|
||||
el = $.el 'div',
|
||||
dialog = (id, position, properties) ->
|
||||
el = $.el 'div',
|
||||
className: 'dialog'
|
||||
id: id
|
||||
$.extend el, properties
|
||||
el.style.cssText = position
|
||||
$.get "#{id}.position", position, (item) ->
|
||||
el.style.cssText = item["#{id}.position"]
|
||||
|
||||
move = $ '.move', el
|
||||
$.on move, 'touchstart mousedown', dragstart
|
||||
for child in move.children
|
||||
continue unless child.tagName
|
||||
$.on child, 'touchstart mousedown', (e) ->
|
||||
e.stopPropagation()
|
||||
|
||||
el
|
||||
|
||||
class Menu
|
||||
currentMenu = null
|
||||
lastToggledButton = null
|
||||
|
||||
constructor: (@type) ->
|
||||
# XXX AddMenuEntry event is deprecated
|
||||
$.on d, 'AddMenuEntry', ({detail}) =>
|
||||
return if detail.type isnt @type
|
||||
delete detail.open
|
||||
@addEntry detail
|
||||
@entries = []
|
||||
|
||||
makeMenu: ->
|
||||
menu = $.el 'div',
|
||||
className: 'dialog'
|
||||
id: id
|
||||
$.extend el, properties
|
||||
el.style.cssText = position
|
||||
$.get "#{id}.position", position, (item) ->
|
||||
el.style.cssText = item["#{id}.position"]
|
||||
id: 'menu'
|
||||
tabIndex: 0
|
||||
$.on menu, 'click', (e) -> e.stopPropagation()
|
||||
$.on menu, 'keydown', @keybinds
|
||||
menu
|
||||
|
||||
move = $ '.move', el
|
||||
$.on move, 'touchstart mousedown', dragstart
|
||||
for child in move.children
|
||||
continue unless child.tagName
|
||||
$.on child, 'touchstart mousedown', (e) ->
|
||||
e.stopPropagation()
|
||||
toggle: (e, button, data) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
el
|
||||
if currentMenu
|
||||
# Close if it's already opened.
|
||||
# Reopen if we clicked on another button.
|
||||
previousButton = lastToggledButton
|
||||
currentMenu.close()
|
||||
return if previousButton is button
|
||||
|
||||
class Menu
|
||||
return unless @entries.length
|
||||
@open button, data
|
||||
|
||||
open: (button, data) ->
|
||||
menu = @menu = @makeMenu()
|
||||
currentMenu = @
|
||||
lastToggledButton = button
|
||||
|
||||
@entries.sort (first, second) ->
|
||||
first.order - second.order
|
||||
|
||||
for entry in @entries
|
||||
@insertEntry entry, menu, data
|
||||
|
||||
$.addClass lastToggledButton, 'active'
|
||||
|
||||
$.on d, 'click CloseMenu', @close
|
||||
$.on d, 'scroll', @close unless @type is 'gallery'
|
||||
$.add button, menu
|
||||
|
||||
# Position
|
||||
mRect = menu.getBoundingClientRect()
|
||||
bRect = button.getBoundingClientRect()
|
||||
bTop = window.scrollY + bRect.top
|
||||
bLeft = window.scrollX + bRect.left
|
||||
cHeight = doc.clientHeight
|
||||
cWidth = doc.clientWidth
|
||||
[top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight
|
||||
[bRect.bottom, null]
|
||||
else
|
||||
[null, cHeight - bRect.top]
|
||||
[left, right] = if bRect.left + mRect.width < cWidth
|
||||
[bRect.left, null]
|
||||
else
|
||||
[null, cWidth - bRect.right]
|
||||
{style} = menu
|
||||
style.top = "#{top}px"
|
||||
style.right = "#{right}px"
|
||||
style.bottom = "#{bottom}px"
|
||||
style.left = "#{left}px"
|
||||
if right
|
||||
$.addClass menu, 'left'
|
||||
|
||||
entry = $ '.entry', menu
|
||||
# We've removed flexbox, so we don't use order anymore.
|
||||
# while prevEntry = @findNextEntry entry, -1
|
||||
# entry = prevEntry
|
||||
@focus entry
|
||||
|
||||
menu.focus()
|
||||
|
||||
insertEntry: (entry, parent, data) ->
|
||||
if typeof entry.open is 'function'
|
||||
try
|
||||
return unless entry.open data
|
||||
catch err
|
||||
Main.handleErrors
|
||||
message: "Error in building the #{@type} menu."
|
||||
error: err
|
||||
return
|
||||
$.add parent, entry.el
|
||||
|
||||
return unless entry.subEntries
|
||||
if submenu = $ '.submenu', entry.el
|
||||
# Reset sub menu, remove irrelevant entries.
|
||||
$.rm submenu
|
||||
submenu = $.el 'div',
|
||||
className: 'dialog submenu'
|
||||
for subEntry in entry.subEntries
|
||||
@insertEntry subEntry, submenu, data
|
||||
$.add entry.el, submenu
|
||||
return
|
||||
|
||||
close: =>
|
||||
$.rm @menu
|
||||
delete @menu
|
||||
$.rmClass lastToggledButton, 'active'
|
||||
currentMenu = null
|
||||
lastToggledButton = null
|
||||
$.off d, 'click scroll CloseMenu', @close
|
||||
|
||||
constructor: (@type) ->
|
||||
# XXX AddMenuEntry event is deprecated
|
||||
$.on d, 'AddMenuEntry', ({detail}) =>
|
||||
return if detail.type isnt @type
|
||||
delete detail.open
|
||||
@addEntry detail
|
||||
@entries = []
|
||||
findNextEntry: (entry, direction) ->
|
||||
entries = [entry.parentNode.children...]
|
||||
entries.sort (first, second) -> first.style.order - second.style.order
|
||||
entries[entries.indexOf(entry) + direction]
|
||||
|
||||
makeMenu: ->
|
||||
menu = $.el 'div',
|
||||
className: 'dialog'
|
||||
id: 'menu'
|
||||
tabIndex: 0
|
||||
$.on menu, 'click', (e) -> e.stopPropagation()
|
||||
$.on menu, 'keydown', @keybinds
|
||||
menu
|
||||
keybinds: (e) =>
|
||||
entry = $ '.focused', @menu
|
||||
while subEntry = $ '.focused', entry
|
||||
entry = subEntry
|
||||
|
||||
toggle: (e, button, data) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if currentMenu
|
||||
# Close if it's already opened.
|
||||
# Reopen if we clicked on another button.
|
||||
previousButton = lastToggledButton
|
||||
currentMenu.close()
|
||||
return if previousButton is button
|
||||
|
||||
return unless @entries.length
|
||||
@open button, data
|
||||
|
||||
open: (button, data) ->
|
||||
menu = @menu = @makeMenu()
|
||||
currentMenu = @
|
||||
lastToggledButton = button
|
||||
|
||||
@entries.sort (first, second) ->
|
||||
first.order - second.order
|
||||
|
||||
for entry in @entries
|
||||
@insertEntry entry, menu, data
|
||||
|
||||
$.addClass lastToggledButton, 'active'
|
||||
|
||||
$.on d, 'click CloseMenu', @close
|
||||
$.on d, 'scroll', @close unless @type is 'gallery'
|
||||
$.add button, menu
|
||||
|
||||
# Position
|
||||
mRect = menu.getBoundingClientRect()
|
||||
bRect = button.getBoundingClientRect()
|
||||
bTop = window.scrollY + bRect.top
|
||||
bLeft = window.scrollX + bRect.left
|
||||
cHeight = doc.clientHeight
|
||||
cWidth = doc.clientWidth
|
||||
[top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight
|
||||
[bRect.bottom, null]
|
||||
switch e.keyCode
|
||||
when 27 # Esc
|
||||
lastToggledButton.focus()
|
||||
@close()
|
||||
when 13, 32 # Enter, Space
|
||||
entry.click()
|
||||
when 38 # Up
|
||||
if next = @findNextEntry entry, -1
|
||||
@focus next
|
||||
when 40 # Down
|
||||
if next = @findNextEntry entry, +1
|
||||
@focus next
|
||||
when 39 # Right
|
||||
if (submenu = $ '.submenu', entry) and next = submenu.firstElementChild
|
||||
while nextPrev = @findNextEntry next, -1
|
||||
next = nextPrev
|
||||
@focus next
|
||||
when 37 # Left
|
||||
if next = $.x 'parent::*[contains(@class,"submenu")]/parent::*', entry
|
||||
@focus next
|
||||
else
|
||||
[null, cHeight - bRect.top]
|
||||
[left, right] = if bRect.left + mRect.width < cWidth
|
||||
[bRect.left, null]
|
||||
else
|
||||
[null, cWidth - bRect.right]
|
||||
{style} = menu
|
||||
style.top = "#{top}px"
|
||||
style.right = "#{right}px"
|
||||
style.bottom = "#{bottom}px"
|
||||
style.left = "#{left}px"
|
||||
if right
|
||||
$.addClass menu, 'left'
|
||||
|
||||
entry = $ '.entry', menu
|
||||
# We've removed flexbox, so we don't use order anymore.
|
||||
# while prevEntry = @findNextEntry entry, -1
|
||||
# entry = prevEntry
|
||||
@focus entry
|
||||
|
||||
menu.focus()
|
||||
|
||||
insertEntry: (entry, parent, data) ->
|
||||
if typeof entry.open is 'function'
|
||||
try
|
||||
return unless entry.open data
|
||||
catch err
|
||||
Main.handleErrors
|
||||
message: "Error in building the #{@type} menu."
|
||||
error: err
|
||||
return
|
||||
$.add parent, entry.el
|
||||
|
||||
return unless entry.subEntries
|
||||
if submenu = $ '.submenu', entry.el
|
||||
# Reset sub menu, remove irrelevant entries.
|
||||
$.rm submenu
|
||||
submenu = $.el 'div',
|
||||
className: 'dialog submenu'
|
||||
for subEntry in entry.subEntries
|
||||
@insertEntry subEntry, submenu, data
|
||||
$.add entry.el, submenu
|
||||
return
|
||||
|
||||
close: =>
|
||||
$.rm @menu
|
||||
delete @menu
|
||||
$.rmClass lastToggledButton, 'active'
|
||||
currentMenu = null
|
||||
lastToggledButton = null
|
||||
$.off d, 'click scroll CloseMenu', @close
|
||||
|
||||
findNextEntry: (entry, direction) ->
|
||||
entries = [entry.parentNode.children...]
|
||||
entries.sort (first, second) -> first.style.order - second.style.order
|
||||
entries[entries.indexOf(entry) + direction]
|
||||
|
||||
keybinds: (e) =>
|
||||
entry = $ '.focused', @menu
|
||||
while subEntry = $ '.focused', entry
|
||||
entry = subEntry
|
||||
|
||||
switch e.keyCode
|
||||
when 27 # Esc
|
||||
lastToggledButton.focus()
|
||||
@close()
|
||||
when 13, 32 # Enter, Space
|
||||
entry.click()
|
||||
when 38 # Up
|
||||
if next = @findNextEntry entry, -1
|
||||
@focus next
|
||||
when 40 # Down
|
||||
if next = @findNextEntry entry, +1
|
||||
@focus next
|
||||
when 39 # Right
|
||||
if (submenu = $ '.submenu', entry) and next = submenu.firstElementChild
|
||||
while nextPrev = @findNextEntry next, -1
|
||||
next = nextPrev
|
||||
@focus next
|
||||
when 37 # Left
|
||||
if next = $.x 'parent::*[contains(@class,"submenu")]/parent::*', entry
|
||||
@focus next
|
||||
else
|
||||
return
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
onFocus: (e) =>
|
||||
e.stopPropagation()
|
||||
@focus e.target
|
||||
|
||||
focus: (entry) ->
|
||||
while focused = $.x 'parent::*/child::*[contains(@class,"focused")]', entry
|
||||
$.rmClass focused, 'focused'
|
||||
for focused in $$ '.focused', entry
|
||||
$.rmClass focused, 'focused'
|
||||
$.addClass entry, 'focused'
|
||||
|
||||
# Submenu positioning.
|
||||
return unless submenu = $ '.submenu', entry
|
||||
sRect = submenu.getBoundingClientRect()
|
||||
eRect = entry.getBoundingClientRect()
|
||||
cHeight = doc.clientHeight
|
||||
cWidth = doc.clientWidth
|
||||
[top, bottom] = if eRect.top + sRect.height < cHeight
|
||||
['0px', 'auto']
|
||||
else
|
||||
['auto', '0px']
|
||||
[left, right] = if eRect.right + sRect.width < cWidth - 150
|
||||
['100%', 'auto']
|
||||
else
|
||||
['auto', '100%']
|
||||
{style} = submenu
|
||||
style.top = top
|
||||
style.bottom = bottom
|
||||
style.left = left
|
||||
style.right = right
|
||||
|
||||
addEntry: (entry) =>
|
||||
@parseEntry entry
|
||||
@entries.push entry
|
||||
|
||||
parseEntry: (entry) ->
|
||||
{el, subEntries} = entry
|
||||
$.addClass el, 'entry'
|
||||
$.on el, 'focus mouseover', @onFocus
|
||||
el.style.order = entry.order or 100
|
||||
return unless subEntries
|
||||
$.addClass el, 'has-submenu'
|
||||
for subEntry in subEntries
|
||||
@parseEntry subEntry
|
||||
return
|
||||
|
||||
dragstart = (e) ->
|
||||
return if e.type is 'mousedown' and e.button isnt 0 # not LMB
|
||||
# prevent text selection
|
||||
e.preventDefault()
|
||||
if isTouching = e.type is 'touchstart'
|
||||
e = e.changedTouches[e.changedTouches.length - 1]
|
||||
# distance from pointer to el edge is constant; calculate it here.
|
||||
el = $.x 'ancestor::div[contains(@class,"dialog")][1]', @
|
||||
rect = el.getBoundingClientRect()
|
||||
screenHeight = doc.clientHeight
|
||||
screenWidth = doc.clientWidth
|
||||
o = {
|
||||
id: el.id
|
||||
style: el.style
|
||||
dx: e.clientX - rect.left
|
||||
dy: e.clientY - rect.top
|
||||
height: screenHeight - rect.height
|
||||
width: screenWidth - rect.width
|
||||
screenHeight: screenHeight
|
||||
screenWidth: screenWidth
|
||||
isTouching: isTouching
|
||||
}
|
||||
|
||||
[o.topBorder, o.bottomBorder] = if Conf['Header auto-hide'] or not Conf['Fixed Header']
|
||||
[0, 0]
|
||||
else if Conf['Bottom Header']
|
||||
[0, Header.bar.getBoundingClientRect().height]
|
||||
else
|
||||
[Header.bar.getBoundingClientRect().height, 0]
|
||||
|
||||
if isTouching
|
||||
o.identifier = e.identifier
|
||||
o.move = touchmove.bind o
|
||||
o.up = touchend.bind o
|
||||
$.on d, 'touchmove', o.move
|
||||
$.on d, 'touchend touchcancel', o.up
|
||||
else # mousedown
|
||||
o.move = drag.bind o
|
||||
o.up = dragend.bind o
|
||||
$.on d, 'mousemove', o.move
|
||||
$.on d, 'mouseup', o.up
|
||||
|
||||
touchmove = (e) ->
|
||||
for touch in e.changedTouches
|
||||
if touch.identifier is @identifier
|
||||
drag.call @, touch
|
||||
return
|
||||
|
||||
drag = (e) ->
|
||||
{clientX, clientY} = e
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
left = clientX - @dx
|
||||
left = if left < 10
|
||||
0
|
||||
else if @width - left < 10
|
||||
null
|
||||
onFocus: (e) =>
|
||||
e.stopPropagation()
|
||||
@focus e.target
|
||||
|
||||
focus: (entry) ->
|
||||
while focused = $.x 'parent::*/child::*[contains(@class,"focused")]', entry
|
||||
$.rmClass focused, 'focused'
|
||||
for focused in $$ '.focused', entry
|
||||
$.rmClass focused, 'focused'
|
||||
$.addClass entry, 'focused'
|
||||
|
||||
# Submenu positioning.
|
||||
return unless submenu = $ '.submenu', entry
|
||||
sRect = submenu.getBoundingClientRect()
|
||||
eRect = entry.getBoundingClientRect()
|
||||
cHeight = doc.clientHeight
|
||||
cWidth = doc.clientWidth
|
||||
[top, bottom] = if eRect.top + sRect.height < cHeight
|
||||
['0px', 'auto']
|
||||
else
|
||||
left / @screenWidth * 100 + '%'
|
||||
|
||||
top = clientY - @dy
|
||||
top = if top < (10 + @topBorder)
|
||||
@topBorder + 'px'
|
||||
else if @height - top < (10 + @bottomBorder)
|
||||
null
|
||||
['auto', '0px']
|
||||
[left, right] = if eRect.right + sRect.width < cWidth - 150
|
||||
['100%', 'auto']
|
||||
else
|
||||
top / @screenHeight * 100 + '%'
|
||||
|
||||
right = if left is null
|
||||
0
|
||||
else
|
||||
null
|
||||
|
||||
bottom = if top is null
|
||||
@bottomBorder + 'px'
|
||||
else
|
||||
null
|
||||
|
||||
{style} = @
|
||||
style.left = left
|
||||
style.right = right
|
||||
['auto', '100%']
|
||||
{style} = submenu
|
||||
style.top = top
|
||||
style.bottom = bottom
|
||||
style.left = left
|
||||
style.right = right
|
||||
|
||||
touchend = (e) ->
|
||||
for touch in e.changedTouches
|
||||
if touch.identifier is @identifier
|
||||
dragend.call @
|
||||
return
|
||||
addEntry: (entry) =>
|
||||
@parseEntry entry
|
||||
@entries.push entry
|
||||
|
||||
dragend = ->
|
||||
if @isTouching
|
||||
$.off d, 'touchmove', @move
|
||||
$.off d, 'touchend touchcancel', @up
|
||||
else # mouseup
|
||||
$.off d, 'mousemove', @move
|
||||
$.off d, 'mouseup', @up
|
||||
$.set "#{@id}.position", @style.cssText
|
||||
parseEntry: (entry) ->
|
||||
{el, subEntries} = entry
|
||||
$.addClass el, 'entry'
|
||||
$.on el, 'focus mouseover', @onFocus
|
||||
el.style.order = entry.order or 100
|
||||
return unless subEntries
|
||||
$.addClass el, 'has-submenu'
|
||||
for subEntry in subEntries
|
||||
@parseEntry subEntry
|
||||
return
|
||||
|
||||
hoverstart = ({root, el, latestEvent, endEvents, height, cb, noRemove}) ->
|
||||
o = {
|
||||
root
|
||||
el
|
||||
style: el.style
|
||||
isImage: el.nodeName in ['IMG', 'VIDEO']
|
||||
cb
|
||||
endEvents
|
||||
latestEvent
|
||||
clientHeight: doc.clientHeight
|
||||
clientWidth: doc.clientWidth
|
||||
height
|
||||
noRemove
|
||||
}
|
||||
o.hover = hover.bind o
|
||||
o.hoverend = hoverend.bind o
|
||||
|
||||
o.hover o.latestEvent
|
||||
new MutationObserver(->
|
||||
o.hover o.latestEvent if el.parentNode
|
||||
).observe el, {childList: true}
|
||||
|
||||
$.on root, endEvents, o.hoverend
|
||||
if $.x 'ancestor::div[contains(@class,"inline")][1]', root
|
||||
$.on d, 'keydown', o.hoverend
|
||||
$.on root, 'mousemove', o.hover
|
||||
|
||||
# Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=674955
|
||||
o.workaround = (e) -> o.hoverend(e) unless root.contains e.target
|
||||
$.on doc, 'mousemove', o.workaround
|
||||
|
||||
hoverstart.padding = 25
|
||||
|
||||
hover = (e) ->
|
||||
@latestEvent = e
|
||||
height = (@height or @el.offsetHeight) + hoverstart.padding
|
||||
{clientX, clientY} = e
|
||||
|
||||
top = if @isImage
|
||||
Math.max 0, clientY * (@clientHeight - height) / @clientHeight
|
||||
else
|
||||
Math.max 0, Math.min(@clientHeight - height, clientY - 120)
|
||||
|
||||
threshold = @clientWidth / 2
|
||||
threshold = Math.max threshold, @clientWidth - 400 unless @isImage
|
||||
[left, right] = if clientX <= threshold
|
||||
[clientX + 45 + 'px', null]
|
||||
else
|
||||
[null, @clientWidth - clientX + 45 + 'px']
|
||||
|
||||
{style} = @
|
||||
style.top = top + 'px'
|
||||
style.left = left
|
||||
style.right = right
|
||||
|
||||
hoverend = (e) ->
|
||||
return if e.type is 'keydown' and e.keyCode isnt 13 or e.target.nodeName is "TEXTAREA"
|
||||
$.rm @el unless @noRemove
|
||||
$.off @root, @endEvents, @hoverend
|
||||
$.off d, 'keydown', @hoverend
|
||||
$.off @root, 'mousemove', @hover
|
||||
# Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=674955
|
||||
$.off doc, 'mousemove', @workaround
|
||||
@cb.call @ if @cb
|
||||
|
||||
checkbox = (name, text, checked) ->
|
||||
checked = Conf[name] unless checked?
|
||||
label = $.el 'label'
|
||||
input = $.el 'input', {type: 'checkbox', name, checked}
|
||||
$.add label, [input, $.tn " #{text}"]
|
||||
label
|
||||
|
||||
return {
|
||||
dialog: dialog
|
||||
Menu: Menu
|
||||
hover: hoverstart
|
||||
checkbox: checkbox
|
||||
dragstart = (e) ->
|
||||
return if e.type is 'mousedown' and e.button isnt 0 # not LMB
|
||||
# prevent text selection
|
||||
e.preventDefault()
|
||||
if isTouching = e.type is 'touchstart'
|
||||
e = e.changedTouches[e.changedTouches.length - 1]
|
||||
# distance from pointer to el edge is constant; calculate it here.
|
||||
el = $.x 'ancestor::div[contains(@class,"dialog")][1]', @
|
||||
rect = el.getBoundingClientRect()
|
||||
screenHeight = doc.clientHeight
|
||||
screenWidth = doc.clientWidth
|
||||
o = {
|
||||
id: el.id
|
||||
style: el.style
|
||||
dx: e.clientX - rect.left
|
||||
dy: e.clientY - rect.top
|
||||
height: screenHeight - rect.height
|
||||
width: screenWidth - rect.width
|
||||
screenHeight: screenHeight
|
||||
screenWidth: screenWidth
|
||||
isTouching: isTouching
|
||||
}
|
||||
|
||||
[o.topBorder, o.bottomBorder] = if Conf['Header auto-hide'] or not Conf['Fixed Header']
|
||||
[0, 0]
|
||||
else if Conf['Bottom Header']
|
||||
[0, Header.bar.getBoundingClientRect().height]
|
||||
else
|
||||
[Header.bar.getBoundingClientRect().height, 0]
|
||||
|
||||
if isTouching
|
||||
o.identifier = e.identifier
|
||||
o.move = touchmove.bind o
|
||||
o.up = touchend.bind o
|
||||
$.on d, 'touchmove', o.move
|
||||
$.on d, 'touchend touchcancel', o.up
|
||||
else # mousedown
|
||||
o.move = drag.bind o
|
||||
o.up = dragend.bind o
|
||||
$.on d, 'mousemove', o.move
|
||||
$.on d, 'mouseup', o.up
|
||||
|
||||
touchmove = (e) ->
|
||||
for touch in e.changedTouches
|
||||
if touch.identifier is @identifier
|
||||
drag.call @, touch
|
||||
return
|
||||
|
||||
drag = (e) ->
|
||||
{clientX, clientY} = e
|
||||
|
||||
left = clientX - @dx
|
||||
left = if left < 10
|
||||
0
|
||||
else if @width - left < 10
|
||||
null
|
||||
else
|
||||
left / @screenWidth * 100 + '%'
|
||||
|
||||
top = clientY - @dy
|
||||
top = if top < (10 + @topBorder)
|
||||
@topBorder + 'px'
|
||||
else if @height - top < (10 + @bottomBorder)
|
||||
null
|
||||
else
|
||||
top / @screenHeight * 100 + '%'
|
||||
|
||||
right = if left is null
|
||||
0
|
||||
else
|
||||
null
|
||||
|
||||
bottom = if top is null
|
||||
@bottomBorder + 'px'
|
||||
else
|
||||
null
|
||||
|
||||
{style} = @
|
||||
style.left = left
|
||||
style.right = right
|
||||
style.top = top
|
||||
style.bottom = bottom
|
||||
|
||||
touchend = (e) ->
|
||||
for touch in e.changedTouches
|
||||
if touch.identifier is @identifier
|
||||
dragend.call @
|
||||
return
|
||||
|
||||
dragend = ->
|
||||
if @isTouching
|
||||
$.off d, 'touchmove', @move
|
||||
$.off d, 'touchend touchcancel', @up
|
||||
else # mouseup
|
||||
$.off d, 'mousemove', @move
|
||||
$.off d, 'mouseup', @up
|
||||
$.set "#{@id}.position", @style.cssText
|
||||
|
||||
hoverstart = ({root, el, latestEvent, endEvents, height, cb, noRemove}) ->
|
||||
o = {
|
||||
root
|
||||
el
|
||||
style: el.style
|
||||
isImage: el.nodeName in ['IMG', 'VIDEO']
|
||||
cb
|
||||
endEvents
|
||||
latestEvent
|
||||
clientHeight: doc.clientHeight
|
||||
clientWidth: doc.clientWidth
|
||||
height
|
||||
noRemove
|
||||
}
|
||||
o.hover = hover.bind o
|
||||
o.hoverend = hoverend.bind o
|
||||
|
||||
o.hover o.latestEvent
|
||||
new MutationObserver(->
|
||||
o.hover o.latestEvent if el.parentNode
|
||||
).observe el, {childList: true}
|
||||
|
||||
$.on root, endEvents, o.hoverend
|
||||
if $.x 'ancestor::div[contains(@class,"inline")][1]', root
|
||||
$.on d, 'keydown', o.hoverend
|
||||
$.on root, 'mousemove', o.hover
|
||||
|
||||
# Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=674955
|
||||
o.workaround = (e) -> o.hoverend(e) unless root.contains e.target
|
||||
$.on doc, 'mousemove', o.workaround
|
||||
|
||||
hoverstart.padding = 25
|
||||
|
||||
hover = (e) ->
|
||||
@latestEvent = e
|
||||
height = (@height or @el.offsetHeight) + hoverstart.padding
|
||||
{clientX, clientY} = e
|
||||
|
||||
top = if @isImage
|
||||
Math.max 0, clientY * (@clientHeight - height) / @clientHeight
|
||||
else
|
||||
Math.max 0, Math.min(@clientHeight - height, clientY - 120)
|
||||
|
||||
threshold = @clientWidth / 2
|
||||
threshold = Math.max threshold, @clientWidth - 400 unless @isImage
|
||||
[left, right] = if clientX <= threshold
|
||||
[clientX + 45 + 'px', null]
|
||||
else
|
||||
[null, @clientWidth - clientX + 45 + 'px']
|
||||
|
||||
{style} = @
|
||||
style.top = top + 'px'
|
||||
style.left = left
|
||||
style.right = right
|
||||
|
||||
hoverend = (e) ->
|
||||
return if e.type is 'keydown' and e.keyCode isnt 13 or e.target.nodeName is "TEXTAREA"
|
||||
$.rm @el unless @noRemove
|
||||
$.off @root, @endEvents, @hoverend
|
||||
$.off d, 'keydown', @hoverend
|
||||
$.off @root, 'mousemove', @hover
|
||||
# Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=674955
|
||||
$.off doc, 'mousemove', @workaround
|
||||
@cb.call @ if @cb
|
||||
|
||||
checkbox = (name, text, checked) ->
|
||||
checked = Conf[name] unless checked?
|
||||
label = $.el 'label'
|
||||
input = $.el 'input', {type: 'checkbox', name, checked}
|
||||
$.add label, [input, $.tn " #{text}"]
|
||||
label
|
||||
|
||||
return {
|
||||
dialog: dialog
|
||||
Menu: Menu
|
||||
hover: hoverstart
|
||||
checkbox: checkbox
|
||||
}
|
||||
|
||||
@ -49,3 +49,5 @@ FappeTyme =
|
||||
toggle: (type) ->
|
||||
@set type, !@enabled[type]
|
||||
$.cb.checked.call @nodes[type] if type is 'werk'
|
||||
|
||||
return FappeTyme
|
||||
|
||||
@ -368,3 +368,5 @@ Gallery =
|
||||
subEntries.push el: delayLabel
|
||||
|
||||
subEntries
|
||||
|
||||
return Gallery
|
||||
|
||||
@ -88,3 +88,5 @@ ImageCommon =
|
||||
@click()
|
||||
else
|
||||
new Notice 'error', "Could not download #{@href}", 30
|
||||
|
||||
return ImageCommon
|
||||
|
||||
@ -302,3 +302,5 @@ ImageExpand =
|
||||
$.event 'change', null, input
|
||||
$.on input, 'change', $.cb.checked
|
||||
el: label
|
||||
|
||||
return ImageExpand
|
||||
|
||||
@ -72,3 +72,5 @@ ImageHover =
|
||||
@src = URL + if @src is URL then '?' + Date.now() else ''
|
||||
else
|
||||
$.rm @
|
||||
|
||||
return ImageHover
|
||||
|
||||
@ -89,3 +89,5 @@ ImageLoader =
|
||||
{thumb} = post.file
|
||||
if Header.isNodeVisible(thumb) or post.nodes.root is qpClone then thumb.play() else thumb.pause()
|
||||
return
|
||||
|
||||
return ImageLoader
|
||||
|
||||
@ -60,3 +60,5 @@ Metadata =
|
||||
else unless element in [0x8538067, 0x549A966] # Segment, Info
|
||||
i += size
|
||||
null
|
||||
|
||||
return Metadata
|
||||
|
||||
@ -17,3 +17,5 @@ RevealSpoilers =
|
||||
thumb.src = @file.thumbURL
|
||||
else
|
||||
thumb.dataset.src = @file.thumbURL
|
||||
|
||||
return RevealSpoilers
|
||||
|
||||
@ -87,3 +87,5 @@ Sauce =
|
||||
name: (post) -> post.file.name
|
||||
'%': -> '%'
|
||||
semi: -> ';'
|
||||
|
||||
return Sauce
|
||||
|
||||
@ -78,3 +78,5 @@ Volume =
|
||||
volume /= 1.1 if e.deltaY > 0
|
||||
el.volume = $.minmax volume - 0.1, 0, 1
|
||||
e.preventDefault()
|
||||
|
||||
return Volume
|
||||
|
||||
@ -395,3 +395,5 @@ Embedding =
|
||||
src: a.dataset.href
|
||||
loop: /^https?:\/\/i\.4cdn\.org\//.test a.dataset.href
|
||||
]
|
||||
|
||||
return Embedding
|
||||
|
||||
@ -155,3 +155,5 @@ Linkify =
|
||||
range.insertNode a
|
||||
|
||||
a
|
||||
|
||||
return Linkify
|
||||
|
||||
@ -51,3 +51,5 @@ ArchiveLink =
|
||||
el: el
|
||||
open: open
|
||||
}
|
||||
|
||||
return ArchiveLink
|
||||
|
||||
@ -132,3 +132,5 @@ DeleteLink =
|
||||
for fileOnly in [false, true] when DeleteLink.auto[+fileOnly][post.fullID]
|
||||
DeleteLink.delete post, fileOnly
|
||||
return
|
||||
|
||||
return DeleteLink
|
||||
|
||||
@ -17,3 +17,5 @@ DownloadLink =
|
||||
a.href = file.url
|
||||
a.download = file.name
|
||||
true
|
||||
|
||||
return DownloadLink
|
||||
|
||||
@ -31,3 +31,5 @@ Menu =
|
||||
$.on button, 'click', (e) ->
|
||||
Menu.menu.toggle e, @, post
|
||||
button
|
||||
|
||||
return Menu
|
||||
|
||||
@ -32,3 +32,5 @@ ReportLink =
|
||||
id = Date.now()
|
||||
set = "toolbar=0,scrollbars=1,location=0,status=1,menubar=0,resizable=1,#{dims}"
|
||||
window.open url, id, set
|
||||
|
||||
return ReportLink
|
||||
|
||||
@ -31,3 +31,5 @@ AntiAutoplay =
|
||||
object.data = object.data.replace(/\?autoplay=1&?/, '?').replace('&autoplay=1', '')
|
||||
$.addClass object, 'autoplay-removed'
|
||||
return
|
||||
|
||||
return AntiAutoplay
|
||||
|
||||
@ -107,3 +107,5 @@ Banner =
|
||||
child.textContent = data.title
|
||||
else
|
||||
Banner.db.delete {boardID: g.BOARD.ID, threadID: className}
|
||||
|
||||
return Banner
|
||||
|
||||
@ -86,3 +86,5 @@ CatalogLinks =
|
||||
if g.BOARD.ID is board and g.VIEW is 'index' then '#index' else "/#{board}/#index"
|
||||
else
|
||||
"/#{board}/"
|
||||
|
||||
return CatalogLinks
|
||||
|
||||
@ -15,3 +15,5 @@ CustomCSS =
|
||||
unless @style
|
||||
return @addStyle()
|
||||
@style.textContent = Conf['usercss']
|
||||
|
||||
return CustomCSS
|
||||
|
||||
@ -71,3 +71,5 @@ ExpandComment =
|
||||
for callback in ExpandComment.callbacks
|
||||
callback.call post
|
||||
return
|
||||
|
||||
return ExpandComment
|
||||
|
||||
@ -103,3 +103,5 @@ ExpandThread =
|
||||
|
||||
postsCount = postsRoot.length
|
||||
a.textContent = Build.summaryText '-', postsCount, filesCount
|
||||
|
||||
return ExpandThread
|
||||
|
||||
@ -48,3 +48,5 @@ FileInfo =
|
||||
r: -> <%= html('${this.file.dimensions || "PDF"}') %>
|
||||
g: -> <%= html('?{this.file.tag}{, ${this.file.tag}}{}') %>
|
||||
'%': -> <%= html('%') %>
|
||||
|
||||
return FileInfo
|
||||
|
||||
@ -10,3 +10,5 @@ Flash =
|
||||
if g.VIEW is 'thread'
|
||||
$.global -> window.Main.tid = location.pathname.split(/\/+/)[3]
|
||||
$.global -> window.SWFEmbed.init()
|
||||
|
||||
return Flash
|
||||
|
||||
@ -73,3 +73,5 @@ Fourchan =
|
||||
$.event 'mathjax', null, @nodes.comment
|
||||
$.on d, 'PostsInserted', cb
|
||||
cb()
|
||||
|
||||
return Fourchan
|
||||
|
||||
@ -47,3 +47,5 @@ IDColor =
|
||||
while i < 8
|
||||
msg = (msg << 5) - msg + uid.charCodeAt i++
|
||||
msg
|
||||
|
||||
return IDColor
|
||||
|
||||
@ -21,3 +21,5 @@ IDHighlight =
|
||||
uniqueID = post.info.uniqueID or post.info.capcode
|
||||
IDHighlight.uniqueID = if IDHighlight.uniqueID is uniqueID then null else uniqueID
|
||||
g.posts.forEach IDHighlight.set
|
||||
|
||||
return IDHighlight
|
||||
|
||||
@ -324,3 +324,5 @@ Keybinds =
|
||||
|
||||
focus: (post) ->
|
||||
$.addClass post, 'highlight'
|
||||
|
||||
return Keybinds
|
||||
|
||||
@ -77,3 +77,5 @@ Nav =
|
||||
d.body.style.marginBottom = null
|
||||
delete Nav.haveExtra
|
||||
$.off d, 'scroll', Nav.removeExtra
|
||||
|
||||
return Nav
|
||||
|
||||
@ -12,3 +12,5 @@ NormalizeURL =
|
||||
pathname = pathname.join '/'
|
||||
if location.pathname isnt pathname
|
||||
history.replaceState history.state, '', "#{location.protocol}//#{location.host}#{pathname}#{location.hash}"
|
||||
|
||||
return NormalizeURL
|
||||
|
||||
@ -54,3 +54,5 @@ PSAHiding =
|
||||
$.after $.id('globalToggle'), psa
|
||||
PSAHiding.hr?.hidden = PSAHiding.hidden
|
||||
return
|
||||
|
||||
return PSAHiding
|
||||
|
||||
@ -119,3 +119,5 @@ RelativeDates =
|
||||
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.
|
||||
RelativeDates.stale.push data
|
||||
|
||||
return RelativeDates
|
||||
|
||||
@ -26,3 +26,5 @@ RemoveSpoilers =
|
||||
$.replace spoiler, span
|
||||
$.add span, [spoiler.childNodes...]
|
||||
return
|
||||
|
||||
return RemoveSpoilers
|
||||
|
||||
@ -65,3 +65,5 @@ Report =
|
||||
if types = $.id('reportTypes')
|
||||
$.on types, 'change', (e) ->
|
||||
$('form').action = if e.target.value is 'illegal' then '#redirect' else ''
|
||||
|
||||
return Report
|
||||
|
||||
@ -18,3 +18,5 @@ ThreadLinks =
|
||||
|
||||
process: (link) ->
|
||||
link.target = '_blank'
|
||||
|
||||
return ThreadLinks
|
||||
|
||||
@ -62,3 +62,5 @@ Time =
|
||||
y: -> @getFullYear().toString()[2..]
|
||||
Y: -> @getFullYear()
|
||||
'%': -> '%'
|
||||
|
||||
return Time
|
||||
|
||||
@ -80,3 +80,5 @@ Favicon =
|
||||
|
||||
dead: 'data:image/gif;base64,<%= readBase64("src/Monitoring/Favicon/dead.gif") %>'
|
||||
logo: 'data:image/png;base64,<%= readBase64("src/meta/icon128.png") %>'
|
||||
|
||||
return Favicon
|
||||
|
||||
@ -40,3 +40,5 @@ MarkNewIPs =
|
||||
markOld: (post) ->
|
||||
post.nodes.nameBlock.title = 'Not the first post from this IP.'
|
||||
$.addClass post.nodes.root, 'old-ip'
|
||||
|
||||
return MarkNewIPs
|
||||
|
||||
@ -119,3 +119,5 @@ ReplyPruning =
|
||||
else
|
||||
Build.summaryText '-', ReplyPruning.total, ReplyPruning.totalFiles
|
||||
ReplyPruning.summary.hidden = (ReplyPruning.total <= +Conf["Max Replies"])
|
||||
|
||||
return ReplyPruning
|
||||
|
||||
@ -6,3 +6,5 @@ ThreadExcerpt =
|
||||
name: 'Thread Excerpt'
|
||||
cb: @node
|
||||
node: -> d.title = Get.threadExcerpt @
|
||||
|
||||
return ThreadExcerpt
|
||||
|
||||
@ -103,3 +103,5 @@ ThreadStats =
|
||||
if g.BOARD.ID isnt 'f' and ThreadStats.lastPost > ThreadStats.lastPageUpdate and ThreadStats.pageCountEl?.textContent isnt '1'
|
||||
clearTimeout ThreadStats.timeout
|
||||
ThreadStats.timeout = setTimeout ThreadStats.fetchPage, 5 * $.SECOND
|
||||
|
||||
return ThreadStats
|
||||
|
||||
@ -356,3 +356,5 @@ ThreadUpdater =
|
||||
postCount: OP.replies + 1
|
||||
fileCount: OP.images + !!OP.fsize
|
||||
ipCount: OP.unique_ips
|
||||
|
||||
return ThreadUpdater
|
||||
|
||||
@ -482,3 +482,5 @@ ThreadWatcher =
|
||||
$.on input, 'change', ThreadWatcher.refresh if name in ['Current Board', 'Show Unread Count']
|
||||
$.on input, 'change', ThreadWatcher.fetchAuto if name in ['Show Unread Count', 'Auto Update Thread Watcher']
|
||||
entry
|
||||
|
||||
return ThreadWatcher
|
||||
|
||||
@ -252,3 +252,5 @@ Unread =
|
||||
Favicon[if isDead then 'dead' else 'default']
|
||||
# `favicon.href = href` doesn't work on Firefox.
|
||||
$.add d.head, Favicon.el
|
||||
|
||||
return Unread
|
||||
|
||||
@ -1 +0,0 @@
|
||||
Captcha = {}
|
||||
1
src/Posting/Captcha.js
Normal file
1
src/Posting/Captcha.js
Normal file
@ -0,0 +1 @@
|
||||
Captcha = {};
|
||||
@ -14,3 +14,5 @@ PassLink =
|
||||
Date.now()
|
||||
'width=500,height=280,toolbar=0'
|
||||
$.before styleSelector.previousSibling, [passLink, $.tn('\u00A0\u00A0')]
|
||||
|
||||
return PassLink
|
||||
|
||||
@ -16,3 +16,5 @@ PostSuccessful =
|
||||
threadID: threadID
|
||||
postID: postID
|
||||
val: true
|
||||
|
||||
return PostSuccessful
|
||||
|
||||
@ -827,3 +827,5 @@ QR =
|
||||
QR.cooldown.auto = false
|
||||
QR.notifications.push new Notice 'info', 'QR upload aborted.', 5
|
||||
QR.status()
|
||||
|
||||
return QR
|
||||
|
||||
@ -58,3 +58,5 @@ QuoteBacklink =
|
||||
getContainer: (id) ->
|
||||
@containers[id] or=
|
||||
$.el 'span', className: 'container'
|
||||
|
||||
return QuoteBacklink
|
||||
|
||||
@ -23,3 +23,5 @@ QuoteCT =
|
||||
if boardID is board.ID and threadID isnt thread.ID
|
||||
$.add quotelink, $.tn QuoteCT.text
|
||||
return
|
||||
|
||||
return QuoteCT
|
||||
|
||||
@ -110,3 +110,5 @@ QuoteInline =
|
||||
QuoteInline.rm inlined, boardID, threadID, postID, context
|
||||
$.rmClass inlined, 'inlined'
|
||||
return
|
||||
|
||||
return QuoteInline
|
||||
|
||||
@ -34,3 +34,5 @@ QuoteOP =
|
||||
if "#{boardID}.#{postID}" is fullID
|
||||
$.add quotelink, $.tn QuoteOP.text
|
||||
return
|
||||
|
||||
return QuoteOP
|
||||
|
||||
@ -53,3 +53,5 @@ QuotePreview =
|
||||
for post in [post].concat post.clones
|
||||
$.rmClass post.nodes.post, 'qphl'
|
||||
return
|
||||
|
||||
return QuotePreview
|
||||
|
||||
@ -14,3 +14,5 @@ QuoteStrikeThrough =
|
||||
if g.posts["#{boardID}.#{postID}"]?.isHidden
|
||||
$.addClass quotelink, 'filtered'
|
||||
return
|
||||
|
||||
return QuoteStrikeThrough
|
||||
|
||||
@ -146,3 +146,5 @@ QuoteThreading =
|
||||
Unread.setLine true
|
||||
Unread.read()
|
||||
Unread.update()
|
||||
|
||||
return QuoteThreading
|
||||
|
||||
@ -72,3 +72,5 @@ QuoteYou =
|
||||
Header.scrollTo post
|
||||
$.addClass post, 'highlight'
|
||||
return true
|
||||
|
||||
return QuoteYou
|
||||
|
||||
@ -84,3 +84,5 @@ Quotify =
|
||||
$.before deadlink, green
|
||||
$.add green, deadlink
|
||||
$.replace deadlink, [deadlink.childNodes...]
|
||||
|
||||
return Quotify
|
||||
|
||||
@ -6,3 +6,5 @@ class Board
|
||||
@posts = new SimpleDict()
|
||||
|
||||
g.boards[@] = @
|
||||
|
||||
return Board
|
||||
|
||||
@ -21,3 +21,5 @@ class Callbacks
|
||||
error: err
|
||||
|
||||
Main.handleErrors errors if errors
|
||||
|
||||
return Callbacks
|
||||
|
||||
@ -13,3 +13,5 @@ class CatalogThread
|
||||
pageCount: $ '.page-count', root
|
||||
comment: $ '.comment', root
|
||||
@thread.catalogView = @
|
||||
|
||||
return CatalogThread
|
||||
|
||||
@ -20,3 +20,5 @@ class Connection
|
||||
for type, value of data
|
||||
@cb[type]? value
|
||||
return
|
||||
|
||||
return Connection
|
||||
|
||||
@ -105,3 +105,5 @@ class DataBoard
|
||||
onSync: (data) =>
|
||||
@data = data or boards: {}
|
||||
@sync?()
|
||||
|
||||
return DataBoard
|
||||
|
||||
@ -200,3 +200,5 @@ class Fetcher
|
||||
'[/moot]': <%= html('</div>') %>
|
||||
'[banned]': <%= html('<strong style="color: red;">') %>
|
||||
'[/banned]': <%= html('</strong>') %>
|
||||
|
||||
return Fetcher
|
||||
|
||||
@ -30,3 +30,5 @@ class Notice
|
||||
$.off d, 'visibilitychange', @add
|
||||
$.rm @el
|
||||
@onclose?()
|
||||
|
||||
return Notice
|
||||
|
||||
@ -268,3 +268,5 @@ class Post
|
||||
for clone in @clones[index..]
|
||||
clone.nodes.root.dataset.clone = index++
|
||||
return
|
||||
|
||||
return Post
|
||||
|
||||
@ -87,3 +87,5 @@ class RandomAccessList
|
||||
next.prev = prev
|
||||
else
|
||||
@last = prev
|
||||
|
||||
return RandomAccessList
|
||||
|
||||
@ -14,3 +14,5 @@ class ShimSet
|
||||
@size--
|
||||
|
||||
window.Set = ShimSet unless 'Set' of window
|
||||
|
||||
return ShimSet
|
||||
|
||||
@ -16,3 +16,5 @@ class SimpleDict
|
||||
forEach: (fn) ->
|
||||
fn @[key] for key in [@keys...]
|
||||
return
|
||||
|
||||
return SimpleDict
|
||||
|
||||
@ -76,3 +76,5 @@ class Thread
|
||||
@posts.forEach (post) -> post.collect()
|
||||
g.threads.rm @fullID
|
||||
@board.threads.rm @
|
||||
|
||||
return Thread
|
||||
|
||||
@ -1022,3 +1022,5 @@ Config =
|
||||
'Max Replies': 1000
|
||||
|
||||
'Autohiding Scrollbar': false
|
||||
|
||||
return Config
|
||||
|
||||
@ -470,4 +470,4 @@ Main =
|
||||
<% } %>
|
||||
]
|
||||
|
||||
Main.init()
|
||||
return Main
|
||||
|
||||
1
src/main/Main.init.js
Normal file
1
src/main/Main.init.js
Normal file
@ -0,0 +1 @@
|
||||
Main.init();
|
||||
@ -1,2 +1,2 @@
|
||||
$$ = (selector, root=d.body) ->
|
||||
return (selector, root=d.body) ->
|
||||
[root.querySelectorAll(selector)...]
|
||||
|
||||
@ -593,3 +593,5 @@ $.clear = (cb) ->
|
||||
$.delete $.listValues().map (key) -> key.replace g.NAMESPACE, ''
|
||||
cb?()
|
||||
<% } %>
|
||||
|
||||
return $
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
CrossOrigin = do ->
|
||||
<% if (type === 'crx') { %>
|
||||
eventPageRequest = do ->
|
||||
callbacks = []
|
||||
chrome.runtime.onMessage.addListener (data) ->
|
||||
callbacks[data.id] data
|
||||
delete callbacks[data.id]
|
||||
(url, responseType, cb) ->
|
||||
chrome.runtime.sendMessage {url, responseType}, (id) ->
|
||||
callbacks[id] = cb
|
||||
<% } %>
|
||||
<% if (type === 'crx') { %>
|
||||
eventPageRequest = do ->
|
||||
callbacks = []
|
||||
chrome.runtime.onMessage.addListener (data) ->
|
||||
callbacks[data.id] data
|
||||
delete callbacks[data.id]
|
||||
(url, responseType, cb) ->
|
||||
chrome.runtime.sendMessage {url, responseType}, (id) ->
|
||||
callbacks[id] = cb
|
||||
|
||||
<% } %>
|
||||
CrossOrigin =
|
||||
binary: (url, cb, headers={}) ->
|
||||
# XXX https://forums.lanik.us/viewtopic.php?f=64&t=24173&p=78310
|
||||
url = url.replace /^((?:https?:)?\/\/(?:\w+\.)?4c(?:ha|d)n\.org)\/adv\//, '$1//adv/'
|
||||
@ -126,3 +126,5 @@ CrossOrigin = do ->
|
||||
delete callbacks[url]
|
||||
responses[url] = response
|
||||
<% } %>
|
||||
|
||||
return CrossOrigin
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
var fs = require('fs');
|
||||
var template = require('./template');
|
||||
var coffee = require('coffee-script');
|
||||
var globalize = require('./globalize');
|
||||
|
||||
for (var name of process.argv.slice(2)) {
|
||||
try {
|
||||
@ -12,8 +11,8 @@ for (var name of process.argv.slice(2)) {
|
||||
script = template(script, {type: parts[2]});
|
||||
if (/\.coffee$/.test(basename)) {
|
||||
script = coffee.compile(script);
|
||||
if (/^([$A-Z][$\w]*)\.coffee$/.test(basename)) {
|
||||
script = globalize.globalize(script, [parts[3]]);
|
||||
if (/^[$A-Z][$\w]*$/.test(parts[3])) {
|
||||
script = `${parts[3]} = ${script}`;
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(name, script);
|
||||
|
||||
@ -1,57 +0,0 @@
|
||||
var fs = require('fs');
|
||||
|
||||
function getNames(part) {
|
||||
var basename = part.split('_')[0]; // e.g. template_crx -> template
|
||||
var sources = fs.readdirSync(`src/${basename}`);
|
||||
|
||||
// Extract variables to be made global from source file list
|
||||
// e.g. ImageExpand from src/Images/ImageExpand.coffee
|
||||
// but not QR.post or eventPage
|
||||
var names = [];
|
||||
for (var f of sources) {
|
||||
var m = f.match(/^([$A-Z][$\w]*)\.coffee$/);
|
||||
if (m) names.push(m[1]);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
function globalize(script, names) {
|
||||
var replaced = 0;
|
||||
|
||||
script = script.replace(
|
||||
|
||||
// matches declaration at the start of the function, not including helper function assignments
|
||||
/^( *var )(.*)(,\n *|;\n)/m,
|
||||
|
||||
function(declaration, v, n, e) {
|
||||
replaced++;
|
||||
var n0 = names.sort().join(', ');
|
||||
if (n0 !== n) throw new Error(`expected variables (${n0}) found (${n})`);
|
||||
return (e[0] === ',') ? v : '';
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
if (replaced !== 1) {
|
||||
throw new Error(`no declaration found`);
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getNames: getNames,
|
||||
globalize: globalize
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
(function() {
|
||||
for (var part of process.argv.slice(2)) {
|
||||
var filename = `tmp/${part}.js`;
|
||||
var names = getNames(part);
|
||||
var script = fs.readFileSync(filename, 'utf8').replace(/\r\n/g, '\n');
|
||||
script = globalize(script, names);
|
||||
fs.writeFileSync(filename, script);
|
||||
}
|
||||
})();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user