HTML templates

This commit is contained in:
ccd0 2014-08-02 22:43:01 -07:00
parent 36fad05cab
commit cff287c9c3
25 changed files with 278 additions and 284 deletions

View File

@ -1,7 +1,30 @@
module.exports = (grunt) -> module.exports = (grunt) ->
importHTML = (filename) -> importHTML = (filename) ->
"'''#{grunt.file.read("src/General/html/#{filename}.html").replace(/^\s+|\s+$</gm, '').replace(/\n/g, '')}'''" "(innerHTML: #{JSON.stringify grunt.file.read("src/General/html/#{filename}.html").replace(/^\s+|\s+$</gm, '').replace(/\n/g, '')})"
html = (template) ->
parts = template.split /([\$&@]){([^}]*)}/
parts2 = []
checkText = ''
for part, i in parts
switch i % 3
when 0
parts2.push JSON.stringify part unless part is ''
checkText += part
when 1
if /<[^>]*$/.test(checkText) and not (part is '$' and /\=['"][^"'<>]*$/.test checkText)
throw new Error "Illegal insertion into HTML template: #{template}"
expr = parts[i+1]
expr = "(#{expr})" for x in parts[i+1].split ')'
parts2.push switch part
when '$' then "E#{expr}"
when '&' then "#{expr}.innerHTML"
when '@' then "#{expr}.map((x) -> x.innerHTML).join('')"
unless /^(<\w+( [\w-]+(='[^"'<>]*'|="[^"'<>]*")?)*>|<\/\w+>|[^"'<>]*)*$/.test checkText
throw new Error "HTML template is ill-formed: #{template}"
output = if parts2.length is 0 then '""' else parts2.join ' + '
"(innerHTML: #{output})"
# Project configuration. # Project configuration.
grunt.initConfig grunt.initConfig
@ -12,6 +35,7 @@ module.exports = (grunt) ->
get: -> get: ->
pkg = grunt.config 'pkg' pkg = grunt.config 'pkg'
pkg.importHTML = importHTML pkg.importHTML = importHTML
pkg.html = html
pkg.tests_enabled or= false pkg.tests_enabled or= false
pkg pkg
enumerable: true enumerable: true

View File

@ -137,8 +137,8 @@ ThreadHiding =
makeButton: (thread, type) -> makeButton: (thread, type) ->
a = $.el 'a', a = $.el 'a',
className: "#{type}-thread-button" className: "#{type}-thread-button"
innerHTML: "<span class='fa fa-#{if type is 'hide' then 'minus' else 'plus'}-square'></span>"
href: 'javascript:;' href: 'javascript:;'
$.extend a, <%= html('<span class="fa fa-${if type is "hide" then "minus" else "plus"}-square"></span>') %>
a.dataset.fullID = thread.fullID a.dataset.fullID = thread.fullID
$.on a, 'click', ThreadHiding.toggle $.on a, 'click', ThreadHiding.toggle
a a

View File

@ -39,7 +39,7 @@ Build =
flagName: Build.unescape data.country_name flagName: Build.unescape data.country_name
date: data.now date: data.now
dateUTC: data.time dateUTC: data.time
h_comment: data.com or '' comment: {innerHTML: data.com or ''}
# thread status # thread status
isSticky: !!data.sticky isSticky: !!data.sticky
isClosed: !!data.closed isClosed: !!data.closed
@ -75,86 +75,75 @@ Build =
postID, threadID, boardID postID, threadID, boardID
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
isSticky, isClosed isSticky, isClosed
comment
file file
} = o } = o
name or= '' name or= ''
subject or= '' subject or= ''
h_comment = o.h_comment
isOP = postID is threadID isOP = postID is threadID
if Build.initPixelRatio >= 2 retina = if Build.initPixelRatio >= 2 then '@2x' else ''
h_retina = '@2x'
else
h_retina = ''
### Name Block ### ### Name Block ###
switch capcode switch capcode
when 'admin', 'admin_highlight' when 'admin', 'admin_highlight'
h_capcodeClass = ' capcodeAdmin' capcodeClass = ' capcodeAdmin'
h_capcodeStart = ' <strong class="capcode hand id_admin" title="Highlight posts by the Administrator">## Admin</strong>' capcodeStart = <%= html(' <strong class="capcode hand id_admin" title="Highlight posts by the Administrator">## Admin</strong>') %>
h_capcodeIcon = "<img src='//s.4cdn.org/image/adminicon#{h_retina}.gif' alt='Admin Icon' title='This user is the 4chan Administrator.' class='identityIcon retina'>" capcodeIcon = <%= html('<img src="//s.4cdn.org/image/adminicon${retina}.gif" alt="Admin Icon" title="This user is the 4chan Administrator." class="identityIcon retina">') %>
when 'mod' when 'mod'
h_capcodeClass = ' capcodeMod' capcodeClass = ' capcodeMod'
h_capcodeStart = ' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>' capcodeStart = <%= html(' <strong class="capcode hand id_mod" title="Highlight posts by Moderators">## Mod</strong>') %>
h_capcodeIcon = "<img src='//s.4cdn.org/image/modicon#{h_retina}.gif' alt='Mod Icon' title='This user is a 4chan Moderator.' class='identityIcon retina'>" capcodeIcon = <%= html('<img src="//s.4cdn.org/image/modicon${retina}.gif" alt="Mod Icon" title="This user is a 4chan Moderator." class="identityIcon retina">') %>
when 'developer' when 'developer'
h_capcodeClass = ' capcodeDeveloper' capcodeClass = ' capcodeDeveloper'
h_capcodeStart = ' <strong class="capcode hand id_developer" title="Highlight posts by Developers">## Developer</strong>' capcodeStart = <%= html(' <strong class="capcode hand id_developer" title="Highlight posts by Developers">## Developer</strong>') %>
h_capcodeIcon = "<img src='//s.4cdn.org/image/developericon#{h_retina}.gif' alt='Developer Icon' title='This user is a 4chan Developer.' class='identityIcon retina'>" capcodeIcon = <%= html('<img src="//s.4cdn.org/image/developericon${retina}.gif" alt="Developer Icon" title="This user is a 4chan Developer." class="identityIcon retina">') %>
else else
h_capcodeClass = '' capcodeClass = ''
h_capcodeStart = '' capcodeStart = <%= html('') %>
h_capcodeIcon = '' capcodeIcon = <%= html('') %>
if capcode nameClass = if capcode then ' capcode' else ''
h_nameClass = ' capcode'
tripcodeField = if tripcode
<%= html(' <span class="postertrip">${tripcode}</span>') %>
else else
h_nameClass = '' <%= html('') %>
if tripcode emailField = <%= html('<span class="name${nameClass}">${name}</span>&{tripcodeField}&{capcodeStart}') %>
h_tripcode = " <span class='postertrip'>#{E tripcode}</span>"
else
h_tripcode = ''
h_emailCont = "<span class='name#{h_nameClass}'>#{E name}</span>#{h_tripcode}#{h_capcodeStart}"
if email if email
emailProcessed = encodeURIComponent(email).replace /%40/g, '@' emailProcessed = encodeURIComponent(email).replace /%40/g, '@'
h_email = "<a href='mailto:#{E emailProcessed}' class='useremail'>#{h_emailCont}</a>" emailField = <%= html('<a href="mailto:${emailProcessed}" class="useremail">&{emailField}</a>') %>
else
h_email = h_emailCont
unless isOP and boardID is 'f' unless isOP and boardID is 'f'
h_email += ' ' emailField = <%= html('&{emailField} ') %>
if !capcode and uniqueID userID = if !capcode and uniqueID
h_userID = " <span class='posteruid id_#{E uniqueID}'>(ID: <span class='hand' title='Highlight posts by this ID'>#{E uniqueID}</span>)</span>" <%= html(' <span class="posteruid id_${uniqueID}">(ID: <span class="hand" title="Highlight posts by this ID">${uniqueID}</span>)</span>') %>
else else
h_userID = '' <%= html('') %>
unless flagCode flag = unless flagCode
h_flag = '' <%= html('') %>
else if boardID is 'pol'
<%= html('<img src="//s.4cdn.org/image/country/troll/${flagCode.toLowerCase()}.gif" alt="${flagCode}" title="${flagName}" class="countryFlag">') %>
else else
flagCodeLC = flagCode.toLowerCase() <%= html('<span title="${flagName}" class="flag flag-${flagCode.toLowerCase()}"></span>') %>
if boardID is 'pol'
h_flag = "<img src='//s.4cdn.org/image/country/troll/#{E flagCodeLC}.gif' alt='#{E flagCode}' title='#{E flagName}' class='countryFlag'>"
else
h_flag = "<span title='#{E flagName}' class='flag flag-#{E flagCodeLC}'></span>"
h_nameBlock = "<span class='nameBlock#{h_capcodeClass}'>" nameBlock = <%= html(
h_nameBlock += "#{h_email}#{h_capcodeIcon}#{h_userID}#{h_flag}" '<span class="nameBlock${capcodeClass}">' +
h_nameBlock += '</span> ' '&{emailField}&{capcodeIcon}&{userID}&{flag}' +
'</span> '
) %>
### Post Info ### ### Post Info ###
if isOP or boardID is 'f' subjectField = if isOP or boardID is 'f'
h_subject = "<span class='subject'>#{E subject}</span> " <%= html('<span class="subject">${subject}</span> ') %>
else else
h_subject = '' <%= html('') %>
if isOP and boardID is 'f' desktop2 = if isOP and boardID is 'f' then '' else ' desktop'
h_desktop2 = ''
else
h_desktop2 = ' desktop'
postLink = Build.postURL boardID, threadID, postID postLink = Build.postURL boardID, threadID, postID
quoteLink = if Build.sameThread boardID, threadID quoteLink = if Build.sameThread boardID, threadID
@ -162,56 +151,59 @@ Build =
else else
"/#{boardID}/thread/#{threadID}\#q#{postID}" "/#{boardID}/thread/#{threadID}\#q#{postID}"
if isOP and g.VIEW is 'index' and Conf['JSON Navigation'] pageIcon = if isOP and g.VIEW is 'index' and Conf['JSON Navigation']
pageNum = Math.floor(Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage) + 1 pageNum = Math.floor(Index.liveThreadIDs.indexOf(postID) / Index.threadsNumPerPage) + 1
h_pageIcon = " <span class='page-num' title='This thread is on page #{+pageNum} in the original index.'>[#{+pageNum}]</span>" <%= html(' <span class="page-num" title="This thread is on page ${pageNum} in the original index.">[${pageNum}]</span>') %>
else else
h_pageIcon = '' <%= html('') %>
if isSticky sticky = if isSticky
h_sticky = " <img src='//s.4cdn.org/image/sticky#{h_retina}.gif' alt='Sticky' title='Sticky' class='stickyIcon retina'>" <%= html(' <img src="//s.4cdn.org/image/sticky${retina}.gif" alt="Sticky" title="Sticky" class="stickyIcon retina">') %>
else else
h_sticky = '' <%= html('') %>
if isClosed closed = if isClosed
h_closed = " <img src='//s.4cdn.org/image/closed#{h_retina}.gif' alt='Closed' title='Closed' class='closedIcon retina'>" <%= html(' <img src="//s.4cdn.org/image/closed${retina}.gif" alt="Closed" title="Closed" class="closedIcon retina">') %>
else else
h_closed = '' <%= html('') %>
if isOP and g.VIEW is 'index' replyLink = if isOP and g.VIEW is 'index'
h_replyLink = " &nbsp; <span>[<a href='/#{E boardID}/thread/#{+threadID}' class='replylink'>Reply</a>]</span>" <%= html(' &nbsp; <span>[<a href="/${boardID}/thread/${threadID}" class="replylink">Reply</a>]</span>') %>
else else
h_replyLink = '' <%= html('') %>
h_postInfo = "<div class='postInfo desktop' id='pi#{+postID}'>" postInfo = <%= html(
h_postInfo += "<input type='checkbox' name='#{+postID}' value='delete'> " '<div class="postInfo desktop" id="pi${postID}">' +
h_postInfo += h_subject '<input type="checkbox" name="${postID}" value="delete"> ' +
h_postInfo += h_nameBlock '&{subjectField}' +
h_postInfo += "<span class='dateTime' data-utc='#{+dateUTC}'>#{E date}</span> " '&{nameBlock}' +
h_postInfo += "<span class='postNum#{h_desktop2}'>" '<span class="dateTime" data-utc="${dateUTC}">${date}</span> ' +
h_postInfo += "<a href='#{E postLink}' title='Link to this post'>No.</a>" '<span class="postNum${desktop2}">' +
h_postInfo += "<a href='#{E quoteLink}' title='Reply to this post'>#{+postID}</a>" '<a href="${postLink}" title="Link to this post">No.</a>' +
h_postInfo += "#{h_pageIcon}#{h_sticky}#{h_closed}#{h_replyLink}" '<a href="${quoteLink}" title="Reply to this post">${postID}</a>' +
h_postInfo += '</span>' '&{pageIcon}&{sticky}&{closed}&{replyLink}' +
h_postInfo += '</div>' '</span>' +
'</div>'
) %>
### File Info ### ### File Info ###
if file?.isDeleted fileCont = if file?.isDeleted
h_fileCont = '<span class="fileThumb">' <%= html(
h_fileCont += "<img src='//s.4cdn.org/image/filedeleted-res#{h_retina}.gif' alt='File deleted.' class='fileDeletedRes retina'>" '<span class="fileThumb">' +
h_fileCont += '</span>' '<img src="//s.4cdn.org/image/filedeleted-res${retina}.gif" alt="File deleted." class="fileDeletedRes retina">' +
'</span>'
) %>
else if file and boardID is 'f' else if file and boardID is 'f'
fileSize = $.bytesToString file.size <%= html(
h_fileCont = "<div class='fileInfo'><span class='fileText' id='fT#{+postID}'>" '<div class="fileInfo"><span class="fileText" id="fT${postID}">' +
h_fileCont += "File: <a data-width='#{+file.width}' data-height='#{+file.height}' href='#{E file.url}' target='_blank'>#{E file.name}</a>" 'File: <a data-width="${file.width}" data-height="${+file.height}" href="${file.url}" target="_blank">${file.name}</a>' +
h_fileCont += "-(#{E fileSize}, #{+file.width}x#{+file.height}, #{E file.tag})" '-(${$.bytesToString file.size}, ${file.width}x${file.height}, ${file.tag})' +
h_fileCont += '</span></div>' '</span></div>'
) %>
else if file else if file
if file.isSpoiler if file.isSpoiler
h_fileTitle1 = "title='#{E file.name}'"
shortFilename = 'Spoiler Image' shortFilename = 'Spoiler Image'
h_spoilerClass = ' imgspoiler'
if spoilerRange = Build.spoilerRange[boardID] if spoilerRange = Build.spoilerRange[boardID]
# Randomize the spoiler image. # Randomize the spoiler image.
fileThumb = "//s.4cdn.org/image/spoiler-#{boardID}#{Math.floor 1 + spoilerRange * Math.random()}.png" fileThumb = "//s.4cdn.org/image/spoiler-#{boardID}#{Math.floor 1 + spoilerRange * Math.random()}.png"
@ -219,58 +211,58 @@ Build =
fileThumb = '//s.4cdn.org/image/spoiler.png' fileThumb = '//s.4cdn.org/image/spoiler.png'
file.twidth = file.theight = 100 file.twidth = file.theight = 100
else else
h_fileTitle1 = ''
shortFilename = Build.shortFilename file.name, !isOP shortFilename = Build.shortFilename file.name, !isOP
h_spoilerClass = ''
fileThumb = file.turl fileThumb = file.turl
if file.isSpoiler or file.name is shortFilename fileSize = $.bytesToString file.size
h_fileTitle2 = '' 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('<a href="${file.url}" target="_blank">${shortFilename}</a>') %>
else else
h_fileTitle2 = "title='#{E file.name}'" <%= html('<a title="${file.name}" href="${file.url}" target="_blank">${shortFilename}</a>') %>
fileSize = $.bytesToString file.size fileText = if file.isSpoiler
<%= html('<div class="fileText" id="fT${postID}" title="${file.name}">File: &{fileLink} (${fileSize}, ${fileDims})</div>') %>
if file.url[-4..] is '.pdf'
h_fileDims = 'PDF'
else else
h_fileDims = "#{+file.width}x#{+file.height}" <%= html('<div class="fileText" id="fT${postID}">File: &{fileLink} (${fileSize}, ${fileDims})</div>') %>
h_fileCont = "<div class='fileText' id='fT#{+postID}' #{h_fileTitle1}>" <%= html(
h_fileCont += "File: <a #{h_fileTitle2} href='#{E file.url}' target='_blank'>#{E shortFilename}</a> (#{E fileSize}, #{h_fileDims})" '&{fileText}' +
h_fileCont += '</div>' '<a class="fileThumb${if file.isSpoiler then " imgspoiler" else ""}" href="${file.url}" target="_blank">' +
h_fileCont += "<a class='fileThumb#{h_spoilerClass}' href='#{E file.url}' target='_blank'>" '<img src="${fileThumb}" alt="${fileSize}" data-md5="${file.MD5}" style="height: ${file.theight}px; width: ${+file.twidth}px;">' +
h_fileCont += "<img src='#{E fileThumb}' alt='#{E fileSize}' data-md5='#{E file.MD5}' style='height: #{+file.theight}px; width: #{+file.twidth}px;'>" '</a>'
h_fileCont += '</a>' ) %>
if file fileBlock = if file
h_file = "<div class='file' id='f#{+postID}'>#{h_fileCont}</div>" <%= html('<div class="file" id="f${postID}">&{fileCont}</div>') %>
else else
h_file = '' <%= html('') %>
### Whole Post ### ### Whole Post ###
if capcode is 'admin_highlight' highlightPost = if capcode is 'admin_highlight' then ' highlightPost' else ''
h_highlightPost = ' highlightPost'
else
h_highlightPost = ''
h_message = "<blockquote class='postMessage' id='m#{+postID}'>#{h_comment}</blockquote>" message = <%= html('<blockquote class="postMessage" id="m${postID}">&{comment}</blockquote>') %>
if isOP wholePost = if isOP
h_post = "<div id='p#{+postID}' class='post op#{h_highlightPost}'>" <%= html(
h_post += "#{h_file}#{h_postInfo}#{h_message}" '<div id="p${postID}" class="post op${highlightPost}">' +
h_post += '</div>' '&{fileBlock}&{postInfo}&{message}' +
'</div>'
) %>
else else
h_post = "<div class='sideArrows' id='sa#{+postID}'>&gt;&gt;</div>" <%= html(
h_post += "<div id='p#{+postID}' class='post reply#{h_highlightPost}'>" '<div class="sideArrows" id="sa${postID}">&gt;&gt;</div>' +
h_post += "#{h_postInfo}#{h_file}#{h_message}" '<div id="p${postID}" class="post reply${highlightPost}">' +
h_post += '</div>' '&{postInfo}&{fileBlock}&{message}' +
'</div>'
) %>
container = $.el 'div', container = $.el 'div',
className: "postContainer #{if isOP then 'op' else 'reply'}Container" className: "postContainer #{if isOP then 'op' else 'reply'}Container"
id: "pc#{postID}" id: "pc#{postID}"
innerHTML: h_post $.extend container, wholePost
# Fix pathnames # Fix pathnames
for quote in $$ '.quotelink', container for quote in $$ '.quotelink', container

