Merge tag '1.9.15.4' into noscript

4chan X v1.9.15.4.

Conflicts:
	src/Posting/QR.captcha.coffee
This commit is contained in:
ccd0 2014-12-12 16:36:20 -08:00
commit 77f3639772
27 changed files with 781 additions and 250 deletions

View File

@ -2,7 +2,58 @@ The attributions below are for work that has been incorporated into the script a
The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x). The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x).
<!-- v1.9.15.x -->
### v1.9.15.4
*2014-12-08* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.4/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.4/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Make `Catalog Links`, `Relative Post Dates`, and `Pin Watched Threads` off by default.
### v1.9.15.3
*2014-12-08* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.3/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.3/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Fix sounds sometimes playing for a short time before `Disable Autoplaying Sounds` halts them (as in 1.9.14.4).
### v1.9.15.2
*2014-12-08* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.2/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.2/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Add `Pin Watched Threads` setting to `Index Navigation` header submenu (default: checked), moving watched threads to the beginning of 4chan X's index/catalog.
- `Alt+Click` in the 4chan X catalog watches/unwatches a thread.
- Add a `Watch Thread`/`Unwatch Thread` item to the menu in the 4chan X catalog.
### v1.9.15.1
*2014-12-07* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.1/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.1/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Center the controls added to formerly autoplaying audio by `Disable Autoplaying Sounds` (as in v1.9.14.3).
### v1.9.15.0
*2014-12-07* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.15.0/builds/4chan-X-noupdate.crx "Chromium version")]
Based on v1.9.14.2.
**MayhemYDG, Matěj Grabovský**
- Quoting now also includes the spoiler and code tags.
**ccd0**
- Quote the original URL of links rather than the title, and don't quote `(embed)`.
- Bug fixes.
<!-- v1.9.14.x --> <!-- v1.9.14.x -->
### v1.9.14.4
*2014-12-08* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.4/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.4/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Fix sounds sometimes playing for a short time before `Disable Autoplaying Sounds` halts them.
### v1.9.14.3
*2014-12-07* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.3/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.3/builds/4chan-X-noupdate.crx "Chromium version")]
**ccd0**
- Center the controls added to formerly autoplaying audio by `Disable Autoplaying Sounds`.
### v1.9.14.2 ### v1.9.14.2
*2014-12-04* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.2/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.2/builds/4chan-X-noupdate.crx "Chromium version")] *2014-12-04* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.2/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.14.2/builds/4chan-X-noupdate.crx "Chromium version")]

View File

@ -25,6 +25,10 @@ module.exports = (grunt) ->
output = if parts2.length is 0 then '""' else parts2.join ' + ' output = if parts2.length is 0 then '""' else parts2.join ' + '
"(innerHTML: #{output})" "(innerHTML: #{output})"
assert = (statement, objs...) ->
return '' unless grunt.config('pkg').tests_enabled
"throw new Error 'Assertion failed: ' + `#{JSON.stringify statement}` unless #{statement}"
# Project configuration. # Project configuration.
grunt.initConfig grunt.initConfig
pkg: grunt.file.readJSON 'package.json' pkg: grunt.file.readJSON 'package.json'
@ -35,6 +39,7 @@ module.exports = (grunt) ->
pkg = grunt.config 'pkg' pkg = grunt.config 'pkg'
pkg.importHTML = importHTML pkg.importHTML = importHTML
pkg.html = html pkg.html = html
pkg.assert = assert
pkg.tests_enabled or= false pkg.tests_enabled or= false
pkg pkg
enumerable: true enumerable: true

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.9.14.2 * 4chan X - Version 1.9.15.4
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/ccd0/4chan-x/blob/master/LICENSE * https://github.com/ccd0/4chan-x/blob/master/LICENSE

View File

