Build = initPixelRatio: window.devicePixelRatio spoilerRange: {} unescape: (text) -> return text unless text? text.replace /&(amp|#039|quot|lt|gt);/g, (c) -> {'&': '&', ''': "'", '"': '"', '<': '<', '>': '>'}[c] shortFilename: (filename, isReply) -> threshold = 30 ext = filename.match(/\.?[^\.]*$/)[0] if filename.length - ext.length > threshold "#{filename[...threshold - 5]}(...)#{ext}" else filename thumbRotate: do -> n = 0 -> n = (n + 1) % 3 sameThread: (boardID, threadID) -> g.VIEW is 'thread' and g.BOARD.ID is boardID and g.THREADID is +threadID postURL: (boardID, threadID, postID) -> if Build.sameThread boardID, threadID "\#p#{postID}" else "/#{boardID}/thread/#{threadID}\#p#{postID}" postFromObject: (data, boardID) -> o = # id postID: data.no threadID: data.resto or data.no boardID: boardID # info name: Build.unescape data.name capcode: data.capcode tripcode: data.trip uniqueID: data.id email: Build.unescape data.email subject: Build.unescape data.sub flagCode: data.country flagName: Build.unescape data.country_name date: data.now dateUTC: data.time comment: {innerHTML: data.com or ''} # thread status isSticky: !!data.sticky isClosed: !!data.closed # file if data.filedeleted o.file = isDeleted: true else if data.ext o.file = name: (Build.unescape data.filename) + data.ext timestamp: "#{data.tim}#{data.ext}" url: if boardID is 'f' "//i.4cdn.org/#{boardID}/#{encodeURIComponent data.filename}#{data.ext}" else "//i.4cdn.org/#{boardID}/#{data.tim}#{data.ext}" height: data.h width: data.w MD5: data.md5 size: data.fsize turl: "//#{Build.thumbRotate()}.t.4cdn.org/#{boardID}/#{data.tim}s.jpg" theight: data.tn_h twidth: data.tn_w isSpoiler: !!data.spoiler isDeleted: false tag: data.tag Build.post o post: (o) -> ### This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS). @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE ### { postID, threadID, boardID name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC isSticky, isClosed comment file } = o name or= '' subject or= '' isOP = postID is threadID retina = if Build.initPixelRatio >= 2 then '@2x' else '' ### Name Block ### switch capcode when 'admin', 'admin_highlight' capcodeClass = ' capcodeAdmin' capcodeStart = <%= html(' ## Admin') %> capcodeIcon = <%= html('Admin Icon') %> when 'mod' capcodeClass = ' capcodeMod' capcodeStart = <%= html(' ## Mod') %> capcodeIcon = <%= html('Mod Icon') %> when 'developer' capcodeClass = ' capcodeDeveloper' capcodeStart = <%= html(' ## Developer') %> capcodeIcon = <%= html('Developer Icon') %> else capcodeClass = '' capcodeStart = <%= html('') %> capcodeIcon = <%= html('') %> nameClass = if capcode then ' capcode' else '' tripcodeField = if tripcode <%= html(' ${tripcode}') %> else <%= html('') %> emailField = <%= html('${name}&{tripcodeField}&{capcodeStart}') %> if email emailProcessed = encodeURIComponent(email).replace /%40/g, '@' emailField = <%= html('&{emailField}') %> unless isOP and boardID is 'f' emailField = <%= html('&{emailField} ') %> userID = if !capcode and uniqueID <%= html(' (ID: ${uniqueID})') %> else <%= html('') %> flag = unless flagCode <%= html('') %> else if boardID is 'pol' <%= html('${flagCode}') %> else <%= html('') %> nameBlock = <%= html( '' + '&{emailField}&{capcodeIcon}&{userID}&{flag}' + ' ' ) %> ### Post Info ### subjectField = if isOP or boardID is 'f' <%= html('${subject} ') %> else <%= html('') %> desktop2 = if isOP and boardID is 'f' then '' else ' desktop' postLink = Build.postURL boardID, threadID, postID quoteLink = if Build.sameThread boardID, threadID "javascript:quote('#{+postID}');" else "/#{boardID}/thread/#{threadID}\#q#{postID}" pageIcon = if isOP and g.VIEW is 'index' and Conf['JSON Navigation'] pageNum = Math.floor(Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage) + 1 <%= html(' [${pageNum}]') %> else <%= html('') %> sticky = if isSticky <%= html(' Sticky') %> else <%= html('') %> closed = if isClosed <%= html(' Closed') %> else <%= html('') %> replyLink = if isOP and g.VIEW is 'index' <%= html('   [Reply]') %> else <%= html('') %> postInfo = <%= html( '
' + ' ' + '&{subjectField}' + '&{nameBlock}' + '${date} ' + '' + 'No.' + '${postID}' + '&{pageIcon}&{sticky}&{closed}&{replyLink}' + '' + '
' ) %> ### File Info ### fileCont = if file?.isDeleted <%= html( '' + 'File deleted.' + '' ) %> else if file and boardID is 'f' <%= html( '
' + 'File: ${file.name}' + '-(${$.bytesToString(file.size)}, ${file.width}x${file.height}, ${file.tag})' + '
' ) %> else if file if file.isSpoiler shortFilename = 'Spoiler Image' if spoilerRange = Build.spoilerRange[boardID] # Randomize the spoiler image. fileThumb = "//s.4cdn.org/image/spoiler-#{boardID}#{Math.floor 1 + spoilerRange * Math.random()}.png" else fileThumb = '//s.4cdn.org/image/spoiler.png' file.twidth = file.theight = 100 else shortFilename = Build.shortFilename file.name, !isOP fileThumb = file.turl fileSize = $.bytesToString file.size fileDims = if file.url[-4..] is '.pdf' then 'PDF' else "#{file.width}x#{file.height}" fileLink = if file.isSpoiler or file.name is shortFilename <%= html('${shortFilename}') %> else <%= html('${shortFilename}') %> fileText = if file.isSpoiler <%= html('
File: &{fileLink} (${fileSize}, ${fileDims})
') %> else <%= html('
File: &{fileLink} (${fileSize}, ${fileDims})
') %> <%= html( '&{fileText}' + '' + '${fileSize}' + '' ) %> fileBlock = if file <%= html('
&{fileCont}
') %> else <%= html('') %> ### Whole Post ### highlightPost = if capcode is 'admin_highlight' then ' highlightPost' else '' message = <%= html('
&{comment}
') %> wholePost = if isOP <%= html( '
' + '&{fileBlock}&{postInfo}&{message}' + '
' ) %> else <%= html( '
>>
' + '
' + '&{postInfo}&{fileBlock}&{message}' + '
' ) %> container = $.el 'div', className: "postContainer #{if isOP then 'op' else 'reply'}Container" id: "pc#{postID}" $.extend container, wholePost # Fix pathnames for quote in $$ '.quotelink', container href = quote.getAttribute 'href' if (href[0] is '#') and !(Build.sameThread boardID, threadID) quote.href = "/#{boardID}/thread/#{threadID}" + href else if (match = href.match /^\/([^\/]+)\/thread\/(\d+)/) and (Build.sameThread match[1], match[2]) quote.href = href.match(/(#[^#]*)?$/)[0] or '#' container summary: (boardID, threadID, posts, files) -> text = [] text.push "#{posts} post#{if posts > 1 then 's' else ''}" text.push "and #{files} image repl#{if files > 1 then 'ies' else 'y'}" if files text.push 'omitted.' $.el 'a', className: 'summary' textContent: text.join ' ' href: "/#{boardID}/thread/#{threadID}" thread: (board, data, full) -> Build.spoilerRange[board] = data.custom_spoiler if (OP = board.posts[data.no]) and root = OP.nodes.root.parentNode $.rmAll root else root = $.el 'div', className: 'thread' id: "t#{data.no}" $.add root, Build[if full then 'fullThread' else 'excerptThread'] board, data, OP root excerptThread: (board, data, OP) -> nodes = [if OP then OP.nodes.root else Build.postFromObject data, board.ID] if data.omitted_posts or !Conf['Show Replies'] and data.replies [posts, files] = if Conf['Show Replies'] [data.omitted_posts, data.omitted_images] else # XXX data.images is not accurate. [data.replies, data.omitted_images + data.last_replies.filter((data) -> !!data.ext).length] nodes.push Build.summary board.ID, data.no, posts, files nodes fullThread: (board, data) -> Build.postFromObject data, board.ID