View File

@ -159,21 +159,24 @@ Get =
root.textContent = data.error root.textContent = data.error
return return
# convert comment to html
h_comment = E (data.comment or '')
# https://github.com/eksopl/fuuka/blob/master/Board/Yotsuba.pm#L413-452 # 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 # https://github.com/eksopl/asagi/blob/master/src/main/java/net/easymodo/asagi/Yotsuba.java#L109-138
h_comment = h_comment.replace /// comment = (data.comment or '').split /(\n|\[\/?(?:b|spoiler|code|moot|banned)\])/
\n comment = for text, i in comment
| if i % 2 is 1
\[/?[a-z]+(:lit)?\] Get.archiveTags[text]
///g, Get.parseMarkup else
greentext = text[0] is '>'
h_comment = h_comment text = text.replace /(\[\/?[a-z]+):lit(\])/, '$1$2'
# greentext text = for text2, j in text.split /(>>(?:>\/[a-z\d]+\/)?\d+)/g
.replace(/(^|>)(&gt;[^<$]*)(<|$)/g, '$1<span class="quote">$2</span>$3') if j % 2 is 1
# quotes <%= html('<span class="deadlink">${text2}</span>') %>
.replace /((&gt;){2}(&gt;\/[a-z\d]+\/)?\d+)/g, '<span class="deadlink">$1</span>' else
<%= html('${text2}') %>
text = <%= html('@{text}') %>
text = <%= html('<span class="quote">&{text}</span>') %> if greentext
text
comment = <%= html('@{comment}') %>
threadID = +data.thread_num threadID = +data.thread_num
o = o =
@ -195,7 +198,7 @@ Get =
flagName: data.poster_country_name flagName: data.poster_country_name
date: data.fourchan_date date: data.fourchan_date
dateUTC: data.timestamp dateUTC: data.timestamp
h_comment: h_comment comment: comment
# file # file
if data.media?.media_filename if data.media?.media_filename
o.file = o.file =
@ -221,17 +224,15 @@ Get =
post.isFetchedQuote = true post.isFetchedQuote = true
Main.callbackNodes Post, [post] Main.callbackNodes Post, [post]
Get.insert post, root, context Get.insert post, root, context
parseMarkup: (text) -> archiveTags:
{ '\n': <%= html('<br>') %>
'\n': '<br>' '[b]': <%= html('<b>') %>
'[b]': '<b>' '[/b]': <%= html('</b>') %>
'[/b]': '</b>' '[spoiler]': <%= html('<s>') %>
'[spoiler]': '<s>' '[/spoiler]': <%= html('</s>') %>
'[/spoiler]': '</s>' '[code]': <%= html('<pre class="prettyprint">') %>
'[code]': '<pre class="prettyprint">' '[/code]': <%= html('</pre>') %>
'[/code]': '</pre>' '[moot]': <%= html('<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">') %>
'[moot]': '<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">' '[/moot]': <%= html('</div>') %>
'[/moot]': '</div>' '[banned]': <%= html('<strong style="color: red;">') %>
'[banned]': '<strong style="color: red;">' '[/banned]': <%= html('</strong>') %>
'[/banned]': '</strong>'
}[text] or text.replace ':lit', ''

