Skip to content
36 changes: 16 additions & 20 deletions src/c4.co
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,25 @@ console.timeStamp "c4-init"
console.time "init"
console.time "interactive"

unf = require \./unfortunate
here = unf.locate window.location

# `board` holds global state about the current page, like `document` for the
# 4chan domain.
global.board = {}
# boards.4chan.org/<name>/'thread' or <page>/<threadid>, or catalog/<searchterm>
[ , &name, page, &thread-no] = window.location.pathname / \/

&is-catalog = page is \catalog
&search-term = &thread-no if &is-catalog

&is-thread = not &is-catalog and !!&thread-no
&is-board = not &is-catalog and not &is-thread
&page = parseInt page, 10 or 0

&url = "//boards.4chan.org/#{&name}/"

&ready = false # flag similar to document.readyState

&favicons = require \./favicon-data

global.board =
# TODO just use `here` as a global instead of legacy names
name: here.board
thread-no: here.tno
is-catalog: here.type is \catalog
is-thread: here.type is \thread
is-board: here.type is \board
page: here.page
url: "//boards.4chan.org/#{here.board}/"
favicons: require \./favicon-data
# TODO moot's crazy spoiler number bullshit
&spoiler-url = "//s.4cdn.org/image/spoiler-#{&name}1.png"
&thumbs-base = "//t.4cdn.org/#{&name}/"
&images-base = "//i.4cdn.org/#{&name}/"
spoiler-url: "//s.4cdn.org/image/spoiler-#{here.board}1.png"
thumbs-base: "//i.4cdn.org/#{here.board}/"
images-base: "//i.4cdn.org/#{here.board}/"

require \./archives
require \./backlinks
Expand Down
7 changes: 6 additions & 1 deletion src/features/image-previews.co
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
{on-posts} = require \../utils/features
lightbox = require \../utils/lightbox

on-posts \.thumb : mouseover: lightbox ({{dataset, href}: parentElement}) ->
boxy = lightbox ({{dataset, href}: parentElement}) ->
{dataset.width, dataset.height, src: href}

on-posts \.thumb : mouseover: (e) ->
# XXX avoid trying to render pdfs (on /tg/)
if not /\.pdf$/.test e.target.parentElement.href
boxy.call(this, e)

# TODO alternative destructuring, I think there's an even shorter version
# though
# { ...it.parentElement{src: href}, ...it.parentElement.dataset{width, height}
Expand Down
2 changes: 1 addition & 1 deletion src/features/postpreviews.co
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fetch-new-post = !(no) ->

# TODO guard against multiple requests in short time period
xhr = new XMLHttpRequest
&open \GET "//api.4chan.org/#board-name/thread/#thread.json"
&open \GET "https://api.4chan.org/#board-name/thread/#thread.json"
&onload = !->
# TODO handle 404 -> archive
if @status is 200
Expand Down
103 changes: 26 additions & 77 deletions src/onready.co
Original file line number Diff line number Diff line change
@@ -1,101 +1,56 @@
{L, $$, $} = require \./utils/dom
parser = require \./parser
{Thread} = require \./parser
{onready} = require \./utils/features
{truncate} = require \./utils/string
{get, set, sset, sget} = require \./utils/storage
board-template = require \templates/board

# pre-create new DOM
html = L \html
&appendChild with head = L \head
&appendChild L \title
&appendChild with L \style
&id = \c4-style
&textContent = require \style/c4
&appendChild with L \script
&src = \//www.google.com/recaptcha/api.js?render=explicit

body = L \body

# replace the original html with the new, but keep a reference to query and
# parse. This speeds up re-rendering consideraby, since the browser doesn't
# even have to attempt displaying the old content and style.
#
# in fact, it's so effective, even the original sript tags don't run, EVEN ON
# CHROME, negating the need to handle 'beforescriptexeute' or whatever. crazy.
d = document.replaceChild html, document.documentElement

catalog-template = require \templates/catalog
unf = require \./unfortunate

# init
<-! document.addEventListener \DOMContentLoaded
page <-! unf.lift {style: require \style/c4} .then

