Merge zixaphir x

This commit is contained in:
Jordan Bates 2013-05-05 22:34:17 -07:00
commit 9845a4c4dc
11 changed files with 130 additions and 34 deletions

View File

@ -1,6 +1,13 @@
detharonil
- Support for %Y in time formatting
- More future-proof %y
MayhemYDG: MayhemYDG:
- Fix whitespaces not being preserved in code tags in /g/. - Fix whitespaces not being preserved in code tags in /g/.
zixaphir:
- Fix custom CSS
### 1.1.11 - 2013-05-04 ### 1.1.11 - 2013-05-04
seaweedchan: seaweedchan:
- Add `Highlight Posts Quoting You` option - Add `Highlight Posts Quoting You` option

View File

@ -59,6 +59,7 @@
* WakiMiko * WakiMiko
* btmcsweeney * btmcsweeney
* AppleBloom * AppleBloom
* detharonil
* *
* All the people who've taken the time to write bug reports. * All the people who've taken the time to write bug reports.
* *

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -353,9 +353,10 @@ Settings =
$.get items, (items) -> $.get items, (items) ->
for key, val of items for key, val of items
continue if ['usercss', 'emojiPos', 'archiver'].contains key continue if ['emojiPos', 'archiver'].contains key
input = inputs[key] input = inputs[key]
input.value = val input.value = val
continue if key is 'usercss'
$.on input, event, Settings[key] $.on input, event, Settings[key]
Settings[key].call input Settings[key].call input
return return

View File

@ -203,7 +203,6 @@ UI = do ->
@parseEntry subEntry @parseEntry subEntry
return return
dragstart = (e) -> dragstart = (e) ->
return if e.type is 'mousedown' and e.button isnt 0 # not LMB return if e.type is 'mousedown' and e.button isnt 0 # not LMB
# prevent text selection # prevent text selection
@ -245,11 +244,13 @@ UI = do ->
o.up = dragend.bind o o.up = dragend.bind o
$.on d, 'mousemove', o.move $.on d, 'mousemove', o.move
$.on d, 'mouseup', o.up $.on d, 'mouseup', o.up
touchmove = (e) -> touchmove = (e) ->
for touch in e.changedTouches for touch in e.changedTouches
if touch.identifier is @identifier if touch.identifier is @identifier
drag.call @, touch drag.call @, touch
return return
drag = (e) -> drag = (e) ->
{clientX, clientY} = e {clientX, clientY} = e
@ -284,11 +285,13 @@ UI = do ->
style.right = right style.right = right
style.top = top style.top = top
style.bottom = bottom style.bottom = bottom
touchend = (e) -> touchend = (e) ->
for touch in e.changedTouches for touch in e.changedTouches
if touch.identifier is @identifier if touch.identifier is @identifier
dragend.call @ dragend.call @
return return
dragend = -> dragend = ->
if @isTouching if @isTouching
$.off d, 'touchmove', @move $.off d, 'touchmove', @move
@ -318,7 +321,9 @@ UI = do ->
o.hover o.latestEvent if el.parentNode o.hover o.latestEvent if el.parentNode
$.on root, endEvents, o.hoverend $.on root, endEvents, o.hoverend
$.on d, 'keydown', o.hoverend
$.on root, 'mousemove', o.hover $.on root, 'mousemove', o.hover
hover = (e) -> hover = (e) ->
@latestEvent = e @latestEvent = e
height = @el.offsetHeight height = @el.offsetHeight
@ -341,9 +346,12 @@ UI = do ->
style.top = top + 'px' style.top = top + 'px'
style.left = left style.left = left
style.right = right style.right = right
hoverend = ->
hoverend = (e) ->
return if e.type is 'keydown' and e.keyCode isnt 13
$.rm @el $.rm @el
$.off @root, @endEvents, @hoverend $.off @root, @endEvents, @hoverend
$.off d, 'keydown', @hoverend
$.off @root, 'mousemove', @hover $.off @root, 'mousemove', @hover
@cb.call @ if @cb @cb.call @ if @cb

View File