View File

@ -5,6 +5,9 @@ doc = d.documentElement
g = g =
VERSION: '<%= version %>' VERSION: '<%= version %>'
NAMESPACE: '<%= meta.name %>.' NAMESPACE: '<%= meta.name %>.'
NAME: '<%= meta.name %>'
FAQ: '<%= meta.faq %>'
CHANGELOG: '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md'
boards: {} boards: {}
E = (text) -> E = (text) ->
(text+'').replace /[&"'<>]/g, (x) -> (text+'').replace /[&"'<>]/g, (x) ->

View File

@ -4,7 +4,7 @@ Header =
menuButton = $.el 'span', menuButton = $.el 'span',
className: 'menu-button' className: 'menu-button'
innerHTML: '<i></i>' $.extend menuButton, <%= html('<i></i>') %>
barFixedToggler = UI.checkbox 'Fixed Header', ' Fixed Header' barFixedToggler = UI.checkbox 'Fixed Header', ' Fixed Header'
headerToggler = UI.checkbox 'Header auto-hide', ' Auto-hide header' headerToggler = UI.checkbox 'Header auto-hide', ' Auto-hide header'
@ -132,7 +132,13 @@ Header =
fourchannav = $.id 'boardNavDesktop' fourchannav = $.id 'boardNavDesktop'
Header.boardList = boardList = $.el 'span', Header.boardList = boardList = $.el 'span',
id: 'board-list' id: 'board-list'
innerHTML: "<span id='custom-board-list'></span><span id='full-board-list' hidden><span class='hide-board-list-container brackets-wrap'><a href='javascript:;' class='hide-board-list-button'>&nbsp;-&nbsp;</a></span> #{fourchannav.innerHTML}</span>" $.extend boardList, <%= html(
'<span id="custom-board-list"></span>' +
'<span id="full-board-list" hidden>' +
'<span class="hide-board-list-container brackets-wrap"><a href="javascript:;" class="hide-board-list-button">&nbsp;-&nbsp;</a></span> ' +
'&{fourchannav}' +
'</span>'
) %>
for a in $$ 'a', boardList for a in $$ 'a', boardList
if a.pathname.split('/')[1] is g.BOARD.ID if a.pathname.split('/')[1] is g.BOARD.ID
a.className = 'current' a.className = 'current'
@ -442,11 +448,11 @@ Header =
return return
el = $.el 'span', el = $.el 'span',
innerHTML: ''' <%= html(
<%= meta.name %> needs your permission to show desktop notifications. '${g.NAME} needs your permission to show desktop notifications. ' +
[<a href='<%= meta.faq %>#why-is-4chan-x-asking-for-permission-to-show-desktop-notifications' target=_blank>FAQ</a>]<br> '[<a href="${g.FAQ}#why-is-4chan-x-asking-for-permission-to-show-desktop-notifications" target="_blank">FAQ</a>]<br>' +
<button>Authorize</button> or <button>Disable</button> '<button>Authorize</button> or <button>Disable</button>'
''' ) %>
[authorize, disable] = $$ 'button', el [authorize, disable] = $$ 'button', el
$.on authorize, 'click', -> $.on authorize, 'click', ->
Notification.requestPermission (status) -> Notification.requestPermission (status) ->

