Merge branch 'mayhem' into v3
Conflicts: CHANGELOG.md CONTRIBUTING.md css/style.css html/General/Settings-section-Main.html json/archives.json package.json src/Archive/Redirect.coffee src/General/Header.coffee src/General/Main.coffee src/General/Settings.coffee src/General/lib/$.coffee src/General/lib/thread.class src/Linkification/Linkify.coffee src/Miscellaneous/AnnouncementHiding.coffee src/Monitoring/ThreadStats.coffee
This commit is contained in:
commit
b6749b91a5
@ -1,5 +1,7 @@
|
||||
### v1.3.2
|
||||
*2014-01-12*
|
||||
**MayhemYDG**:
|
||||
- Added a `Reset Settings` button in the settings.
|
||||
- More stability update.
|
||||
- Stability update.
|
||||
|
||||
**seaweedchan**:
|
||||
- Fix Menu errors on older Firefox versions, such as the ESR
|
||||
|
||||
48
CONTRIBUTING.md
Normal file
48
CONTRIBUTING.md
Normal file
@ -0,0 +1,48 @@
|
||||
## Reporting bugs and suggestions
|
||||
|
||||
Reporting bugs:
|
||||
|
||||
1. Make sure both your **browser** and **4chan X** are up to date.<br>
|
||||
Only **Chrome**, **Firefox** and **Opera** are supported.<br>
|
||||
**SRWare Iron**, **Firefox ESR**, **Pale Moon**, **Waterfox**, and other derivatives are not supported, use them at your own risk.
|
||||
2. Look at the list of [known problems and solutions](https://github.com/MayhemYDG/4chan-x/wiki/FAQ#known-problems).
|
||||
3. Disable your other extensions & scripts to identify conflicts.
|
||||
4. If your issue persists, open a [new issue](https://github.com/MayhemYDG/4chan-x/issues) with the following information:
|
||||
1. Precise steps to reproduce the problem, with the expected and actual results.
|
||||
2. [Console errors](https://github.com/MayhemYDG/4chan-x/wiki/FAQ#console-errors), if any.
|
||||
3. 4chan X version, browser variant, browser version, and Greasemonkey version if you are using it.
|
||||
4. Your exported settings. If your settings contains sensible information (e.g. personas), edit the text file manually.
|
||||
|
||||
Respect these guidelines:
|
||||
- Describe the issue clearly, put some effort into it. A one-liner isn't a good enough description.
|
||||
- If you want to get your suggestion implemented sooner, make it convincing.
|
||||
- If you want to criticize, make it convincing and constructive.
|
||||
- Be mature. Act like an idiot and you will be blocked without warning.
|
||||
|
||||
## Development & Contribution
|
||||
|
||||
### Get started
|
||||
|
||||
- Install [node.js](http://nodejs.org/).
|
||||
- Install [Grunt's CLI](http://gruntjs.com/) with `npm install -g grunt-cli`.
|
||||
- Clone 4chan X.
|
||||
- `cd` into it.
|
||||
- Install/Update 4chan X dependencies with `npm install`.
|
||||
|
||||
### Build
|
||||
|
||||
- Build with `grunt`.
|
||||
- Continuously build with `grunt watch`.
|
||||
|
||||
### Release
|
||||
|
||||
- Update the version with `grunt patch`, `grunt minor` or `grunt major`.
|
||||
- Release with `grunt release`.
|
||||
|
||||
Note: this is only used to release new 4chan X versions, and is **not** needed or wanted in pull requests.
|
||||
|
||||
### Contribute
|
||||
|
||||
- Edit the sources.
|
||||
- If the edits affect regular users, edit the changelog.
|
||||
- Open a pull request.
|
||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 4chan X - Version 1.3.2 - 2014-01-21
|
||||
* 4chan X - Version 1.3.2 - 2014-01-22
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name 4chan X
|
||||
// @version 1.3.2
|
||||
// @minGMVer 1.13
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||
@ -13,6 +13,7 @@
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_listValues
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL https://github.com/seaweedchan/4chan-x/raw/stable/builds/4chan-X.meta.js
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
18
package.json
18
package.json
@ -21,22 +21,22 @@
|
||||
"min": {
|
||||
"chrome": "31",
|
||||
"firefox": "26",
|
||||
"greasemonkey": "1.13"
|
||||
"greasemonkey": "1.14"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.0.3.tar.gz",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-bump": "~0.0.11",
|
||||
"grunt-concurrent": "~0.4.0",
|
||||
"font-awesome": "~4.0.3",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-concurrent": "~0.4.3",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-coffee": "~0.8.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-coffee": "~0.8.2",
|
||||
"grunt-contrib-compress": "~0.6.0",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-copy": "~0.5.0",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-shell": "~0.6.0",
|
||||
"load-grunt-tasks": "~0.2.0"
|
||||
"grunt-shell": "~0.6.3",
|
||||
"load-grunt-tasks": "~0.2.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
Redirect =
|
||||
|
||||
init: ->
|
||||
o =
|
||||
thread: {}
|
||||
@ -52,8 +51,8 @@ Redirect =
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "4plebs"
|
||||
boards: ["hr", "o", "pol", "s4s", "tg", "tv", "x"]
|
||||
files: ["hr", "o", "pol", "s4s", "tg", "tv", "x"]
|
||||
boards: ["adv", "hr", "o", "pol", "s4s", "tg", "tv", "x"]
|
||||
files: ["adv", "hr", "o", "pol", "s4s", "tg", "tv", "x"]
|
||||
data:
|
||||
domain: "archive.4plebs.org"
|
||||
http: true
|
||||
@ -68,6 +67,15 @@ Redirect =
|
||||
http: true
|
||||
https: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "Love is Over"
|
||||
boards: ["d", "i"],
|
||||
files: ["d", "i"]
|
||||
data:
|
||||
domain: "loveisover.me"
|
||||
http: true
|
||||
https: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "Install Gentoo"
|
||||
boards: ["diy", "g", "sci"]
|
||||
@ -82,7 +90,7 @@ Redirect =
|
||||
boards: ["cgl", "g", "mu", "w"]
|
||||
files: ["cgl", "g", "mu", "w"]
|
||||
data:
|
||||
domain: "rbt.asia"
|
||||
domain: "archive.rebeccablacktech.com"
|
||||
http: true
|
||||
https: true
|
||||
software: "fuuka"
|
||||
@ -100,9 +108,33 @@ Redirect =
|
||||
files: ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "tg", "vr"]
|
||||
data:
|
||||
domain: "fuuka.warosu.org"
|
||||
http: true
|
||||
https: true
|
||||
software: "fuuka"
|
||||
,
|
||||
name: "fgts"
|
||||
boards: ["soc"]
|
||||
files: ["soc"]
|
||||
data:
|
||||
domain: "fgts.eu"
|
||||
http: true
|
||||
https: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "maware"
|
||||
boards: ["t"]
|
||||
files: ["t"]
|
||||
data:
|
||||
domain: "archive.mawa.re"
|
||||
http: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "installgentoo.com"
|
||||
boards: ["g", "t"]
|
||||
files: ["g", "t"]
|
||||
data:
|
||||
domain: "chan.installgentoo.com"
|
||||
http: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "Foolz Beta"
|
||||
boards: ["a", "co", "d", "gd", "h", "jp", "m", "mlp", "sp", "tg", "tv", "u", "v", "vg", "vp", "vr", "wsg"],
|
||||
@ -113,15 +145,6 @@ Redirect =
|
||||
https: true
|
||||
withCredentials: true
|
||||
software: "foolfuuka"
|
||||
,
|
||||
name: "Love is Over"
|
||||
boards: ["d", "i"],
|
||||
files: ["d", "i"]
|
||||
data:
|
||||
domain: "loveisover.me"
|
||||
http: true
|
||||
https: true
|
||||
software: "foolfuuka"
|
||||
]
|
||||
|
||||
to: (dest, data) ->
|
||||
|
||||
@ -58,7 +58,7 @@ ThreadHiding =
|
||||
$.cache "//a.4cdn.org/#{g.BOARD}/threads.json", ->
|
||||
return unless @status is 200
|
||||
threads = {}
|
||||
for page in JSON.parse @response
|
||||
for page in @response
|
||||
for thread in page.threads
|
||||
if thread.no of hiddenThreadsOnCatalog
|
||||
threads[thread.no] = hiddenThreadsOnCatalog[thread.no]
|
||||
|
||||
@ -80,6 +80,7 @@ Get =
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
responseType: 'json'
|
||||
withCredentials: url.archive.withCredentials
|
||||
insert: (post, root, context) ->
|
||||
# Stop here if the container has been removed while loading.
|
||||
@ -118,7 +119,7 @@ Get =
|
||||
"Error #{req.statusText} (#{req.status})."
|
||||
return
|
||||
|
||||
posts = JSON.parse(req.response).posts
|
||||
{posts} = req.response
|
||||
Build.spoilerRange[boardID] = posts[0].custom_spoiler
|
||||
for post in posts
|
||||
break if post.no is postID # we found it!
|
||||
@ -149,7 +150,7 @@ Get =
|
||||
Get.insert post, root, context
|
||||
return
|
||||
|
||||
data = JSON.parse req.response
|
||||
data = req.response
|
||||
if data.error
|
||||
$.addClass root, 'warning'
|
||||
root.textContent = data.error
|
||||
@ -227,4 +228,4 @@ Get =
|
||||
'[/moot]': '</div>'
|
||||
'[banned]': '<strong style="color: red;">'
|
||||
'[/banned]': '</strong>'
|
||||
}[text] or text.replace ':lit', ''
|
||||
}[text] or text.replace ':lit', ''
|
||||
|
||||
@ -305,17 +305,15 @@ Header =
|
||||
|
||||
toggleHideBarOnScroll: (e) ->
|
||||
hide = @checked
|
||||
$.set 'Header auto-hide on scroll', hide
|
||||
$.cb.checked.call @
|
||||
Header.setHideBarOnScroll hide
|
||||
|
||||
hideBarOnScroll: ->
|
||||
offsetY = window.pageYOffset
|
||||
if offsetY > (Header.previousOffset or 0)
|
||||
$.addClass Header.bar, 'autohide'
|
||||
$.addClass Header.bar, 'scroll'
|
||||
$.addClass Header.bar, 'autohide', 'scroll'
|
||||
else
|
||||
$.rmClass Header.bar, 'autohide'
|
||||
$.rmClass Header.bar, 'scroll'
|
||||
$.rmClass Header.bar, 'autohide', 'scroll'
|
||||
Header.previousOffset = offsetY
|
||||
|
||||
setBarPosition: (bottom) ->
|
||||
@ -389,9 +387,21 @@ Header =
|
||||
scrollTo: (root, down, needed) ->
|
||||
if down
|
||||
x = Header.getBottomOf root
|
||||
if Conf['Header auto-hide on scroll'] and Conf['Bottom header']
|
||||
{height} = Header.bar.getBoundingClientRect()
|
||||
if x <= 0
|
||||
x += height if !Header.isHidden()
|
||||
else
|
||||
x -= height if Header.isHidden()
|
||||
window.scrollBy 0, -x unless needed and x >= 0
|
||||
else
|
||||
x = Header.getTopOf root
|
||||
if Conf['Header auto-hide on scroll'] and !Conf['Bottom header']
|
||||
{height} = Header.bar.getBoundingClientRect()
|
||||
if x >= 0
|
||||
x += height if !Header.isHidden()
|
||||
else
|
||||
x -= height if Header.isHidden()
|
||||
window.scrollBy 0, x unless needed and x >= 0
|
||||
|
||||
scrollToIfNeeded: (root, down) ->
|
||||
@ -411,6 +421,12 @@ Header =
|
||||
headRect = Header.toggle.getBoundingClientRect()
|
||||
bottom -= clientHeight - headRect.bottom + headRect.height
|
||||
bottom
|
||||
isHidden: ->
|
||||
{top} = Header.bar.getBoundingClientRect()
|
||||
if Conf['Bottom header']
|
||||
top is doc.clientHeight
|
||||
else
|
||||
top < 0
|
||||
|
||||
addShortcut: (el) ->
|
||||
shortcut = $.el 'span',
|
||||
|
||||
@ -279,7 +279,7 @@ Index =
|
||||
|
||||
try
|
||||
if req.status is 200
|
||||
Index.parse JSON.parse(req.response), pageNum
|
||||
Index.parse req.response, pageNum
|
||||
else if req.status is 304 and pageNum?
|
||||
Index.pageNav pageNum
|
||||
catch err
|
||||
@ -475,6 +475,7 @@ Index =
|
||||
else
|
||||
pageNum = Index.getCurrentPage()
|
||||
else
|
||||
return unless Index.searchInput.dataset.searching
|
||||
pageNum = Index.pageBeforeSearch
|
||||
delete Index.pageBeforeSearch
|
||||
<% if (type === 'userscript') { %>
|
||||
|
||||
@ -78,16 +78,9 @@ Main =
|
||||
return if !Main.isThisPageLegit() or $.hasClass doc, 'fourchan-x'
|
||||
# disable the mobile layout
|
||||
$('link[href*=mobile]', d.head)?.disabled = true
|
||||
<% if (type === 'crx') { %>
|
||||
$.addClass doc, 'blink'
|
||||
<% } else { %>
|
||||
$.addClass doc, 'gecko'
|
||||
<% } %>
|
||||
$.addClass doc, 'fourchan-x'
|
||||
$.addClass doc, 'seaweedchan'
|
||||
$.addClass doc, g.VIEW
|
||||
$.addClass doc, 'fourchan-x', 'seaweedchan', g.VIEW, '<% if (type === 'crx') { %>blink<% } else { %>gecko<% } %>'
|
||||
$.addStyle Main.css
|
||||
|
||||
|
||||
Main.setClass()
|
||||
|
||||
setClass: ->
|
||||
@ -124,6 +117,7 @@ Main =
|
||||
# Something might have gone wrong!
|
||||
Main.initStyle()
|
||||
|
||||
# 4chan Pass Link
|
||||
if styleSelector = $.id 'styleSelector'
|
||||
passLink = $.el 'a',
|
||||
textContent: '4chan Pass'
|
||||
@ -134,12 +128,18 @@ Main =
|
||||
'left=0,top=0,width=500,height=255,toolbar=0,resizable=0'
|
||||
$.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0']
|
||||
|
||||
# Parse HTML or skip it and start building from JSON.
|
||||
unless Conf['JSON Navigation'] and g.VIEW is 'index'
|
||||
Main.initThread()
|
||||
else
|
||||
$.event '4chanXInitFinished'
|
||||
|
||||
<% if (type === 'userscript') { %>
|
||||
test = $.el 'span'
|
||||
test.classList.add 'a', 'b'
|
||||
if test.className isnt 'a b'
|
||||
new Notice 'warning', "Your version of Firefox is outdated (v<%= meta.min.firefox %> minimum) and <%= meta.name %> may not operate correctly.", 30
|
||||
|
||||
GMver = GM_info.version.split '.'
|
||||
for v, i in "<%= meta.min.greasemonkey %>".split '.'
|
||||
continue if v is GMver[i]
|
||||
@ -176,6 +176,17 @@ Main =
|
||||
Main.callbackNodesDB Post, posts, ->
|
||||
$.event '4chanXInitFinished'
|
||||
|
||||
$.get 'previousversion', null, ({previousversion}) ->
|
||||
return if previousversion is g.VERSION
|
||||
if previousversion
|
||||
changelog = '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md'
|
||||
el = $.el 'span',
|
||||
innerHTML: "<%= meta.name %> has been updated to <a href='#{changelog}' target=_blank>version #{g.VERSION}</a>."
|
||||
new Notice 'info', el, 15
|
||||
else
|
||||
Settings.open()
|
||||
$.set 'previousversion', g.VERSION
|
||||
|
||||
callbackNodes: (klass, nodes) ->
|
||||
i = 0
|
||||
cb = klass.callbacks
|
||||
|
||||
@ -249,7 +249,7 @@ Navigate =
|
||||
Navigate.title()
|
||||
|
||||
try
|
||||
Navigate.parse JSON.parse(req.response).posts
|
||||
Navigate.parse req.response.posts
|
||||
catch err
|
||||
console.error 'Navigate failure:'
|
||||
console.log err
|
||||
|
||||
@ -9,19 +9,6 @@ Settings =
|
||||
|
||||
Header.addShortcut link
|
||||
|
||||
$.get 'previousversion', null, (item) ->
|
||||
if previous = item['previousversion']
|
||||
return if previous is g.VERSION
|
||||
|
||||
changelog = '<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md'
|
||||
el = $.el 'span',
|
||||
innerHTML: "<%= meta.name %> has been updated to <a href='#{changelog}' target=_blank>version #{g.VERSION}</a>."
|
||||
if Conf['Show Updated Notifications']
|
||||
new Notice 'info', el, 30
|
||||
else
|
||||
$.on d, '4chanXInitFinished', Settings.open
|
||||
$.set 'previousversion', g.VERSION
|
||||
|
||||
Settings.addSection 'Main', Settings.main
|
||||
Settings.addSection 'Filter', Settings.filter
|
||||
Settings.addSection 'Sauce', Settings.sauce
|
||||
@ -37,7 +24,6 @@ Settings =
|
||||
localStorage.setItem '4chan-settings', JSON.stringify settings
|
||||
|
||||
open: (openSection) ->
|
||||
$.off d, '4chanXInitFinished', Settings.open
|
||||
return if Settings.dialog
|
||||
$.event 'CloseMenu'
|
||||
|
||||
@ -53,6 +39,7 @@ Settings =
|
||||
|
||||
$.on $('.export', Settings.dialog), 'click', Settings.export
|
||||
$.on $('.import', Settings.dialog), 'click', Settings.import
|
||||
$.on $('.reset', Settings.dialog), 'click', Settings.reset
|
||||
$.on $('input', Settings.dialog), 'change', Settings.onImport
|
||||
|
||||
links = []
|
||||
@ -124,56 +111,39 @@ Settings =
|
||||
div = $.el 'div',
|
||||
innerHTML: "<button></button><span class=description>: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
|
||||
button = $ 'button', div
|
||||
hiddenNum = 0
|
||||
$.get 'hiddenThreads', boards: {}, (item) ->
|
||||
for ID, board of item.hiddenThreads.boards
|
||||
$.get {hiddenThreads: {}, hiddenPosts: {}}, ({hiddenThreads, hiddenPosts}) ->
|
||||
hiddenNum = 0
|
||||
for ID, board of hiddenThreads.boards
|
||||
hiddenNum += Object.keys(board).length
|
||||
for ID, board of hiddenPosts.boards
|
||||
for ID, thread of board
|
||||
hiddenNum++
|
||||
button.textContent = "Hidden: #{hiddenNum}"
|
||||
$.get 'hiddenPosts', boards: {}, (item) ->
|
||||
for ID, board of item.hiddenPosts.boards
|
||||
for ID, thread of board
|
||||
for ID, post of thread
|
||||
hiddenNum++
|
||||
hiddenNum += Object.keys(thread).length
|
||||
button.textContent = "Hidden: #{hiddenNum}"
|
||||
$.on button, 'click', ->
|
||||
@textContent = 'Hidden: 0'
|
||||
$.get 'hiddenThreads', boards: {}, (item) ->
|
||||
for boardID of item.hiddenThreads.boards
|
||||
$.get 'hiddenThreads', {}, ({hiddenThreads}) ->
|
||||
for boardID of hiddenThreads.boards
|
||||
localStorage.removeItem "4chan-hide-t-#{boardID}"
|
||||
$.delete ['hiddenThreads', 'hiddenPosts']
|
||||
$.after $('input[name="Stubs"]', section).parentNode.parentNode, div
|
||||
export: (now, data) ->
|
||||
unless typeof now is 'number'
|
||||
now = Date.now()
|
||||
data =
|
||||
version: g.VERSION
|
||||
date: now
|
||||
for db in DataBoard.keys
|
||||
Conf[db] = boards: {}
|
||||
# Make sure to export the most recent data.
|
||||
$.get Conf, (Conf) ->
|
||||
# XXX don't export archives.
|
||||
delete Conf['archives']
|
||||
data.Conf = Conf
|
||||
Settings.export now, data
|
||||
return
|
||||
export: ->
|
||||
# Make sure to export the most recent data.
|
||||
$.get Conf, (Conf) ->
|
||||
# XXX don't export archives.
|
||||
delete Conf['archives']
|
||||
Settings.downloadExport {version: g.VERSION, date: Date.now(), Conf}
|
||||
downloadExport: (data) ->
|
||||
a = $.el 'a',
|
||||
className: 'warning'
|
||||
textContent: 'Save me!'
|
||||
download: "<%= meta.name %> v#{g.VERSION}-#{now}.json"
|
||||
download: "<%= meta.name %> v#{g.VERSION}-#{data.date}.json"
|
||||
href: "data:application/json;base64,#{btoa unescape encodeURIComponent JSON.stringify data, null, 2}"
|
||||
target: '_blank'
|
||||
<% if (type === 'userscript') { %>
|
||||
# XXX Firefox won't let us download automatically.
|
||||
p = $ '.imp-exp-result', Settings.dialog
|
||||
$.rmAll p
|
||||
$.add p, a
|
||||
<% } else { %>
|
||||
a.click()
|
||||
<% } %>
|
||||
a.click()
|
||||
import: ->
|
||||
@nextElementSibling.click()
|
||||
$('input', @parentNode).click()
|
||||
onImport: ->
|
||||
return unless file = @files[0]
|
||||
output = $('.imp-exp-result')
|
||||
@ -183,8 +153,7 @@ Settings =
|
||||
reader = new FileReader()
|
||||
reader.onload = (e) ->
|
||||
try
|
||||
data = JSON.parse e.target.result
|
||||
Settings.loadSettings data
|
||||
Settings.loadSettings JSON.parse e.target.result
|
||||
if confirm 'Import successful. Reload now?'
|
||||
window.location.reload()
|
||||
catch err
|
||||
@ -194,6 +163,11 @@ Settings =
|
||||
loadSettings: (data) ->
|
||||
version = data.version.split '.'
|
||||
if version[0] is '2'
|
||||
convertSettings = (data, map) ->
|
||||
for prevKey, newKey of map
|
||||
data.Conf[newKey] = data.Conf[prevKey] if newKey
|
||||
delete data.Conf[prevKey]
|
||||
data
|
||||
data = Settings.convertSettings data,
|
||||
# General confs
|
||||
'Disable 4chan\'s extension': ''
|
||||
@ -265,11 +239,9 @@ Settings =
|
||||
data.Conf['watchedThreads'] = boards: ThreadWatcher.convert data.Conf['WatchedThreads']
|
||||
delete data.Conf['WatchedThreads']
|
||||
$.set data.Conf
|
||||
convertSettings: (data, map) ->
|
||||
for prevKey, newKey of map
|
||||
data.Conf[newKey] = data.Conf[prevKey] if newKey
|
||||
delete data.Conf[prevKey]
|
||||
data
|
||||
reset: ->
|
||||
if confirm 'Your current settings will be entirely wiped, are you sure?'
|
||||
$.clear -> window.location.reload() if confirm 'Reset successful. Reload now?'
|
||||
|
||||
filter: (section) ->
|
||||
section.innerHTML = <%= importHTML('Settings/Filter-select') %>
|
||||
|
||||
@ -157,6 +157,9 @@ UI = do ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
onFocus: (e) =>
|
||||
e.stopPropagation()
|
||||
@focus e.target
|
||||
focus: (entry) ->
|
||||
while focused = $.x 'parent::*/child::*[contains(@class,"focused")]', entry
|
||||
$.rmClass focused, 'focused'
|
||||
@ -199,10 +202,7 @@ UI = do ->
|
||||
parseEntry: (entry) ->
|
||||
{el, subEntries} = entry
|
||||
$.addClass el, 'entry'
|
||||
$.on el, 'focus mouseover', ((e) ->
|
||||
e.stopPropagation()
|
||||
@focus el
|
||||
).bind @
|
||||
$.on el, 'focus mouseover', @onFocus
|
||||
el.style.order = entry.order or 100
|
||||
return unless subEntries
|
||||
$.addClass el, 'has-submenu'
|
||||
|
||||
@ -653,6 +653,15 @@ span.hide-announcement {
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dashed;
|
||||
}
|
||||
@supports (text-decoration-style: dashed) or (-moz-text-decoration-style: dashed) {
|
||||
.quotelink.forwardlink,
|
||||
.backlink.forwardlink {
|
||||
text-decoration: underline;
|
||||
-moz-text-decoration-style: dashed;
|
||||
text-decoration-style: dashed;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.filtered {
|
||||
text-decoration: underline line-through;
|
||||
}
|
||||
|
||||
@ -4,11 +4,12 @@
|
||||
<div class=credits>
|
||||
<a class=export>Export</a> |
|
||||
<a class=import>Import</a> |
|
||||
<input type=file style='display: none;'>
|
||||
<button class="reset">Reset Settings</button> |
|
||||
<input type=file hidden>
|
||||
<a href='<%= meta.page %>' target=_blank><%= meta.name %></a> |
|
||||
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/CHANGELOG.md' target=_blank>#{g.VERSION}</a> |
|
||||
<a href='<%= meta.repo %>blob/<%= meta.mainBranch %>/README.md#reporting-bugs-and-suggestions' target=_blank>Issues</a> |
|
||||
<a href=javascript:; class=close title=Close>×</a>
|
||||
<a href=javascript:; class='fa fa-times' title=Close></a>
|
||||
</div>
|
||||
</nav>
|
||||
<div class=section-container><section></section></div>
|
||||
@ -54,6 +54,8 @@ $.ajax = do ->
|
||||
if whenModified
|
||||
r.setRequestHeader 'If-Modified-Since', lastModified[url] if url of lastModified
|
||||
$.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified'
|
||||
if /\.json$/.test url
|
||||
r.responseType = 'json'
|
||||
$.extend r, options
|
||||
$.extend r.upload, upCallbacks
|
||||
r.send form
|
||||
@ -113,11 +115,11 @@ $.X = (path, root) ->
|
||||
# XPathResult.ORDERED_NODE_SNAPSHOT_TYPE === 7
|
||||
d.evaluate path, root, null, 7, null
|
||||
|
||||
$.addClass = (el, className) ->
|
||||
el.classList.add className
|
||||
$.addClass = (el, className...) ->
|
||||
el.classList.add className...
|
||||
|
||||
$.rmClass = (el, className) ->
|
||||
el.classList.remove className
|
||||
$.rmClass = (el, className...) ->
|
||||
el.classList.remove className...
|
||||
|
||||
$.toggleClass = (el, className) ->
|
||||
el.classList.toggle className
|
||||
@ -332,29 +334,50 @@ $.get = (key, val, cb) ->
|
||||
chrome.storage.sync.get syncItems, done
|
||||
|
||||
$.set = do ->
|
||||
items = {}
|
||||
localItems = {}
|
||||
items =
|
||||
sync: {}
|
||||
local: {}
|
||||
timeout = {}
|
||||
|
||||
set = $.debounce $.SECOND, ->
|
||||
setArea = (area) ->
|
||||
data = items[area]
|
||||
return if !Object.keys(data).length or timeout[area]
|
||||
items[area] = {}
|
||||
chrome.storage[area].set data, ->
|
||||
if chrome.runtime.lastError
|
||||
c.error chrome.runtime.lastError.message
|
||||
for key, val of data when key not of items[area]
|
||||
items[area][key] = val
|
||||
timeout[area] = setTimeout setArea, $.MINUTE, area
|
||||
return
|
||||
delete timeout[area]
|
||||
|
||||
setAll = $.debounce $.SECOND, ->
|
||||
for key in $.localKeys
|
||||
if key of items
|
||||
(localItems or= {})[key] = items[key]
|
||||
delete items[key]
|
||||
if key of items.sync
|
||||
items.local[key] = items.sync[key]
|
||||
delete items.sync[key]
|
||||
try
|
||||
chrome.storage.local.set localItems
|
||||
chrome.storage.sync.set items
|
||||
items = {}
|
||||
localItems = {}
|
||||
setArea 'local'
|
||||
setArea 'sync'
|
||||
catch err
|
||||
c.error err.stack
|
||||
|
||||
(key, val) ->
|
||||
if typeof key is 'string'
|
||||
items[key] = val
|
||||
items.sync[key] = val
|
||||
else
|
||||
$.extend items, key
|
||||
set()
|
||||
|
||||
$.extend items.sync, key
|
||||
setAll()
|
||||
$.clear = (cb) ->
|
||||
count = 2
|
||||
done = ->
|
||||
if chrome.runtime.lastError
|
||||
c.error chrome.runtime.lastError.message
|
||||
return
|
||||
cb?() unless --count
|
||||
chrome.storage.local.clear done
|
||||
chrome.storage.sync.clear done
|
||||
<% } else { %>
|
||||
|
||||
# http://wiki.greasespot.net/Main_Page
|
||||
@ -402,6 +425,9 @@ $.set = do ->
|
||||
for key, val of keys
|
||||
set key, val
|
||||
return
|
||||
$.clear = (cb) ->
|
||||
$.delete GM_listValues().map (key) -> key.replace g.NAMESPACE, ''
|
||||
cb?()
|
||||
<% } %>
|
||||
|
||||
$$ = (selector, root=d.body) ->
|
||||
|
||||
@ -78,7 +78,7 @@ class DataBoard
|
||||
return
|
||||
board = @data.boards[boardID]
|
||||
threads = {}
|
||||
for page in JSON.parse e.target.response
|
||||
for page in e.target.response
|
||||
for thread in page.threads
|
||||
if thread.no of board
|
||||
threads[thread.no] = board[thread.no]
|
||||
@ -93,4 +93,4 @@ class DataBoard
|
||||
disconnect: ->
|
||||
$.desync @key
|
||||
delete @sync
|
||||
delete @data
|
||||
delete @data
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_deleteValue
|
||||
// @grant GM_listValues
|
||||
// @grant GM_openInTab
|
||||
// @run-at document-start
|
||||
// @updateURL <%= meta.repo %>raw/stable/builds/<%= meta.files.metajs %>
|
||||
|
||||
@ -153,10 +153,19 @@ ImageExpand =
|
||||
return
|
||||
|
||||
timeoutID = setTimeout ImageExpand.expand, 10000, post
|
||||
<% if (type === 'crx') { %>
|
||||
$.ajax @src,
|
||||
onloadend: ->
|
||||
return if @status isnt 404
|
||||
clearTimeout timeoutID
|
||||
post.kill true
|
||||
,
|
||||
type: 'head'
|
||||
<% } else { %>
|
||||
# XXX CORS for i.4cdn.org WHEN?
|
||||
$.ajax "//a.4cdn.org/#{post.board}/res/#{post.thread}.json", onload: ->
|
||||
return if @status isnt 200
|
||||
for postObj in JSON.parse(@response).posts
|
||||
for postObj in @response.posts
|
||||
break if postObj.no is post.ID
|
||||
if postObj.no isnt post.ID
|
||||
clearTimeout timeoutID
|
||||
@ -164,6 +173,7 @@ ImageExpand =
|
||||
else if postObj.filedeleted
|
||||
clearTimeout timeoutID
|
||||
post.kill true
|
||||
<% } %>
|
||||
|
||||
menu:
|
||||
init: ->
|
||||
|
||||
@ -38,10 +38,19 @@ ImageHover =
|
||||
return
|
||||
|
||||
timeoutID = setTimeout (=> @src = post.file.URL + '?' + Date.now()), 3000
|
||||
<% if (type === 'crx') { %>
|
||||
$.ajax @src,
|
||||
onloadend: ->
|
||||
return if @status isnt 404
|
||||
clearTimeout timeoutID
|
||||
post.kill true
|
||||
,
|
||||
type: 'head'
|
||||
<% } else { %>
|
||||
# XXX CORS for i.4cdn.org WHEN?
|
||||
$.ajax "//a.4cdn.org/#{post.board}/res/#{post.thread}.json", onload: ->
|
||||
return if @status isnt 200
|
||||
for postObj in JSON.parse(@response).posts
|
||||
for postObj in @response.posts
|
||||
break if postObj.no is post.ID
|
||||
if postObj.no isnt post.ID
|
||||
clearTimeout timeoutID
|
||||
@ -49,3 +58,4 @@ ImageHover =
|
||||
else if postObj.filedeleted
|
||||
clearTimeout timeoutID
|
||||
post.kill true
|
||||
<% } %>
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
PSAHiding =
|
||||
init: ->
|
||||
return if !Conf['Announcement Hiding']
|
||||
|
||||
$.addClass doc, 'hide-announcement'
|
||||
|
||||
$.on d, '4chanXInitFinished', @setup
|
||||
|
||||
setup: ->
|
||||
$.off d, '4chanXInitFinished', PSAHiding.setup
|
||||
|
||||
|
||||
@ -77,13 +77,13 @@ ExpandThread =
|
||||
a.textContent = "Error #{req.statusText} (#{req.status})"
|
||||
return
|
||||
|
||||
data = JSON.parse(req.response).posts
|
||||
Build.spoilerRange[thread.board] = data.shift().custom_spoiler
|
||||
Build.spoilerRange[thread.board] = req.response.posts[0].custom_spoiler
|
||||
|
||||
posts = []
|
||||
postsRoot = []
|
||||
filesCount = 0
|
||||
for postData in data
|
||||
for postData in req.response.posts
|
||||
continue if postData.no is thread.ID
|
||||
if post = thread.posts[postData.no]
|
||||
filesCount++ if 'file' of post
|
||||
postsRoot.push post.nodes.root
|
||||
|
||||
@ -77,9 +77,8 @@ ThreadStats =
|
||||
|
||||
onThreadsLoad: ->
|
||||
return unless Conf["Page Count in Stats"] and @status is 200
|
||||
pages = JSON.parse @response
|
||||
for page in pages
|
||||
for page in @response
|
||||
for thread in page.threads when thread.no is ThreadStats.thread.ID
|
||||
ThreadStats.pageCountEl.textContent = page.page
|
||||
(if page.page is pages.length - 1 then $.addClass else $.rmClass) ThreadStats.pageCountEl, 'warning'
|
||||
return
|
||||
(if page.page is @response.length - 1 then $.addClass else $.rmClass) ThreadStats.pageCountEl, 'warning'
|
||||
return
|
||||
@ -158,7 +158,7 @@ ThreadUpdater =
|
||||
switch req.status
|
||||
when 200
|
||||
g.DEAD = false
|
||||
ThreadUpdater.parse JSON.parse(req.response).posts
|
||||
ThreadUpdater.parse req.response.posts
|
||||
ThreadUpdater.setInterval()
|
||||
when 404
|
||||
g.DEAD = true
|
||||
|
||||
@ -670,7 +670,7 @@ QR =
|
||||
# Too many frequent mistyped captchas will auto-ban you!
|
||||
# On connection error, the post most likely didn't go through.
|
||||
QR.cooldown.set delay: 2
|
||||
else if err.textContent and m = err.textContent.match /wait\s(\d+)\ssecond/i
|
||||
else if err.textContent and m = err.textContent.match /wait\s+(\d+)\s+second/i
|
||||
QR.cooldown.auto = if QR.captcha.isEnabled
|
||||
!!QR.captcha.captchas.length
|
||||
else
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user