@ -31,7 +31,7 @@
<div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div> <div>Supported <a href=//en.wikipedia.org/wiki/Date_%28Unix%29#Formatting>format specifiers</a>:</div>
<div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div> <div>Day: <code>%a</code>, <code>%A</code>, <code>%d</code>, <code>%e</code></div>
<div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div> <div>Month: <code>%m</code>, <code>%b</code>, <code>%B</code></div>
<div>Year: <code>%y</code></div> <div>Year: <code>%y</code>, <code>%Y</code></div>
<div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div> <div>Hour: <code>%k</code>, <code>%H</code>, <code>%l</code>, <code>%I</code>, <code>%p</code>, <code>%P</code></div>
<div>Minute: <code>%M</code></div> <div>Minute: <code>%M</code></div>
<div>Second: <code>%S</code></div> <div>Second: <code>%S</code></div>

View File

@ -59,6 +59,7 @@
* WakiMiko * WakiMiko
* btmcsweeney * btmcsweeney
* AppleBloom * AppleBloom
* detharonil
* *
* All the people who've taken the time to write bug reports. * All the people who've taken the time to write bug reports.
* *

View File

@ -56,4 +56,5 @@ Time =
p: -> if @getHours() < 12 then 'AM' else 'PM' p: -> if @getHours() < 12 then 'AM' else 'PM'
P: -> if @getHours() < 12 then 'am' else 'pm' P: -> if @getHours() < 12 then 'am' else 'pm'
S: -> Time.zeroPad @getSeconds() S: -> Time.zeroPad @getSeconds()
y: -> @getFullYear() - 2000 y: -> @getFullYear() % 100
Y: -> @getFullYear()

View File