View File

@ -15,9 +15,9 @@ Index =
modeEntry = modeEntry =
el: $.el 'span', textContent: 'Index mode' el: $.el 'span', textContent: 'Index mode'
subEntries: [ subEntries: [
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Mode" value="paged"> Paged' } { el: $.el 'label', <%= html('<input type="radio" name="Index Mode" value="paged"> Paged') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Mode" value="infinite"> Infinite scrolling' } { el: $.el 'label', <%= html('<input type="radio" name="Index Mode" value="infinite"> Infinite scrolling') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Mode" value="all pages"> All threads' } { el: $.el 'label', <%= html('<input type="radio" name="Index Mode" value="all pages"> All threads') %> }
] ]
for label in modeEntry.subEntries for label in modeEntry.subEntries
input = label.el.firstChild input = label.el.firstChild
@ -28,11 +28,11 @@ Index =
sortEntry = sortEntry =
el: $.el 'span', textContent: 'Sort by' el: $.el 'span', textContent: 'Sort by'
subEntries: [ subEntries: [
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Sort" value="bump"> Bump order' } { el: $.el 'label', <%= html('<input type="radio" name="Index Sort" value="bump"> Bump order') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Sort" value="lastreply"> Last reply' } { el: $.el 'label', <%= html('<input type="radio" name="Index Sort" value="lastreply"> Last reply') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Sort" value="birth"> Creation date' } { el: $.el 'label', <%= html('<input type="radio" name="Index Sort" value="birth"> Creation date') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Sort" value="replycount"> Reply count' } { el: $.el 'label', <%= html('<input type="radio" name="Index Sort" value="replycount"> Reply count') %> }
{ el: $.el 'label', innerHTML: '<input type="radio" name="Index Sort" value="filecount"> File count' } { el: $.el 'label', <%= html('<input type="radio" name="Index Sort" value="filecount"> File count') %> }
] ]
for label in sortEntry.subEntries for label in sortEntry.subEntries
input = label.el.firstChild input = label.el.firstChild
@ -66,10 +66,10 @@ Index =
@pagelist = $.el 'div', @pagelist = $.el 'div',
className: 'pagelist' className: 'pagelist'
hidden: true hidden: true
innerHTML: <%= importHTML('Features/Index-pagelist') %> $.extend @pagelist, <%= importHTML('Features/Index-pagelist') %>
@navLinks = $.el 'div', @navLinks = $.el 'div',
className: 'navLinks' className: 'navLinks'
innerHTML: <%= importHTML('Features/Index-navlinks') %> $.extend @navLinks, <%= importHTML('Features/Index-navlinks') %>
$('.returnlink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/" $('.returnlink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/"
$('.cataloglink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/catalog" $('.cataloglink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/catalog"
@searchInput = $ '#index-search', @navLinks @searchInput = $ '#index-search', @navLinks

View File

@ -189,7 +189,7 @@ Main =
return if previousversion is g.VERSION return if previousversion is g.VERSION
if previousversion if previousversion
el = $.el 'span', el = $.el 'span',
innerHTML: '<%= meta.name %> has been updated to <a href="<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md" target="_blank">version <%= version %></a>.' <%= html('${g.NAME} has been updated to <a href="${g.CHANGELOG}" target="_blank">version ${g.VERSION}</a>.') %>
new Notice 'info', el, 15 new Notice 'info', el, 15
else else
Settings.open() Settings.open()
@ -230,7 +230,7 @@ Main =
return return
div = $.el 'div', div = $.el 'div',
innerHTML: "#{+errors.length} errors occurred. [<a href='javascript:;'>show</a>]" <%= html('${errors.length} errors occurred. [<a href="javascript:;">show</a>]') %>
$.on div.lastElementChild, 'click', -> $.on div.lastElementChild, 'click', ->
[@textContent, logs.hidden] = if @textContent is 'show' [@textContent, logs.hidden] = if @textContent is 'show'
['hide', false] ['hide', false]

View File

@ -34,7 +34,7 @@ Settings =
Settings.dialog = dialog = $.el 'div', Settings.dialog = dialog = $.el 'div',
id: 'fourchanx-settings' id: 'fourchanx-settings'
className: 'dialog' className: 'dialog'
innerHTML: <%= importHTML('Settings/Settings') %> $.extend dialog, <%= importHTML('Settings/Settings') %>
$.on $('.export', Settings.dialog), 'click', Settings.export $.on $('.export', Settings.dialog), 'click', Settings.export
$.on $('.import', Settings.dialog), 'click', Settings.import $.on $('.import', Settings.dialog), 'click', Settings.import
@ -90,8 +90,7 @@ Settings =
inputs = {} inputs = {}
for key, obj of Config.main for key, obj of Config.main
fs = $.el 'fieldset', fs = $.el 'fieldset',
innerHTML: '<legend></legend>' <%= html('<legend>${key}</legend>') %>
fs.firstElementChild.textContent = key
for key, arr of obj for key, arr of obj
description = arr[1] description = arr[1]
div = $.el 'div' div = $.el 'div'
@ -112,7 +111,7 @@ Settings =
return return
div = $.el 'div', div = $.el 'div',
innerHTML: '<button></button><span class="description">: Clear manually-hidden threads and posts on all boards. Reload the page to apply.' <%= html('<button></button><span class="description">: Clear manually-hidden threads and posts on all boards. Reload the page to apply.') %>
button = $ 'button', div button = $ 'button', div
$.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) -> $.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) ->
hiddenNum = 0 hiddenNum = 0
@ -247,7 +246,7 @@ Settings =
$.clear -> window.location.reload() if confirm 'Reset successful. Reload now?' $.clear -> window.location.reload() if confirm 'Reset successful. Reload now?'
filter: (section) -> filter: (section) ->
section.innerHTML = <%= importHTML('Settings/Filter-select') %> $.extend section, <%= importHTML('Settings/Filter-select') %>
select = $ 'select', section select = $ 'select', section
$.on select, 'change', Settings.selectFilter $.on select, 'change', Settings.selectFilter
Settings.selectFilter.call select Settings.selectFilter.call select
@ -265,11 +264,11 @@ Settings =
$.on ta, 'change', $.cb.value $.on ta, 'change', $.cb.value
$.add div, ta $.add div, ta
return return
div.innerHTML = <%= importHTML('Settings/Filter-guide') %> $.extend div, <%= importHTML('Settings/Filter-guide') %>
$('.warning', div).hidden = Conf['Filter'] $('.warning', div).hidden = Conf['Filter']
sauce: (section) -> sauce: (section) ->
section.innerHTML = <%= importHTML('Settings/Sauce') %> $.extend section, <%= importHTML('Settings/Sauce') %>
$('.warning', section).hidden = Conf['Sauce'] $('.warning', section).hidden = Conf['Sauce']
ta = $ 'textarea', section ta = $ 'textarea', section
$.get 'sauces', Conf['sauces'], (item) -> $.get 'sauces', Conf['sauces'], (item) ->
@ -277,7 +276,7 @@ Settings =
$.on ta, 'change', $.cb.value $.on ta, 'change', $.cb.value
advanced: (section) -> advanced: (section) ->
section.innerHTML = <%= importHTML('Settings/Advanced') %> $.extend section, <%= importHTML('Settings/Advanced') %>
warning.hidden = Conf[warning.dataset.feature] for warning in $$ '.warning', section warning.hidden = Conf[warning.dataset.feature] for warning in $$ '.warning', section
items = {} items = {}
@ -387,7 +386,7 @@ Settings =
textContent: archive textContent: archive
value: archive value: archive
td.innerHTML = '<select></select>' $.extend td, <%= html('<select></select>') %>
select = td.firstElementChild select = td.firstElementChild
unless select.disabled = length is 1 unless select.disabled = length is 1
# XXX GM can't into datasets # XXX GM can't into datasets
@ -441,7 +440,7 @@ Settings =
CustomCSS.update() CustomCSS.update()
keybinds: (section) -> keybinds: (section) ->
section.innerHTML = <%= importHTML('Settings/Keybinds') %> $.extend section, <%= importHTML('Settings/Keybinds') %>
$('.warning', section).hidden = Conf['Keybinds'] $('.warning', section).hidden = Conf['Keybinds']
tbody = $ 'tbody', section tbody = $ 'tbody', section
@ -449,8 +448,7 @@ Settings =
inputs = {} inputs = {}
for key, arr of Config.hotkeys for key, arr of Config.hotkeys
tr = $.el 'tr', tr = $.el 'tr',
innerHTML: '<td></td><td><input class="field"></td>' <%= html('<td>${arr[1]}</td><td><input class="field"></td>') %>
tr.firstElementChild.textContent = arr[1]
input = $ 'input', tr input = $ 'input', tr
input.name = key input.name = key
input.spellcheck = false input.spellcheck = false

