4chan-x/src/General/Main.coffee
ccd0 0fa2498d71 Remember mute/volume settings of last video adjusted.
Also put mute/volume controls in the header menu.
2015-01-31 17:56:45 -08:00

362 lines
12 KiB
CoffeeScript
Executable File

Main =
init: ->
if location.hostname is 'www.google.com'
return $.ready -> Captcha.noscript.initFrame()
g.threads = new SimpleDict
g.posts = new SimpleDict
pathname = location.pathname.split '/'
g.BOARD = new Board pathname[1]
return if g.BOARD.ID in ['z', 'fk']
g.VIEW =
switch pathname[2]
when 'res', 'thread'
'thread'
when 'catalog'
'catalog'
when 'archive'
'archive'
else
'index'
if g.VIEW is 'thread'
g.THREADID = +pathname[3]
# flatten Config into Conf
# and get saved or default values
flatten = (parent, obj) ->
if obj instanceof Array
Conf[parent] = obj[0]
else if typeof obj is 'object'
for key, val of obj
flatten key, val
else # string or number
Conf[parent] = obj
return
flatten null, Config
for db in DataBoard.keys
Conf[db] = boards: {}
Conf['selectedArchives'] = {}
$.get Conf, (items) ->
$.extend Conf, items
$.asap (-> doc = d.documentElement), Main.initFeatures
# set up CSS when <head> is completely loaded
$.asap (-> doc = d.documentElement), ->
$.onExists doc, 'body', false, Main.initStyle
initFeatures: ->
switch location.hostname
when 'a.4cdn.org'
return
when 'sys.4chan.org'
return
when 'i.4cdn.org'
$.asap (-> d.readyState isnt 'loading'), ->
if Conf['404 Redirect'] and d.title in ['4chan - Temporarily Offline', '4chan - 404 Not Found']
Redirect.init()
pathname = location.pathname.split '/'
URL = Redirect.to 'file',
boardID: g.BOARD.ID
filename: pathname[pathname.length - 1]
Redirect.navigate URL
else if Conf['Loop in New Tab'] and video = $ 'video'
video.loop = true
video.controls = false
video.play()
ImageCommon.addControls video
return
if Conf['Normalize URL'] and g.VIEW is 'thread'
pathname = location.pathname.split '/'
if pathname[2] isnt 'thread' or pathname.length > 4
pathname[2] = 'thread'
history.replaceState null, '', pathname[0...4].join('/') + location.hash
# c.time 'All initializations'
for [name, feature] in Main.features
# c.time "#{name} initialization"
try
feature.init()
catch err
Main.handleErrors
message: "\"#{name}\" initialization crashed."
error: err
# finally
# c.timeEnd "#{name} initialization"
# c.timeEnd 'All initializations'
$.ready Main.initReady
initStyle: ->
return if !Main.isThisPageLegit() or $.hasClass doc, 'fourchan-x'
# disable the mobile layout
$('link[href*=mobile]', d.head)?.disabled = true
$.addClass doc, 'fourchan-x', 'seaweedchan'
$.addClass doc, if g.VIEW is 'thread' then 'thread-view' else g.VIEW
$.addClass doc, if chrome? then 'blink' else 'gecko'
$.addStyle Main.css, 'fourchanx-css'
Main.setClass()
setClass: ->
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
new MutationObserver(setStyle).observe mainStyleSheet,
attributes: true
attributeFilter: ['href']
initReady: ->
if d.title in ['4chan - Temporarily Offline', '4chan - 404 Not Found']
if Conf['404 Redirect'] and g.VIEW is 'thread'
href = Redirect.to 'thread',
boardID: g.BOARD.ID
threadID: g.THREADID
postID: +location.hash.match /\d+/ # post number or 0
Redirect.navigate href, "/#{g.BOARD}/"
return
# 4chan Pass Link
if styleSelector = $.id 'styleSelector'
passLink = $.el 'a',
textContent: '4chan Pass'
href: 'javascript:;'
$.on passLink, 'click', ->
window.open '//sys.4chan.org/auth',
'This will steal your data.'
'left=0,top=0,width=500,height=255,toolbar=0,resizable=0'
$.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0']
# Parse HTML or skip it and start building from JSON.
unless Conf['JSON Navigation'] and g.VIEW is 'index'
Main.initThread()
else
$.event '4chanXInitFinished'
$.get 'previousversion', null, ({previousversion}) ->
return if previousversion is g.VERSION
if previousversion
el = $.el 'span',
<%= html('${g.NAME} has been updated to <a href="${g.CHANGELOG}" target="_blank">version ${g.VERSION}</a>.') %>
new Notice 'info', el, 15
else
Settings.open()
$.set 'previousversion', g.VERSION
return unless Conf['Show Support Message']
<% if (type === 'userscript') { %>
GMver = GM_info.version.split '.'
for v, i in "<%= meta.min.greasemonkey %>".split '.'
continue if v is GMver[i]
(v < GMver[i]) or new Notice 'warning', "Your version of Greasemonkey is outdated (v#{GM_info.version} instead of v<%= meta.min.greasemonkey %> minimum) and <%= meta.name %> may not operate correctly.", 30
break
<% } %>
try
localStorage.getItem '4chan-settings'
catch err
new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to operate properly.', 30
initThread: ->
if board = $ '.board'
threads = []
posts = []
for threadRoot in $$ '.board > .thread', board
thread = new Thread +threadRoot.id[1..], g.BOARD
threads.push thread
for postRoot in $$ '.thread > .postContainer', threadRoot
try
posts.push new Post postRoot, thread, g.BOARD
catch err
# Skip posts that we failed to parse.
unless errors
errors = []
errors.push
message: "Parsing of Post No.#{postRoot.id.match(/\d+/)} failed. Post will be skipped."
error: err
Main.handleErrors errors if errors
if g.VIEW is 'thread'
scriptData = Get.scriptData()
threads[0].postLimit = /\bbumplimit *= *1\b/.test scriptData
threads[0].fileLimit = /\bimagelimit *= *1\b/.test scriptData
threads[0].ipCount = if m = scriptData.match /\bunique_ips *= *(\d+)\b/ then +m[1]
Main.callbackNodes Thread, threads
Main.callbackNodesDB Post, posts, ->
QuoteThreading.insert post for post in posts
$.event '4chanXInitFinished'
else
$.event '4chanXInitFinished'
callbackNodes: (klass, nodes) ->
i = 0
cb = klass.callbacks
while node = nodes[i++]
cb.execute node
return
callbackNodesDB: (klass, nodes, cb) ->
i = 0
cbs = klass.callbacks
fn = ->
return false unless node = nodes[i]
cbs.execute node
++i % 25
softTask = ->
while fn()
continue
unless nodes[i]
cb() if cb
return
setTimeout softTask, 0
softTask()
handleErrors: (errors) ->
unless errors instanceof Array
error = errors
else if errors.length is 1
error = errors[0]
if error
new Notice 'error', Main.parseError(error), 15
return
div = $.el 'div',
<%= html('${errors.length} errors occurred. [<a href="javascript:;">show</a>]') %>
$.on div.lastElementChild, 'click', ->
[@textContent, logs.hidden] = if @textContent is 'show'
['hide', false]
else
['show', true]
logs = $.el 'div',
hidden: true
for error in errors
$.add logs, Main.parseError error
new Notice 'error', [div, logs], 30
parseError: (data) ->
c.error data.message, data.error.stack
message = $.el 'div',
textContent: data.message
error = $.el 'div',
textContent: "#{data.error.name or 'Error'}: #{data.error.message or 'see console for details'}"
[message, error]
isThisPageLegit: ->
# 404 error page or similar.
unless 'thisPageIsLegit' of Main
Main.thisPageIsLegit = location.hostname is 'boards.4chan.org' and
!$('link[href*="favicon-status.ico"]', d.head) and
d.title not in ['4chan - Temporarily Offline', '4chan - Error', '504 Gateway Time-out']
Main.thisPageIsLegit
ready: (cb) ->
$.ready ->
cb() if Main.isThisPageLegit()
css: """
<%= grunt.file.read('src/General/css/font-awesome.css').replace(/\s+/g, ' ').replace(/\\/g, '\\\\').trim() %>
<%= grunt.file.read('src/General/css/style.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/yotsuba.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/yotsuba-b.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/futaba.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/burichan.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/tomorrow.css').replace(/\s+/g, ' ').trim() %>
<%= grunt.file.read('src/General/css/photon.css').replace(/\s+/g, ' ').trim() %>
"""
features: [
['Polyfill', Polyfill]
['Redirect', Redirect]
['Header', Header]
['Catalog Links', CatalogLinks]
['Settings', Settings]
['Index Generator', Index]
['Disable Autoplay', AntiAutoplay]
['Announcement Hiding', PSAHiding]
['Fourchan thingies', Fourchan]
['Color User IDs', IDColor]
['Highlight by User ID', IDHighlight]
['Custom CSS', CustomCSS]
['Linkify', Linkify]
['Reveal Spoilers', RemoveSpoilers]
['Resurrect Quotes', Quotify]
['Filter', Filter]
['Thread Hiding Buttons', ThreadHiding]
['Reply Hiding Buttons', PostHiding]
['Recursive', Recursive]
['Strike-through Quotes', QuoteStrikeThrough]
['Quick Reply', QR]
['Menu', Menu]
['Index Generator (Menu)', Index.menu]
['Report Link', ReportLink]
['Thread Hiding (Menu)', ThreadHiding.menu]
['Reply Hiding (Menu)', PostHiding.menu]
['Delete Link', DeleteLink]
['Filter (Menu)', Filter.menu]
['Download Link', DownloadLink]
['Archive Link', ArchiveLink]
['Quote Inlining', QuoteInline]
['Quote Previewing', QuotePreview]
['Quote Backlinks', QuoteBacklink]
['Mark Quotes of You', QuoteYou]
['Mark OP Quotes', QuoteOP]
['Mark Cross-thread Quotes', QuoteCT]
['Anonymize', Anonymize]
['Time Formatting', Time]
['Relative Post Dates', RelativeDates]
['File Info Formatting', FileInfo]
['Fappe Tyme', FappeTyme]
['Gallery', Gallery]
['Gallery (menu)', Gallery.menu]
['Sauce', Sauce]
['Image Expansion', ImageExpand]
['Image Expansion (Menu)', ImageExpand.menu]
['Reveal Spoiler Thumbnails', RevealSpoilers]
['Image Loading', ImageLoader]
['Image Hover', ImageHover]
['Volume Control', Volume]
['Comment Expansion', ExpandComment]
['Thread Expansion', ExpandThread]
['Thread Excerpt', ThreadExcerpt]
['Favicon', Favicon]
['Unread', Unread]
['Quote Threading', QuoteThreading]
['Thread Stats', ThreadStats]
['Thread Updater', ThreadUpdater]
['Thread Watcher', ThreadWatcher]
['Thread Watcher (Menu)', ThreadWatcher.menu]
['Mark New IPs', MarkNewIPs]
['Index Navigation', Nav]
['Keybinds', Keybinds]
['Banner', Banner]
<% if (tests_enabled) { %>
['Build Test', BuildTest]
<% } %>
]
Main.init()