@ -39,6 +39,9 @@ If you want to install the current beta version but get updates from the stable
## Security note ## Security note
4chan X currently shares your settings and post history between the HTTP and HTTPS versions of 4chan. If you are concerned about protecting your privacy against a man-in-the-middle attack, you should disable 4chan X on the HTTP version of 4chan and/or install [HTTPS Everywhere](https://www.eff.org/https-everywhere). 4chan X currently shares your settings and post history between the HTTP and HTTPS versions of 4chan. If you are concerned about protecting your privacy against a man-in-the-middle attack, you should disable 4chan X on the HTTP version of 4chan and/or install [HTTPS Everywhere](https://www.eff.org/https-everywhere).
## Uninstalling
4chan X disables the native extension, so if you uninstall 4chan X, you'll need to re-enable it. To do this, click the `[Settings]` link in the top right corner and uncheck "`Disable the native extension`" in the panel that appears.
## More information ## More information
- [Source Code](https://github.com/ccd0/4chan-x) - [Source Code](https://github.com/ccd0/4chan-x)
- [Changelog](https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md) - [Changelog](https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md)

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X beta // @name 4chan X beta
// @version 1.9.14.2 // @version 1.9.15.4
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.9.14.2 // @version 1.9.15.4
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.9.14.2' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.9.15.4' />
</app> </app>
</gupdate> </gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'> <app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.9.14.2' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.9.15.4' />
</app> </app>
</gupdate> </gupdate>

View File

@ -47,6 +47,8 @@ Only the latest stable version of 4chan X is available.</p>
<p>If you want to install the current beta version but get updates from the stable channel after that, install it from <a href="https://github.com/ccd0/4chan-x/raw/beta/builds/4chan-X.user.js">here</a> for Firefox or <a href="https://github.com/ccd0/4chan-x/raw/beta/builds/4chan-X.crx">here</a> for Chromium.</p> <p>If you want to install the current beta version but get updates from the stable channel after that, install it from <a href="https://github.com/ccd0/4chan-x/raw/beta/builds/4chan-X.user.js">here</a> for Firefox or <a href="https://github.com/ccd0/4chan-x/raw/beta/builds/4chan-X.crx">here</a> for Chromium.</p>
<h2 id="security-note">Security note</h2> <h2 id="security-note">Security note</h2>
<p>4chan X currently shares your settings and post history between the HTTP and HTTPS versions of 4chan. If you are concerned about protecting your privacy against a man-in-the-middle attack, you should disable 4chan X on the HTTP version of 4chan and/or install <a href="https://www.eff.org/https-everywhere">HTTPS Everywhere</a>.</p> <p>4chan X currently shares your settings and post history between the HTTP and HTTPS versions of 4chan. If you are concerned about protecting your privacy against a man-in-the-middle attack, you should disable 4chan X on the HTTP version of 4chan and/or install <a href="https://www.eff.org/https-everywhere">HTTPS Everywhere</a>.</p>
<h2 id="uninstalling">Uninstalling</h2>
<p>4chan X disables the native extension, so if you uninstall 4chan X, you&#39;ll need to re-enable it. To do this, click the <code>[Settings]</code> link in the top right corner and uncheck &quot;<code>Disable the native extension</code>&quot; in the panel that appears.</p>
<h2 id="more-information">More information</h2> <h2 id="more-information">More information</h2>
<ul> <ul>
<li><a href="https://github.com/ccd0/4chan-x">Source Code</a></li> <li><a href="https://github.com/ccd0/4chan-x">Source Code</a></li>

View File

@ -3,7 +3,7 @@
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",
"version": "1.9.14.2", "version": "1.9.15.4",
"repo": "https://github.com/ccd0/4chan-x/", "repo": "https://github.com/ccd0/4chan-x/",
"page": "https://github.com/ccd0/4chan-x", "page": "https://github.com/ccd0/4chan-x",
"downloads": "https://ccd0.github.io/4chan-x/builds/", "downloads": "https://ccd0.github.io/4chan-x/builds/",

View File

@ -14,7 +14,7 @@ Config =
'Link to 4chan X\'s catalog instead of the native 4chan one.' 'Link to 4chan X\'s catalog instead of the native 4chan one.'
] ]
'Catalog Links': [ 'Catalog Links': [
true false
'Add toggle link in header menu to turn Navigation links into links to each board\'s catalog.' 'Add toggle link in header menu to turn Navigation links into links to each board\'s catalog.'
] ]
'QR Shortcut': [ 'QR Shortcut': [
@ -46,7 +46,7 @@ Config =
'Localize and format timestamps.' 'Localize and format timestamps.'
] ]
'Relative Post Dates': [ 'Relative Post Dates': [
true false
'Display dates like "3 minutes ago". Tooltip shows the timestamp.' 'Display dates like "3 minutes ago". Tooltip shows the timestamp.'
] ]
'Comment Expansion': [ 'Comment Expansion': [
@ -589,6 +589,7 @@ http://iqdb.org/?url=%TURL
'Index Sort': 'bump' 'Index Sort': 'bump'
'Index Size': 'small' 'Index Size': 'small'
'Show Replies': true 'Show Replies': true
'Pin Watched Threads': false
'Anchor Hidden Threads': true 'Anchor Hidden Threads': true
'Refreshed Navigation': false 'Refreshed Navigation': false

View File

@ -24,25 +24,27 @@ Index =
Header.addShortcut @button, 1 Header.addShortcut @button, 1
repliesEntry = el: UI.checkbox 'Show Replies', ' Show replies' repliesEntry = el: UI.checkbox 'Show Replies', ' Show replies'
pinEntry = el: UI.checkbox 'Pin Watched Threads', ' Pin watched threads'
anchorEntry = el: UI.checkbox 'Anchor Hidden Threads', ' Anchor hidden threads' anchorEntry = el: UI.checkbox 'Anchor Hidden Threads', ' Anchor hidden threads'
refNavEntry = el: UI.checkbox 'Refreshed Navigation', ' Refreshed navigation' refNavEntry = el: UI.checkbox 'Refreshed Navigation', ' Refreshed navigation'
anchorEntry.el.title = 'Move hidden threads at the end of the index.' pinEntry.el.title = 'Move watched threads to the start of the index.'
anchorEntry.el.title = 'Move hidden threads to the end of the index.'
refNavEntry.el.title = 'Refresh index when navigating through pages.' refNavEntry.el.title = 'Refresh index when navigating through pages.'
for label in [repliesEntry, anchorEntry, refNavEntry] for label in [repliesEntry, pinEntry, anchorEntry, refNavEntry]
input = label.el.firstChild input = label.el.firstChild
{name} = input {name} = input
$.on input, 'change', $.cb.checked $.on input, 'change', $.cb.checked
switch name switch name
when 'Show Replies' when 'Show Replies'
$.on input, 'change', @cb.replies $.on input, 'change', @cb.replies
when 'Anchor Hidden Threads' when 'Pin Watched Threads', 'Anchor Hidden Threads'
$.on input, 'change', @cb.sort $.on input, 'change', @cb.sort
Header.menu.addEntry Header.menu.addEntry
el: $.el 'span', el: $.el 'span',
textContent: 'Index Navigation' textContent: 'Index Navigation'
order: 98 order: 98
subEntries: [repliesEntry, anchorEntry, refNavEntry] subEntries: [repliesEntry, pinEntry, anchorEntry, refNavEntry]
$.addClass doc, 'index-loading', "#{Conf['Index Mode'].replace /\ /g, '-'}-mode" $.addClass doc, 'index-loading', "#{Conf['Index Mode'].replace /\ /g, '-'}-mode"
@root = $.el 'div', className: 'board' @root = $.el 'div', className: 'board'
@ -252,9 +254,9 @@ Index =
1 1
else else
+window.location.pathname.split('/')[2] or 1 +window.location.pathname.split('/')[2] or 1
userPageNav: (page) -> userPageNav: (page, noRefresh) ->
state = Index.pushState {page} state = Index.pushState {page}
if Conf['Refreshed Navigation'] if Conf['Refreshed Navigation'] and !noRefresh
Index.update state Index.update state
else else
Index.pageLoad state if state.page Index.pageLoad state if state.page
@ -542,7 +544,7 @@ Index =
# Sticky threads # Sticky threads
Index.sortOnTop (thread) -> thread.isSticky Index.sortOnTop (thread) -> thread.isSticky
# Highlighted threads # Highlighted threads
Index.sortOnTop (thread) -> thread.isOnTop Index.sortOnTop (thread) -> thread.isOnTop or Conf['Pin Watched Threads'] and ThreadWatcher.isWatched thread
# Non-hidden threads # Non-hidden threads
Index.sortOnTop((thread) -> !thread.isHidden) if Conf['Anchor Hidden Threads'] Index.sortOnTop((thread) -> !thread.isHidden) if Conf['Anchor Hidden Threads']
@ -561,6 +563,11 @@ Index =
nodes = Index.buildCatalogViews() nodes = Index.buildCatalogViews()
Index.sizeCatalogViews nodes Index.sizeCatalogViews nodes
else else
if Index.followedThreadID?
i = 0
i++ while Index.followedThreadID isnt Get.threadFromRoot(Index.sortedNodes[i]).ID
page = i // Index.threadsNumPerPage + 1
Index.pushState {page} if page isnt Index.getCurrentPage()
nodes = Index.buildSinglePage Index.getCurrentPage() nodes = Index.buildSinglePage Index.getCurrentPage()
$.rmAll Index.root $.rmAll Index.root
$.rmAll Header.hover $.rmAll Header.hover
@ -569,6 +576,8 @@ Index =
else else
Index.buildReplies nodes if Conf['Show Replies'] Index.buildReplies nodes if Conf['Show Replies']
Index.buildStructure nodes Index.buildStructure nodes
if Index.followedThreadID? and (post = g.posts["#{g.BOARD}.#{Index.followedThreadID}"])
Header.scrollTo post.nodes.root
buildSinglePage: (pageNum) -> buildSinglePage: (pageNum) ->
nodesPerPage = Index.threadsNumPerPage nodesPerPage = Index.threadsNumPerPage

View File

@ -103,7 +103,9 @@ hr + div.center:not(.ad-cnt):not(.topad):not(.middlead):not(.bottomad) {
/* party hats */ /* party hats */
pointer-events: none; pointer-events: none;
} }
.center > audio {
/* Anti-autoplay */
audio.controls-added {
display: block; display: block;
margin: auto; margin: auto;
} }
@ -888,6 +890,7 @@ span.hide-announcement {
-webkit-align-self: stretch; -webkit-align-self: stretch;
align-self: stretch; align-self: stretch;
} }
.catalog-thread.watched .werkTyme-filename,
.filter-highlight .werkTyme-filename { .filter-highlight .werkTyme-filename {
border: 2px solid rgba(255, 0, 0, .5); border: 2px solid rgba(255, 0, 0, .5);
} }
@ -909,6 +912,7 @@ span.hide-announcement {
.filter-highlight > .reply { .filter-highlight > .reply {
box-shadow: -5px 0 rgba(255, 0, 0, .5); box-shadow: -5px 0 rgba(255, 0, 0, .5);
} }
.catalog-thread.watched .catalog-thumb,
.filter-highlight .catalog-thumb { .filter-highlight .catalog-thumb {
border: 2px solid rgba(255, 0, 0, .5); border: 2px solid rgba(255, 0, 0, .5);
} }
@ -918,6 +922,12 @@ span.hide-announcement {
:root.reveal-spoilers s > a { :root.reveal-spoilers s > a {
color: white !important; color: white !important;
} }
:root.reveal-spoilers .removed-spoiler::before {
content: "[spoiler]";
}
:root.reveal-spoilers .removed-spoiler::after {
content: "[/spoiler]";
}
/* Thread & Reply Hiding */ /* Thread & Reply Hiding */
.hide-thread-button, .hide-thread-button,

View File

@ -10,20 +10,20 @@
</div> </div>
<form> <form>
<div class=persona> <div class=persona>
<input name=name data-name=name list="list-name" placeholder=Name class=field size=1 tabindex=10> <input name=name data-name=name list="list-name" placeholder=Name class=field size=1>
<input name=email data-name=email list="list-email" placeholder=Options class=field size=1 tabindex=20> <input name=email data-name=email list="list-email" placeholder=Options class=field size=1>
<input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1 tabindex=30> <input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1>
</div> </div>
<div class=textarea> <div class=textarea>
<textarea data-name=com placeholder=Comment class=field tabindex=40></textarea> <textarea data-name=com placeholder=Comment class=field></textarea>
<span id=char-count></span> <span id=char-count></span>
</div> </div>
<div id=dump-list-container> <div id=dump-list-container>
<div id=dump-list></div> <div id=dump-list></div>
<a id=add-post href=javascript:; title="Add a post" tabindex=50>+</a> <a id=add-post href=javascript:; title="Add a post">+</a>
</div> </div>
<div id=file-n-submit> <div id=file-n-submit>
<span id=qr-filename-container class=field tabindex=60> <span id=qr-filename-container class=field tabindex=0>
<span id=qr-no-file>No selected file</span> <span id=qr-no-file>No selected file</span>
<input id="qr-filename" data-name="filename" spellcheck="false"> <input id="qr-filename" data-name="filename" spellcheck="false">
<span id=qr-extras-container> <span id=qr-extras-container>
@ -33,9 +33,9 @@
</span> </span>
</span> </span>
<label id=qr-spoiler-label> <label id=qr-spoiler-label>
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=70> <input type=checkbox id=qr-file-spoiler title='Spoiler image'>
</label> </label>
<input type=submit tabindex=80> <input type=submit>
</div> </div>
<input type=file multiple> <input type=file multiple>
</form> </form>

View File

@ -52,16 +52,20 @@ Linkify =
endNode = saved endNode = saved
{data} = saved {data} = saved
word += data
{length} = data
if end = space.exec data if end = space.exec data
# Set our snapshot and regex to start on this node at this position when the loop resumes # Set our snapshot and regex to start on this node at this position when the loop resumes
word += data[...end.index]
test.lastIndex = length = end.index test.lastIndex = length = end.index
i-- i--
break break
else
{length} = data
word += data
links.push Linkify.makeRange node, endNode, index, length if Linkify.regString.exec word if Linkify.regString.test word
links.push Linkify.makeRange node, endNode, index, length
<%= assert('word is links[links.length-1].toString()') %>
break unless test.lastIndex and node is endNode break unless test.lastIndex and node is endNode
@ -84,9 +88,9 @@ Linkify =
[a-z\d%/] [a-z\d%/]
) )
| # This should account for virtually all links posted without http: | # This should account for virtually all links posted without http:
[-a-z\d]+[.]( ([-a-z\d]+[.])+(
aero|asia|biz|cat|com|coop|info|int|jobs|mobi|moe|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2} aero|asia|biz|cat|com|coop|info|int|jobs|mobi|moe|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2}
)([:/]|(?!.)) )([:/]|(?![^\s'"]))
| # IPv4 Addresses | # IPv4 Addresses
[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3} [\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}
| # E-mails | # E-mails
@ -103,10 +107,9 @@ Linkify =
text = range.toString() text = range.toString()
# Clean start of range # Clean start of range
i = 0 i = text.search Linkify.regString
i++ while /[(\[{<>]/.test text.charAt i
if i if i > 0
text = text.slice i text = text.slice i
i-- while range.startOffset + i >= range.startContainer.data.length i-- while range.startOffset + i >= range.startContainer.data.length
@ -237,9 +240,11 @@ Linkify =
"#{status}'d" "#{status}'d"
}" }"
link.dataset.original = link.textContent
link.textContent = text link.textContent = text
for post2 in post.clones for post2 in post.clones
for link2 in $$ 'a.linkify', post2.nodes.comment when link2.href is link.href for link2 in $$ 'a.linkify', post2.nodes.comment when link2.href is link.href
link2.dataset.original = link2.textContent
link2.textContent = text link2.textContent = text
return return

View File

@ -1,10 +1,13 @@
AntiAutoplay = AntiAutoplay =
init: -> init: ->
return if !Conf['Disable Autoplaying Sounds'] return if !Conf['Disable Autoplaying Sounds']
$.ready @ready @stop audio for audio in $$ 'audio[autoplay]', doc
window.addEventListener 'loadstart', ((e) => @stop e.target), true
ready: -> stop: (audio) ->
for audio in $$ 'audio[autoplay]' return unless audio.autoplay
audio.pause() audio.pause()
audio.autoplay = false audio.autoplay = false
audio.controls = true return if audio.controls
audio.controls = true
$.addClass audio, 'controls-added'

View File

@ -1,14 +1,10 @@
RemoveSpoilers = RemoveSpoilers =
init: -> init: ->
if Conf['Reveal Spoilers'] and !Conf['Remove Spoilers'] if Conf['Reveal Spoilers']
$.addClass doc, 'reveal-spoilers' $.addClass doc, 'reveal-spoilers'
return unless Conf['Remove Spoilers'] return unless Conf['Remove Spoilers']
if Conf['Reveal Spoilers']
@wrapper = (text) ->
"[spoiler]#{text}[/spoiler]"
Post.callbacks.push Post.callbacks.push
name: 'Reveal Spoilers' name: 'Reveal Spoilers'
cb: @node cb: @node
@ -16,11 +12,10 @@ RemoveSpoilers =
name: 'Reveal Spoilers' name: 'Reveal Spoilers'
cb: @node cb: @node
wrapper: (text) ->
text
node: (post) -> node: (post) ->
spoilers = $$ 's', @nodes.comment spoilers = $$ 's', @nodes.comment
for spoiler in spoilers for spoiler in spoilers
$.replace spoiler, $.tn RemoveSpoilers.wrapper spoiler.textContent span = $.el 'span', className: 'removed-spoiler'
$.replace spoiler, span
$.add span, [spoiler.childNodes...]
return return

View File

@ -42,6 +42,29 @@ ThreadWatcher =
Thread.callbacks.push Thread.callbacks.push
name: 'Thread Watcher' name: 'Thread Watcher'
cb: @node cb: @node
CatalogThread.callbacks.push
name: 'Thread Watcher'
cb: @catalogNode
if g.VIEW is 'index' and Conf['JSON Navigation'] and Conf['Menu'] and g.BOARD.ID isnt 'f'
Menu.menu.addEntry
el: $.el 'a', href: 'javascript:;'
order: 6
open: ({thread}) ->
return false if Conf['Index Mode'] isnt 'catalog'
@el.textContent = if ThreadWatcher.isWatched thread
'Unwatch thread'
else
'Watch thread'
$.off @el, 'click', @cb if @cb
@cb = ->
$.event 'CloseMenu'
ThreadWatcher.toggle thread
$.on @el, 'click', @cb
true
isWatched: (thread) ->
ThreadWatcher.db?.get {boardID: thread.board.ID, threadID: thread.ID}
node: -> node: ->
toggler = $.el 'img', toggler = $.el 'img',
@ -49,6 +72,13 @@ ThreadWatcher =
$.on toggler, 'click', ThreadWatcher.cb.toggle $.on toggler, 'click', ThreadWatcher.cb.toggle
$.before $('input', @OP.nodes.post), toggler $.before $('input', @OP.nodes.post), toggler
catalogNode: ->
$.addClass @nodes.root, 'watched' if ThreadWatcher.isWatched @thread
$.on @nodes.thumb.parentNode, 'click', (e) =>
return unless e.button is 0 and e.altKey
ThreadWatcher.toggle @thread
e.preventDefault()
ready: -> ready: ->
$.off d, '4chanXInitFinished', ThreadWatcher.ready $.off d, '4chanXInitFinished', ThreadWatcher.ready
return unless Main.isThisPageLegit() return unless Main.isThisPageLegit()
@ -83,7 +113,10 @@ ThreadWatcher =
ThreadWatcher.refresh() ThreadWatcher.refresh()
$.event 'CloseMenu' $.event 'CloseMenu'
toggle: -> toggle: ->
ThreadWatcher.toggle Get.postFromNode(@).thread {thread} = Get.postFromNode @
Index.followedThreadID = thread.ID
ThreadWatcher.toggle thread
delete Index.followedThreadID
rm: -> rm: ->
[boardID, threadID] = @parentNode.dataset.fullID.split '.' [boardID, threadID] = @parentNode.dataset.fullID.split '.'
ThreadWatcher.rm boardID, +threadID ThreadWatcher.rm boardID, +threadID
@ -240,14 +273,17 @@ ThreadWatcher =
for threadID in threads.keys for threadID in threads.keys
thread = threads[threadID] thread = threads[threadID]
toggler = $ '.watch-thread-link', thread.OP.nodes.post toggler = $ '.watch-thread-link', thread.OP.nodes.post
watched = ThreadWatcher.db.get {boardID: thread.board.ID, threadID} helper = if ThreadWatcher.isWatched thread then ['addClass', 'Unwatch'] else ['rmClass', 'Watch']
helper = if watched then ['addClass', 'Unwatch'] else ['rmClass', 'Watch']
$[helper[0]] toggler, 'watched' $[helper[0]] toggler, 'watched'
$[helper[0]] thread.catalogView.nodes.root, 'watched' if thread.catalogView
toggler.title = "#{helper[1]} Thread" toggler.title = "#{helper[1]} Thread"
for refresher in ThreadWatcher.menu.refreshers for refresher in ThreadWatcher.menu.refreshers
refresher() refresher()
return
if Index.nodes and Conf['Pin Watched Threads']
Index.sort()
Index.buildIndex()
toggle: (thread) -> toggle: (thread) ->
boardID = thread.board.ID boardID = thread.board.ID

View File

@ -14,7 +14,6 @@ QR.captcha =
title: 'Verification' title: 'Verification'
autocomplete: 'off' autocomplete: 'off'
spellcheck: false spellcheck: false
tabIndex: 45
@nodes = {container, input} @nodes = {container, input}
$.on input, 'blur', QR.focusout $.on input, 'blur', QR.focusout

View File

@ -213,12 +213,34 @@ QR =
e?.preventDefault() e?.preventDefault()
return unless QR.postingIsEnabled return unless QR.postingIsEnabled
sel = d.getSelection() sel = d.getSelection()
post = Get.postFromNode @ post = Get.postFromNode @
text = ">>#{post}\n" text = ">>#{post}\n"
if (s = sel.toString().trim()) and post is Get.postFromNode sel.anchorNode if sel.toString().trim() and post is Get.postFromNode sel.anchorNode
s = s.replace /\n/g, '\n>' range = sel.getRangeAt 0
text += ">#{s}\n" frag = range.cloneContents()
ancestor = range.commonAncestorContainer
# Quoting the insides of a spoiler/code tag.
if $.x 'ancestor-or-self::*[self::s or contains(@class,"removed-spoiler")]', ancestor
$.prepend frag, $.tn '[spoiler]'
$.add frag, $.tn '[/spoiler]'
if insideCode = $.x 'ancestor-or-self::pre[contains(@class,"prettyprint")]', ancestor
$.prepend frag, $.tn '[code]'
$.add frag, $.tn '[/code]'
for node in $$ (if insideCode then 'br' else '.prettyprint br'), frag
$.replace node, $.tn '\n'
for node in $$ 'br', frag
$.replace node, $.tn '\n>' unless node is frag.lastChild
for node in $$ 's, .removed-spoiler', frag
$.replace node, [$.tn('[spoiler]'), node.childNodes..., $.tn '[/spoiler]']
for node in $$ '.prettyprint', frag
$.replace node, [$.tn('[code]'), node.childNodes..., $.tn '[/code]']
for node in $$ '.linkify[data-original]', frag
$.replace node, $.tn node.dataset.original
for node in $$ '.embedder', frag
$.rm node.previousSibling if node.previousSibling?.nodeValue is ' '
$.rm node
text += ">#{frag.textContent.trim()}\n"
QR.open() QR.open()
if QR.selected.isLocked if QR.selected.isLocked