View File

@ -46,9 +46,11 @@ $.ajax = do ->
blockedError = (url) -> blockedError = (url) ->
return if blockedURLs[url] return if blockedURLs[url]
blockedURLs[url] = true blockedURLs[url] = true
h_message = '<%= meta.name %> was blocked from loading the following URL:<br><span></span><br>' message = $.el 'div',
h_message += '[<a href="<%= meta.faq %>#why-was-4chan-x-blocked-from-loading-a-url" target="_blank">More info</a>]' <%= html(
message = $.el 'div', innerHTML: h_message '${g.NAME} was blocked from loading the following URL:<br><span></span><br>' +
'[<a href="${g.FAQ}#why-was-4chan-x-blocked-from-loading-a-url" target="_blank">More info</a>]'
) %>
$('span', message).textContent = (if /^\/\//.test url then location.protocol else '') + url $('span', message).textContent = (if /^\/\//.test url then location.protocol else '') + url
new Notice 'error', message, 30, -> delete blockedURLs[url] new Notice 'error', message, 30, -> delete blockedURLs[url]
(url, options, extra={}) -> (url, options, extra={}) ->

View File

@ -1,7 +1,7 @@
class Notice class Notice
constructor: (type, content, @timeout, @onclose) -> constructor: (type, content, @timeout, @onclose) ->
@el = $.el 'div', @el = $.el 'div',
innerHTML: '<a href="javascript:;" class="close fa fa-times" title="Close"></a><div class="message"></div>' <%= html('<a href="javascript:;" class="close fa fa-times" title="Close"></a><div class="message"></div>') %>
@el.style.opacity = 0 @el.style.opacity = 0
@setType type @setType type
$.on @el.firstElementChild, 'click', @close $.on @el.firstElementChild, 'click', @close

View File

@ -36,7 +36,7 @@ Gallery =
nodes.el = dialog = $.el 'div', nodes.el = dialog = $.el 'div',
id: 'a-gallery' id: 'a-gallery'
innerHTML: <%= importHTML('Features/Gallery') %> $.extend dialog, <%= importHTML('Features/Gallery') %>
nodes[key] = $ value, dialog for key, value of { nodes[key] = $ value, dialog for key, value of {
buttons: '.gal-buttons' buttons: '.gal-buttons'
@ -288,7 +288,7 @@ Gallery =
createSubEntries: -> createSubEntries: ->
subEntries = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'].map Gallery.menu.createSubEntry subEntries = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'].map Gallery.menu.createSubEntry
delayLabel = $.el 'label', innerHTML: 'Slide Delay: <input type="number" name="Slide Delay" min="0" step="any" class="field">' delayLabel = $.el 'label', <%= html('Slide Delay: <input type="number" name="Slide Delay" min="0" step="any" class="field">') %>
delayInput = delayLabel.firstElementChild delayInput = delayLabel.firstElementChild
delayInput.value = Gallery.delay delayInput.value = Gallery.delay
$.on delayInput, 'change', Gallery.cb.setDelay $.on delayInput, 'change', Gallery.cb.setDelay

View File

@ -10,6 +10,8 @@ ImageExpand =
$.on @EAI, 'click', @cb.toggleAll $.on @EAI, 'click', @cb.toggleAll
Header.addShortcut @EAI, 3 Header.addShortcut @EAI, 3
$.on d, 'scroll visibilitychange', @cb.playVideos $.on d, 'scroll visibilitychange', @cb.playVideos
@videoControls = $.el 'span', className: 'video-controls'
$.extend @videoControls, <%= html('\u00A0<a href="javascript:;" title="You can also contract the video by dragging it to the left.">contract</a>') %>
Post.callbacks.push Post.callbacks.push
name: 'Image Expansion' name: 'Image Expansion'
@ -219,10 +221,6 @@ ImageExpand =
if controls if controls
ImageCommon.addControls fullImage ImageCommon.addControls fullImage
videoControls: $.el 'span',
className: 'video-controls'
innerHTML: '\u00A0<a href="javascript:;" title="You can also contract the video by dragging it to the left.">contract</a>'
videoCB: do -> videoCB: do ->
# dragging to the left contracts the video # dragging to the left contracts the video
mousedown = false mousedown = false

View File

@ -14,7 +14,7 @@ ImageLoader =
return unless Conf['Image Prefetching'] and g.VIEW is 'thread' return unless Conf['Image Prefetching'] and g.VIEW is 'thread'
prefetch = $.el 'label', prefetch = $.el 'label',
innerHTML: '<input type="checkbox" name="prefetch"> Prefetch Images' <%= html('<input type="checkbox" name="prefetch"> Prefetch Images') %>
@el = prefetch.firstElementChild @el = prefetch.firstElementChild
$.on @el, 'change', @toggle $.on @el, 'change', @toggle

View File

@ -175,8 +175,7 @@ Linkify =
try try
$.cache service.api(uid), (-> Linkify.cb.title @, data), responseType: 'json' $.cache service.api(uid), (-> Linkify.cb.title @, data), responseType: 'json'
catch err catch err
link.innerHTML = '<span class="warning">Title Link Blocked</span> (are you using NoScript?)</a>' $.extend link, <%= html('[${key}] <span class="warning">Title Link Blocked</span> (are you using NoScript?)</a>') %>
$.prepend link, $.tn "[#{key}] "
return return
cb: cb:
@ -239,7 +238,7 @@ Linkify =
key: 'gist' key: 'gist'
regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/ regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/
el: (a) -> el: (a) ->
div = $.el 'iframe', $.el 'iframe',
# Github doesn't allow embedding straight from the site, so we use an external site to bypass that. # Github doesn't allow embedding straight from the site, so we use an external site to bypass that.
src: "http://www.purplegene.com/script?url=https://gist.github.com/#{a.dataset.uid}.js" src: "http://www.purplegene.com/script?url=https://gist.github.com/#{a.dataset.uid}.js"
title: title:
@ -251,10 +250,7 @@ Linkify =
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/ regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/
style: 'border: 0; width: auto; height: auto;' style: 'border: 0; width: auto; height: auto;'
el: (a) -> el: (a) ->
el = $.el 'div' $.el 'div', <%= html('<a target="_blank" href="${a.href}"><img src="${a.href}"></a>') %>
el.innerHTML = '<a target="_blank"><img></a>'
el.firstChild.href = el.firstChild.firstChild.src = a.href
el
, ,
key: 'InstallGentoo' key: 'InstallGentoo'
regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/ regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/
@ -297,17 +293,13 @@ Linkify =
return div.textContent = "ERROR: Not a valid filetype" unless embed return div.textContent = "ERROR: Not a valid filetype" unless embed
switch embed.type switch embed.type
when 'video/mp4', 'video/webm', 'video/ogv' when 'video/mp4', 'video/webm', 'video/ogv'
el.innerHTML = '<video autoplay loop><source type="video/mp4"><source type="video/webm"><source type="video/ogg"></video>' $.extend el, <%= html('<video autoplay loop><source type="video/mp4"><source type="video/webm"></video>') %>
for ext, i in ['mp4', 'webm', 'ogv'] for ext, i in ['mp4', 'webm']
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg' when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg'
el.innerHTML = '<a target="_blank"><img></a>' $.extend el, <%= html('<a target="_blank" href="${a.href}"><img src="https://mediacru.sh/${file.file}"></a>') %>
el.firstChild.href = a.href
el.firstChild.firstChild.src = "https://mediacru.sh/#{file.file}"
when 'audio/mpeg', 'audio/ogg' when 'audio/mpeg', 'audio/ogg'
el.innerHTML = '<audio controls><source type="audio/ogg"><source type="audio/mpeg"></audio>' $.extend el, <%= html('<audio controls><source type="audio/ogg" src="https://mediacru.sh/${a.dataset.uid}.ogg"></audio>') %>
for ext, i in ['ogg', 'mp3']
el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}"
else else
el.textContent = "ERROR: No valid filetype." el.textContent = "ERROR: No valid filetype."
el el
@ -350,14 +342,14 @@ Linkify =
idparam = {'b': 'archive_id', 'c': 'chapter_id'} idparam = {'b': 'archive_id', 'c': 'chapter_id'}
obj = $.el 'object', obj = $.el 'object',
data: 'http://www.twitch.tv/widgets/archive_embed_player.swf' data: 'http://www.twitch.tv/widgets/archive_embed_player.swf'
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">' $.extend obj, <%= html('<param name="allowFullScreen" value="true"><param name="flashvars">') %>
obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}" obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}"
obj obj
else else
channel = (/(\w+)/.exec a.dataset.uid)[0] channel = (/(\w+)/.exec a.dataset.uid)[0]
obj = $.el 'object', obj = $.el 'object',
data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}" data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}"
obj.innerHTML = '<param name="allowFullScreen" value="true"><param name="flashvars">' $.extend obj, <%= html('<param name="allowFullScreen" value="true"><param name="flashvars">') %>
obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25" obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25"
obj obj
, ,