console.time "initial render"

console.time "parse page"

# get other useful information
board
&title = d.querySelector \.boardTitle ?.textContent or ''
&subtitle = d.querySelector \.boardSubtitle ?.innerHTML or ''
&nav = d.querySelector \#boardNavDesktop .innerHTML
&banner = d.querySelector \#bannerCnt .dataset.src
&message = d.querySelector \.globalMessage ?.innerHTML

# detect based on favicon href
&sfw =
d.querySelector 'link[rel="shortcut icon"]' .href.slice(-6) is \ws.ico
&title = page.title
&subtitle = page.subtitle
&nav = page.oldDoc.querySelector \#boardNavDesktop .innerHTML
&banner = page.banner
&message = page.message
&sfw = page.sfw

&type = if &sfw then \sfw else \nsfw
&favicon = board.favicons[&type]

# for post deletion
&password = get \password or Math.random!toString!substr -8

console.timeEnd "parse page"

console.log board

# XXX needs to go somewhere else
body
document.body
&id = board.name
&className = "#{board.type} \
#{if board.isThread then \threadpage else \boardpage}"

if board.is-catalog
# find script tag that defines `catalog`
[catalog-text] = Array::filter.call d.querySelectorAll(\script), ->
/var catalog/.test it.textContent
throw new Error "what is happening" unless catalog-text

# eval the script tag, which needs `new FC().applyCSS()` in scope...
class FC then applyCSS: ->

catalog = eval catalog-text.text-content + "; catalog"

board.catalog = catalog

console.log catalog
catalog = board.catalog = page.data

order = get \catalog-order or \date
console.time "generate new HTML body"
body-html = catalog-template catalog, {order}
console.timeEnd "generate new HTML body"

console.time "parse new body HTML"
body.innerHTML = body-html
document.body.innerHTML = body-html
console.timeEnd "parse new body HTML"

# XXX need to think a lot harder about how to structure this code. hiding the
# two types of pages behind if-statements isn't that great of an architecture
require \./catalog
else
#console.profile!

console.time "parse board"
board.threads = parser.dom d, board.name
console.timeEnd "parse board"
board.thread = board.threads.0 if board.isThread
# XXX this is awkward, change unf's api pls
if board.isThread
board.thread = new Thread page.data
board.threads = [board.thread]
else
board.threads = for t of page.data
new Thread t

# global lookup post by hash
# XXX cross-board still conflicts
Expand All @@ -104,34 +59,32 @@ else
for &posts
board.posts[&no] = &

# XXX used in hide.co, really want IDB/minimongo/'real man's db'
# XXX used in features, really want IDB/minimongo/'real man's db'
board.threads-by-id = {}
for board.threads
board.threads-by-id[&op.no] = &

console.log board

console.time "generate new HTML body"
body-html = board-template board
console.timeEnd "generate new HTML body"

console.time "parse new body HTML"
body.innerHTML = body-html
document.body.innerHTML = body-html
console.timeEnd "parse new body HTML"

console.log board

console.time "prerender handlers"
document.dispatchEvent new CustomEvent do
\c4-prerender
detail: {body}
detail: {body: document.body}
console.timeEnd "prerender handlers"

console.time "render new body"
html.appendChild body
console.timeEnd "render new body"

if board.isBoard
console.time "highlight current page"
body.querySelector "\#pages a[href=\"#{board.page or board.url}\"]"
href = if board.page is 1 then board.url else board.page
document.body.querySelector "\#pages a[href=\"#href\"]"
.id = \current
console.timeEnd "highlight current page"

Expand Down Expand Up @@ -171,8 +124,6 @@ if window.location.hash and not sget document.URL
sset {+(document.URL)}
window.removeEventListener \scroll registerPage

board.ready = true

# cache current thread hash (which is updated by updater)
version = c4_COMPILATION_VERSION
if board.is-thread
Expand All @@ -184,5 +135,3 @@ document.dispatchEvent new CustomEvent do
\c4-ready
detail: {board.threads, el: $ \threads}
console.timeEnd "onready handlers"

#console.profileEnd!
Loading