Start bolting on Appchan X
Broken as shit.
This commit is contained in:
parent
6d59cc03f1
commit
d09ab8a19f
@ -16,6 +16,7 @@ module.exports = (grunt) ->
|
|||||||
'lib/ui.coffee'
|
'lib/ui.coffee'
|
||||||
'lib/$.coffee'
|
'lib/$.coffee'
|
||||||
'lib/polyfill.coffee'
|
'lib/polyfill.coffee'
|
||||||
|
'src/appchan.coffee'
|
||||||
'src/features.coffee'
|
'src/features.coffee'
|
||||||
'src/qr.coffee'
|
'src/qr.coffee'
|
||||||
'src/report.coffee'
|
'src/report.coffee'
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name 4chan X Beta
|
// @name appchan-x
|
||||||
// @version 3.0.0
|
// @version 2.0.0
|
||||||
// @namespace 4chan-X
|
// @namespace appchan-x
|
||||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||||
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
// @grant GM_deleteValue
|
// @grant GM_deleteValue
|
||||||
// @grant GM_openInTab
|
// @grant GM_openInTab
|
||||||
// @run-at document-start
|
// @run-at document-start
|
||||||
// @updateURL https://github.com/MayhemYDG/4chan-x/raw/v3/4chan-X.meta.js
|
// @updateURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.meta.js
|
||||||
// @downloadURL https://github.com/MayhemYDG/4chan-x/raw/v3/4chan-X.user.js
|
// @downloadURL https://github.com/zixaphir/appchan-x/raw/Av2/appchan-x.user.js
|
||||||
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
File diff suppressed because one or more lines are too long
19
package.json
19
package.json
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "4chan-X",
|
"name": "appchan-x",
|
||||||
"version": "3.0.0",
|
"version": "2.0.0",
|
||||||
"description": "Cross-browser userscript for maximum lurking on 4chan.",
|
"description": "The most comprehensive 4chan userscript.",
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "4chan X Beta",
|
"name": "appchan-x",
|
||||||
"repo": "https://github.com/MayhemYDG/4chan-x/",
|
"repo": "https://github.com/zixaphir/appchan-x/",
|
||||||
"page": "http://mayhemydg.github.com/4chan-x/",
|
"page": "http://zixaphir.github.com/appchan-x/",
|
||||||
"mainBranch": "v3",
|
"mainBranch": "Av2",
|
||||||
"matches": [
|
"matches": [
|
||||||
"*://api.4chan.org/*",
|
"*://api.4chan.org/*",
|
||||||
"*://boards.4chan.org/*",
|
"*://boards.4chan.org/*",
|
||||||
@ -25,10 +25,11 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/MayhemYDG/4chan-x.git"
|
"url": "git://github.com/zixaphir/appchan-x.git"
|
||||||
},
|
},
|
||||||
"author": "Nicolas Stepien <stepien.nicolas@gmail.com>",
|
"author": "Zixaphir <zixaphirmoxphar@gmail.com>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
"Nicolas Stepien <stepien.nicolas@gmail.com>",
|
||||||
"James Campos <james.r.campos@gmail.com>"
|
"James Campos <james.r.campos@gmail.com>"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
266
src/appchan.coffee
Normal file
266
src/appchan.coffee
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
Style =
|
||||||
|
init: ->
|
||||||
|
@agent = {
|
||||||
|
'gecko': '-moz-'
|
||||||
|
'webkit': '-webkit-'
|
||||||
|
'presto': '-o-'
|
||||||
|
}[$.engine]
|
||||||
|
|
||||||
|
@sizing = "#{if $.engine is 'gecko' then @agent else ''}box-sizing"
|
||||||
|
|
||||||
|
$.ready ->
|
||||||
|
return unless $.id 'navtopright'
|
||||||
|
Style.padding.nav = $ "#boardNavDesktop", d.body
|
||||||
|
Style.padding.pages = $(".pagelist", d.body)
|
||||||
|
Style.padding()
|
||||||
|
$.on window, "resize", Style.padding
|
||||||
|
|
||||||
|
# Give ExLinks and 4sight a little time to append their dialog links
|
||||||
|
setTimeout (->
|
||||||
|
Style.iconPositions()
|
||||||
|
if exLink = $ "#navtopright .exlinksOptionsLink", d.body
|
||||||
|
$.on exLink, "click", ->
|
||||||
|
setTimeout Style.rice, 100
|
||||||
|
), 500
|
||||||
|
|
||||||
|
Main.callbacks.push @node
|
||||||
|
@setup()
|
||||||
|
|
||||||
|
setup: ->
|
||||||
|
if d.head
|
||||||
|
@addStyleReady()
|
||||||
|
@remStyle()
|
||||||
|
unless Style.headCount
|
||||||
|
return @cleanup()
|
||||||
|
@observe()
|
||||||
|
|
||||||
|
observe: ->
|
||||||
|
if MutationObserver
|
||||||
|
Style.observer = new MutationObserver onMutationObserver = @wrapper
|
||||||
|
Style.observer.observe d,
|
||||||
|
childList: true
|
||||||
|
subtree: true
|
||||||
|
else
|
||||||
|
$.on d, 'DOMNodeInserted', @wrapper
|
||||||
|
|
||||||
|
wrapper: ->
|
||||||
|
if d.head
|
||||||
|
if Style.addStyleReady
|
||||||
|
Style.addStyleReady()
|
||||||
|
|
||||||
|
Style.remStyle()
|
||||||
|
|
||||||
|
if not Style.headCount or d.readyState is 'complete'
|
||||||
|
if Style.observer
|
||||||
|
Style.observer.disconnect()
|
||||||
|
else
|
||||||
|
$.off d, 'DOMNodeInserted', Style.wrapper
|
||||||
|
Style.cleanup()
|
||||||
|
|
||||||
|
cleanup: ->
|
||||||
|
delete Style.observe
|
||||||
|
delete Style.wrapper
|
||||||
|
delete Style.remStyle
|
||||||
|
delete Style.headCount
|
||||||
|
delete Style.cleanup
|
||||||
|
|
||||||
|
addStyle: (theme) ->
|
||||||
|
_conf = Conf
|
||||||
|
unless theme
|
||||||
|
theme = Themes[_conf['theme']]
|
||||||
|
|
||||||
|
MascotTools.init _conf["mascot"]
|
||||||
|
Style.layoutCSS.textContent = Style.layout()
|
||||||
|
Style.themeCSS.textContent = Style.theme(theme)
|
||||||
|
Style.iconPositions()
|
||||||
|
|
||||||
|
headCount: 12
|
||||||
|
|
||||||
|
addStyleReady: ->
|
||||||
|
theme = Themes[Conf['theme']]
|
||||||
|
$.extend Style,
|
||||||
|
layoutCSS: $.addStyle Style.layout(), 'layout'
|
||||||
|
themeCSS: $.addStyle Style.theme(theme), 'theme'
|
||||||
|
icons: $.addStyle "", 'icons'
|
||||||
|
paddingSheet: $.addStyle "", 'padding'
|
||||||
|
mascot: $.addStyle "", 'mascotSheet'
|
||||||
|
|
||||||
|
# Non-customizable
|
||||||
|
$.addStyle Style.jsColorCSS(), 'jsColor'
|
||||||
|
|
||||||
|
delete Style.addStyleReady
|
||||||
|
|
||||||
|
remStyle: ->
|
||||||
|
nodes = d.head.children
|
||||||
|
i = nodes.length
|
||||||
|
while i--
|
||||||
|
break unless Style.headCount
|
||||||
|
node = nodes[i]
|
||||||
|
if (node.nodeName is 'STYLE' and !node.id) or ("#{node.rel}".contains('stylesheet') and node.href[..3] isnt 'data')
|
||||||
|
Style.headCount--
|
||||||
|
$.rm node
|
||||||
|
continue
|
||||||
|
return
|
||||||
|
|
||||||
|
filter: (text, background) ->
|
||||||
|
|
||||||
|
matrix = (fg, bg) -> "
|
||||||
|
#{bg.r} #{-fg.r} 0 0 #{fg.r}
|
||||||
|
#{bg.g} #{-fg.g} 0 0 #{fg.g}
|
||||||
|
#{bg.b} #{-fg.b} 0 0 #{fg.b}
|
||||||
|
"
|
||||||
|
|
||||||
|
fgHex = Style.colorToHex text
|
||||||
|
bgHex = Style.colorToHex background
|
||||||
|
string = matrix {
|
||||||
|
r: parseInt(fgHex.substr(0, 2), 16) / 255
|
||||||
|
g: parseInt(fgHex.substr(2, 2), 16) / 255
|
||||||
|
b: parseInt(fgHex.substr(4, 2), 16) / 255
|
||||||
|
}, {
|
||||||
|
r: parseInt(bgHex.substr(0, 2), 16) / 255
|
||||||
|
g: parseInt(bgHex.substr(2, 2), 16) / 255
|
||||||
|
b: parseInt(bgHex.substr(4, 2), 16) / 255
|
||||||
|
}
|
||||||
|
|
||||||
|
return "filter: url(\"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='filters' color-interpolation-filters='sRGB'><feColorMatrix values='#{string} 0 0 0 1 0' /></filter></svg>#filters\");"
|
||||||
|
|
||||||
|
Banner =
|
||||||
|
init: ->
|
||||||
|
$.asap (-> doc), ->
|
||||||
|
$.asap (-> $ '.abovePostForm'), Banner.ready
|
||||||
|
|
||||||
|
ready: ->
|
||||||
|
banner = $ ".boardBanner"
|
||||||
|
title = $.el "div",
|
||||||
|
id: "boardTitle"
|
||||||
|
children = banner.children
|
||||||
|
i = children.length
|
||||||
|
nodes = []
|
||||||
|
while i--
|
||||||
|
child = children[i]
|
||||||
|
if child.tagName.toLowerCase() is "img"
|
||||||
|
child.id = "Banner"
|
||||||
|
continue
|
||||||
|
|
||||||
|
if Conf['Custom Board Titles']
|
||||||
|
cachedTest = child.innerHTML
|
||||||
|
if not Conf['Persistent Custom Board Titles'] or cachedTest is $.get "#{g.BOARD}.#{child.className}.orig", cachedTest
|
||||||
|
child.innerHTML = $.get "#{g.BOARD}.#{child.className}", cachedTest
|
||||||
|
else
|
||||||
|
$.set "#{g.BOARD}.#{child.className}.orig", cachedTest
|
||||||
|
$.set "#{g.BOARD}.#{child.className}", cachedTest
|
||||||
|
|
||||||
|
$.on child, 'click', (e) ->
|
||||||
|
if e.shiftKey
|
||||||
|
@contentEditable = true
|
||||||
|
|
||||||
|
$.on child, 'keydown', (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
$.on child, 'focus', ->
|
||||||
|
@textContent = @innerHTML
|
||||||
|
|
||||||
|
$.on child, 'blur', ->
|
||||||
|
$.set "#{g.BOARD}.#{@className}", @textContent
|
||||||
|
@innerHTML = @textContent
|
||||||
|
@contentEditable = false
|
||||||
|
|
||||||
|
nodes.push child
|
||||||
|
|
||||||
|
$.add title, nodes.reverse()
|
||||||
|
$.after banner, title
|
||||||
|
return
|
||||||
|
|
||||||
|
GlobalMessage =
|
||||||
|
init: ->
|
||||||
|
$.asap (-> doc), ->
|
||||||
|
$.asap (-> $.id 'delform'), GlobalMessage.ready
|
||||||
|
|
||||||
|
ready: ->
|
||||||
|
if el = $ "#globalMessage", d.body
|
||||||
|
for child in el.children
|
||||||
|
child.cssText = ""
|
||||||
|
return
|
||||||
|
|
||||||
|
Rice =
|
||||||
|
init: ->
|
||||||
|
$.ready ->
|
||||||
|
Rice.nodes d.body
|
||||||
|
|
||||||
|
checkclick: ->
|
||||||
|
@check.click()
|
||||||
|
|
||||||
|
selectclick: ->
|
||||||
|
e.stopPropagation()
|
||||||
|
if Rice.ul
|
||||||
|
return Rice.remSelect()
|
||||||
|
rect = @getBoundingClientRect()
|
||||||
|
{clientHeight} = d.documentElement
|
||||||
|
ul = Rice.ul = $.el 'ul',
|
||||||
|
id: "selectrice"
|
||||||
|
{style} = ul
|
||||||
|
style.width = "#{rect.width}px"
|
||||||
|
if clientHeight - rect.bottom < 200
|
||||||
|
style.bottom = "#{clientHeight - rect.top}px"
|
||||||
|
else
|
||||||
|
style.top = "#{rect.bottom}px"
|
||||||
|
style.left = "#{rect.left}px"
|
||||||
|
input = @previousSibling
|
||||||
|
for option in input.options
|
||||||
|
li = $.el 'li',
|
||||||
|
textContent: option.textContent
|
||||||
|
li.setAttribute 'data-value', option.value
|
||||||
|
$.on li, 'click', (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
|
container = @parentElement.parentElement
|
||||||
|
input = container.previousSibling
|
||||||
|
container.firstChild.textContent = @textContent
|
||||||
|
input.value = @getAttribute 'data-value'
|
||||||
|
ev = document.createEvent 'HTMLEvents'
|
||||||
|
ev.initEvent "change", true, true
|
||||||
|
$.event input, ev
|
||||||
|
Rice.remSelect()
|
||||||
|
$.add ul, li
|
||||||
|
$.on ul, 'click scroll blur', (e) ->
|
||||||
|
e.stopPropagation()
|
||||||
|
$.on d, 'click scroll blur resize', Rice.remSelect
|
||||||
|
$.add @, ul
|
||||||
|
|
||||||
|
remSelect: ->
|
||||||
|
$.off d, 'click scroll blur resize', Rice.remSelect
|
||||||
|
$.rm Rice.ul
|
||||||
|
delete Rice.ul
|
||||||
|
|
||||||
|
nodes: (source) ->
|
||||||
|
checkboxes = $$('[type=checkbox]:not(.riced)', source)
|
||||||
|
checkrice = Rice.checkbox
|
||||||
|
for input in checkboxes
|
||||||
|
checkrice input
|
||||||
|
|
||||||
|
selects = $$('select:not(.riced)', source)
|
||||||
|
selectrice = Rice.select
|
||||||
|
for input in selects
|
||||||
|
selectrice input
|
||||||
|
return
|
||||||
|
|
||||||
|
node: ->
|
||||||
|
Rice.checkbox $ '.postInfo input', @
|
||||||
|
|
||||||
|
checkbox: (input) ->
|
||||||
|
return if $.hasClass input, 'riced'
|
||||||
|
$.addClass input, 'riced'
|
||||||
|
div = $.el 'div',
|
||||||
|
className: 'rice'
|
||||||
|
div.check = input
|
||||||
|
$.after input, div
|
||||||
|
if div.parentElement.tagName.toLowerCase() != 'label'
|
||||||
|
$.on div, 'click', Rice.click
|
||||||
|
|
||||||
|
select: (input) ->
|
||||||
|
$.addClass input, 'riced'
|
||||||
|
div = $.el 'div',
|
||||||
|
className: 'selectrice'
|
||||||
|
innerHTML: "<div>#{input.options[input.selectedIndex].textContent or null}</div>"
|
||||||
|
$.on div, "click", (e),
|
||||||
|
|
||||||
|
$.after input, div
|
||||||
@ -118,6 +118,7 @@ class Notification
|
|||||||
|
|
||||||
CatalogLinks =
|
CatalogLinks =
|
||||||
init: ->
|
init: ->
|
||||||
|
$.ready @ready
|
||||||
return unless Conf['Catalog Links']
|
return unless Conf['Catalog Links']
|
||||||
el = $.el 'a',
|
el = $.el 'a',
|
||||||
id: 'toggleCatalog'
|
id: 'toggleCatalog'
|
||||||
@ -163,6 +164,12 @@ CatalogLinks =
|
|||||||
"//boards.4chan.org/#{board}/catalog"
|
"//boards.4chan.org/#{board}/catalog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ready: ->
|
||||||
|
if catalogLink = ($('.pages.cataloglink a', d.body) or $ '[href=".././catalog"]', d.body)
|
||||||
|
if !g.VIEW is thread
|
||||||
|
$.add d.body, catalogLink
|
||||||
|
catalogLink.id = 'catalog'
|
||||||
|
|
||||||
Settings =
|
Settings =
|
||||||
init: ->
|
init: ->
|
||||||
# 4chan X settings link
|
# 4chan X settings link
|
||||||
|
|||||||
@ -391,42 +391,8 @@ Main =
|
|||||||
# c.timeEnd 'All initializations'
|
# c.timeEnd 'All initializations'
|
||||||
|
|
||||||
$.on d, 'AddCallback', Main.addCallback
|
$.on d, 'AddCallback', Main.addCallback
|
||||||
$.on d, '4chanMainInit', Main.initStyle
|
|
||||||
$.ready Main.initReady
|
$.ready Main.initReady
|
||||||
|
|
||||||
initStyle: ->
|
|
||||||
return unless Main.isThisPageLegit()
|
|
||||||
# disable the mobile layout
|
|
||||||
$('link[href*=mobile]', d.head)?.disabled = true
|
|
||||||
$.addClass doc, $.engine
|
|
||||||
$.addClass doc, 'fourchan-x'
|
|
||||||
$.addStyle Main.css
|
|
||||||
|
|
||||||
if g.VIEW is 'catalog'
|
|
||||||
$.addClass doc, $.id('base-css').href.match(/catalog_(\w+)/)[1].replace('_new', '').replace /_+/g, '-'
|
|
||||||
return
|
|
||||||
|
|
||||||
style = 'yotsuba-b'
|
|
||||||
mainStyleSheet = $ 'link[title=switch]', d.head
|
|
||||||
styleSheets = $$ 'link[rel="alternate stylesheet"]', d.head
|
|
||||||
setStyle = ->
|
|
||||||
$.rmClass doc, style
|
|
||||||
for styleSheet in styleSheets
|
|
||||||
if styleSheet.href is mainStyleSheet.href
|
|
||||||
style = styleSheet.title.toLowerCase().replace('new', '').trim().replace /\s+/g, '-'
|
|
||||||
break
|
|
||||||
$.addClass doc, style
|
|
||||||
setStyle()
|
|
||||||
return unless mainStyleSheet
|
|
||||||
if MutationObserver = window.MutationObserver or window.WebKitMutationObserver or window.OMutationObserver
|
|
||||||
observer = new MutationObserver setStyle
|
|
||||||
observer.observe mainStyleSheet,
|
|
||||||
attributes: true
|
|
||||||
attributeFilter: ['href']
|
|
||||||
else
|
|
||||||
# XXX this doesn't seem to work?
|
|
||||||
$.on mainStyleSheet, 'DOMAttrModified', setStyle
|
|
||||||
|
|
||||||
initReady: ->
|
initReady: ->
|
||||||
if d.title is '4chan - 404 Not Found'
|
if d.title is '4chan - 404 Not Found'
|
||||||
if Conf['404 Redirect'] and g.VIEW is 'thread'
|
if Conf['404 Redirect'] and g.VIEW is 'thread'
|
||||||
@ -536,14 +502,5 @@ Main =
|
|||||||
Main.thisPageIsLegit = !$('link[href*="favicon-status.ico"]', d.head) and d.title isnt '4chan - Temporarily Offline'
|
Main.thisPageIsLegit = !$('link[href*="favicon-status.ico"]', d.head) and d.title isnt '4chan - Temporarily Offline'
|
||||||
Main.thisPageIsLegit
|
Main.thisPageIsLegit
|
||||||
|
|
||||||
css: """
|
|
||||||
<%= grunt.file.read('css/style.css') %>
|
|
||||||
<%= grunt.file.read('css/yotsuba.css') %>
|
|
||||||
<%= grunt.file.read('css/yotsuba-b.css') %>
|
|
||||||
<%= grunt.file.read('css/futaba.css') %>
|
|
||||||
<%= grunt.file.read('css/burichan.css') %>
|
|
||||||
<%= grunt.file.read('css/tomorrow.css') %>
|
|
||||||
<%= grunt.file.read('css/photon.css') %>
|
|
||||||
"""
|
|
||||||
|
|
||||||
Main.init()
|
Main.init()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user