View File

@ -16,8 +16,8 @@ Menu =
makeButton: do -> makeButton: do ->
a = $.el 'a', a = $.el 'a',
className: 'menu-button' className: 'menu-button'
innerHTML: '<i class="fa fa-angle-down"></i>'
href: 'javascript:;' href: 'javascript:;'
$.extend a, <%= html('<i class="fa fa-angle-down"></i>') %>
-> ->
button = a.cloneNode true button = a.cloneNode true
$.on button, 'click', Menu.toggle $.on button, 'click', Menu.toggle

View File

@ -22,10 +22,9 @@ PSAHiding =
$.on entry.el, 'click', PSAHiding.toggle $.on entry.el, 'click', PSAHiding.toggle
PSAHiding.btn = btn = $.el 'span', PSAHiding.btn = btn = $.el 'span',
innerHTML: '[<a href="javascript:;">Dismiss</a>]'
title: 'Mark announcement as read and hide.' title: 'Mark announcement as read and hide.'
className: 'hide-announcement' className: 'hide-announcement'
href: 'javascript:;' $.extend btn, <%= html('[<a href="javascript:;">Dismiss</a>]') %>
$.on btn, 'click', PSAHiding.toggle $.on btn, 'click', PSAHiding.toggle
$.get 'hiddenPSA', 0, ({hiddenPSA}) -> $.get 'hiddenPSA', 0, ({hiddenPSA}) ->

View File

