diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 60220c8af..426576abe 100755 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -1,7 +1,30 @@ module.exports = (grunt) -> importHTML = (filename) -> - "'''#{grunt.file.read("src/General/html/#{filename}.html").replace(/^\s+|\s+$ + 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. grunt.initConfig @@ -12,6 +35,7 @@ module.exports = (grunt) -> get: -> pkg = grunt.config 'pkg' pkg.importHTML = importHTML + pkg.html = html pkg.tests_enabled or= false pkg enumerable: true diff --git a/src/Filtering/ThreadHiding.coffee b/src/Filtering/ThreadHiding.coffee index e0555b226..ea5555bbb 100755 --- a/src/Filtering/ThreadHiding.coffee +++ b/src/Filtering/ThreadHiding.coffee @@ -137,8 +137,8 @@ ThreadHiding = makeButton: (thread, type) -> a = $.el 'a', className: "#{type}-thread-button" - innerHTML: "" href: 'javascript:;' + $.extend a, <%= html('') %> a.dataset.fullID = thread.fullID $.on a, 'click', ThreadHiding.toggle a diff --git a/src/General/Build.coffee b/src/General/Build.coffee index 091208e75..59973e2bf 100755 --- a/src/General/Build.coffee +++ b/src/General/Build.coffee @@ -39,7 +39,7 @@ Build = flagName: Build.unescape data.country_name date: data.now dateUTC: data.time - h_comment: data.com or '' + comment: {innerHTML: data.com or ''} # thread status isSticky: !!data.sticky isClosed: !!data.closed @@ -75,86 +75,75 @@ Build = postID, threadID, boardID name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC isSticky, isClosed + comment file } = o name or= '' subject or= '' - h_comment = o.h_comment isOP = postID is threadID - if Build.initPixelRatio >= 2 - h_retina = '@2x' - else - h_retina = '' + retina = if Build.initPixelRatio >= 2 then '@2x' else '' ### Name Block ### switch capcode when 'admin', 'admin_highlight' - h_capcodeClass = ' capcodeAdmin' - h_capcodeStart = ' ## Admin' - h_capcodeIcon = "Admin Icon" + capcodeClass = ' capcodeAdmin' + capcodeStart = <%= html(' ## Admin') %> + capcodeIcon = <%= html('Admin Icon') %> when 'mod' - h_capcodeClass = ' capcodeMod' - h_capcodeStart = ' ## Mod' - h_capcodeIcon = "Mod Icon" + capcodeClass = ' capcodeMod' + capcodeStart = <%= html(' ## Mod') %> + capcodeIcon = <%= html('Mod Icon') %> when 'developer' - h_capcodeClass = ' capcodeDeveloper' - h_capcodeStart = ' ## Developer' - h_capcodeIcon = "Developer Icon" + capcodeClass = ' capcodeDeveloper' + capcodeStart = <%= html(' ## Developer') %> + capcodeIcon = <%= html('Developer Icon') %> else - h_capcodeClass = '' - h_capcodeStart = '' - h_capcodeIcon = '' + capcodeClass = '' + capcodeStart = <%= html('') %> + capcodeIcon = <%= html('') %> - if capcode - h_nameClass = ' capcode' + nameClass = if capcode then ' capcode' else '' + + tripcodeField = if tripcode + <%= html(' ${tripcode}') %> else - h_nameClass = '' + <%= html('') %> - if tripcode - h_tripcode = " #{E tripcode}" - else - h_tripcode = '' - - h_emailCont = "#{E name}#{h_tripcode}#{h_capcodeStart}" + emailField = <%= html('${name}&{tripcodeField}&{capcodeStart}') %> if email emailProcessed = encodeURIComponent(email).replace /%40/g, '@' - h_email = "#{h_emailCont}" - else - h_email = h_emailCont + emailField = <%= html('&{emailField}') %> unless isOP and boardID is 'f' - h_email += ' ' + emailField = <%= html('&{emailField} ') %> - if !capcode and uniqueID - h_userID = " (ID: #{E uniqueID})" + userID = if !capcode and uniqueID + <%= html(' (ID: ${uniqueID})') %> else - h_userID = '' + <%= html('') %> - unless flagCode - h_flag = '' + flag = unless flagCode + <%= html('') %> + else if boardID is 'pol' + <%= html('${flagCode}') %> else - flagCodeLC = flagCode.toLowerCase() - if boardID is 'pol' - h_flag = "#{E flagCode}" - else - h_flag = "" + <%= html('') %> - h_nameBlock = "" - h_nameBlock += "#{h_email}#{h_capcodeIcon}#{h_userID}#{h_flag}" - h_nameBlock += ' ' + nameBlock = <%= html( + '' + + '&{emailField}&{capcodeIcon}&{userID}&{flag}' + + ' ' + ) %> ### Post Info ### - if isOP or boardID is 'f' - h_subject = "#{E subject} " + subjectField = if isOP or boardID is 'f' + <%= html('${subject} ') %> else - h_subject = '' + <%= html('') %> - if isOP and boardID is 'f' - h_desktop2 = '' - else - h_desktop2 = ' desktop' + desktop2 = if isOP and boardID is 'f' then '' else ' desktop' postLink = Build.postURL boardID, threadID, postID quoteLink = if Build.sameThread boardID, threadID @@ -162,56 +151,59 @@ Build = else "/#{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 - h_pageIcon = " [#{+pageNum}]" + <%= html(' [${pageNum}]') %> else - h_pageIcon = '' + <%= html('') %> - if isSticky - h_sticky = " Sticky" + sticky = if isSticky + <%= html(' Sticky') %> else - h_sticky = '' + <%= html('') %> - if isClosed - h_closed = " Closed" + closed = if isClosed + <%= html(' Closed') %> else - h_closed = '' + <%= html('') %> - if isOP and g.VIEW is 'index' - h_replyLink = "   [Reply]" + replyLink = if isOP and g.VIEW is 'index' + <%= html('   [Reply]') %> else - h_replyLink = '' + <%= html('') %> - h_postInfo = "
" - h_postInfo += " " - h_postInfo += h_subject - h_postInfo += h_nameBlock - h_postInfo += "#{E date} " - h_postInfo += "" - h_postInfo += "No." - h_postInfo += "#{+postID}" - h_postInfo += "#{h_pageIcon}#{h_sticky}#{h_closed}#{h_replyLink}" - h_postInfo += '' - h_postInfo += '
' + postInfo = <%= html( + '
' + + ' ' + + '&{subjectField}' + + '&{nameBlock}' + + '${date} ' + + '' + + 'No.' + + '${postID}' + + '&{pageIcon}&{sticky}&{closed}&{replyLink}' + + '' + + '
' + ) %> ### File Info ### - if file?.isDeleted - h_fileCont = '' - h_fileCont += "File deleted." - h_fileCont += '' + fileCont = if file?.isDeleted + <%= html( + '' + + 'File deleted.' + + '' + ) %> else if file and boardID is 'f' - fileSize = $.bytesToString file.size - h_fileCont = "
" - h_fileCont += "File: #{E file.name}" - h_fileCont += "-(#{E fileSize}, #{+file.width}x#{+file.height}, #{E file.tag})" - h_fileCont += '
' + <%= html( + '
' + + 'File: ${file.name}' + + '-(${$.bytesToString file.size}, ${file.width}x${file.height}, ${file.tag})' + + '
' + ) %> else if file if file.isSpoiler - h_fileTitle1 = "title='#{E file.name}'" shortFilename = 'Spoiler Image' - h_spoilerClass = ' imgspoiler' if spoilerRange = Build.spoilerRange[boardID] # Randomize the spoiler image. 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' file.twidth = file.theight = 100 else - h_fileTitle1 = '' shortFilename = Build.shortFilename file.name, !isOP - h_spoilerClass = '' fileThumb = file.turl - if file.isSpoiler or file.name is shortFilename - h_fileTitle2 = '' + 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 - h_fileTitle2 = "title='#{E file.name}'" + <%= html('${shortFilename}') %> - fileSize = $.bytesToString file.size - - if file.url[-4..] is '.pdf' - h_fileDims = 'PDF' + fileText = if file.isSpoiler + <%= html('
File: &{fileLink} (${fileSize}, ${fileDims})
') %> else - h_fileDims = "#{+file.width}x#{+file.height}" + <%= html('
File: &{fileLink} (${fileSize}, ${fileDims})
') %> - h_fileCont = "
" - h_fileCont += "File: #{E shortFilename} (#{E fileSize}, #{h_fileDims})" - h_fileCont += '
' - h_fileCont += "" - h_fileCont += "#{E fileSize}" - h_fileCont += '' + <%= html( + '&{fileText}' + + '' + + '${fileSize}' + + '' + ) %> - if file - h_file = "
#{h_fileCont}
" + fileBlock = if file + <%= html('
&{fileCont}
') %> else - h_file = '' + <%= html('') %> ### Whole Post ### - if capcode is 'admin_highlight' - h_highlightPost = ' highlightPost' - else - h_highlightPost = '' + highlightPost = if capcode is 'admin_highlight' then ' highlightPost' else '' - h_message = "
#{h_comment}
" + message = <%= html('
&{comment}
') %> - if isOP - h_post = "
" - h_post += "#{h_file}#{h_postInfo}#{h_message}" - h_post += '
' + wholePost = if isOP + <%= html( + '
' + + '&{fileBlock}&{postInfo}&{message}' + + '
' + ) %> else - h_post = "
>>
" - h_post += "
" - h_post += "#{h_postInfo}#{h_file}#{h_message}" - h_post += '
' + <%= html( + '
>>
' + + '
' + + '&{postInfo}&{fileBlock}&{message}' + + '
' + ) %> container = $.el 'div', className: "postContainer #{if isOP then 'op' else 'reply'}Container" id: "pc#{postID}" - innerHTML: h_post + $.extend container, wholePost # Fix pathnames for quote in $$ '.quotelink', container diff --git a/src/General/Get.coffee b/src/General/Get.coffee index 92c926282..87ee63c13 100755 --- a/src/General/Get.coffee +++ b/src/General/Get.coffee @@ -159,21 +159,24 @@ Get = root.textContent = data.error 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/asagi/blob/master/src/main/java/net/easymodo/asagi/Yotsuba.java#L109-138 - h_comment = h_comment.replace /// - \n - | - \[/?[a-z]+(:lit)?\] - ///g, Get.parseMarkup - - h_comment = h_comment - # greentext - .replace(/(^|>)(>[^<$]*)(<|$)/g, '$1$2$3') - # quotes - .replace /((>){2}(>\/[a-z\d]+\/)?\d+)/g, '$1' + comment = (data.comment or '').split /(\n|\[\/?(?:b|spoiler|code|moot|banned)\])/ + comment = for text, i in comment + if i % 2 is 1 + Get.archiveTags[text] + else + greentext = text[0] is '>' + text = text.replace /(\[\/?[a-z]+):lit(\])/, '$1$2' + text = for text2, j in text.split /(>>(?:>\/[a-z\d]+\/)?\d+)/g + if j % 2 is 1 + <%= html('${text2}') %> + else + <%= html('${text2}') %> + text = <%= html('@{text}') %> + text = <%= html('&{text}') %> if greentext + text + comment = <%= html('@{comment}') %> threadID = +data.thread_num o = @@ -195,7 +198,7 @@ Get = flagName: data.poster_country_name date: data.fourchan_date dateUTC: data.timestamp - h_comment: h_comment + comment: comment # file if data.media?.media_filename o.file = @@ -221,17 +224,15 @@ Get = post.isFetchedQuote = true Main.callbackNodes Post, [post] Get.insert post, root, context - parseMarkup: (text) -> - { - '\n': '
' - '[b]': '' - '[/b]': '' - '[spoiler]': '' - '[/spoiler]': '' - '[code]': '
'
-      '[/code]':    '
' - '[moot]': '
' - '[/moot]': '
' - '[banned]': '' - '[/banned]': '' - }[text] or text.replace ':lit', '' + archiveTags: + '\n': <%= html('
') %> + '[b]': <%= html('') %> + '[/b]': <%= html('') %> + '[spoiler]': <%= html('') %> + '[/spoiler]': <%= html('') %> + '[code]': <%= html('
') %>
+    '[/code]':    <%= html('
') %> + '[moot]': <%= html('
') %> + '[/moot]': <%= html('
') %> + '[banned]': <%= html('') %> + '[/banned]': <%= html('') %> diff --git a/src/General/Globals.coffee b/src/General/Globals.coffee index 2334e7813..538393b13 100755 --- a/src/General/Globals.coffee +++ b/src/General/Globals.coffee @@ -5,6 +5,9 @@ doc = d.documentElement g = VERSION: '<%= version %>' NAMESPACE: '<%= meta.name %>.' + NAME: '<%= meta.name %>' + FAQ: '<%= meta.faq %>' + CHANGELOG: '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md' boards: {} E = (text) -> (text+'').replace /[&"'<>]/g, (x) -> diff --git a/src/General/Header.coffee b/src/General/Header.coffee index ead795dbb..c4ee7f4b7 100755 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -4,7 +4,7 @@ Header = menuButton = $.el 'span', className: 'menu-button' - innerHTML: '' + $.extend menuButton, <%= html('') %> barFixedToggler = UI.checkbox 'Fixed Header', ' Fixed Header' headerToggler = UI.checkbox 'Header auto-hide', ' Auto-hide header' @@ -132,7 +132,13 @@ Header = fourchannav = $.id 'boardNavDesktop' Header.boardList = boardList = $.el 'span', id: 'board-list' - innerHTML: "" + $.extend boardList, <%= html( + '' + + '' + ) %> for a in $$ 'a', boardList if a.pathname.split('/')[1] is g.BOARD.ID a.className = 'current' @@ -442,11 +448,11 @@ Header = return el = $.el 'span', - innerHTML: ''' - <%= meta.name %> needs your permission to show desktop notifications. - [FAQ]
- or - ''' + <%= html( + '${g.NAME} needs your permission to show desktop notifications. ' + + '[FAQ]
' + + ' or ' + ) %> [authorize, disable] = $$ 'button', el $.on authorize, 'click', -> Notification.requestPermission (status) -> diff --git a/src/General/Index.coffee b/src/General/Index.coffee index a0dcfa6a1..1ad465b22 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -15,9 +15,9 @@ Index = modeEntry = el: $.el 'span', textContent: 'Index mode' subEntries: [ - { el: $.el 'label', innerHTML: ' Paged' } - { el: $.el 'label', innerHTML: ' Infinite scrolling' } - { el: $.el 'label', innerHTML: ' All threads' } + { el: $.el 'label', <%= html(' Paged') %> } + { el: $.el 'label', <%= html(' Infinite scrolling') %> } + { el: $.el 'label', <%= html(' All threads') %> } ] for label in modeEntry.subEntries input = label.el.firstChild @@ -28,11 +28,11 @@ Index = sortEntry = el: $.el 'span', textContent: 'Sort by' subEntries: [ - { el: $.el 'label', innerHTML: ' Bump order' } - { el: $.el 'label', innerHTML: ' Last reply' } - { el: $.el 'label', innerHTML: ' Creation date' } - { el: $.el 'label', innerHTML: ' Reply count' } - { el: $.el 'label', innerHTML: ' File count' } + { el: $.el 'label', <%= html(' Bump order') %> } + { el: $.el 'label', <%= html(' Last reply') %> } + { el: $.el 'label', <%= html(' Creation date') %> } + { el: $.el 'label', <%= html(' Reply count') %> } + { el: $.el 'label', <%= html(' File count') %> } ] for label in sortEntry.subEntries input = label.el.firstChild @@ -66,10 +66,10 @@ Index = @pagelist = $.el 'div', className: 'pagelist' hidden: true - innerHTML: <%= importHTML('Features/Index-pagelist') %> + $.extend @pagelist, <%= importHTML('Features/Index-pagelist') %> @navLinks = $.el 'div', className: 'navLinks' - innerHTML: <%= importHTML('Features/Index-navlinks') %> + $.extend @navLinks, <%= importHTML('Features/Index-navlinks') %> $('.returnlink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/" $('.cataloglink a', @navLinks).href = "//boards.4chan.org/#{g.BOARD}/catalog" @searchInput = $ '#index-search', @navLinks diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 3ada33895..396ab0033 100755 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -189,7 +189,7 @@ Main = return if previousversion is g.VERSION if previousversion el = $.el 'span', - innerHTML: '<%= meta.name %> has been updated to version <%= version %>.' + <%= html('${g.NAME} has been updated to version ${g.VERSION}.') %> new Notice 'info', el, 15 else Settings.open() @@ -230,7 +230,7 @@ Main = return div = $.el 'div', - innerHTML: "#{+errors.length} errors occurred. [show]" + <%= html('${errors.length} errors occurred. [show]') %> $.on div.lastElementChild, 'click', -> [@textContent, logs.hidden] = if @textContent is 'show' ['hide', false] diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index 059454fe4..e304685bc 100755 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -34,7 +34,7 @@ Settings = Settings.dialog = dialog = $.el 'div', id: 'fourchanx-settings' className: 'dialog' - innerHTML: <%= importHTML('Settings/Settings') %> + $.extend dialog, <%= importHTML('Settings/Settings') %> $.on $('.export', Settings.dialog), 'click', Settings.export $.on $('.import', Settings.dialog), 'click', Settings.import @@ -90,8 +90,7 @@ Settings = inputs = {} for key, obj of Config.main fs = $.el 'fieldset', - innerHTML: '' - fs.firstElementChild.textContent = key + <%= html('${key}') %> for key, arr of obj description = arr[1] div = $.el 'div' @@ -112,7 +111,7 @@ Settings = return div = $.el 'div', - innerHTML: ': Clear manually-hidden threads and posts on all boards. Reload the page to apply.' + <%= html(': Clear manually-hidden threads and posts on all boards. Reload the page to apply.') %> button = $ 'button', div $.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) -> hiddenNum = 0 @@ -247,7 +246,7 @@ Settings = $.clear -> window.location.reload() if confirm 'Reset successful. Reload now?' filter: (section) -> - section.innerHTML = <%= importHTML('Settings/Filter-select') %> + $.extend section, <%= importHTML('Settings/Filter-select') %> select = $ 'select', section $.on select, 'change', Settings.selectFilter Settings.selectFilter.call select @@ -265,11 +264,11 @@ Settings = $.on ta, 'change', $.cb.value $.add div, ta return - div.innerHTML = <%= importHTML('Settings/Filter-guide') %> + $.extend div, <%= importHTML('Settings/Filter-guide') %> $('.warning', div).hidden = Conf['Filter'] sauce: (section) -> - section.innerHTML = <%= importHTML('Settings/Sauce') %> + $.extend section, <%= importHTML('Settings/Sauce') %> $('.warning', section).hidden = Conf['Sauce'] ta = $ 'textarea', section $.get 'sauces', Conf['sauces'], (item) -> @@ -277,7 +276,7 @@ Settings = $.on ta, 'change', $.cb.value advanced: (section) -> - section.innerHTML = <%= importHTML('Settings/Advanced') %> + $.extend section, <%= importHTML('Settings/Advanced') %> warning.hidden = Conf[warning.dataset.feature] for warning in $$ '.warning', section items = {} @@ -387,7 +386,7 @@ Settings = textContent: archive value: archive - td.innerHTML = '' + $.extend td, <%= html('') %> select = td.firstElementChild unless select.disabled = length is 1 # XXX GM can't into datasets @@ -441,7 +440,7 @@ Settings = CustomCSS.update() keybinds: (section) -> - section.innerHTML = <%= importHTML('Settings/Keybinds') %> + $.extend section, <%= importHTML('Settings/Keybinds') %> $('.warning', section).hidden = Conf['Keybinds'] tbody = $ 'tbody', section @@ -449,8 +448,7 @@ Settings = inputs = {} for key, arr of Config.hotkeys tr = $.el 'tr', - innerHTML: '' - tr.firstElementChild.textContent = arr[1] + <%= html('${arr[1]}') %> input = $ 'input', tr input.name = key input.spellcheck = false diff --git a/src/General/lib/$.coffee b/src/General/lib/$.coffee index 1574641c7..6a03efe78 100755 --- a/src/General/lib/$.coffee +++ b/src/General/lib/$.coffee @@ -46,9 +46,11 @@ $.ajax = do -> blockedError = (url) -> return if blockedURLs[url] blockedURLs[url] = true - h_message = '<%= meta.name %> was blocked from loading the following URL:

' - h_message += '[More info]' - message = $.el 'div', innerHTML: h_message + message = $.el 'div', + <%= html( + '${g.NAME} was blocked from loading the following URL:

' + + '[More info]' + ) %> $('span', message).textContent = (if /^\/\//.test url then location.protocol else '') + url new Notice 'error', message, 30, -> delete blockedURLs[url] (url, options, extra={}) -> diff --git a/src/General/lib/notice.class b/src/General/lib/notice.class index 0d4ae079a..2e6d4a18e 100644 --- a/src/General/lib/notice.class +++ b/src/General/lib/notice.class @@ -1,7 +1,7 @@ class Notice constructor: (type, content, @timeout, @onclose) -> @el = $.el 'div', - innerHTML: '
' + <%= html('
') %> @el.style.opacity = 0 @setType type $.on @el.firstElementChild, 'click', @close diff --git a/src/Images/Gallery.coffee b/src/Images/Gallery.coffee index 1810fa3e7..ae84dd317 100644 --- a/src/Images/Gallery.coffee +++ b/src/Images/Gallery.coffee @@ -36,7 +36,7 @@ Gallery = nodes.el = dialog = $.el 'div', id: 'a-gallery' - innerHTML: <%= importHTML('Features/Gallery') %> + $.extend dialog, <%= importHTML('Features/Gallery') %> nodes[key] = $ value, dialog for key, value of { buttons: '.gal-buttons' @@ -288,7 +288,7 @@ Gallery = createSubEntries: -> subEntries = ['Hide Thumbnails', 'Fit Width', 'Fit Height', 'Scroll to Post'].map Gallery.menu.createSubEntry - delayLabel = $.el 'label', innerHTML: 'Slide Delay: ' + delayLabel = $.el 'label', <%= html('Slide Delay: ') %> delayInput = delayLabel.firstElementChild delayInput.value = Gallery.delay $.on delayInput, 'change', Gallery.cb.setDelay diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 339d2112e..892c6e101 100755 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -10,6 +10,8 @@ ImageExpand = $.on @EAI, 'click', @cb.toggleAll Header.addShortcut @EAI, 3 $.on d, 'scroll visibilitychange', @cb.playVideos + @videoControls = $.el 'span', className: 'video-controls' + $.extend @videoControls, <%= html('\u00A0contract') %> Post.callbacks.push name: 'Image Expansion' @@ -219,10 +221,6 @@ ImageExpand = if controls ImageCommon.addControls fullImage - videoControls: $.el 'span', - className: 'video-controls' - innerHTML: '\u00A0contract' - videoCB: do -> # dragging to the left contracts the video mousedown = false diff --git a/src/Images/ImageLoader.coffee b/src/Images/ImageLoader.coffee index 2153c68ff..7fc8337c4 100755 --- a/src/Images/ImageLoader.coffee +++ b/src/Images/ImageLoader.coffee @@ -14,7 +14,7 @@ ImageLoader = return unless Conf['Image Prefetching'] and g.VIEW is 'thread' prefetch = $.el 'label', - innerHTML: ' Prefetch Images' + <%= html(' Prefetch Images') %> @el = prefetch.firstElementChild $.on @el, 'change', @toggle diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 24293cdc5..36db98d3b 100755 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -175,8 +175,7 @@ Linkify = try $.cache service.api(uid), (-> Linkify.cb.title @, data), responseType: 'json' catch err - link.innerHTML = 'Title Link Blocked (are you using NoScript?)' - $.prepend link, $.tn "[#{key}] " + $.extend link, <%= html('[${key}] Title Link Blocked (are you using NoScript?)') %> return cb: @@ -239,7 +238,7 @@ Linkify = key: 'gist' regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/ 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. src: "http://www.purplegene.com/script?url=https://gist.github.com/#{a.dataset.uid}.js" title: @@ -251,10 +250,7 @@ Linkify = regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/ style: 'border: 0; width: auto; height: auto;' el: (a) -> - el = $.el 'div' - el.innerHTML = '' - el.firstChild.href = el.firstChild.firstChild.src = a.href - el + $.el 'div', <%= html('') %> , key: 'InstallGentoo' regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/ @@ -297,17 +293,13 @@ Linkify = return div.textContent = "ERROR: Not a valid filetype" unless embed switch embed.type when 'video/mp4', 'video/webm', 'video/ogv' - el.innerHTML = '' - for ext, i in ['mp4', 'webm', 'ogv'] + $.extend el, <%= html('') %> + for ext, i in ['mp4', 'webm'] el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" when 'image/svg+xml', 'image/png', 'image/gif', 'image/jpeg' - el.innerHTML = '' - el.firstChild.href = a.href - el.firstChild.firstChild.src = "https://mediacru.sh/#{file.file}" + $.extend el, <%= html('') %> when 'audio/mpeg', 'audio/ogg' - el.innerHTML = '' - for ext, i in ['ogg', 'mp3'] - el.firstChild.children[i].src = "https://mediacru.sh/#{a.dataset.uid}.#{ext}" + $.extend el, <%= html('') %> else el.textContent = "ERROR: No valid filetype." el @@ -350,14 +342,14 @@ Linkify = idparam = {'b': 'archive_id', 'c': 'chapter_id'} obj = $.el 'object', data: 'http://www.twitch.tv/widgets/archive_embed_player.swf' - obj.innerHTML = '' + $.extend obj, <%= html('') %> obj.children[1].value = "channel=#{channel}&start_volume=25&auto_play=false&#{idparam[type]}=#{id}" obj else channel = (/(\w+)/.exec a.dataset.uid)[0] obj = $.el 'object', data: "http://www.twitch.tv/widgets/live_embed_player.swf?channel=#{channel}" - obj.innerHTML = '' + $.extend obj, <%= html('') %> obj.children[1].value = "hostname=www.twitch.tv&channel=#{channel}&auto_play=true&start_volume=25" obj , diff --git a/src/Menu/Menu.coffee b/src/Menu/Menu.coffee index aa67c193f..20a2992b6 100755 --- a/src/Menu/Menu.coffee +++ b/src/Menu/Menu.coffee @@ -16,8 +16,8 @@ Menu = makeButton: do -> a = $.el 'a', className: 'menu-button' - innerHTML: '' href: 'javascript:;' + $.extend a, <%= html('') %> -> button = a.cloneNode true $.on button, 'click', Menu.toggle diff --git a/src/Miscellaneous/AnnouncementHiding.coffee b/src/Miscellaneous/AnnouncementHiding.coffee index 24ab1eee2..07d9892ce 100755 --- a/src/Miscellaneous/AnnouncementHiding.coffee +++ b/src/Miscellaneous/AnnouncementHiding.coffee @@ -22,10 +22,9 @@ PSAHiding = $.on entry.el, 'click', PSAHiding.toggle PSAHiding.btn = btn = $.el 'span', - innerHTML: '[Dismiss]' title: 'Mark announcement as read and hide.' className: 'hide-announcement' - href: 'javascript:;' + $.extend btn, <%= html('[Dismiss]') %> $.on btn, 'click', PSAHiding.toggle $.get 'hiddenPSA', 0, ({hiddenPSA}) -> diff --git a/src/Miscellaneous/FileInfo.coffee b/src/Miscellaneous/FileInfo.coffee index 44360cc82..703e0202d 100755 --- a/src/Miscellaneous/FileInfo.coffee +++ b/src/Miscellaneous/FileInfo.coffee @@ -7,58 +7,34 @@ FileInfo = cb: @node node: -> return if !@file or @isClone - @file.text.innerHTML = '' + $.extend @file.text, <%= html('') %> FileInfo.format Conf['fileInfo'], @, @file.text.firstElementChild format: (formatString, post, outputNode) -> - FileInfo.innerHTML = '' + output = [] formatString.replace /%(.)|[^%]+/g, (s, c) -> - if c of FileInfo.formatters + output.push if c of FileInfo.formatters FileInfo.formatters[c].call post else - FileInfo.innerHTML += E s + <%= html('${s}') %> '' - outputNode.innerHTML = FileInfo.innerHTML + $.extend outputNode, <%= html('@{output}') %> formatters: - t: -> - timestamp = @file.URL.match(/\d+\..+$/)[0] - FileInfo.innerHTML += E timestamp - T: -> - FileInfo.innerHTML += "" - FileInfo.formatters.t.call @ - FileInfo.innerHTML += '' - l: -> - FileInfo.innerHTML += "" - FileInfo.formatters.n.call @ - FileInfo.innerHTML += '' - L: -> - FileInfo.innerHTML += "" - FileInfo.formatters.N.call @ - FileInfo.innerHTML += '' + t: -> <%= html('${@file.URL.match(/\\d+\\..+$/)[0]}') %> + T: -> <%= html('&{FileInfo.formatters.t.call @}') %> + l: -> <%= html('&{FileInfo.formatters.n.call @}') %> + L: -> <%= html('&{FileInfo.formatters.N.call @}') %> n: -> fullname = @file.name shortname = Build.shortFilename @file.name, @isReply if fullname is shortname - FileInfo.innerHTML += E fullname + <%= html('${fullname}') %> else - FileInfo.innerHTML += "#{E shortname}#{E fullname}" - N: -> - FileInfo.innerHTML += E @file.name - p: -> - if @file.isSpoiler - FileInfo.innerHTML += 'Spoiler, ' - s: -> - FileInfo.innerHTML += E @file.size - B: -> - 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 += '%' + <%= html('${shortname}${fullname}') %> + N: -> <%= html('${@file.name}') %> + p: -> if @file.isSpoiler then <%= html('Spoiler, ') %> else <%= html('') %> + s: -> <%= html('${@file.size}') %> + B: -> <%= html('${Math.round @file.sizeInBytes} Bytes') %> + K: -> <%= html('${Math.round(@file.sizeInBytes/1024)} KB') %> + M: -> <%= html('${Math.round(@file.sizeInBytes/1048576*100)/100} MB') %> + r: -> <%= html('${@file.dimensions or "PDF"}') %> + '%': -> <%= html('%') %> diff --git a/src/Monitoring/ThreadStats.coffee b/src/Monitoring/ThreadStats.coffee index af24dcb5d..393b497e9 100755 --- a/src/Monitoring/ThreadStats.coffee +++ b/src/Monitoring/ThreadStats.coffee @@ -2,16 +2,19 @@ ThreadStats = init: -> return if g.VIEW isnt 'thread' or !Conf['Thread Stats'] + countHTML = <%= html('0 / 0') %> + countHTML = <%= html('&{countHTML} / 0') %> if Conf['Page Count in Stats'] + if Conf['Updater and Stats in Header'] @dialog = sc = $.el 'span', - innerHTML: "0 / 0#{if Conf['Page Count in Stats'] then ' / 0' else ''}" id: 'thread-stats' title: 'Post Count / File Count' + (if Conf["Page Count in Stats"] then " / Page Count" else "") + $.extend sc, countHTML $.ready -> Header.addShortcut sc else @dialog = sc = UI.dialog 'thread-stats', 'bottom: 0px; right: 0px;', - innerHTML: "
0 / 0#{if Conf['Page Count in Stats'] then ' / 0' else ''}
" + <%= html('
&{countHTML}
') %> $.ready => $.add d.body, sc diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index e75ab2864..52bcee0db 100755 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -4,13 +4,13 @@ ThreadUpdater = if Conf['Updater and Stats in Header'] @dialog = sc = $.el 'span', - innerHTML: '' id: 'updater' + $.extend sc, <%= html('') %> $.ready -> Header.addShortcut sc else @dialog = sc = UI.dialog 'updater', 'bottom: 0px; left: 0px;', - innerHTML: '
' + <%= html('
') %> $.addClass doc, 'float' $.ready => $.addClass doc, 'float' @@ -26,8 +26,8 @@ ThreadUpdater = $.on @status, 'click', @update updateLink = $.el 'span', - innerHTML: 'Update' className: 'brackets-wrap updatelink' + $.extend updateLink, <%= html('Update') %> $.ready -> $.add $('.navLinksBot'), [$.tn(' '), updateLink] $.on updateLink.firstElementChild, 'click', @update @@ -46,7 +46,7 @@ ThreadUpdater = subEntries.push el: el @settings = $.el 'span', - innerHTML: 'Interval' + <%= html('Interval') %> $.on @settings, 'click', @intervalShortcut diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index f048b4d53..00d2923d1 100755 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -10,7 +10,7 @@ ThreadWatcher = className: 'disabled fa fa-eye' @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 @list = @dialog.lastElementChild diff --git a/src/Posting/QR.captcha.coffee b/src/Posting/QR.captcha.coffee index 05f194a44..1501b9317 100644 --- a/src/Posting/QR.captcha.coffee +++ b/src/Posting/QR.captcha.coffee @@ -8,7 +8,7 @@ QR.captcha = imgContainer = $.el 'div', className: 'captcha-img' title: 'Reload reCAPTCHA' - innerHTML: '' + $.extend imgContainer, <%= html('') %> input = $.el 'input', className: 'captcha-input field' title: 'Verification' diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index c9d1dd925..2cb601c28 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -45,9 +45,9 @@ QR = return unless QR.postingIsEnabled link = $.el 'h1', - innerHTML: "#{if g.VIEW is 'thread' then 'Reply to Thread' else 'Start a Thread'}" className: "qr-link-container" - + $.extend link, <%= html('${if g.VIEW is "thread" then "Reply to Thread" else "Start a Thread"}') %> + QR.link = link.firstElementChild $.on link.firstChild, 'click', -> $.event 'CloseMenu' @@ -58,8 +58,8 @@ QR = if Conf['Bottom QR Link'] and g.VIEW is 'thread' linkBot = $.el 'div', - innerHTML: 'Reply to Thread' className: "brackets-wrap qr-link-container-bottom" + $.extend linkBot, <%= html('Reply to Thread') %> $.on linkBot.firstElementChild, 'click', -> $.event 'CloseMenu' @@ -422,7 +422,7 @@ QR = dialog: -> 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) -> nodes[name] = $ query, dialog @@ -484,17 +484,16 @@ QR = nodes.spoiler.parentElement.hidden = true if g.BOARD.ID is 'f' and g.VIEW isnt 'thread' - nodes.flashTag = $.el 'select', - name: 'filetag' - innerHTML: ''' - - - - - - - - ''' + nodes.flashTag = $.el 'select', name: 'filetag' + $.extend nodes.flashTag, <%= html( + '' + + '' + + '' + + '' + + '' + + '' + + '' + ) %> nodes.flashTag.dataset.default = '4' $.add nodes.form, nodes.flashTag @@ -682,10 +681,11 @@ QR = QR.cooldown.auto = false QR.status() QR.error $.el 'span', - innerHTML: ''' - 4chan X encountered an error while posting. - [Banned?] [More info] - ''' + <%= html( + '4chan X encountered an error while posting. ' + + '[Banned?] ' + + '[More info]' + ) %> extra = form: $.formData formData upCallbacks: @@ -718,9 +718,9 @@ QR = if ban = $ '.banType', resDoc # banned/warning err = $.el 'span', if ban.textContent.toLowerCase() is 'banned' - innerHTML: "You are banned on #{$('.board', resDoc).innerHTML}! ;_;
Click here to see the reason." + <%= html('You are banned on &{$(".board", resDoc)}! ;_;
Click here to see the reason.') %> else - innerHTML: "You were issued a warning on #{$('.board', resDoc).innerHTML} as #{$('.nameBlock', resDoc).innerHTML}.
Reason: #{$('.reason', resDoc).innerHTML}" + <%= html('You were issued a warning on &{$(".board", resDoc)} as &{$(".nameBlock", resDoc)}.
Reason: &{$(".reason", resDoc)}') %> else if err = resDoc.getElementById 'errmsg' # error! $('a', err)?.target = '_blank' # duplicate image link else if resDoc.title isnt 'Post successful!' diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee index d3330299b..f0dab5857 100644 --- a/src/Posting/QR.post.coffee +++ b/src/Posting/QR.post.coffee @@ -4,7 +4,7 @@ QR.post = class className: 'qr-preview' draggable: true href: 'javascript:;' - innerHTML: '' + $.extend el, <%= html('') %> @nodes = el: el diff --git a/src/Quotelinks/QuoteThreading.coffee b/src/Quotelinks/QuoteThreading.coffee index a54d2cf5d..0fcc84223 100755 --- a/src/Quotelinks/QuoteThreading.coffee +++ b/src/Quotelinks/QuoteThreading.coffee @@ -8,7 +8,7 @@ QuoteThreading = @enabled = true @controls = $.el 'span', - innerHTML: '' + <%= html('') %> input = $ 'input', @controls $.on input, 'change', @toggle