From 202d7617e3e213fdd1510d2c741db42edb9f4555 Mon Sep 17 00:00:00 2001 From: noface Date: Tue, 18 Jun 2013 19:42:42 +0200 Subject: [PATCH 01/30] Add Linkification. --- Gruntfile.coffee | 1 + src/General/Config.coffee | 3 + src/General/Main.coffee | 1 + src/Linkification/Linkify.coffee | 92 ++++++++++++++++++++++++++ src/Miscellaneous/ExpandComment.coffee | 2 + 5 files changed, 99 insertions(+) create mode 100644 src/Linkification/Linkify.coffee diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 2c0ff150b..753ac3df2 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -31,6 +31,7 @@ module.exports = (grunt) -> 'src/Quotelinks/**/*' 'src/Posting/**/*' 'src/Images/**/*' + 'src/Linkification/**/*' 'src/Menu/**/*' 'src/Monitoring/**/*' 'src/Archive/**/*' diff --git a/src/General/Config.coffee b/src/General/Config.coffee index fc174dcfb..b35d0a399 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -27,6 +27,9 @@ Config = 'Image Hover': [false, 'Show a floating expanded image on hover.'] 'Sauce': [true, 'Add sauce links to images.'] 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'] + 'Linkification': + 'Linkify': [true, 'Convert text links into hyperlinks.'] + 'Clean Links': [true, 'Remove spoiler texts commonly used to bypass banned links.'] 'Menu': 'Menu': [true, 'Add a drop-down menu to posts.'] 'Report Link': [true, 'Add a report link to the menu.'] diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 4c1be0574..1aeaafa1f 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -128,6 +128,7 @@ Main = initFeature 'Index Navigation', Nav initFeature 'Keybinds', Keybinds initFeature 'Show Dice Roll', Dice + initFeature 'Linkify', Linkify # c.timeEnd 'All initializations' $.on d, 'AddCallback', Main.addCallback diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee new file mode 100644 index 000000000..febbc3e42 --- /dev/null +++ b/src/Linkification/Linkify.coffee @@ -0,0 +1,92 @@ +Linkify = + init: -> + return if g.VIEW is 'catalog' or !Conf['Linkify'] + + @catchAll = /\b(?:([a-z][\w-]+):(?:\/{1,3}|[a-z0-9%]|(\?(?:dn|xl|xt|as|xs|kt|mt|tr)=))|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/i + + @globalCatchAll = ///#{@catchAll.source}///g + + Post::callbacks.push + name: 'Linkify' + cb: @node + + node: -> + return if @isClone or !links = @info.comment.match Linkify.globalCatchAll + walker = d.createTreeWalker @nodes.comment, 4, null, false + anchor = false + while (node = walker.nextNode())? + {parentNode} = node + if parentNode.nodeName is 'A' + # prettyprint has some issues + if parentNode.textContent is links[0] + delete links[0] + walker.currentNode = parentNode.lastChild + continue + continue unless data = node.data + while !anchor + return unless link = links.shift() + [anchor, link] = Linkify.parseLink link + if data.length >= link.length and (index = data.indexOf link) >= 0 + walker.currentNode = Linkify.sourround anchor, link, index, index + link.length, node + anchor = false + continue + index = found = 0 + nextContent = node.nextSibling?.textContent + while index isnt data.length + start = data[index++..] + startLength = start.length + threshold = startLength is 2 + if threshold and nextContent and link[...startLength + nextContent.length] is start + nextContent + found = true + if threshold or found = link[...startLength] is start + index-- + break + continue unless found + startNode = node + while start.length < link.length + start += data = (node = walker.nextNode())?.data + {parentNode} = node + if parentNode.nodeName is 'S' and Conf['Clean Links'] + $.replace parentNode, node + continue unless start[...link.length] is link + endIndex = link[start.length - data.length...].length + walker.currentNode = Linkify.sourround anchor, link, index, endIndex, startNode, node + anchor = false + return + + parseLink: (link) -> + unless result = link.match @catchAll + return false + [link, protocol, isMagnet] = result + try + decodeURIComponent link + catch + return false + target = if isMagnet or /^(irc|ftps?)$/.test protocol + '_self' + else + '_blank' + href = if protocol + link + else + "http://#{link}" + anchor = $.el 'a', + target: target + href: href + rel: 'noreferrer' + [anchor, link] + + sourround: (anchor, link, startIndex, endIndex, startNode, endNode = startNode) -> + parent = startNode.parentNode + if parent?.nodeName is 'S' and parent.textContent.length < link.length + parentClone = parent.cloneNode true + $.replace parent, startNode + range = d.createRange() + range.setStart startNode, startIndex + range.setEnd endNode, endIndex + try + range.surroundContents anchor + if !Conf['Clean Links'] and parentClone and anchor.firstChild + $.replace anchor.firstChild, parentClone + catch + endNode diff --git a/src/Miscellaneous/ExpandComment.coffee b/src/Miscellaneous/ExpandComment.coffee index 8d87de91e..3567e9f84 100644 --- a/src/Miscellaneous/ExpandComment.coffee +++ b/src/Miscellaneous/ExpandComment.coffee @@ -72,3 +72,5 @@ ExpandComment = Fourchan.code.call post if g.BOARD.ID is 'sci' Fourchan.math.call post + if Conf['Linkify'] + Linkify.node.call post From 7b842c01bea8a418af5ec0c246575a6812186d00 Mon Sep 17 00:00:00 2001 From: noface Date: Sun, 18 Aug 2013 16:56:01 +0200 Subject: [PATCH 02/30] Fix spoiler issue. --- src/Linkification/Linkify.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index febbc3e42..0e3d8602d 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -45,9 +45,10 @@ Linkify = startNode = node while start.length < link.length start += data = (node = walker.nextNode())?.data - {parentNode} = node - if parentNode.nodeName is 'S' and Conf['Clean Links'] - $.replace parentNode, node + if Conf['Clean Links'] + {parentNode} = node + if parentNode.nodeName is 'S' and parentNode.textContent.length < link.length + $.replace parentNode, node continue unless start[...link.length] is link endIndex = link[start.length - data.length...].length walker.currentNode = Linkify.sourround anchor, link, index, endIndex, startNode, node @@ -88,5 +89,4 @@ Linkify = range.surroundContents anchor if !Conf['Clean Links'] and parentClone and anchor.firstChild $.replace anchor.firstChild, parentClone - catch endNode From 58531319ca86d1e55c39b65b41b9f37c3ce5f163 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Sun, 18 Aug 2013 20:55:23 +0200 Subject: [PATCH 03/30] sourround -> surround --- src/Linkification/Linkify.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 0e3d8602d..6093e5e26 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -27,7 +27,7 @@ Linkify = return unless link = links.shift() [anchor, link] = Linkify.parseLink link if data.length >= link.length and (index = data.indexOf link) >= 0 - walker.currentNode = Linkify.sourround anchor, link, index, index + link.length, node + walker.currentNode = Linkify.surround anchor, link, index, index + link.length, node anchor = false continue index = found = 0 @@ -51,7 +51,7 @@ Linkify = $.replace parentNode, node continue unless start[...link.length] is link endIndex = link[start.length - data.length...].length - walker.currentNode = Linkify.sourround anchor, link, index, endIndex, startNode, node + walker.currentNode = Linkify.surround anchor, link, index, endIndex, startNode, node anchor = false return @@ -77,7 +77,7 @@ Linkify = rel: 'noreferrer' [anchor, link] - sourround: (anchor, link, startIndex, endIndex, startNode, endNode = startNode) -> + surround: (anchor, link, startIndex, endIndex, startNode, endNode = startNode) -> parent = startNode.parentNode if parent?.nodeName is 'S' and parent.textContent.length < link.length parentClone = parent.cloneNode true From 108c1ea793675074ac76c1f92f1445f2d3f2bae4 Mon Sep 17 00:00:00 2001 From: NemDiggers Date: Mon, 19 Aug 2013 02:55:34 -0400 Subject: [PATCH 04/30] Add HTTPS support, minor rename. --- json/archives.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json/archives.json b/json/archives.json index 2f1ac503c..578fbee55 100644 --- a/json/archives.json +++ b/json/archives.json @@ -54,10 +54,10 @@ "files": ["cm", "d", "e", "i", "n", "o", "p", "s", "trv", "y"] }, { "uid": 12, - "name": "fap archive", + "name": "FapArchive", "domain": "fuuka.worldathleticproject.org", "http": true, - "https": false, + "https": true, "software": "foolfuuka", "boards": ["b", "e", "h", "hc", "p", "s", "u"], "files": ["b", "e", "h", "hc", "p", "s", "u"] From 6d5f422c3f228911ac9438034ce4be26b48adcf5 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 12:21:49 +0200 Subject: [PATCH 05/30] Tweak/rewrite Linkify. --- src/Linkification/Linkify.coffee | 134 +++++++++++++------------------ 1 file changed, 58 insertions(+), 76 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 6093e5e26..a8ad3dc4b 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -2,91 +2,73 @@ Linkify = init: -> return if g.VIEW is 'catalog' or !Conf['Linkify'] - @catchAll = /\b(?:([a-z][\w-]+):(?:\/{1,3}|[a-z0-9%]|(\?(?:dn|xl|xt|as|xs|kt|mt|tr)=))|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/i - - @globalCatchAll = ///#{@catchAll.source}///g + # gruber revised + magnet support + # http://rodneyrehm.de/t/url-regex.html + @catchAll = /\b([a-z][\w-]+:(\/{1,3}|[a-z0-9%]|\?(dn|x[lts]|as|kt|mt|tr)=)|www\d{0,3}\.|[a-z0-9.\-]+\.[a-z]{2,4}\/)([^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/g Post::callbacks.push name: 'Linkify' cb: @node node: -> - return if @isClone or !links = @info.comment.match Linkify.globalCatchAll - walker = d.createTreeWalker @nodes.comment, 4, null, false - anchor = false - while (node = walker.nextNode())? - {parentNode} = node - if parentNode.nodeName is 'A' - # prettyprint has some issues - if parentNode.textContent is links[0] - delete links[0] - walker.currentNode = parentNode.lastChild - continue - continue unless data = node.data - while !anchor - return unless link = links.shift() - [anchor, link] = Linkify.parseLink link - if data.length >= link.length and (index = data.indexOf link) >= 0 - walker.currentNode = Linkify.surround anchor, link, index, index + link.length, node - anchor = false - continue - index = found = 0 - nextContent = node.nextSibling?.textContent - while index isnt data.length - start = data[index++..] - startLength = start.length - threshold = startLength is 2 - if threshold and nextContent and link[...startLength + nextContent.length] is start + nextContent - found = true - if threshold or found = link[...startLength] is start - index-- - break - continue unless found - startNode = node - while start.length < link.length - start += data = (node = walker.nextNode())?.data - if Conf['Clean Links'] - {parentNode} = node - if parentNode.nodeName is 'S' and parentNode.textContent.length < link.length - $.replace parentNode, node - continue unless start[...link.length] is link - endIndex = link[start.length - data.length...].length - walker.currentNode = Linkify.surround anchor, link, index, endIndex, startNode, node - anchor = false + return if @isClone or !links = @info.comment.match Linkify.catchAll + walker = d.createTreeWalker @nodes.comment, 4 + for link in links + boundaries = Linkify.find link, walker + # continue unless boundaries + anchor = Linkify.createLink link + if Linkify.surround anchor, link, boundaries + Linkify.cleanLink anchor if Conf['Clean Links'] + walker.currentNode = anchor.lastChild + else + walker.currentNode = boundaries.endNode return - parseLink: (link) -> - unless result = link.match @catchAll - return false - [link, protocol, isMagnet] = result - try - decodeURIComponent link - catch - return false - target = if isMagnet or /^(irc|ftps?)$/.test protocol - '_self' - else - '_blank' - href = if protocol - link - else - "http://#{link}" - anchor = $.el 'a', - target: target - href: href - rel: 'noreferrer' - [anchor, link] + find: (link, walker) -> + # Walk through the nodes until we find the entire link. + text = '' + while node = walker.nextNode() + {data} = node + text += node.data + if text.indexOf(link) > -1 + startNode = endNode = node + break - surround: (anchor, link, startIndex, endIndex, startNode, endNode = startNode) -> - parent = startNode.parentNode - if parent?.nodeName is 'S' and parent.textContent.length < link.length - parentClone = parent.cloneNode true - $.replace parent, startNode + # Walk backwards to find the startNode. + text = data + until (index = text.indexOf link) > -1 + startNode = walker.previousNode() + text = "#{startNode.data}#{text}" + + return { + startNode, endNode + startOffset: index + endOffset: endNode.length - (text.length - index - link.length) + } + + createLink: (link) -> + unless /^[a-z][\w-]+:/.test link + link = "http://#{link}" + a = $.el 'a', + href: link + target: '_blank' + a + + surround: (anchor, link, {startOffset, endOffset, startNode, endNode}) -> + # parent = startNode.parentNode + # if parent?.nodeName is 'S' and parent.textContent.length < link.length + # parentClone = parent.cloneNode true + # $.replace parent, startNode range = d.createRange() - range.setStart startNode, startIndex - range.setEnd endNode, endIndex + range.setStart startNode, startOffset + range.setEnd endNode, endOffset try range.surroundContents anchor - if !Conf['Clean Links'] and parentClone and anchor.firstChild - $.replace anchor.firstChild, parentClone - endNode + # if !Conf['Clean Links'] and parentClone and anchor.firstChild + # $.replace anchor.firstChild, parentClone + true + catch + false + + cleanLink: (anchor) -> + # TODO From a5adff0ab63709f0aa74ddc534833dd8ea39420d Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 12:27:04 +0200 Subject: [PATCH 06/30] Fix parsing of empty text nodes in Post::parseComment(). --- src/General/Post.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/General/Post.coffee b/src/General/Post.coffee index 1b890c2ec..7319235fd 100644 --- a/src/General/Post.coffee +++ b/src/General/Post.coffee @@ -56,6 +56,8 @@ class Post @kill() if that.isArchived parseComment: -> + # Merge text nodes and remove empty ones. + @nodes.comment.normalize() # Get the comment's text. #
-> \n # Remove: From 27c1a77b863e6cbb2ffcf0822bfb55e0c1f65287 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 12:32:15 +0200 Subject: [PATCH 07/30] Create a single range per post, and detach it when we're done. --- src/Linkification/Linkify.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index a8ad3dc4b..fad3c8c41 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -13,16 +13,17 @@ Linkify = node: -> return if @isClone or !links = @info.comment.match Linkify.catchAll walker = d.createTreeWalker @nodes.comment, 4 + range = d.createRange() for link in links boundaries = Linkify.find link, walker # continue unless boundaries anchor = Linkify.createLink link - if Linkify.surround anchor, link, boundaries + if Linkify.surround anchor, link, range, boundaries Linkify.cleanLink anchor if Conf['Clean Links'] walker.currentNode = anchor.lastChild else walker.currentNode = boundaries.endNode - return + range.detach() find: (link, walker) -> # Walk through the nodes until we find the entire link. @@ -54,12 +55,11 @@ Linkify = target: '_blank' a - surround: (anchor, link, {startOffset, endOffset, startNode, endNode}) -> + surround: (anchor, link, range, {startOffset, endOffset, startNode, endNode}) -> # parent = startNode.parentNode # if parent?.nodeName is 'S' and parent.textContent.length < link.length # parentClone = parent.cloneNode true # $.replace parent, startNode - range = d.createRange() range.setStart startNode, startOffset range.setEnd endNode, endOffset try From b378db78f5b0719293ba6d3babb68337228e07ec Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 17:15:57 +0200 Subject: [PATCH 08/30] Linkify: Attempt to handle un-surroundable contents. --- src/Linkification/Linkify.coffee | 49 ++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index fad3c8c41..1a7f421e7 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -16,9 +16,9 @@ Linkify = range = d.createRange() for link in links boundaries = Linkify.find link, walker - # continue unless boundaries + # break unless boundaries anchor = Linkify.createLink link - if Linkify.surround anchor, link, range, boundaries + if Linkify.surround anchor, range, boundaries Linkify.cleanLink anchor if Conf['Clean Links'] walker.currentNode = anchor.lastChild else @@ -29,14 +29,13 @@ Linkify = # Walk through the nodes until we find the entire link. text = '' while node = walker.nextNode() - {data} = node text += node.data - if text.indexOf(link) > -1 - startNode = endNode = node - break + break if text.indexOf(link) > -1 + # return unless node + startNode = endNode = node # Walk backwards to find the startNode. - text = data + text = node.data until (index = text.indexOf link) > -1 startNode = walker.previousNode() text = "#{startNode.data}#{text}" @@ -55,20 +54,40 @@ Linkify = target: '_blank' a - surround: (anchor, link, range, {startOffset, endOffset, startNode, endNode}) -> - # parent = startNode.parentNode - # if parent?.nodeName is 'S' and parent.textContent.length < link.length - # parentClone = parent.cloneNode true - # $.replace parent, startNode + surround: (anchor, range, boundaries) -> + {startOffset, endOffset, startNode, endNode} = boundaries range.setStart startNode, startOffset range.setEnd endNode, endOffset try range.surroundContents anchor - # if !Conf['Clean Links'] and parentClone and anchor.firstChild - # $.replace anchor.firstChild, parentClone true catch - false + # Attempt to handle cases such as: + # [spoiler]www.[/spoiler]example.com # + # www.example[spoiler].com[/spoiler] # + return false if boundaries.areRelocated + Linkify.relocate boundaries + Linkify.surround anchor, range, boundaries + + relocate: (boundaries) -> + # What do you mean, "silly"? + boundaries.areRelocated = true + + if boundaries.startOffset is 0 + parentNode = boundaries.startNode + until parentNode.previousSibling + {parentNode} = parentNode + parent = parentNode.parentNode + boundaries.startNode = parent + boundaries.startOffset = [parent.childNodes...].indexOf parentNode + + if boundaries.endOffset is boundaries.endNode.length + parentNode = boundaries.endNode + until parentNode.nextSibling + {parentNode} = parentNode + parent = parentNode.parentNode + boundaries.endNode = parent + boundaries.endOffset = [parent.childNodes...].indexOf parentNode cleanLink: (anchor) -> # TODO From 19524d26b64288e4abb131a22db5eaf3698b6ce6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 17:41:31 +0200 Subject: [PATCH 09/30] Fix endOffset when relocating. --- src/Linkification/Linkify.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 1a7f421e7..61bde6fe8 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -87,7 +87,7 @@ Linkify = {parentNode} = parentNode parent = parentNode.parentNode boundaries.endNode = parent - boundaries.endOffset = [parent.childNodes...].indexOf parentNode + boundaries.endOffset = [parent.childNodes...].indexOf(parentNode) + 1 cleanLink: (anchor) -> # TODO From abedf859735891c408442f974739988a958ef9c3 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 20:49:59 +0200 Subject: [PATCH 10/30] Disable error reports if localStorage is blocked. --- src/General/Main.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 4c1be0574..9a26ad43b 100644 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -42,7 +42,7 @@ Main = # Track resolution of this bug. Main.logError message: 'Chrome Storage API bug' - error: new Error chrome.runtime.lastError.message or 'no lastError.message' + error: new Error '~' <% } %> Main.initFeatures() @@ -202,13 +202,14 @@ Main = Main.callbackNodes Post, posts if $.hasClass d.body, 'fourchan_x' - Main.v2Detected = true + Main.disableReports = true alert '4chan X v2 detected: Disable it or v3 will break.' try localStorage.getItem '4chan-settings' catch err new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to properly function.', 30 + Main.disableReports = true $.event '4chanXInitFinished' @@ -284,7 +285,7 @@ Main = Main.errors.push data postErrors: -> - return if Main.v2Detected + return if Main.disableReports errors = Main.errors.filter((d) -> !!d.error.stack).map((d) -> <% if (type === 'userscript') { %> # Before: From 7ee6b24606972c39ca9904d4b40728b38b772e4b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 22:09:52 +0200 Subject: [PATCH 11/30] Handle a Chrome/WebKit/Blink bug. --- src/Linkification/Linkify.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 61bde6fe8..bce234d20 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -62,6 +62,10 @@ Linkify = range.surroundContents anchor true catch + <% if (type === 'crx') { %> + # Chrome bug: crbug.com/275848 + return true if anchor.parentNode + <% } %> # Attempt to handle cases such as: # [spoiler]www.[/spoiler]example.com # # www.example[spoiler].com[/spoiler] # From fc745767c4d9ab689ad99b8bd0f3d3531bceaf69 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 23:15:54 +0200 Subject: [PATCH 12/30] Replace already-linkified links. --- src/Linkification/Linkify.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index bce234d20..1665e276a 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -19,6 +19,10 @@ Linkify = # break unless boundaries anchor = Linkify.createLink link if Linkify.surround anchor, range, boundaries + if (parent = anchor.parentNode).href is anchor.href + # Replace already-linkified links, + # f.e.: https://boards.4chan.org/b/% + $.replace parent, anchor Linkify.cleanLink anchor if Conf['Clean Links'] walker.currentNode = anchor.lastChild else From abfbd734aa7c2cf78a1875d4d1f85177656769ab Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 00:05:41 +0200 Subject: [PATCH 13/30] Add a 'linkified' class. --- src/Linkification/Linkify.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 1665e276a..ba9125f5a 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -53,10 +53,10 @@ Linkify = createLink: (link) -> unless /^[a-z][\w-]+:/.test link link = "http://#{link}" - a = $.el 'a', + $.el 'a', href: link + className: 'linkified' target: '_blank' - a surround: (anchor, range, boundaries) -> {startOffset, endOffset, startNode, endNode} = boundaries From 4196ce2600d986ad68bf27b83a40ab3c5da9301e Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 00:33:56 +0200 Subject: [PATCH 14/30] Clean links from spoiler and code tags. --- src/General/Config.coffee | 2 +- src/Linkification/Linkify.coffee | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/General/Config.coffee b/src/General/Config.coffee index b35d0a399..24fa40faf 100644 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -29,7 +29,7 @@ Config = 'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.'] 'Linkification': 'Linkify': [true, 'Convert text links into hyperlinks.'] - 'Clean Links': [true, 'Remove spoiler texts commonly used to bypass banned links.'] + 'Clean Links': [true, 'Remove spoiler and code tags commonly used to bypass blocked links.'] 'Menu': 'Menu': [true, 'Add a drop-down menu to posts.'] 'Report Link': [true, 'Add a report link to the menu.'] diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index ba9125f5a..99f667fbe 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -23,7 +23,7 @@ Linkify = # Replace already-linkified links, # f.e.: https://boards.4chan.org/b/% $.replace parent, anchor - Linkify.cleanLink anchor if Conf['Clean Links'] + Linkify.cleanLink anchor, link if Conf['Clean Links'] walker.currentNode = anchor.lastChild else walker.currentNode = boundaries.endNode @@ -97,5 +97,8 @@ Linkify = boundaries.endNode = parent boundaries.endOffset = [parent.childNodes...].indexOf(parentNode) + 1 - cleanLink: (anchor) -> - # TODO + cleanLink: (anchor, link) -> + {length} = link + for node in $$ 's, .prettyprint', anchor + $.replace node, [node.childNodes...] if length > node.textContent.length + return From 8b6647b3448881e67d32c9cecb867ed0a31cdc0b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 00:45:14 +0200 Subject: [PATCH 15/30] Changelog. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bbdbb486..7a9b09c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +- **New feature**: `Linkify` and `Clean Links`, enabled by default + - Linkify will turn text URLs into working links. + - Clean Links will get rid of spoiler and code tags in linkified URLs used to bypass spam blocks. + ## 3.9.0 - *2013-08-18* - **New feature**: `Desktop Notifications` From 7cd4b7cee0e5d8e3d3376200d4409c649a0efcee Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 17:06:23 +0200 Subject: [PATCH 16/30] Use FontAwesome to replace the thread watcher toggle icon. --- img/favicons/empty.gif | Bin 94 -> 0 bytes src/Monitoring/Favicon.coffee | 1 - src/Monitoring/ThreadWatcher.coffee | 17 ++++++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 img/favicons/empty.gif diff --git a/img/favicons/empty.gif b/img/favicons/empty.gif deleted file mode 100644 index 5ad41fc95990f0039ecb705d82ad5897d157f05d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94 zcmZ?wbhEHb6krfwn8*ME|NsBLefu_$RQ$=p$iTqNpaT*G$ultN&*@*e`oUiw0g(lf s{9' dead: 'data:image/gif;base64,<%= grunt.file.read("img/favicons/dead.gif", {encoding: "base64"}) %>' logo: 'data:image/png;base64,<%= grunt.file.read("img/icon128.png", {encoding: "base64"}) %>' diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 9465187ba..de775049a 100644 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -31,10 +31,11 @@ ThreadWatcher = name: 'Thread Watcher' cb: @node node: -> - toggler = $.el 'img', + toggler = $.el 'a', className: 'watcher-toggler' + href: 'javascript:;' $.on toggler, 'click', ThreadWatcher.cb.toggle - $.before $('input', @OP.nodes.post), toggler + $.after $('input', @OP.nodes.post), [toggler, $.tn ' '] ready: -> $.off d, '4chanXInitFinished', ThreadWatcher.ready return unless Main.isThisPageLegit() @@ -154,11 +155,13 @@ ThreadWatcher = $.add list, nodes for threadID, thread of g.BOARD.threads - toggler = $ '.watcher-toggler', thread.OP.nodes.post - toggler.src = if ThreadWatcher.db.get {boardID: thread.board.ID, threadID} - Favicon.default - else - Favicon.empty + $.extend $('.watcher-toggler', thread.OP.nodes.post), + if ThreadWatcher.db.get {boardID: thread.board.ID, threadID} + className: 'watcher-toggler icon-bookmark' + title: 'Unwatch thread' + else + className: 'watcher-toggler icon-bookmark-empty' + title: 'Watch thread' for refresher in ThreadWatcher.menu.refreshers refresher() From 5aff534c367b244cb7e936c083c3f14cc8be8a6d Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 17:10:11 +0200 Subject: [PATCH 17/30] Normalize the #qr select font. --- css/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/css/style.css b/css/style.css index 3be4907ab..c312f0fee 100644 --- a/css/style.css +++ b/css/style.css @@ -624,6 +624,7 @@ a.hide-announcement { appearance: none; border: none; background: none; + font: inherit; } #qr option { color: #000; @@ -867,8 +868,7 @@ a.hide-announcement { background: none; border: none !important; color: inherit; - font-family: inherit; - font-size: inherit; + font: inherit; -webkit-flex: 1; flex: 1; text-overflow: ellipsis; From 3f04351e488cc0bfd2e141eb822e4cd526f0678b Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 17:19:04 +0200 Subject: [PATCH 18/30] Mention Gruber's regexp in the LICENSE. --- LICENSE | 3 +++ src/Linkification/Linkify.coffee | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 6743356de..9329b9c22 100644 --- a/LICENSE +++ b/LICENSE @@ -34,5 +34,8 @@ audio/beep.wav from http://freesound.org/people/pierrecartoons1979/sounds/90112/ Font Awesome by Dave Gandy (http://fontawesome.io) license: http://fontawesome.io/license/ +URL-matching regular expression by John Gruber (http://df4.us/fv9) + "Consider it public domain." + seaweedchan/4chan-x (https://github.com/seaweedchan/4chan-x) license: https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 99f667fbe..5136cdfce 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -3,7 +3,7 @@ Linkify = return if g.VIEW is 'catalog' or !Conf['Linkify'] # gruber revised + magnet support - # http://rodneyrehm.de/t/url-regex.html + # http://df4.us/fv9 @catchAll = /\b([a-z][\w-]+:(\/{1,3}|[a-z0-9%]|\?(dn|x[lts]|as|kt|mt|tr)=)|www\d{0,3}\.|[a-z0-9.\-]+\.[a-z]{2,4}\/)([^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/g Post::callbacks.push From a7d26c173d135a051e7c40ae3a6486840b032e5a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Tue, 20 Aug 2013 18:18:17 +0200 Subject: [PATCH 19/30] Replace the Header & Thread Watcher menu icon with a FontAwesome icon. Also fix .brackets-wrap spacing. --- css/style.css | 18 +++++++++++------- html/Monitoring/ThreadWatcher.html | 2 +- src/General/Header.coffee | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/css/style.css b/css/style.css index c312f0fee..12d1c712b 100644 --- a/css/style.css +++ b/css/style.css @@ -191,17 +191,14 @@ a[href="javascript:;"] { text-decoration: none; padding: 1px; } -#shortcuts::after { - margin-left: 2px; -} .shortcut:not(:last-child)::after { content: " / "; } .brackets-wrap::before { - content: "\\00a0["; + content: " [ "; } .brackets-wrap::after { - content: "]\\00a0"; + content: " ] "; } /* Notifications */ @@ -885,10 +882,9 @@ a.hide-announcement { /* Menu */ .menu-button { - display: inline-block; position: relative; } -.menu-button i { +.menu-button i:not(.icon-reorder) { border-top: 6px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; @@ -896,6 +892,14 @@ a.hide-announcement { margin: 2px; vertical-align: middle; } +:root.blink .menu-button .icon-reorder { + /* crbug.com/25541 */ + font-size: 14px; +} +:root.blink #shortcuts .icon-reorder { + /* crbug.com/25541 */ + vertical-align: -1px; +} #menu { border-bottom: 0; display: -webkit-flex; diff --git a/html/Monitoring/ThreadWatcher.html b/html/Monitoring/ThreadWatcher.html index 8ea19b356..c0b5810b2 100644 --- a/html/Monitoring/ThreadWatcher.html +++ b/html/Monitoring/ThreadWatcher.html @@ -1,5 +1,5 @@
Thread Watcher - [] +
diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 9c395a752..c3f7e8c02 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -12,7 +12,7 @@ Header = @menu = new UI.Menu 'header' menuButton = $.el 'a', className: 'menu-button' - innerHTML: '' + innerHTML: '' href: 'javascript:;' $.on menuButton, 'click', @menuToggle @addShortcut menuButton, 0 From 13f7afba63a6d68c10417b24b92299cdf50713a6 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 02:00:29 +0200 Subject: [PATCH 20/30] Handle icon-reorder better on 1dppx screens. #1254 --- css/style.css | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/css/style.css b/css/style.css index 12d1c712b..54440e226 100644 --- a/css/style.css +++ b/css/style.css @@ -892,13 +892,13 @@ a.hide-announcement { margin: 2px; vertical-align: middle; } -:root.blink .menu-button .icon-reorder { - /* crbug.com/25541 */ - font-size: 14px; -} -:root.blink #shortcuts .icon-reorder { - /* crbug.com/25541 */ - vertical-align: -1px; +@media screen and (resolution: 1dppx) { + .icon-reorder { + font-size: 14px; + } + #shortcuts .icon-reorder { + vertical-align: -1px; + } } #menu { border-bottom: 0; From 606cbcc1c17d5aa822d0c556505355c1dc819a60 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 03:25:56 +0200 Subject: [PATCH 21/30] Shave a few lines. --- src/Monitoring/Unread.coffee | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index af85ad18f..8bf976073 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -49,11 +49,8 @@ Unread = {root} = Unread.thread.posts[posts[posts.length - 1]].nodes onload = -> Header.scrollToPost root if checkPosition root checkPosition = (target) -> - # Don't scroll to the target if - # - it's visible. - # - we've scrolled past it. - {top, height} = target.getBoundingClientRect() - top + height - doc.clientHeight > 0 + # Scroll to the target unless we scrolled past it. + target.getBoundingClientRect().bottom > doc.clientHeight # Prevent the browser to scroll back to # the previous scroll location on page load. $.on window, 'load', onload @@ -136,8 +133,7 @@ Unread = return if d.hidden or !Unread.posts.length height = doc.clientHeight for post, i in Unread.posts - {bottom} = post.nodes.root.getBoundingClientRect() - break if bottom > height # post is not completely read + break if post.nodes.root.getBoundingClientRect().bottom > height # post is not completely read return unless i Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID From 08ea3cf7d031958db25588c3d353526df884d27c Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 15:45:32 +0200 Subject: [PATCH 22/30] Count unread posts if desktop notifications are enabled. Also fix missing Conf check, and return too early in counting replies to you. Minor tweaks here and there. --- src/Monitoring/Unread.coffee | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 8bf976073..9c31a2dd2 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -1,6 +1,6 @@ Unread = init: -> - return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Tab Icon'] + return if g.VIEW isnt 'thread' or !Conf['Unread Count'] and !Conf['Unread Tab Icon'] and !Conf['Desktop Notifications'] @db = new DataBoard 'lastReadPosts', @sync @hr = $.el 'hr', @@ -30,10 +30,10 @@ Unread = for ID, post of Unread.thread.posts posts.push post if post.isReply Unread.addPosts posts - return unless Conf['Scroll to Last Read Post'] Unread.scroll() scroll: -> + return unless Conf['Scroll to Last Read Post'] # Let the header's onload callback handle it. return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts if Unread.posts.length @@ -64,7 +64,7 @@ Unread = Unread.lastReadPost = lastReadPost Unread.readArray Unread.posts Unread.readArray Unread.postsQuotingYou - Unread.setLine() + Unread.setLine() if Conf['Unread Line'] Unread.update() addPosts: (posts) -> @@ -91,7 +91,7 @@ Unread = for quotelink in post.nodes.quotelinks when QR.db.get Get.postDataFromLink quotelink Unread.postsQuotingYou.push post Unread.openNotification post - return + return openNotification: (post) -> return unless Header.areNotificationsEnabled name = if Conf['Anonymize'] @@ -150,12 +150,11 @@ Unread = setLine: (force) -> return unless d.hidden or force is true - if post = Unread.posts[0] - {root} = post.nodes - if root isnt $ '.thread > .replyContainer', root.parentNode # not the first reply - $.before root, Unread.hr - else + unless post = Unread.posts[0] $.rm Unread.hr + return + if $.x 'preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root # not the first reply + $.before post.nodes.root, Unread.hr update: <% if (type === 'crx') { %>(dontrepeat) <% } %>-> count = Unread.posts.length @@ -167,18 +166,18 @@ Unread = # crbug.com/124381 # Call it one second later, # but don't display outdated unread count. - unless dontrepeat - setTimeout -> - d.title = '' - Unread.update true - , $.SECOND + return if dontrepeat + setTimeout -> + d.title = '' + Unread.update true + , $.SECOND <% } %> return unless Conf['Unread Tab Icon'] Favicon.el.href = if g.DEAD - if Unread.postsQuotingYou.length + if Unread.postsQuotingYou[0] Favicon.unreadDeadY else if count Favicon.unreadDead @@ -186,7 +185,7 @@ Unread = Favicon.dead else if count - if Unread.postsQuotingYou.length + if Unread.postsQuotingYou[0] Favicon.unreadY else Favicon.unread From 6454090cfd85b2d5a61100ce3c52671ad670e845 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 16:24:48 +0200 Subject: [PATCH 23/30] Warn with a desktop notification when we're running low on cached captchas. Close #1253. Also increase delay to close the notifications from 5 to 7 seconds. #1252 --- CHANGELOG.md | 2 ++ src/Monitoring/Unread.coffee | 2 +- src/Posting/QR.coffee | 13 +++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a9b09c5d..973ad4b42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ - **New feature**: `Linkify` and `Clean Links`, enabled by default - Linkify will turn text URLs into working links. - Clean Links will get rid of spoiler and code tags in linkified URLs used to bypass spam blocks. +- New desktop notification: + - The QR will now warn you when you are running low on cached captchas while auto-posting. ## 3.9.0 - *2013-08-18* diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 9c31a2dd2..fdcbc7f16 100644 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -106,7 +106,7 @@ Unread = window.focus() setTimeout -> notif.close() - , 5 * $.SECOND + , 7 * $.SECOND onUpdate: (e) -> if e.detail[404] diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index f3526edf1..5a5d62219 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -125,7 +125,7 @@ QR = setTimeout -> notif.onclose = null notif.close() - , 5 * $.SECOND + , 7 * $.SECOND <% } %> notifications: [] cleanNotifications: -> @@ -1101,7 +1101,16 @@ QR = } # Enable auto-posting if we have stuff to post, disable it otherwise. - QR.cooldown.auto = QR.posts.length > 1 and isReply + postsCount = QR.posts.length + QR.cooldown.auto = postsCount > 1 and isReply + if QR.cooldown.auto and QR.captcha.isEnabled and (captchasCount = QR.captcha.captchas.length) < 3 and captchasCount < postsCount + notif = new Notification 'Quick reply warning', + body: "You are running low on cached captchas. Cache count: #{captchasCount}." + icon: Favicon.logo + notif.onclick = -> window.focus() + setTimeout -> + notif.close() + , 7 * $.SECOND unless Conf['Persistent QR'] or QR.cooldown.auto QR.close() From 6e88579cc851698b07551ef72dd0cd3a05709c8c Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 17:25:49 +0200 Subject: [PATCH 24/30] Close #1250. --- src/General/Header.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/General/Header.coffee b/src/General/Header.coffee index c3f7e8c02..5515c70e6 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -285,7 +285,8 @@ Header = el = $.el 'span', innerHTML: """ - Desktop notification permissions are not granted:
+ Desktop notification permissions are not granted. + [FAQ]
or """ [authorize, disable] = $$ 'button', el From b5edee8a91f0cce502453fcc1c321b1754a5d097 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 18:34:19 +0200 Subject: [PATCH 25/30] Sightly smaller header bar. --- css/style.css | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/css/style.css b/css/style.css index 54440e226..1ac29e067 100644 --- a/css/style.css +++ b/css/style.css @@ -120,7 +120,7 @@ a[href="javascript:;"] { border-width: 0; display: -webkit-flex; display: flex; - padding: 3px 4px 4px; + padding: 3px; position: relative; transition: all .1s .05s ease-in-out; } @@ -131,10 +131,6 @@ a[href="javascript:;"] { box-shadow: 0 -1px 2px rgba(0, 0, 0, .15); border-top-width: 1px; } -#header.bottom .menu-button i { - border-top: none; - border-bottom: 6px solid; -} #board-list { -webkit-flex: 1; flex: 1; @@ -163,23 +159,11 @@ a[href="javascript:;"] { } #header.top #toggle-header-bar { cursor: n-resize; - bottom: -8px; + bottom: -10px; } #header.bottom #toggle-header-bar { cursor: s-resize; - top: -8px; -} -#header-bar.autohide:not(:hover) #toggle-header-bar, -#toggle-header-bar:hover { - height: 18px; -} -#header.top #header-bar.autohide:not(:hover) #toggle-header-bar, -#header.top #toggle-header-bar:hover { - bottom: -16px; -} -#header.bottom #header-bar.autohide:not(:hover) #toggle-header-bar, -#header.bottom #toggle-header-bar:hover { - top: -16px; + top: -10px; } #header.top #header-bar.autohide #toggle-header-bar { cursor: s-resize; From a5e20db33f4d4de24f2257ae9ee994a0bda09872 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 20:25:44 +0200 Subject: [PATCH 26/30] Refine QR previews dragging. --- css/style.css | 2 ++ src/Posting/QR.coffee | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/css/style.css b/css/style.css index 1ac29e067..67c936a26 100644 --- a/css/style.css +++ b/css/style.css @@ -726,10 +726,12 @@ a.hide-announcement { .qr-preview.drag { border-color: red; border-style: dashed; + opacity: 1; } .qr-preview.over { border-color: #FFF; border-style: dashed; + opacity: 1; } .remove { color: #E00 !important; diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 5a5d62219..50c95a0f8 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -664,7 +664,9 @@ QR = QR.nodes.com.value = @com @nodes.span.textContent = @com reader.readAsText file - dragStart: -> $.addClass @, 'drag' + dragStart: (e) -> + e.dataTransfer.setDragImage @, e.offsetX, e.offsetY + $.addClass @, 'drag' dragEnd: -> $.rmClass @, 'drag' dragEnter: -> $.addClass @, 'over' dragLeave: -> $.rmClass @, 'over' From 7d51b560d82f20d1ad159be1529dcbfb351a45f4 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 20:49:40 +0200 Subject: [PATCH 27/30] offset -> layer Because Fx doesn't have offsetX/Y. --- src/Posting/QR.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 50c95a0f8..b068b20b0 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -665,7 +665,7 @@ QR = @nodes.span.textContent = @com reader.readAsText file dragStart: (e) -> - e.dataTransfer.setDragImage @, e.offsetX, e.offsetY + e.dataTransfer.setDragImage @, e.layerX, e.layerY $.addClass @, 'drag' dragEnd: -> $.rmClass @, 'drag' dragEnter: -> $.addClass @, 'over' From ae8e633ee31cf1ef0e4582669141616ed7d7c372 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 22:32:55 +0200 Subject: [PATCH 28/30] Refactor file input handling. --- src/Posting/QR.coffee | 83 ++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index b068b20b0..461b338d4 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -392,56 +392,51 @@ QR = return unless e.dataTransfer.files.length e.preventDefault() QR.open() - QR.fileInput e.dataTransfer.files + QR.handleFiles e.dataTransfer.files $.addClass QR.nodes.el, 'dump' paste: (e) -> files = [] - for item in e.clipboardData.items - if item.kind is 'file' - blob = item.getAsFile() - blob.name = 'file' - blob.name += '.' + blob.type.split('/')[1] if blob.type - files.push blob + for item in e.clipboardData.items when item.kind is 'file' + blob = item.getAsFile() + blob.name = 'file' + blob.name += '.' + blob.type.split('/')[1] if blob.type + files.push blob return unless files.length QR.open() - QR.fileInput files + QR.handleFiles files + $.addClass QR.nodes.el, 'dump' + handleFiles: (files) -> + if @ isnt QR # file input + files = [@files...] + @value = null + return unless files.length + max = QR.nodes.fileInput.max + isSingle = files.length is 1 + QR.cleanNotifications() + for file in files + QR.handleFile file, isSingle, max + $.addClass QR.nodes.el, 'dump' unless isSingle + handleFile: (file, isSingle, max) -> + if file.size > max + QR.error "#{file.name}: File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})." + return + unless file.type in QR.mimeTypes + unless /^text/.test file.type + QR.error "#{file.name}: Unsupported file type." + return + if isSingle + post = QR.selected + else if (post = QR.posts[QR.posts.length - 1]).com + post = new QR.post() + post.pasteText file + return + if isSingle + post = QR.selected + else if (post = QR.posts[QR.posts.length - 1]).file + post = new QR.post() + post.setFile file openFileInput: -> QR.nodes.fileInput.click() - fileInput: (files) -> - if files instanceof Event # file input - files = [@files...] - QR.nodes.fileInput.value = null # Don't hold the files from being modified on windows - {length} = files - return unless length - max = QR.nodes.fileInput.max - QR.cleanNotifications() - # Set or change current post's file. - if length is 1 - file = files[0] - if /^text/.test file.type - QR.selected.pasteText file - else if file.size > max - QR.error "File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})." - else unless file.type in QR.mimeTypes - QR.error 'Unsupported file type.' - else - QR.selected.setFile file - return - # Create new posts with these files. - for file in files - if /^text/.test file.type - if (post = QR.posts[QR.posts.length - 1]).com - post = new QR.post() - post.pasteText file - else if file.size > max - QR.error "#{file.name}: File too large (file: #{$.bytesToString file.size}, max: #{$.bytesToString max})." - else unless file.type in QR.mimeTypes - QR.error "#{file.name}: Unsupported file type." - else - if (post = QR.posts[QR.posts.length - 1]).file - post = new QR.post() - post.setFile file - $.addClass QR.nodes.el, 'dump' posts: [] post: class @@ -884,7 +879,7 @@ QR = $.on nodes.form, 'submit', QR.submit $.on nodes.fileRM, 'click', -> QR.selected.rmFile() $.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click() - $.on nodes.fileInput, 'change', QR.fileInput + $.on nodes.fileInput, 'change', QR.handleFiles # save selected post's data for name in ['name', 'email', 'sub', 'com', 'filename'] $.on nodes[name], 'input', -> QR.selected.save @ From 24762fd1825b4336f9e65f5bcb5d1cc977573a96 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Wed, 21 Aug 2013 22:37:47 +0200 Subject: [PATCH 29/30] Un-hide the QR and focus the captcha input when clicking on the low-captcha notification. --- src/Posting/QR.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 461b338d4..eb88f66c8 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -1104,7 +1104,10 @@ QR = notif = new Notification 'Quick reply warning', body: "You are running low on cached captchas. Cache count: #{captchasCount}." icon: Favicon.logo - notif.onclick = -> window.focus() + notif.onclick = -> + QR.open() + QR.captcha.nodes.input.focus() + window.focus() setTimeout -> notif.close() , 7 * $.SECOND From 132d94d441ddbdcd281934c25e5156d8c4274a2f Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 22 Aug 2013 13:21:37 +0200 Subject: [PATCH 30/30] Release 4chan X v3.10.0. --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 973ad4b42..7fa81c571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## 3.10.0 - *2013-08-22* + - **New feature**: `Linkify` and `Clean Links`, enabled by default - Linkify will turn text URLs into working links. - Clean Links will get rid of spoiler and code tags in linkified URLs used to bypass spam blocks. diff --git a/package.json b/package.json index 5b96d8f58..a8957cbb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "3.9.0", + "version": "3.10.0", "description": "Cross-browser extension for productive lurking on 4chan.", "meta": { "name": "4chan X",