@ -68,7 +68,6 @@ QR =
else else
QR.status() QR.status()
node: -> node: ->
$.on $('a[title="Quote this post"]', @nodes.info), 'click', QR.quote $.on $('a[title="Quote this post"]', @nodes.info), 'click', QR.quote
@ -172,6 +171,7 @@ QR =
for type, arr of types for type, arr of types
QR.persona.loadPersonas type, arr QR.persona.loadPersonas type, arr
return return
parseItem: (item, types) -> parseItem: (item, types) ->
return if item[0] is '#' return if item[0] is '#'
return unless match = item.match /(name|email|subject|password):"(.*)"/i return unless match = item.match /(name|email|subject|password):"(.*)"/i
@ -181,7 +181,7 @@ QR =
item = item.replace match, '' item = item.replace match, ''
boards = item.match(/boards:([^;]+)/i)?[1].toLowerCase() or 'global' boards = item.match(/boards:([^;]+)/i)?[1].toLowerCase() or 'global'
if boards isnt 'global' and not (g.BOARD.ID in boards.split ',') if boards isnt 'global' and not ((boards.split ',').contains g.BOARD.ID)
return return
if type is 'password' if type is 'password'
@ -193,14 +193,16 @@ QR =
if /always/i.test item if /always/i.test item
QR.persona.always[type] = val QR.persona.always[type] = val
unless val in types[type] unless types[type].contains val
types[type].push val types[type].push val
loadPersonas: (type, arr) -> loadPersonas: (type, arr) ->
list = $ "#list-#{type}", QR.nodes.el list = $ "#list-#{type}", QR.nodes.el
for val in arr for val in arr
$.add list, $.el 'option', $.add list, $.el 'option',
textContent: val textContent: val
return return
getPassword: -> getPassword: ->
unless QR.persona.pwd unless QR.persona.pwd
QR.persona.pwd = if m = d.cookie.match /4chan_pass=([^;]+)/ QR.persona.pwd = if m = d.cookie.match /4chan_pass=([^;]+)/
@ -213,9 +215,11 @@ QR =
# we'd rather use #postPassword when we can. # we'd rather use #postPassword when we can.
$.id('delPassword').value $.id('delPassword').value
return QR.persona.pwd return QR.persona.pwd
get: (cb) -> get: (cb) ->
$.get 'QR.persona', {}, ({'QR.persona': persona}) -> $.get 'QR.persona', {}, ({'QR.persona': persona}) ->
cb persona cb persona
set: (post) -> set: (post) ->
$.get 'QR.persona', {}, ({'QR.persona': persona}) -> $.get 'QR.persona', {}, ({'QR.persona': persona}) ->
persona = persona =
@ -242,17 +246,20 @@ QR =
QR.cooldown.cooldowns = item["cooldown.#{board}"] QR.cooldown.cooldowns = item["cooldown.#{board}"]
QR.cooldown.start() QR.cooldown.start()
$.sync "cooldown.#{board}", QR.cooldown.sync $.sync "cooldown.#{board}", QR.cooldown.sync
start: -> start: ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
return if QR.cooldown.isCounting return if QR.cooldown.isCounting
QR.cooldown.isCounting = true QR.cooldown.isCounting = true
QR.cooldown.count() QR.cooldown.count()
sync: (cooldowns) -> sync: (cooldowns) ->
# Add each cooldowns, don't overwrite everything in case we # Add each cooldowns, don't overwrite everything in case we
# still need to prune one in the current tab to auto-post. # still need to prune one in the current tab to auto-post.
for id of cooldowns for id of cooldowns
QR.cooldown.cooldowns[id] = cooldowns[id] QR.cooldown.cooldowns[id] = cooldowns[id]
QR.cooldown.start() QR.cooldown.start()
set: (data) -> set: (data) ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
{req, post, isReply, delay} = data {req, post, isReply, delay} = data
@ -282,12 +289,14 @@ QR =
QR.cooldown.cooldowns[start] = cooldown QR.cooldown.cooldowns[start] = cooldown
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns $.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
QR.cooldown.start() QR.cooldown.start()
unset: (id) -> unset: (id) ->
delete QR.cooldown.cooldowns[id] delete QR.cooldown.cooldowns[id]
if Object.keys(QR.cooldown.cooldowns).length if Object.keys(QR.cooldown.cooldowns).length
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns $.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
else else
$.delete "cooldown.#{g.BOARD}" $.delete "cooldown.#{g.BOARD}"
count: -> count: ->
unless Object.keys(QR.cooldown.cooldowns).length unless Object.keys(QR.cooldown.cooldowns).length
$.delete "#{g.BOARD}.cooldown" $.delete "#{g.BOARD}.cooldown"
@ -393,9 +402,11 @@ QR =
toggle = if e.type is 'dragstart' then $.off else $.on toggle = if e.type is 'dragstart' then $.off else $.on
toggle d, 'dragover', QR.dragOver toggle d, 'dragover', QR.dragOver
toggle d, 'drop', QR.dropFile toggle d, 'drop', QR.dropFile
dragOver: (e) -> dragOver: (e) ->
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'copy' # cursor feedback e.dataTransfer.dropEffect = 'copy' # cursor feedback
dropFile: (e) -> dropFile: (e) ->
# Let it only handle files from the desktop. # Let it only handle files from the desktop.
return unless e.dataTransfer.files.length return unless e.dataTransfer.files.length
@ -403,6 +414,7 @@ QR =
QR.open() QR.open()
QR.fileInput e.dataTransfer.files QR.fileInput e.dataTransfer.files
$.addClass QR.nodes.el, 'dump' $.addClass QR.nodes.el, 'dump'
paste: (e) -> paste: (e) ->
files = [] files = []
for item in e.clipboardData.items for item in e.clipboardData.items
@ -414,9 +426,11 @@ QR =
return unless files.length return unless files.length
QR.open() QR.open()
QR.fileInput files QR.fileInput files
openFileInput: (e) -> openFileInput: (e) ->
return if e.keyCode and e.keyCode isnt 32 return if e.keyCode and e.keyCode isnt 32
QR.nodes.fileInput.click() QR.nodes.fileInput.click()
fileInput: (files) -> fileInput: (files) ->
if @ instanceof Element #or files instanceof Event # file input if @ instanceof Element #or files instanceof Event # file input
files = [@files...] files = [@files...]
@ -454,6 +468,7 @@ QR =
$.addClass QR.nodes.el, 'dump' $.addClass QR.nodes.el, 'dump'
posts: [] posts: []
post: class post: class
constructor: (select) -> constructor: (select) ->
el = $.el 'a', el = $.el 'a',
@ -521,6 +536,7 @@ QR =
@load() if QR.selected is @ # load persona @load() if QR.selected is @ # load persona
@select() if select @select() if select
@unlock() @unlock()
rm: -> rm: ->
$.rm @nodes.el $.rm @nodes.el
index = QR.posts.indexOf @ index = QR.posts.indexOf @
@ -531,6 +547,7 @@ QR =
QR.posts.splice index, 1 QR.posts.splice index, 1
return unless window.URL return unless window.URL
URL.revokeObjectURL @URL URL.revokeObjectURL @URL
lock: (lock=true) -> lock: (lock=true) ->
@isLocked = lock @isLocked = lock
return unless @ is QR.selected return unless @ is QR.selected
@ -541,8 +558,10 @@ QR =
(if lock then $.off else $.on) QR.nodes.filename.parentNode, 'click', QR.openFileInput (if lock then $.off else $.on) QR.nodes.filename.parentNode, 'click', QR.openFileInput
@nodes.spoiler.disabled = lock @nodes.spoiler.disabled = lock
@nodes.el.draggable = !lock @nodes.el.draggable = !lock
unlock: -> unlock: ->
@lock false @lock false
select: -> select: ->
if QR.selected if QR.selected
QR.selected.nodes.el.id = null QR.selected.nodes.el.id = null
@ -556,12 +575,14 @@ QR =
@nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width/2 - rectList.left - rectList.width/2 @nodes.el.parentNode.scrollLeft += rectEl.left + rectEl.width/2 - rectList.left - rectList.width/2
@load() @load()
$.event 'QRPostSelection', @ $.event 'QRPostSelection', @
load: -> load: ->
# Load this post's values. # Load this post's values.
for name in ['thread', 'name', 'email', 'sub', 'com'] for name in ['thread', 'name', 'email', 'sub', 'com']
QR.nodes[name].value = @[name] or null QR.nodes[name].value = @[name] or null
@showFileData() @showFileData()
QR.characterCount() QR.characterCount()
save: (input) -> save: (input) ->
if input.type is 'checkbox' if input.type is 'checkbox'
@spoiler = input.checked @spoiler = input.checked
@ -575,6 +596,7 @@ QR =
# during the last 5 seconds of the cooldown. # during the last 5 seconds of the cooldown.
if QR.cooldown.auto and @ is QR.posts[0] and 0 < QR.cooldown.seconds <= 5 if QR.cooldown.auto and @ is QR.posts[0] and 0 < QR.cooldown.seconds <= 5
QR.cooldown.auto = false QR.cooldown.auto = false
forceSave: -> forceSave: ->
return unless @ is QR.selected return unless @ is QR.selected
# Do this in case people use extensions # Do this in case people use extensions
@ -582,6 +604,7 @@ QR =
for name in ['thread', 'name', 'email', 'sub', 'com', 'spoiler'] for name in ['thread', 'name', 'email', 'sub', 'com', 'spoiler']
@save QR.nodes[name] @save QR.nodes[name]
return return
setFile: (@file) -> setFile: (@file) ->
@filename = "#{file.name} (#{$.bytesToString file.size})" @filename = "#{file.name} (#{$.bytesToString file.size})"
@nodes.el.title = @filename @nodes.el.title = @filename
@ -592,6 +615,7 @@ QR =
@nodes.el.style.backgroundImage = null @nodes.el.style.backgroundImage = null
return return
@setThumbnail() @setThumbnail()
setThumbnail: (fileURL) -> setThumbnail: (fileURL) ->
# XXX Opera does not support blob URL # XXX Opera does not support blob URL
# Create a redimensioned thumbnail. # Create a redimensioned thumbnail.
@ -651,6 +675,7 @@ QR =
applyBlob new Blob [ui8a], type: 'image/png' applyBlob new Blob [ui8a], type: 'image/png'
img.src = fileURL img.src = fileURL
rmFile: -> rmFile: ->
delete @file delete @file
delete @filename delete @filename
@ -660,6 +685,7 @@ QR =
@showFileData() @showFileData()
return unless window.URL return unless window.URL
URL.revokeObjectURL @URL URL.revokeObjectURL @URL
showFileData: -> showFileData: ->
if @file if @file
QR.nodes.filename.textContent = @filename QR.nodes.filename.textContent = @filename
@ -668,6 +694,7 @@ QR =
$.addClass QR.nodes.fileSubmit, 'has-file' $.addClass QR.nodes.fileSubmit, 'has-file'
else else
$.rmClass QR.nodes.fileSubmit, 'has-file' $.rmClass QR.nodes.fileSubmit, 'has-file'
pasteText: (file) -> pasteText: (file) ->
reader = new FileReader() reader = new FileReader()
reader.onload = (e) => reader.onload = (e) =>
@ -680,17 +707,23 @@ QR =
QR.nodes.com.value = @com QR.nodes.com.value = @com
@nodes.span.textContent = @com @nodes.span.textContent = @com
reader.readAsText file reader.readAsText file
dragStart: -> dragStart: ->
$.addClass @, 'drag' $.addClass @, 'drag'
dragEnd: -> dragEnd: ->
$.rmClass @, 'drag' $.rmClass @, 'drag'
dragEnter: -> dragEnter: ->
$.addClass @, 'over' $.addClass @, 'over'
dragLeave: -> dragLeave: ->
$.rmClass @, 'over' $.rmClass @, 'over'
dragOver: (e) -> dragOver: (e) ->
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'move' e.dataTransfer.dropEffect = 'move'
drop: -> drop: ->
el = $ '.drag', @parentNode el = $ '.drag', @parentNode
$.rmClass el, 'drag' # Opera doesn't fire dragEnd if we drop it on something else $.rmClass el, 'drag' # Opera doesn't fire dragEnd if we drop it on something else
@ -708,6 +741,7 @@ QR =
return if d.cookie.indexOf('pass_enabled=1') >= 0 return if d.cookie.indexOf('pass_enabled=1') >= 0
return unless @isEnabled = !!$.id 'captchaFormPart' return unless @isEnabled = !!$.id 'captchaFormPart'
$.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @ $.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @
ready: -> ready: ->
setLifetime = (e) => @lifetime = e.detail setLifetime = (e) => @lifetime = e.detail
$.on window, 'captcha:timeout', setLifetime $.on window, 'captcha:timeout', setLifetime
@ -754,8 +788,10 @@ QR =
$.addClass QR.nodes.el, 'has-captcha' $.addClass QR.nodes.el, 'has-captcha'
$.after QR.nodes.com.parentNode, [imgContainer, input] $.after QR.nodes.com.parentNode, [imgContainer, input]
sync: (@captchas) -> sync: (@captchas) ->
QR.captcha.count() QR.captcha.count()
getOne: -> getOne: ->
@clear() @clear()
if captcha = @captchas.shift() if captcha = @captchas.shift()
@ -771,6 +807,7 @@ QR =
# If there's only one word, duplicate it. # If there's only one word, duplicate it.
response = "#{response} #{response}" unless /\s/.test response response = "#{response} #{response}" unless /\s/.test response
{challenge, response} {challenge, response}
save: -> save: ->
return unless response = @nodes.input.value.trim() return unless response = @nodes.input.value.trim()
@captchas.push @captchas.push
@ -780,6 +817,7 @@ QR =
@count() @count()
@reload() @reload()
$.set 'captchas', @captchas $.set 'captchas', @captchas
clear: -> clear: ->
now = Date.now() now = Date.now()
for captcha, i in @captchas for captcha, i in @captchas
@ -788,6 +826,7 @@ QR =
@captchas = @captchas[i..] @captchas = @captchas[i..]
@count() @count()
$.set 'captchas', @captchas $.set 'captchas', @captchas
load: -> load: ->
return unless @nodes.challenge.firstChild return unless @nodes.challenge.firstChild
# -1 minute to give upload some time. # -1 minute to give upload some time.
@ -797,6 +836,7 @@ QR =
@nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}" @nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
@nodes.input.value = null @nodes.input.value = null
@clear() @clear()
count: -> count: ->
count = @captchas.length count = @captchas.length
@nodes.input.placeholder = switch count @nodes.input.placeholder = switch count
@ -806,12 +846,14 @@ QR =
'Verification (1 cached captcha)' 'Verification (1 cached captcha)'
else else
"Verification (#{count} cached captchas)" "Verification (#{count} cached captchas)"
@nodes.input.alt = count # For XTRM RICE. @nodes.input.alt = count
reload: (focus) -> reload: (focus) ->
# the 't' argument prevents the input from being focused # the 't' argument prevents the input from being focused
$.globalEval 'Recaptcha.reload("t")' $.globalEval 'Recaptcha.reload("t")'
# Focus if we meant to. # Focus if we meant to.
@nodes.input.focus() if focus @nodes.input.focus() if focus
keydown: (e) -> keydown: (e) ->
if e.keyCode is 8 and not @nodes.input.value if e.keyCode is 8 and not @nodes.input.value
@reload() @reload()
@ -935,6 +977,7 @@ QR =
$.event 'QRDialogCreation', null, dialog $.event 'QRDialogCreation', null, dialog
preSubmitHooks: [] preSubmitHooks: []
submit: (e) -> submit: (e) ->
e?.preventDefault() e?.preventDefault()