@ -7,58 +7,34 @@ FileInfo =
cb: @node cb: @node
node: -> node: ->
return if !@file or @isClone return if !@file or @isClone
@file.text.innerHTML = '<span class="file-info"></span>' $.extend @file.text, <%= html('<span class="file-info"></span>') %>
FileInfo.format Conf['fileInfo'], @, @file.text.firstElementChild FileInfo.format Conf['fileInfo'], @, @file.text.firstElementChild
format: (formatString, post, outputNode) -> format: (formatString, post, outputNode) ->
FileInfo.innerHTML = '' output = []
formatString.replace /%(.)|[^%]+/g, (s, c) -> formatString.replace /%(.)|[^%]+/g, (s, c) ->
if c of FileInfo.formatters output.push if c of FileInfo.formatters
FileInfo.formatters[c].call post FileInfo.formatters[c].call post
else else
FileInfo.innerHTML += E s <%= html('${s}') %>
'' ''
outputNode.innerHTML = FileInfo.innerHTML $.extend outputNode, <%= html('@{output}') %>
formatters: formatters:
t: -> t: -> <%= html('${@file.URL.match(/\\d+\\..+$/)[0]}') %>
timestamp = @file.URL.match(/\d+\..+$/)[0] T: -> <%= html('<a href="${@file.URL}" target="_blank">&{FileInfo.formatters.t.call @}</a>') %>
FileInfo.innerHTML += E timestamp l: -> <%= html('<a href="${@file.URL}" target="_blank">&{FileInfo.formatters.n.call @}</a>') %>
T: -> L: -> <%= html('<a href="${@file.URL}" target="_blank">&{FileInfo.formatters.N.call @}</a>') %>
FileInfo.innerHTML += "<a href='#{E @file.URL}' target='_blank'>"
FileInfo.formatters.t.call @
FileInfo.innerHTML += '</a>'
l: ->
FileInfo.innerHTML += "<a href='#{E @file.URL}' target='_blank'>"
FileInfo.formatters.n.call @
FileInfo.innerHTML += '</a>'
L: ->
FileInfo.innerHTML += "<a href='#{E @file.URL}' target='_blank'>"
FileInfo.formatters.N.call @
FileInfo.innerHTML += '</a>'
n: -> n: ->
fullname = @file.name fullname = @file.name
shortname = Build.shortFilename @file.name, @isReply shortname = Build.shortFilename @file.name, @isReply
if fullname is shortname if fullname is shortname
FileInfo.innerHTML += E fullname <%= html('${fullname}') %>
else else
FileInfo.innerHTML += "<span class='fnswitch'><span class='fntrunc'>#{E shortname}</span><span class='fnfull'>#{E fullname}</span></span>" <%= html('<span class="fnswitch"><span class="fntrunc">${shortname}</span><span class="fnfull">${fullname}</span></span>') %>
N: -> N: -> <%= html('${@file.name}') %>
FileInfo.innerHTML += E @file.name p: -> if @file.isSpoiler then <%= html('Spoiler, ') %> else <%= html('') %>
p: -> s: -> <%= html('${@file.size}') %>
if @file.isSpoiler B: -> <%= html('${Math.round @file.sizeInBytes} Bytes') %>
FileInfo.innerHTML += 'Spoiler, ' K: -> <%= html('${Math.round(@file.sizeInBytes/1024)} KB') %>
s: -> M: -> <%= html('${Math.round(@file.sizeInBytes/1048576*100)/100} MB') %>
FileInfo.innerHTML += E @file.size r: -> <%= html('${@file.dimensions or "PDF"}') %>
B: -> '%': -> <%= html('%') %>
sizeB = Math.round(@file.sizeInBytes)
FileInfo.innerHTML += "#{+sizeB} Bytes"
K: ->
sizeKB = Math.round(@file.sizeInBytes/1024)
FileInfo.innerHTML += "#{+sizeKB} KB"
M: ->
sizeMB = Math.round(@file.sizeInBytes/1048576*100)/100
FileInfo.innerHTML += "#{+sizeMB} MB"
r: ->
dim = @file.dimensions or 'PDF'
FileInfo.innerHTML += E dim
'%': ->
FileInfo.innerHTML += '%'

View File

@ -2,16 +2,19 @@ ThreadStats =
init: -> init: ->
return if g.VIEW isnt 'thread' or !Conf['Thread Stats'] return if g.VIEW isnt 'thread' or !Conf['Thread Stats']
countHTML = <%= html('<span id="post-count">0</span> / <span id="file-count">0</span>') %>
countHTML = <%= html('&{countHTML} / <span id="file-count">0</span>') %> if Conf['Page Count in Stats']
if Conf['Updater and Stats in Header'] if Conf['Updater and Stats in Header']
@dialog = sc = $.el 'span', @dialog = sc = $.el 'span',
innerHTML: "<span id='post-count'>0</span> / <span id='file-count'>0</span>#{if Conf['Page Count in Stats'] then ' / <span id="page-count">0</span>' else ''}"
id: 'thread-stats' id: 'thread-stats'
title: 'Post Count / File Count' + (if Conf["Page Count in Stats"] then " / Page Count" else "") title: 'Post Count / File Count' + (if Conf["Page Count in Stats"] then " / Page Count" else "")
$.extend sc, countHTML
$.ready -> $.ready ->
Header.addShortcut sc Header.addShortcut sc
else else
@dialog = sc = UI.dialog 'thread-stats', 'bottom: 0px; right: 0px;', @dialog = sc = UI.dialog 'thread-stats', 'bottom: 0px; right: 0px;',
innerHTML: "<div class='move' title='Post Count / File Count#{if Conf['Page Count in Stats'] then ' / Page Count' else ''}'><span id='post-count'>0</span> / <span id='file-count'>0</span>#{if Conf['Page Count in Stats'] then ' / <span id="page-count">0</span>' else ''}</div>" <%= html('<div class="move" title="Post Count / File Count${if Conf["Page Count in Stats"] then " / Page Count" else ""}">&{countHTML}</div>') %>
$.ready => $.ready =>
$.add d.body, sc $.add d.body, sc

View File

@ -4,13 +4,13 @@ ThreadUpdater =
if Conf['Updater and Stats in Header'] if Conf['Updater and Stats in Header']
@dialog = sc = $.el 'span', @dialog = sc = $.el 'span',
innerHTML: '<span id="update-status"></span><span id="update-timer" title="Update now"></span>'
id: 'updater' id: 'updater'
$.extend sc, <%= html('<span id="update-status"></span><span id="update-timer" title="Update now"></span>') %>
$.ready -> $.ready ->
Header.addShortcut sc Header.addShortcut sc
else else
@dialog = sc = UI.dialog 'updater', 'bottom: 0px; left: 0px;', @dialog = sc = UI.dialog 'updater', 'bottom: 0px; left: 0px;',
innerHTML: '<div class="move"></div><span id="update-status"></span><span id="update-timer" title="Update now"></span>' <%= html('<div class="move"></div><span id="update-status"></span><span id="update-timer" title="Update now"></span>') %>
$.addClass doc, 'float' $.addClass doc, 'float'
$.ready => $.ready =>
$.addClass doc, 'float' $.addClass doc, 'float'
@ -26,8 +26,8 @@ ThreadUpdater =
$.on @status, 'click', @update $.on @status, 'click', @update
updateLink = $.el 'span', updateLink = $.el 'span',
innerHTML: '<a href="javascript:;">Update</a>'
className: 'brackets-wrap updatelink' className: 'brackets-wrap updatelink'
$.extend updateLink, <%= html('<a href="javascript:;">Update</a>') %>
$.ready -> $.ready ->
$.add $('.navLinksBot'), [$.tn(' '), updateLink] $.add $('.navLinksBot'), [$.tn(' '), updateLink]
$.on updateLink.firstElementChild, 'click', @update $.on updateLink.firstElementChild, 'click', @update
@ -46,7 +46,7 @@ ThreadUpdater =
subEntries.push el: el subEntries.push el: el
@settings = $.el 'span', @settings = $.el 'span',
innerHTML: '<a href="javascript:;">Interval</a>' <%= html('<a href="javascript:;">Interval</a>') %>
$.on @settings, 'click', @intervalShortcut $.on @settings, 'click', @intervalShortcut

