diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 9e5b7ab58..f7395d548 100755 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -1,10 +1,14 @@ Build = - staticPath: '//s.4cdn.org/image/' - gifIcon: if window.devicePixelRatio >= 2 then '@2x.gif' else '.gif' + h_staticPath: '//s.4cdn.org/image/' + h_gifIcon: if window.devicePixelRatio >= 2 then '@2x.gif' else '.gif' spoilerRange: {} - escape: (name) -> - name.replace /[&"'<>]/g, (c) -> - {'&': '&', "'": ''', '"': '"', '<': '<', '>': '>'}[c] + h_escape: (text) -> + (text+'').replace /[&"'<>]/g, (c) -> + {'&': '&', "'": ''', '"': '"', '<': '<', '>': '>'}[c] + unescape: (text) -> + return text unless text? + text.replace /&(amp|#039|quot|lt|gt);/g, (c) -> + {'&': '&', ''': "'", '"': '"', '<': '<', '>': '>'}[c] shortFilename: (filename, isReply) -> # FILENAME SHORTENING SCIENCE: # OPs have a +10 characters threshold. @@ -25,27 +29,30 @@ Build = threadID: data.resto or data.no boardID: boardID # info - name: data.name + name: Build.unescape 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 + email: Build.unescape data.email + subject: Build.unescape data.sub flagCode: data.country - flagName: data.country_name + flagName: Build.unescape data.country_name date: data.now dateUTC: data.time - comment: data.com + h_comment: data.com or '' # thread status isSticky: !!data.sticky isClosed: !!data.closed # file - if data.ext or data.filedeleted + if data.filedeleted o.file = - name: data.filename + data.ext + 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}".replace /'/g, ''' + "//i.4cdn.org/#{boardID}/#{encodeURIComponent data.filename}#{data.ext}" else "//i.4cdn.org/#{boardID}/#{data.tim}#{data.ext}" height: data.h @@ -56,144 +63,146 @@ Build = theight: data.tn_h twidth: data.tn_w isSpoiler: !!data.spoiler - isDeleted: !!data.filedeleted + isDeleted: false 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 ### + E = Build.h_escape { postID, threadID, boardID name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC isSticky, isClosed - comment + h_comment file } = o + name or= '' + subject or= '' isOP = postID is threadID - {staticPath, gifIcon} = Build + {h_staticPath, h_gifIcon} = Build - tripcode = if tripcode - " #{tripcode}" + if isOP + h_sideArrows = '' else - '' + h_sideArrows = "
>>
" + + h_postClass = "post #{if isOP then 'op' else 'reply'}#{if capcode is 'admin_highlight' then ' highlightPost' else ''}" + + if tripcode + h_tripcode = " #{E tripcode}" + else + h_tripcode = '' if email - emailStart = '' - emailEnd = '' + h_emailStart = "" + h_emailEnd = '' else - emailStart = '' - emailEnd = '' + h_emailStart = '' + h_emailEnd = '' switch capcode when 'admin', 'admin_highlight' - capcodeClass = " capcodeAdmin" - capcodeStart = " ## Admin" - capcodeIcon = " " + h_capcodeClass = ' capcodeAdmin' + h_capcodeStart = ' ## Admin' + h_capcodeIcon = " " when 'mod' - capcodeClass = " capcodeMod" - capcodeStart = " ## Mod" - capcodeIcon = " " + h_capcodeClass = ' capcodeMod' + h_capcodeStart = ' ## Mod' + h_capcodeIcon = " " when 'developer' - capcodeClass = " capcodeDeveloper" - capcodeStart = " ## Developer" - capcodeIcon = " " + h_capcodeClass = ' capcodeDeveloper' + h_capcodeStart = ' ## Developer' + h_capcodeIcon = " " else - capcodeClass = '' - capcodeStart = '' - capcodeIcon = '' + h_capcodeClass = '' + h_capcodeStart = '' + h_capcodeIcon = '' - userID = - if !capcode and uniqueID - " (ID: " + - "#{uniqueID}) " - else - '' - - flag = unless flagCode - '' - else if boardID is 'pol' - " #{flagCode}" + if !capcode and uniqueID + h_userID = " (ID: #{E uniqueID}) " else - " " + h_userID = '' + + unless flagCode + h_flag = '' + else if boardID is 'pol' + h_flag = " #{E flagCode}" + else + h_flag = " " if file?.isDeleted - fileHTML = if isOP - "
" + - "File deleted." + - "
" + if isOP + h_file = "
" + h_file += "File deleted." + h_file += '
' else - "
" + - "File deleted." + - "
" + h_file = "
" + h_file += "File deleted." + h_file += '
' else if file fileSize = $.bytesToString file.size fileThumb = file.turl if file.isSpoiler fileSize = "Spoiler Image, #{fileSize}" unless isArchived - fileThumb = "#{staticPath}spoiler" + fileThumb = "#{h_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 + shortFilename = Build.shortFilename file.name - imgSrc = if boardID is 'f' - '' + if boardID is 'f' + h_imgSrc = '' else - "" + - "#{fileSize}" + - "" + h_imgSrc = "" + h_imgSrc += "#{E fileSize}" + h_imgSrc += '' - # 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, ''' + if file.url[-4..] is '.pdf' + h_fileDims = 'PDF' + else + h_fileDims = "#{+file.width}x#{+file.height}" + h_fileInfo = "
#{E shortFilename}" + h_fileInfo += ')
' - 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}
" + h_file = "
#{h_fileInfo}#{h_imgSrc}
" else - fileHTML = '' + h_file = '' - sticky = if isSticky - " Sticky" + if g.VIEW is 'thread' and g.THREADID is +threadID + h_quoteLink = "javascript:quote(#{+postID})" else - '' - closed = if isClosed - " Closed" + h_quoteLink = "/#{E boardID}/thread/#{+threadID}\#q#{+postID}" + + if isSticky + h_sticky = " Sticky" else - '' + h_sticky = '' + if isClosed + h_closed = " Closed" + else + h_closed = '' if isOP and g.VIEW is 'index' and Conf['JSON Navigation'] - pageNum = Math.floor Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage + 1 - pageIcon = " [#{pageNum}]" + pageNum = Math.floor(Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage) + 1 + h_pageIcon = " [#{+pageNum}]" else - pageIcon = '' + h_pageIcon = '' if isOP and g.VIEW is 'index' - replyLink = "   [Reply]" + h_replyLink = "   [Reply]" else - replyLink = '' + h_replyLink = '' container = $.el 'div', id: "pc#{postID}" diff --git a/src/General/Get.coffee b/src/General/Get.coffee index ad0a666e1..d9a0fee47 100755 --- a/src/General/Get.coffee +++ b/src/General/Get.coffee @@ -158,20 +158,20 @@ Get = return # convert comment to html - bq = $.el 'blockquote', textContent: data.comment # set this first to convert text to HTML entities + h_comment = Build.h_escape data.comment # https://github.com/eksopl/fuuka/blob/master/Board/Yotsuba.pm#L413-452 # https://github.com/eksopl/asagi/blob/master/src/main/java/net/easymodo/asagi/Yotsuba.java#L109-138 - bq.innerHTML = bq.innerHTML.replace /// + h_comment = h_comment.replace /// \n | \[/?[a-z]+(:lit)?\] ///g, Get.parseMarkup - comment = bq.innerHTML + h_comment = h_comment # greentext - .replace(/(^|>)(>[^<$]*)(<|$)/g, '$1$2$3') + .replace(/(^|>)(>[^<$]*)(<|$)/g, '$1$2$3') # quotes - .replace /((>){2}(>\/[a-z\d]+\/)?\d+)/g, '$1' + .replace /((>){2}(>\/[a-z\d]+\/)?\d+)/g, '$1' threadID = +data.thread_num o = @@ -180,24 +180,24 @@ Get = threadID: threadID boardID: boardID # info - name: data.name_processed + name: data.name capcode: switch data.capcode when 'M' then 'mod' when 'A' then 'admin' when 'D' then 'developer' tripcode: data.trip uniqueID: data.poster_hash - email: if data.email then encodeURI data.email else '' - subject: data.title_processed + email: data.email or '' + subject: data.title flagCode: data.poster_country - flagName: data.poster_country_name_processed + flagName: data.poster_country_name date: data.fourchan_date dateUTC: data.timestamp - comment: comment + h_comment: h_comment # file if data.media?.media_filename o.file = - name: data.media.media_filename_processed + name: data.media.media_filename timestamp: data.media.media_orig url: data.media.media_link or data.media.remote_media_link height: data.media.media_h @@ -223,7 +223,7 @@ Get = '[/b]': '' '[spoiler]': '' '[/spoiler]': '' - '[code]': '
'
+      '[code]':     '
'
       '[/code]':    '
' '[moot]': '
' '[/moot]': '
' diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index f228b9031..c091b15cc 100755 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -417,7 +417,7 @@ Settings = dimensions: '1280x720' isImage: true isSpoiler: true - @nextElementSibling.innerHTML = FileInfo.format @value, data + @nextElementSibling.innerHTML = FileInfo.h_format @value, data favicon: -> Favicon.switch() Unread.update() if g.VIEW is 'thread' and Conf['Unread Favicon'] diff --git a/src/General/html/Build/post.html b/src/General/html/Build/post.html index c92354f68..30147d121 100755 --- a/src/General/html/Build/post.html +++ b/src/General/html/Build/post.html @@ -1,36 +1,26 @@ -"""#{if isOP then '' else "
>>
"} -
+"""#{h_sideArrows} +
- #{if isOP then fileHTML else ''} + #{if isOP then h_file else ''} - """ diff --git a/src/Miscellaneous/FileInfo.coffee b/src/Miscellaneous/FileInfo.coffee index 2f89bbb26..4ec8b6183 100755 --- a/src/Miscellaneous/FileInfo.coffee +++ b/src/Miscellaneous/FileInfo.coffee @@ -7,39 +7,29 @@ FileInfo = cb: @node node: -> return if !@file or @isClone - @file.text.innerHTML = "#{FileInfo.format Conf['fileInfo'], @}" - format: (formatString, post) -> + @file.text.innerHTML = "#{FileInfo.h_format Conf['fileInfo'], @}" + h_format: (formatString, post) -> formatString.replace /%([A-Za-z])|[^%]+/g, (s, c) -> - if c of FileInfo.formatters - FileInfo.formatters[c].call(post) + if c of FileInfo.h_formatters + FileInfo.h_formatters[c].call(post) else - Build.escape s - convertUnit: (size, unit) -> - if unit is 'B' - return "#{size.toFixed()} Bytes" - i = 1 + ['KB', 'MB'].indexOf unit - size /= 1024 while i-- - size = if unit is 'MB' - Math.round(size * 100) / 100 - else - size.toFixed() - "#{size} #{unit}" - formatters: - t: -> Build.escape @file.URL.match(/\d+\..+$/)[0] - T: -> "#{FileInfo.formatters.t.call @}" - l: -> "#{FileInfo.formatters.n.call @}" - L: -> "#{FileInfo.formatters.N.call @}" + Build.h_escape s + h_formatters: + t: -> Build.h_escape @file.URL.match(/\d+\..+$/)[0] + T: -> "#{FileInfo.h_formatters.t.call @}" + l: -> "#{FileInfo.h_formatters.n.call @}" + L: -> "#{FileInfo.h_formatters.N.call @}" n: -> fullname = @file.name shortname = Build.shortFilename @file.name, @isReply if fullname is shortname - Build.escape fullname + Build.h_escape fullname else - "#{Build.escape shortname}#{Build.escape fullname}" - N: -> Build.escape @file.name + "#{Build.h_escape shortname}#{Build.h_escape fullname}" + N: -> Build.h_escape @file.name p: -> if @file.isSpoiler then 'Spoiler, ' else '' - s: -> Build.escape @file.size - B: -> FileInfo.convertUnit @file.sizeInBytes, 'B' - K: -> FileInfo.convertUnit @file.sizeInBytes, 'KB' - M: -> FileInfo.convertUnit @file.sizeInBytes, 'MB' - r: -> Build.escape (@file.dimensions or 'PDF') + s: -> Build.h_escape @file.size + B: -> return "#{+@file.sizeInBytes} Bytes" + K: -> "#{+Math.round(@file.sizeInBytes/1024)} KB" + M: -> "#{+Math.round(@file.sizeInBytes/1048576*100)/100} MB" + r: -> Build.h_escape (@file.dimensions or 'PDF')