Merge Zixaphir X

This commit is contained in:
seaweedchan 2013-08-25 01:15:47 -07:00
commit 6598b5a45e
13 changed files with 640 additions and 291 deletions

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.2.35 - 2013-08-24 * 4chan X - Version 1.2.35 - 2013-08-25
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -179,6 +179,10 @@ Config =
false false
'Hide posts without images. *hint* *hint*' 'Hide posts without images. *hint* *hint*'
] ]
'Werk Tyme': [
false
'Hide all post images.'
]
'Menu': 'Menu':
'Menu': [ 'Menu': [
@ -313,6 +317,7 @@ Config =
true true
'When disabled, shows a red border on the CAPTCHA input until a key is pressed instead of a notification.' 'When disabled, shows a red border on the CAPTCHA input until a key is pressed instead of a notification.'
] ]
'Quote Links': 'Quote Links':
'Quote Backlinks': [ 'Quote Backlinks': [
true true
@ -397,6 +402,18 @@ Config =
'Advance to next post when contracting an expanded image.' 'Advance to next post when contracting an expanded image.'
] ]
gallery:
# Gallery mostly gets its config from imageExpansion
'Hide thumbnails': [
false
]
'Gallery fit width': [
true
]
'Gallery fit height': [
true
]
threadWatcher: threadWatcher:
'Current Board': [ 'Current Board': [
false false
@ -598,10 +615,18 @@ q-replace
'e' 'e'
'Expand all images.' 'Expand all images.'
] ]
'Open Gallery': [
'g'
'Opens the gallery.'
]
'fappeTyme': [ 'fappeTyme': [
'f' 'f'
'Fappe Tyme.' 'Fappe Tyme.'
] ]
'werkTyme': [
'Shift+w'
'Werk Tyme'
]
# Board Navigation # Board Navigation
'Front page': [ 'Front page': [
'0' '0'

View File

@ -54,6 +54,10 @@ a[href="javascript:;"] {
a { a {
outline: none !important; outline: none !important;
} }
.painted {
border-radius: 3px;
padding: 0px 2px;
}
/* 4chan style fixes */ /* 4chan style fixes */
.opContainer, .op { .opContainer, .op {
@ -1097,7 +1101,6 @@ a:only-of-type > .remove {
<%= align %>-items: stretch; <%= align %>-items: stretch;
<%= flex %>-direction: row; <%= flex %>-direction: row;
<%= flex %>: 1 1 auto; <%= flex %>: 1 1 auto;
position: relative;
} }
.gal-thumbnails { .gal-thumbnails {
<%= flex %>: 0 0 150px; <%= flex %>: 0 0 150px;
@ -1107,14 +1110,18 @@ a:only-of-type > .remove {
<%= align %>-items: stretch; <%= align %>-items: stretch;
text-align: center; text-align: center;
background: rgba(0,0,0,.5); background: rgba(0,0,0,.5);
border-left: 1px solid #222;
} }
.gal-thumbnails img { .hide-thumbnails .gal-thumbnails {
display: none;
}
.gal-thumb img {
max-width: 125px; max-width: 125px;
max-height: 125px; max-height: 125px;
height: auto; height: auto;
width: auto; width: auto;
} }
.gal-thumbnails a { .gal-thumb {
<%= flex %>: 0 0 auto; <%= flex %>: 0 0 auto;
padding: 3px; padding: 3px;
line-height: 0; line-height: 0;
@ -1125,6 +1132,7 @@ a:only-of-type > .remove {
} }
.gal-prev { .gal-prev {
order: 0; order: 0;
border-right: 1px solid #222;
} }
.gal-next { .gal-next {
order: 2; order: 2;
@ -1135,7 +1143,6 @@ a:only-of-type > .remove {
<%= flex %>: 0 0 20px; <%= flex %>: 0 0 20px;
position: relative; position: relative;
cursor: pointer; cursor: pointer;
border-right: 1px solid #222;
opacity: 0.7; opacity: 0.7;
background-color: rgba(0, 0, 0, 0.3); background-color: rgba(0, 0, 0, 0.3);
} }
@ -1167,30 +1174,46 @@ a:only-of-type > .remove {
display: <%= flex %>; display: <%= flex %>;
<%= align %>-items: flex-start; <%= align %>-items: flex-start;
<%= justify %>: space-around; <%= justify %>: space-around;
overflow: hidden; overflow: auto;
/* Flex > Non-Flex child max-width and overflow fix (Firefox only?) */ /* Flex > Non-Flex child max-width and overflow fix (Firefox only?) */
width: 1%; width: 1%;
} }
.gal-image a { .gal-image a {
margin: auto; margin: auto;
line-height: 0;
} }
.gal-image img { .fit-width .gal-image img {
max-width: 100%; max-width: 100%;
max-height: 100vh;
} }
.gal-close { .fit-height .gal-image img {
max-height: calc(100vh - 25px);
}
.gal-buttons {
font-size: 2em; font-size: 2em;
padding-right: 8px; margin-right: 10px;
position: fixed;
top: 5px; top: 5px;
right: 180px;
color: #ffffff; color: #ffffff;
text-shadow: 0px 0px 1px #000000; text-shadow: 0px 0px 1px #000000;
} }
.gal-name { .gal-buttons i {
vertical-align: baseline;
border-top-width: .5em;
border-right-width: .3em;
border-left-width: .3em;
}
.gal-buttons,
.gal-name,
.gal-count {
position: fixed; position: fixed;
bottom: 5px;
right: 178px; right: 178px;
}
.hide-thumbnails .gal-buttons,
.hide-thumbnails .gal-count,
.hide-thumbnails .gal-name {
right: 28px;
}
.gal-name {
bottom: 5px;
background: rgba(0,0,0,0.6) !important; background: rgba(0,0,0,0.6) !important;
border-radius: 3px; border-radius: 3px;
padding: 1px 5px 2px 5px; padding: 1px 5px 2px 5px;
@ -1202,9 +1225,7 @@ a:only-of-type > .remove {
color: rgb(95, 95, 101) !important; color: rgb(95, 95, 101) !important;
} }
.gal-count { .gal-count {
position: fixed;
bottom: 26px; bottom: 26px;
right: 178px;
background: rgba(0,0,0,0.6) !important; background: rgba(0,0,0,0.6) !important;
border-radius: 3px; border-radius: 3px;
padding: 1px 5px 2px 5px; padding: 1px 5px 2px 5px;

View File

@ -74,10 +74,7 @@ class DataBoard
ajaxClean: (boardID) -> ajaxClean: (boardID) ->
$.cache "//api.4chan.org/#{boardID}/threads.json", (e) => $.cache "//api.4chan.org/#{boardID}/threads.json", (e) =>
if e.target.status is 404 return if e.target.status isnt 200
# Deleted board.
@delete boardID
else if e.target.status is 200
board = @data.boards[boardID] board = @data.boards[boardID]
threads = {} threads = {}
for page in JSON.parse e.target.response for page in JSON.parse e.target.response

View File

@ -22,7 +22,7 @@ Polyfill =
# DataUrl to Binary code from Aeosynth's 4chan X repo # DataUrl to Binary code from Aeosynth's 4chan X repo
l = data.length l = data.length
ui8a = new Uint8Array l ui8a = new Uint8Array l
for i in [0...l] for i in [0...l] by 1
ui8a[i] = data.charCodeAt i ui8a[i] = data.charCodeAt i
cb new Blob [ui8a], type: 'image/png' cb new Blob [ui8a], type: 'image/png'
visibility: -> visibility: ->

View File

@ -1,19 +1,35 @@
FappeTyme = FappeTyme =
init: -> init: ->
return if !Conf['Fappe Tyme'] or g.VIEW is 'catalog' or g.BOARD is 'f' return if !(Conf['Fappe Tyme'] or Conf['Werk Tyme']) or g.VIEW is 'catalog' or g.BOARD is 'f'
if Conf['Fappe Tyme']
el = $.el 'label', el = $.el 'label',
innerHTML: "<input type=checkbox name=fappe-tyme> Fappe Tyme" innerHTML: "<input type=checkbox name=fappe-tyme> Fappe Tyme"
title: 'Fappe Tyme' title: 'Fappe Tyme'
FappeTyme.input = input = el.firstElementChild FappeTyme.fappe = input = el.firstElementChild
$.on input, 'change', FappeTyme.toggle $.on input, 'change', FappeTyme.cb.fappe
$.event 'AddMenuEntry', $.event 'AddMenuEntry',
type: 'header' type: 'header'
el: el el: el
order: 97 order: 97
if Conf['Werk Tyme']
el = $.el 'label',
innerHTML: "<input type=checkbox name=werk-tyme> Werk Tyme"
title: 'Werk Tyme'
FappeTyme.werk = input = el.firstElementChild
$.on input, 'change', FappeTyme.cb.werk
$.event 'AddMenuEntry',
type: 'header'
el: el
order: 98
Post::callbacks.push Post::callbacks.push
name: 'Fappe Tyme' name: 'Fappe Tyme'
cb: @node cb: @node
@ -22,6 +38,10 @@ FappeTyme =
return if @file return if @file
$.addClass @nodes.root, "noFile" $.addClass @nodes.root, "noFile"
toggle: -> cb:
$.event 'CloseMenu' fappe: ->
(if @checked then $.addClass else $.rmClass) doc, 'fappeTyme' $.toggleClass doc, 'fappeTyme'
FappeTyme.fappe.checked = $.hasClass doc, 'fappeTyme'
werk: ->
$.toggleClass doc, 'werkTyme'
FappeTyme.werk.checked = $.hasClass doc, 'werkTyme'

View File

@ -19,19 +19,25 @@ Gallery =
node: -> node: ->
return unless @file?.isImage return unless @file?.isImage
if Gallery.el if Gallery.nodes
Gallery.generateThumb $ '.file', @nodes.root Gallery.generateThumb $ '.file', @nodes.root
Gallery.total.textContent = Gallery.images.length Gallery.nodes.total.textContent = Gallery.images.length
unless Conf['Image Expansion'] unless Conf['Image Expansion']
$.on @file.thumb.parentNode, 'click', Gallery.cb.image $.on @file.thumb.parentNode, 'click', Gallery.cb.image
build: (image) -> build: (image) ->
Gallery.el = dialog = $.el 'div', Gallery.images = []
nodes = Gallery.nodes = {}
nodes.el = dialog = $.el 'div',
id: 'a-gallery' id: 'a-gallery'
innerHTML: """ innerHTML: """
<div class=gal-viewport> <div class=gal-viewport>
<span class=gal-buttons>
<a class="menu-button" href="javascript:;"><i></i></a>
<a href=javascript:; class=gal-close>×</a> <a href=javascript:; class=gal-close>×</a>
</span>
<a class=gal-name target="_blank"></a> <a class=gal-name target="_blank"></a>
<span class=gal-count><span class='count'></span> / <span class='total'></span></a></span> <span class=gal-count><span class='count'></span> / <span class='total'></span></a></span>
<div class=gal-prev></div> <div class=gal-prev></div>
@ -42,7 +48,8 @@ Gallery =
</div> </div>
<div class=gal-thumbnails></div> <div class=gal-thumbnails></div>
""" """
Gallery[key] = $ value, dialog for key, value of {
nodes[key] = $ value, dialog for key, value of {
frame: '.gal-image' frame: '.gal-image'
name: '.gal-name' name: '.gal-name'
count: '.count' count: '.count'
@ -52,34 +59,49 @@ Gallery =
current: '.gal-image img' current: '.gal-image img'
} }
Gallery.images = [] menuButton = $ '.menu-button', dialog
nodes.menu = new UI.Menu 'gallery'
$.on Gallery.frame, 'click', Gallery.cb.blank {cb} = Gallery
$.on Gallery.current, 'click', Gallery.cb.download $.on nodes.frame, 'click', cb.blank
$.on Gallery.next, 'click', Gallery.cb.next $.on nodes.current, 'click', cb.download
$.on ($ '.gal-prev', dialog), 'click', Gallery.cb.prev $.on nodes.next, 'click', cb.next
$.on ($ '.gal-next', dialog), 'click', Gallery.cb.next $.on ($ '.gal-prev', dialog), 'click', cb.prev
$.on ($ '.gal-close', dialog), 'click', Gallery.cb.close $.on ($ '.gal-next', dialog), 'click', cb.next
$.on ($ '.gal-close', dialog), 'click', cb.close
$.on d, 'keydown', Gallery.cb.keybinds $.on menuButton, 'click', (e) ->
nodes.menu.toggle e, @, g
{createSubEntry} = Gallery.menu
for name in ['Gallery fit width', 'Gallery fit height', 'Hide thumbnails']
{el} = createSubEntry name
$.event 'AddMenuEntry',
type: 'gallery'
el: el
order: 0
$.on d, 'keydown', cb.keybinds
$.off d, 'keydown', Keybinds.keydown $.off d, 'keydown', Keybinds.keydown
i = 0 i = 0
files = $$ '.post .file' files = $$ '.post .file'
while file = files[i++] while file = files[i++]
continue if $ '.fileDeletedRes, .fileDeleted', file
Gallery.generateThumb file Gallery.generateThumb file
$.add d.body, dialog $.add d.body, dialog
Gallery.thumbs.scrollTop = 0 nodes.thumbs.scrollTop = 0
Gallery.current.parentElement.scrollTop = 0 nodes.current.parentElement.scrollTop = 0
Gallery.cb.open.call if image Gallery.cb.open.call if image
$ "[href='#{image.href.replace /https?:/, ''}']", Gallery.thumbs $ "[href='#{image.href.replace /https?:/, ''}']", nodes.thumbs
else else
Gallery.images[0] Gallery.images[0]
d.body.style.overflow = 'hidden' d.body.style.overflow = 'hidden'
Gallery.total.textContent = --i nodes.total.textContent = --i
generateThumb: (file) -> generateThumb: (file) ->
title = ($ '.fileText a', file).textContent title = ($ '.fileText a', file).textContent
@ -87,7 +109,7 @@ Gallery =
if double = $ 'img + img', thumb if double = $ 'img + img', thumb
$.rm double $.rm double
thumb.className = 'a-thumb' thumb.className = 'gal-thumb'
thumb.title = title thumb.title = title
thumb.dataset.id = Gallery.images.length thumb.dataset.id = Gallery.images.length
thumb.firstElementChild.style.cssText = '' thumb.firstElementChild.style.cssText = ''
@ -95,7 +117,7 @@ Gallery =
$.on thumb, 'click', Gallery.cb.open $.on thumb, 'click', Gallery.cb.open
Gallery.images.push thumb Gallery.images.push thumb
$.add Gallery.thumbs, thumb $.add Gallery.nodes.thumbs, thumb
cb: cb:
keybinds: (e) -> keybinds: (e) ->
@ -116,35 +138,78 @@ Gallery =
open: (e) -> open: (e) ->
e.preventDefault() if e e.preventDefault() if e
return unless @
{nodes} = Gallery
{name} = nodes
$.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', Gallery.thumbs $.rmClass el, 'gal-highlight' if el = $ '.gal-highlight', Gallery.thumbs
$.addClass @, 'gal-highlight' $.addClass @, 'gal-highlight'
img = $.el 'img', img = $.el 'img',
src: Gallery.name.href = @href src: name.href = @href
title: Gallery.name.download = Gallery.name.textContent = @title title: name.download = name.textContent = @title
img.dataset.id = @dataset.id img.dataset.id = @dataset.id
$.replace Gallery.current, img $.replace nodes.current, img
Gallery.count.textContent = +@dataset.id + 1 nodes.count.textContent = +@dataset.id + 1
Gallery.current = img nodes.current = img
Gallery.frame.scrollTop = 0 nodes.frame.scrollTop = 0
Gallery.current.focus() nodes.next.focus()
# Scroll
rect = @getBoundingClientRect()
{top} = rect
if top > 0
top += rect.height - doc.clientHeight
return if top < 0
nodes.thumbs.scrollTop += top
image: (e) -> image: (e) ->
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
Gallery.build @ Gallery.build @
prev: -> Gallery.cb.open.call Gallery.images[+Gallery.current.dataset.id - 1] prev: -> Gallery.cb.open.call Gallery.images[+Gallery.nodes.current.dataset.id - 1]
next: -> Gallery.cb.open.call Gallery.images[+Gallery.current.dataset.id + 1] next: -> Gallery.cb.open.call Gallery.images[+Gallery.nodes.current.dataset.id + 1]
toggle: -> (if Gallery.el then Gallery.cb.close else Gallery.build)() toggle: -> (if Gallery.nodes then Gallery.cb.close else Gallery.build)()
blank: (e) -> Gallery.cb.close() if e.target is @ blank: (e) -> Gallery.cb.close() if e.target is @
close: -> close: ->
$.rm Gallery.el $.rm Gallery.nodes.el
delete Gallery.el delete Gallery.nodes
d.body.style.overflow = '' d.body.style.overflow = ''
$.off d, 'keydown', Gallery.cb.keybinds $.off d, 'keydown', Gallery.cb.keybinds
$.on d, 'keydown', Keybinds.keydown $.on d, 'keydown', Keybinds.keydown
menu:
init: ->
return if g.VIEW is 'catalog' or !Conf['Gallery'] or Conf['Image Expansion']
el = $.el 'span',
textContent: 'Gallery'
className: 'gallery-link'
{createSubEntry} = Gallery.menu
subEntries = []
for name in ['Gallery fit width', 'Gallery fit height', 'Hide thumbnails']
subEntries.push createSubEntry name
$.event 'AddMenuEntry',
type: 'header'
el: el
order: 105
subEntries: subEntries
createSubEntry: (name) ->
label = $.el 'label',
innerHTML: "<input type=checkbox name='#{name}'> #{name}"
input = label.firstElementChild
# Reusing ImageExpand here because this code doesn't need any auditing to work for what we need
$.on input, 'change', ImageExpand.cb.setFitness
input.checked = Conf[name]
$.event 'change', null, input
$.on input, 'change', $.cb.checked
el: label

View File

@ -189,6 +189,3 @@ ImageExpand =
$.event 'change', null, input $.event 'change', null, input
$.on input, 'change', $.cb.checked $.on input, 'change', $.cb.checked
el: label el: label
menuToggle: (e) ->
ImageExpand.opmenu.toggle e, @, g

View File

@ -1,7 +1,6 @@
IDColor = IDColor =
init: -> init: ->
return if g.VIEW is 'catalog' or !Conf['Color User IDs'] return if g.VIEW is 'catalog' or not Conf['Color User IDs']
@ids = {} @ids = {}
Post::callbacks.push Post::callbacks.push
@ -9,30 +8,34 @@ IDColor =
cb: @node cb: @node
node: -> node: ->
return if @isClone or not str = @info.uniqueID return if @isClone or not uid = @info.uniqueID
uid = $ '.hand', @nodes.uniqueID span = $ '.hand', @nodes.uniqueID
return unless uid and uid.nodeName is 'SPAN' return unless span and span.nodeName is 'SPAN'
uid.style.cssText = IDColor.css IDColor.ids[str] or IDColor.compute str rgb = IDColor.compute uid
{style} = span
style.color = rgb[3]
style.backgroundColor = "rgb(#{rgb[0]},#{rgb[1]},#{rgb[2]})"
$.addClass span, 'painted'
span.title = 'Highlight posts by this ID'
compute: (str) -> compute: (uid) ->
hash = IDColor.hash str return IDColor.ids[uid] if IDColor.ids[uid]
hash = IDColor.hash uid
rgb = [ rgb = [
(hash >> 24) & 0xFF (hash >> 24) & 0xFF
(hash >> 16) & 0xFF (hash >> 16) & 0xFF
(hash >> 8) & 0xFF (hash >> 8) & 0xFF
] ]
rgb[3] = if (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 125
'#000'
else
'#fff'
@ids[uid] = rgb
rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125 hash: (uid) ->
@ids[str] = rgb
rgb
css: (rgb) -> "background-color: rgb(#{rgb[0]},#{rgb[1]},#{rgb[2]}); color: #{if rgb[3] then "#000" else "#fff"}; border-radius: 3px; padding: 0px 2px;"
hash: (str) ->
msg = 0 msg = 0
i = 0 i = 0
while i < 8 while i < 8
msg = ((msg << 5) - msg) + str.charCodeAt i++ msg = (msg << 5) - msg + uid.charCodeAt i++
msg msg

View File

@ -69,10 +69,12 @@ Keybinds =
Keybinds.img threadRoot Keybinds.img threadRoot
when Conf['Expand images'] when Conf['Expand images']
Keybinds.img threadRoot, true Keybinds.img threadRoot, true
when Conf['Open Gallery']
Gallery.cb.toggle()
when Conf['fappeTyme'] when Conf['fappeTyme']
unless $('#menu.left') FappeTyme.cb.fappe()
Header.menuButton.click() when Conf['werkTyme']
FappeTyme.input.click() FappeTyme.cb.werk()
# Board Navigation # Board Navigation
when Conf['Front page'] when Conf['Front page']
window.location = "/#{g.BOARD}/0#delform" window.location = "/#{g.BOARD}/0#delform"

View File

@ -77,7 +77,8 @@ QR =
persist: -> persist: ->
return unless QR.postingIsEnabled return unless QR.postingIsEnabled
QR.open() QR.open()
QR.hide() if Conf['Auto Hide QR'] QR.hide() if Conf['Auto-Hide QR'] or g.VIEW is 'catalog'
open: -> open: ->
if QR.nodes if QR.nodes
QR.nodes.el.hidden = false QR.nodes.el.hidden = false