View File

@ -10,7 +10,7 @@ ThreadWatcher =
className: 'disabled fa fa-eye' className: 'disabled fa fa-eye'
@db = new DataBoard 'watchedThreads', @refresh, true @db = new DataBoard 'watchedThreads', @refresh, true
@dialog = UI.dialog 'thread-watcher', 'top: 50px; left: 0px;', innerHTML: <%= importHTML('Monitoring/ThreadWatcher') %> @dialog = UI.dialog 'thread-watcher', 'top: 50px; left: 0px;', <%= importHTML('Monitoring/ThreadWatcher') %>
@status = $ '#watcher-status', @dialog @status = $ '#watcher-status', @dialog
@list = @dialog.lastElementChild @list = @dialog.lastElementChild

View File

@ -8,7 +8,7 @@ QR.captcha =
imgContainer = $.el 'div', imgContainer = $.el 'div',
className: 'captcha-img' className: 'captcha-img'
title: 'Reload reCAPTCHA' title: 'Reload reCAPTCHA'
innerHTML: '<img>' $.extend imgContainer, <%= html('<img>') %>
input = $.el 'input', input = $.el 'input',
className: 'captcha-input field' className: 'captcha-input field'
title: 'Verification' title: 'Verification'

View File

@ -45,8 +45,8 @@ QR =
return unless QR.postingIsEnabled return unless QR.postingIsEnabled
link = $.el 'h1', link = $.el 'h1',
innerHTML: "<a href='javascript:;' class='qr-link'>#{if g.VIEW is 'thread' then 'Reply to Thread' else 'Start a Thread'}</a>"
className: "qr-link-container" className: "qr-link-container"
$.extend link, <%= html('<a href="javascript:;" class="qr-link">${if g.VIEW is "thread" then "Reply to Thread" else "Start a Thread"}</a>') %>
QR.link = link.firstElementChild QR.link = link.firstElementChild
$.on link.firstChild, 'click', -> $.on link.firstChild, 'click', ->
@ -58,8 +58,8 @@ QR =
if Conf['Bottom QR Link'] and g.VIEW is 'thread' if Conf['Bottom QR Link'] and g.VIEW is 'thread'
linkBot = $.el 'div', linkBot = $.el 'div',
innerHTML: '<a href="javascript:;" class="qr-link-bottom">Reply to Thread</a>'
className: "brackets-wrap qr-link-container-bottom" className: "brackets-wrap qr-link-container-bottom"
$.extend linkBot, <%= html('<a href="javascript:;" class="qr-link-bottom">Reply to Thread</a>') %>
$.on linkBot.firstElementChild, 'click', -> $.on linkBot.firstElementChild, 'click', ->
$.event 'CloseMenu' $.event 'CloseMenu'
@ -422,7 +422,7 @@ QR =
dialog: -> dialog: ->
QR.nodes = nodes = QR.nodes = nodes =
el: dialog = UI.dialog 'qr', 'top:0;right:0;', innerHTML: <%= importHTML('Features/QuickReply') %> el: dialog = UI.dialog 'qr', 'top:0;right:0;', <%= importHTML('Features/QuickReply') %>
setNode = (name, query) -> setNode = (name, query) ->
nodes[name] = $ query, dialog nodes[name] = $ query, dialog
@ -484,17 +484,16 @@ QR =
nodes.spoiler.parentElement.hidden = true nodes.spoiler.parentElement.hidden = true
if g.BOARD.ID is 'f' and g.VIEW isnt 'thread' if g.BOARD.ID is 'f' and g.VIEW isnt 'thread'
nodes.flashTag = $.el 'select', nodes.flashTag = $.el 'select', name: 'filetag'
name: 'filetag' $.extend nodes.flashTag, <%= html(
innerHTML: ''' '<option value="0">Hentai</option>' +
<option value=0>Hentai</option> '<option value="6">Porn</option>' +
<option value=6>Porn</option> '<option value="1">Japanese</option>' +
<option value=1>Japanese</option> '<option value="2">Anime</option>' +
<option value=2>Anime</option> '<option value="3">Game</option>' +
<option value=3>Game</option> '<option value="5">Loop</option>' +
<option value=5>Loop</option> '<option value="4" selected>Other</option>'
<option value=4 selected>Other</option> ) %>
'''
nodes.flashTag.dataset.default = '4' nodes.flashTag.dataset.default = '4'
$.add nodes.form, nodes.flashTag $.add nodes.form, nodes.flashTag
@ -682,10 +681,11 @@ QR =
QR.cooldown.auto = false QR.cooldown.auto = false
QR.status() QR.status()
QR.error $.el 'span', QR.error $.el 'span',
innerHTML: ''' <%= html(
4chan X encountered an error while posting. '4chan X encountered an error while posting. ' +
[<a href="//4chan.org/banned" target="_blank">Banned?</a>] [<a href="<%= meta.faq %>#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target="_blank">More info</a>] '[<a href="//4chan.org/banned" target="_blank">Banned?</a>] ' +
''' '[<a href="${g.FAQ}#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target="_blank">More info</a>]'
) %>
extra = extra =
form: $.formData formData form: $.formData formData
upCallbacks: upCallbacks:
@ -718,9 +718,9 @@ QR =
if ban = $ '.banType', resDoc # banned/warning if ban = $ '.banType', resDoc # banned/warning
err = $.el 'span', err = $.el 'span',
if ban.textContent.toLowerCase() is 'banned' if ban.textContent.toLowerCase() is 'banned'
innerHTML: "You are banned on #{$('.board', resDoc).innerHTML}! ;_;<br>Click <a href='//www.4chan.org/banned' target='_blank'>here</a> to see the reason." <%= html('You are banned on &{$(".board", resDoc)}! ;_;<br>Click <a href="//www.4chan.org/banned" target="_blank">here</a> to see the reason.') %>
else else
innerHTML: "You were issued a warning on #{$('.board', resDoc).innerHTML} as #{$('.nameBlock', resDoc).innerHTML}.<br>Reason: #{$('.reason', resDoc).innerHTML}" <%= html('You were issued a warning on &{$(".board", resDoc)} as &{$(".nameBlock", resDoc)}.<br>Reason: &{$(".reason", resDoc)}') %>
else if err = resDoc.getElementById 'errmsg' # error! else if err = resDoc.getElementById 'errmsg' # error!
$('a', err)?.target = '_blank' # duplicate image link $('a', err)?.target = '_blank' # duplicate image link
else if resDoc.title isnt 'Post successful!' else if resDoc.title isnt 'Post successful!'

View File

@ -4,7 +4,7 @@ QR.post = class
className: 'qr-preview' className: 'qr-preview'
draggable: true draggable: true
href: 'javascript:;' href: 'javascript:;'
innerHTML: '<a class="remove fa fa-times-circle" title="Remove"></a><label hidden><input type="checkbox"> Spoiler</label><span></span>' $.extend el, <%= html('<a class="remove fa fa-times-circle" title="Remove"></a><label hidden><input type="checkbox"> Spoiler</label><span></span>') %>
@nodes = @nodes =
el: el el: el

View File

@ -8,7 +8,7 @@ QuoteThreading =
@enabled = true @enabled = true
@controls = $.el 'span', @controls = $.el 'span',
innerHTML: '<label><input id="threadingControl" type="checkbox" checked> Threading</label>' <%= html('<label><input id="threadingControl" type="checkbox" checked> Threading</label>') %>
input = $ 'input', @controls input = $ 'input', @controls
$.on input, 'change', @toggle $.on input, 'change', @toggle