Build = staticPath: '//s.4cdn.org/image/' gifIcon: if window.devicePixelRatio >= 2 then '@2x.gif' else '.gif' spoilerRange: {} shortFilename: (filename, isReply) -> # FILENAME SHORTENING SCIENCE: # OPs have a +10 characters threshold. # The file extension is not taken into account. threshold = if isReply then 30 else 40 if filename.length - 4 > threshold "#{filename[...threshold - 5]}(...).#{filename[-3..]}" else filename thumbRotate: do -> n = 0 -> n = (n + 1) % 3 postFromObject: (data, boardID) -> o = # id postID: data.no threadID: data.resto or data.no boardID: boardID # info name: data.name capcode: data.capcode tripcode: data.trip uniqueID: data.id email: if data.email then encodeURI data.email.replace /"/g, '"' else '' subject: data.sub flagCode: data.country flagName: data.country_name date: data.now dateUTC: data.time comment: data.com # thread status isSticky: !!data.sticky isClosed: !!data.closed # file if data.ext or data.filedeleted o.file = name: data.filename + data.ext timestamp: "#{data.tim}#{data.ext}" url: if boardID is 'f' "//i.4cdn.org/#{boardID}/src/#{data.filename}#{data.ext}" else "//i.4cdn.org/#{boardID}/src/#{data.tim}#{data.ext}" height: data.h width: data.w MD5: data.md5 size: data.fsize turl: "//#{Build.thumbRotate()}.t.4cdn.org/#{boardID}/thumb/#{data.tim}s.jpg" theight: data.tn_h twidth: data.tn_w isSpoiler: !!data.spoiler isDeleted: !!data.filedeleted Build.post o post: (o, isArchived) -> ### 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 isOP = postID is threadID {staticPath, gifIcon} = Build tripcode = if tripcode " #{tripcode}" else '' if email emailStart = '' emailEnd = '' else emailStart = '' emailEnd = '' switch capcode when 'admin', 'admin_highlight' capcodeClass = " capcodeAdmin" capcodeStart = " ## Admin" capcodeIcon = " " when 'mod' capcodeClass = " capcodeMod" capcodeStart = " ## Mod" capcodeIcon = " " when 'developer' capcodeClass = " capcodeDeveloper" capcodeStart = " ## Developer" capcodeIcon = " " else capcodeClass = '' capcodeStart = '' capcodeIcon = '' userID = if !capcode and uniqueID " (ID: " + "#{uniqueID}) " else '' flag = unless flagCode '' else if boardID is 'pol' " #{flagCode}" else " " if file?.isDeleted fileHTML = if isOP "
" + "File deleted." + "
" else "
" + "File deleted." + "
" else if file fileSize = $.bytesToString file.size fileThumb = file.turl if file.isSpoiler fileSize = "Spoiler Image, #{fileSize}" unless isArchived fileThumb = "#{staticPath}spoiler" if spoilerRange = Build.spoilerRange[boardID] # Randomize the spoiler image. fileThumb += "-#{boardID}" + Math.floor 1 + spoilerRange * Math.random() fileThumb += '.png' file.twidth = file.theight = 100 imgSrc = if boardID is 'f' '' else "" + "#{fileSize}" + "" # html -> text, translate WebKit's %22s into "s a = $.el 'a', innerHTML: file.name filename = a.textContent.replace /%22/g, '"' # shorten filename, get html a.textContent = Build.shortFilename filename shortFilename = a.innerHTML # get html a.textContent = filename filename = a.innerHTML.replace /'/g, ''' fileDims = if file.name[-3..] is 'pdf' then 'PDF' else "#{file.width}x#{file.height}" fileInfo = "
File: #{file.timestamp}" + "-(#{fileSize}, #{fileDims}#{ if file.isSpoiler '' else ", #{shortFilename}" }" + ")
" fileHTML = "
#{fileInfo}#{imgSrc}
" else fileHTML = '' sticky = if isSticky " Sticky" else '' closed = if isClosed " Closed" else '' if isOP and g.VIEW is 'index' pageNum = Math.floor Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage pageIcon = " Page #{pageNum}" replyLink = "   [Reply]" else pageIcon = replyLink = '' container = $.el 'div', id: "pc#{postID}" className: "postContainer #{if isOP then 'op' else 'reply'}Container" innerHTML: <%= grunt.file.read('src/General/html/Build/post.html').replace(/>\s+/g, '>').replace(/\s+ for quote in $$ '.quotelink', container href = quote.getAttribute 'href' continue if href[0] is '/' # Cross-board quote, or board link quote.href = "/#{boardID}/res/#{href}" # Fix pathnames 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}/res/#{threadID}" thread: (board, data) -> 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}" 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 $.add root, nodes root