Merge Mayhem X
This commit is contained in:
commit
6d4da42eb2
@ -1,3 +1,6 @@
|
||||
**MayhemYDG**:
|
||||
- /pol/ flag selector
|
||||
|
||||
**seaweedchan**:
|
||||
- Delete cooldown update
|
||||
|
||||
|
||||
@ -1,21 +1,14 @@
|
||||
module.exports = (grunt) ->
|
||||
|
||||
concatOptions =
|
||||
process: Object.create(null, data:
|
||||
get: -> grunt.config 'pkg'
|
||||
enumerable: true
|
||||
)
|
||||
shellOptions =
|
||||
stdout: true
|
||||
stderr: true
|
||||
failOnError: true
|
||||
|
||||
# Project configuration.
|
||||
grunt.initConfig
|
||||
pkg: grunt.file.readJSON 'package.json'
|
||||
concat:
|
||||
options: process: Object.create(null, data:
|
||||
get: -> grunt.config 'pkg'
|
||||
enumerable: true
|
||||
)
|
||||
coffee:
|
||||
options: concatOptions
|
||||
src: [
|
||||
'src/General/Config.coffee'
|
||||
'src/General/Globals.coffee'
|
||||
@ -41,13 +34,11 @@ module.exports = (grunt) ->
|
||||
dest: 'tmp-<%= pkg.type %>/script.coffee'
|
||||
|
||||
meta:
|
||||
options: concatOptions
|
||||
files:
|
||||
'LICENSE': 'src/General/meta/banner.js',
|
||||
'latest.js': 'src/General/meta/latest.js'
|
||||
|
||||
crx:
|
||||
options: concatOptions
|
||||
files:
|
||||
'builds/crx/manifest.json': 'src/General/meta/manifest.json'
|
||||
'builds/crx/script.js': [
|
||||
@ -57,7 +48,6 @@ module.exports = (grunt) ->
|
||||
'tmp-<%= pkg.type %>/script.js'
|
||||
]
|
||||
userscript:
|
||||
options: concatOptions
|
||||
files:
|
||||
'builds/<%= pkg.name %>.meta.js': 'src/General/meta/metadata.js'
|
||||
'builds/<%= pkg.name %>.user.js': [
|
||||
@ -96,22 +86,23 @@ module.exports = (grunt) ->
|
||||
push: false
|
||||
|
||||
shell:
|
||||
options:
|
||||
stdout: true
|
||||
stderr: true
|
||||
failOnError: true
|
||||
commit:
|
||||
options: shellOptions
|
||||
command: [
|
||||
'git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
'git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
'git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>."'
|
||||
].join ' && '
|
||||
|
||||
command: """
|
||||
git commit -am "Release <%= pkg.meta.name %> v<%= pkg.version %>."
|
||||
git tag -a <%= pkg.version %> -m "<%= pkg.meta.name %> v<%= pkg.version %>."
|
||||
git tag -af stable -m "<%= pkg.meta.name %> v<%= pkg.version %>."
|
||||
"""
|
||||
push:
|
||||
options: shellOptions
|
||||
command: 'git push origin --tags -f && git push origin --all'
|
||||
|
||||
watch:
|
||||
options:
|
||||
interrupt: true
|
||||
all:
|
||||
options:
|
||||
interrupt: true
|
||||
files: [
|
||||
'Gruntfile.coffee'
|
||||
'package.json'
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 4chan X - Version 1.2.39 - 2013-09-21
|
||||
* 4chan X - Version 1.2.39 - 2013-09-22
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -23,14 +23,14 @@
|
||||
"font-awesome": "git://github.com/MayhemYDG/Font-Awesome.git#df4285951124f9ca1f3907438462e5ba9e464bcb",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-bump": "~0.0.11",
|
||||
"grunt-concurrent": "~0.3.0",
|
||||
"grunt-concurrent": "~0.3.1",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-coffee": "~0.7.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-contrib-watch": "~0.5.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-shell": "~0.4.0",
|
||||
"load-grunt-tasks": "~0.1.0"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@ -25,6 +25,7 @@ Redirect =
|
||||
'4plebs':
|
||||
domain: 'archive.4plebs.org'
|
||||
http: true
|
||||
https: true
|
||||
software: 'foolfuuka'
|
||||
boards: ['hr', 'tg', 'tv', 'x']
|
||||
files: ['hr', 'tg', 'tv', 'x']
|
||||
@ -34,8 +35,8 @@ Redirect =
|
||||
http: true
|
||||
https: false
|
||||
software: 'foolfuuka'
|
||||
boards: ['b', 'e', 'h', 'hc', 'p', 's', 'u']
|
||||
files: ['b', 'e', 'h', 'hc', 'p', 's', 'u']
|
||||
boards: ['b', 'e', 'h', 'hc', 'p', 's', 'soc', 'sp', 'u']
|
||||
files: ['b', 'e', 'h', 'hc', 'p', 's', 'soc', 'sp', 'u']
|
||||
|
||||
'Foolz':
|
||||
domain: 'archive.foolz.us'
|
||||
@ -146,12 +147,7 @@ Redirect =
|
||||
post: (archive, {boardID, postID}) ->
|
||||
# For fuuka-based archives:
|
||||
# https://github.com/eksopl/fuuka/issues/27
|
||||
protocol = Redirect.protocol archive
|
||||
# XXX foolz had HSTS set for 120 days, which broke XHR+CORS+Redirection when on HTTP.
|
||||
# Remove necessary HTTPS procotol in September 2013.
|
||||
if ['Foolz', 'NSFW Foolz'].contains archive.name
|
||||
protocol = 'https://'
|
||||
URL = new String "#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
||||
URL = new String "#{Redirect.protocol archive}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
||||
URL.archive = archive
|
||||
URL
|
||||
|
||||
|
||||
@ -15,4 +15,4 @@ Anonymize =
|
||||
delete @nodes.tripcode
|
||||
if @info.email
|
||||
$.replace email, name
|
||||
delete @nodes.email
|
||||
delete @nodes.email
|
||||
|
||||
@ -118,17 +118,18 @@ Get =
|
||||
Build.spoilerRange[boardID] = posts[0].custom_spoiler
|
||||
for post in posts
|
||||
break if post.no is postID # we found it!
|
||||
if post.no > postID
|
||||
# The post can be deleted by the time we check a quote.
|
||||
if url = Redirect.to 'post', {boardID, postID}
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
withCredentials: url.archive.withCredentials
|
||||
else
|
||||
$.addClass root, 'warning'
|
||||
root.textContent = "Post No.#{postID} was not found."
|
||||
return
|
||||
|
||||
if post.no isnt postID
|
||||
# The post can be deleted by the time we check a quote.
|
||||
if url = Redirect.to 'post', {boardID, postID}
|
||||
$.cache url,
|
||||
-> Get.archivedPost @, boardID, postID, root, context
|
||||
,
|
||||
withCredentials: url.archive.withCredentials
|
||||
else
|
||||
$.addClass root, 'warning'
|
||||
root.textContent = "Post No.#{postID} was not found."
|
||||
return
|
||||
|
||||
board = g.boards[boardID] or
|
||||
new Board boardID
|
||||
|
||||
@ -19,18 +19,6 @@ Main =
|
||||
Conf['CachedTitles'] = []
|
||||
$.get Conf, (items) ->
|
||||
$.extend Conf, items
|
||||
<% if (type === 'crx') { %>
|
||||
unless items
|
||||
new Notice 'error', $.el 'span',
|
||||
innerHTML: """
|
||||
It seems like your <%= meta.name %> settings became corrupted due to a <a href="https://code.google.com/p/chromium/issues/detail?id=261623" target=_blank>Chrome bug</a>.<br>
|
||||
Unfortunately, you'll have to <a href="https://github.com/MayhemYDG/4chan-x/wiki/FAQ#known-problems" target=_blank>fix it yourself</a>.
|
||||
"""
|
||||
# Track resolution of this bug.
|
||||
Main.logError
|
||||
message: 'Chrome Storage API bug'
|
||||
error: new Error '~'
|
||||
<% } %>
|
||||
Main.initFeatures()
|
||||
|
||||
$.on d, '4chanMainInit', Main.initStyle
|
||||
|
||||
@ -122,8 +122,7 @@ UI = do ->
|
||||
|
||||
findNextEntry: (entry, direction) ->
|
||||
entries = [entry.parentNode.children...]
|
||||
entries.sort (first, second) ->
|
||||
+(first.style.order or first.style.webkitOrder) - +(second.style.order or second.style.webkitOrder)
|
||||
entries.sort (first, second) -> first.style.order - second.style.order
|
||||
entries[entries.indexOf(entry) + direction]
|
||||
|
||||
keybinds: (e) =>
|
||||
@ -197,8 +196,7 @@ UI = do ->
|
||||
e.stopPropagation()
|
||||
@focus el
|
||||
).bind @
|
||||
{style} = el
|
||||
style.webkitOrder = style.order = entry.order or 100
|
||||
el.style.order = entry.order or 100
|
||||
return unless subEntries
|
||||
$.addClass el, 'has-submenu'
|
||||
for subEntry in subEntries
|
||||
|
||||
@ -675,7 +675,7 @@ a.hide-announcement {
|
||||
:root.hide-original-post-form .postingMode,
|
||||
:root.hide-original-post-form #togglePostForm,
|
||||
#qr.autohide:not(.has-focus):not(:hover) > form,
|
||||
.postingMode ~ #qr select,
|
||||
.postingMode ~ #qr select[data-name=thread],
|
||||
#file-n-submit:not(.has-file) #qr-filerm {
|
||||
display: none;
|
||||
}
|
||||
@ -837,7 +837,7 @@ input#qr-filename:not(.edit) {
|
||||
position: absolute;
|
||||
}
|
||||
/* Thread Select / Spoiler Label */
|
||||
#qr select {
|
||||
#qr select[data-name=thread] {
|
||||
float: right;
|
||||
}
|
||||
#qr.has-spoiler .has-file #qr-spoiler-label {
|
||||
|
||||
@ -58,7 +58,7 @@ ImageExpand =
|
||||
unless post.file.isExpanded or $.hasClass thumb, 'expanding'
|
||||
ImageExpand.expand post
|
||||
return
|
||||
ImageExpand.contract post
|
||||
|
||||
# Scroll back to the thumbnail when contracting the image
|
||||
# to avoid being left miles away from the relevant post.
|
||||
{root} = post.nodes
|
||||
@ -81,6 +81,7 @@ ImageExpand =
|
||||
if rect.left < 0
|
||||
x = -window.scrollX
|
||||
window.scrollBy x, y if x or y
|
||||
ImageExpand.contract post
|
||||
|
||||
contract: (post) ->
|
||||
$.rmClass post.nodes.root, 'expanded-image'
|
||||
|
||||
@ -31,14 +31,6 @@ ThreadWatcher =
|
||||
ThreadWatcher.fetchAllStatus()
|
||||
@db.save()
|
||||
|
||||
# XXX tmp conversion from old to new format
|
||||
$.get 'WatchedThreads', null, ({WatchedThreads}) ->
|
||||
return unless WatchedThreads
|
||||
for boardID, threads of ThreadWatcher.convert WatchedThreads
|
||||
for threadID, data of threads
|
||||
ThreadWatcher.db.set {boardID, threadID, val: data}
|
||||
$.delete 'WatchedThreads'
|
||||
|
||||
Thread::callbacks.push
|
||||
name: 'Thread Watcher'
|
||||
cb: @node
|
||||
|
||||
@ -104,9 +104,10 @@ Unread =
|
||||
notif.onclick = ->
|
||||
Header.scrollToPost post.nodes.root
|
||||
window.focus()
|
||||
setTimeout ->
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
notif.onshow = ->
|
||||
setTimeout ->
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
|
||||
onUpdate: (e) ->
|
||||
if e.detail[404]
|
||||
|
||||
@ -163,10 +163,11 @@ QR =
|
||||
# Firefox automatically closes notifications
|
||||
# so we can't control the onclose properly.
|
||||
notif.onclose = -> notice.close()
|
||||
setTimeout ->
|
||||
notif.onclose = null
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
notif.onshow = ->
|
||||
setTimeout ->
|
||||
notif.onclose = null
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
<% } %>
|
||||
|
||||
notifications: []
|
||||
@ -267,13 +268,14 @@ QR =
|
||||
name: post.name
|
||||
email: if /^sage$/.test post.email then persona.email else post.email
|
||||
sub: if Conf['Remember Subject'] then post.sub else undefined
|
||||
flag: post.flag
|
||||
$.set 'QR.persona', persona
|
||||
|
||||
cooldown:
|
||||
init: ->
|
||||
return unless Conf['Cooldown']
|
||||
setTimers = (e) => QR.cooldown.types = e.detail
|
||||
$.on window, 'cooldown:timers', setTimers
|
||||
$.on window, 'cooldown:timers', setTimers
|
||||
$.globalEval 'window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))'
|
||||
QR.cooldown.types or= {} # XXX tmp workaround until all pages and the catalogs get the cooldowns var.
|
||||
$.off window, 'cooldown:timers', setTimers
|
||||
@ -306,11 +308,10 @@ QR =
|
||||
if delay
|
||||
cooldown = {delay}
|
||||
else
|
||||
if post.file
|
||||
if hasFile = !!post.file
|
||||
upSpd = post.file.size / ((start - req.uploadStartTime) / $.SECOND)
|
||||
QR.cooldown.upSpdAccuracy = ((upSpd > QR.cooldown.upSpd * .9) + QR.cooldown.upSpdAccuracy) / 2
|
||||
QR.cooldown.upSpd = upSpd
|
||||
hasFile = !!post.file
|
||||
cooldown = {isReply, hasFile, threadID}
|
||||
QR.cooldown.cooldowns[start] = cooldown
|
||||
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
|
||||
@ -357,24 +358,28 @@ QR =
|
||||
|
||||
if isReply is cooldown.isReply
|
||||
# Only cooldowns relevant to this post can set the seconds variable:
|
||||
# reply cooldown with a reply, thread cooldown with a thread
|
||||
# reply cooldown with a reply, thread cooldown with a thread
|
||||
elapsed = Math.floor (now - start) / $.SECOND
|
||||
continue if elapsed < 0 # clock changed since then?
|
||||
type = unless isReply
|
||||
'thread'
|
||||
unless isReply
|
||||
type = 'thread'
|
||||
else if hasFile
|
||||
'image'
|
||||
# You can post an image reply immediately after a non-image reply.
|
||||
unless cooldown.hasFile
|
||||
seconds = Math.max seconds, 0
|
||||
continue
|
||||
type = 'image'
|
||||
else
|
||||
'reply'
|
||||
maxTimer = Math.max types[type] or 0, types[type + '_intra'] or 0
|
||||
type = 'reply'
|
||||
maxTimer = Math.max types[type] or 0, types[type + '_intra'] or 0
|
||||
unless start <= now <= start + maxTimer * $.SECOND
|
||||
QR.cooldown.unset start
|
||||
type += '_intra' if isReply and +post.thread is cooldown.threadID
|
||||
type += '_intra' if isReply and +post.thread is cooldown.threadID
|
||||
seconds = Math.max seconds, types[type] - elapsed
|
||||
|
||||
if seconds and Conf['Cooldown Prediction'] and hasFile and upSpd
|
||||
seconds -= Math.floor post.file.size / upSpd * upSpdAccuracy
|
||||
seconds = Math.max seconds, 0
|
||||
seconds = Math.max seconds, 0
|
||||
# Update the status when we change posting type.
|
||||
# Don't get stuck at some random number.
|
||||
# Don't interfere with progress status updates.
|
||||
@ -564,6 +569,12 @@ QR =
|
||||
if prev then prev.sub else persona.sub
|
||||
else
|
||||
''
|
||||
|
||||
if QR.nodes.flag
|
||||
@flag = if prev
|
||||
prev.flag
|
||||
else
|
||||
persona.flag
|
||||
@load() if QR.selected is @ # load persona
|
||||
@select() if select
|
||||
@unlock()
|
||||
@ -585,8 +596,9 @@ QR =
|
||||
lock: (lock=true) ->
|
||||
@isLocked = lock
|
||||
return unless @ is QR.selected
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'spoiler']
|
||||
QR.nodes[name].disabled = lock
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'fileButton', 'filename', 'spoiler', 'flag']
|
||||
continue unless node = QR.nodes[name]
|
||||
node.disabled = lock
|
||||
@nodes.rm.style.visibility = if lock then 'hidden' else ''
|
||||
(if lock then $.off else $.on) QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput
|
||||
@nodes.spoiler.disabled = lock
|
||||
@ -611,8 +623,9 @@ QR =
|
||||
|
||||
load: ->
|
||||
# Load this post's values.
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename']
|
||||
QR.nodes[name].value = @[name] or null
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag']
|
||||
continue unless node = QR.nodes[name]
|
||||
node.value = @[name] or node.dataset.default or null
|
||||
@showFileData()
|
||||
QR.characterCount()
|
||||
|
||||
@ -621,7 +634,7 @@ QR =
|
||||
@spoiler = input.checked
|
||||
return
|
||||
{name} = input.dataset
|
||||
@[name] = input.value
|
||||
@[name] = input.value or input.dataset.default or null
|
||||
switch name
|
||||
when 'thread'
|
||||
QR.status()
|
||||
@ -646,8 +659,9 @@ QR =
|
||||
return unless @ is QR.selected
|
||||
# Do this in case people use extensions
|
||||
# that do not trigger the `input` event.
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'spoiler']
|
||||
@save QR.nodes[name]
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'spoiler', 'flag']
|
||||
continue unless node = QR.nodes[name]
|
||||
@save node
|
||||
return
|
||||
|
||||
setFile: (@file) ->
|
||||
@ -947,7 +961,13 @@ QR =
|
||||
<option value=5>Loop</option>
|
||||
<option value=4 selected>Other</option>
|
||||
"""
|
||||
nodes.flashTag.dataset.default = '4'
|
||||
$.add nodes.form, nodes.flashTag
|
||||
if flagSelector = $ '.flagSelector'
|
||||
nodes.flag = flagSelector.cloneNode true
|
||||
nodes.flag.dataset.name = 'flag'
|
||||
nodes.flag.dataset.default = '0'
|
||||
$.add nodes.form, nodes.flag
|
||||
|
||||
# Make a list of threads.
|
||||
for thread of g.BOARD.threads
|
||||
@ -978,11 +998,11 @@ QR =
|
||||
$.on nodes.spoiler, 'change', -> QR.selected.nodes.spoiler.click()
|
||||
$.on nodes.fileInput, 'change', QR.handleFiles
|
||||
# save selected post's data
|
||||
items = ['name', 'email', 'sub', 'com', 'filename']
|
||||
i = 0
|
||||
while name = items[i++]
|
||||
$.on nodes[name], 'input', -> QR.selected.save @
|
||||
$.on nodes.thread, 'change', -> QR.selected.save @
|
||||
save = -> QR.selected.save @
|
||||
for name in ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag']
|
||||
continue unless node = nodes[name]
|
||||
event = if node.nodeName is 'SELECT' then 'change' else 'input'
|
||||
$.on nodes[name], event, save
|
||||
|
||||
<% if (type === 'userscript') { %>
|
||||
if Conf['Remember QR Size']
|
||||
@ -1028,7 +1048,7 @@ QR =
|
||||
# prevent errors
|
||||
if threadID is 'new'
|
||||
threadID = null
|
||||
if g.BOARD.ID is 'vg' and !post.sub
|
||||
if g.BOARD.ID is 'vg' and !post.sub
|
||||
err = 'New threads require a subject.'
|
||||
else unless post.file or textOnly = !!$ 'input[name=textonly]', $.id 'postForm'
|
||||
err = 'No file selected.'
|
||||
@ -1064,7 +1084,7 @@ QR =
|
||||
|
||||
post.lock()
|
||||
|
||||
postData =
|
||||
formData =
|
||||
resto: threadID
|
||||
name: post.name
|
||||
email: post.email
|
||||
@ -1073,6 +1093,7 @@ QR =
|
||||
upfile: post.file
|
||||
filetag: filetag
|
||||
spoiler: post.spoiler
|
||||
flag: post.flag
|
||||
textonly: textOnly
|
||||
mode: 'regist'
|
||||
pwd: QR.persona.pwd
|
||||
@ -1096,7 +1117,7 @@ QR =
|
||||
[<a href="//4chan.org/banned" target=_blank>Banned?</a>] [<a href="https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target=_blank>More info</a>]
|
||||
"""
|
||||
extra =
|
||||
form: $.formData postData
|
||||
form: $.formData formData
|
||||
upCallbacks:
|
||||
onload: ->
|
||||
# Upload done, waiting for server response.
|
||||
@ -1201,9 +1222,9 @@ QR =
|
||||
postID
|
||||
}
|
||||
|
||||
# Enable auto-posting if we have stuff to post, disable it otherwise.
|
||||
postsCount = QR.posts.length
|
||||
QR.cooldown.auto = postsCount > 1 and isReply
|
||||
# Enable auto-posting if we have stuff left to post, disable it otherwise.
|
||||
postsCount = QR.posts.length - 1
|
||||
QR.cooldown.auto = postsCount 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}."
|
||||
@ -1212,9 +1233,10 @@ QR =
|
||||
QR.open()
|
||||
QR.captcha.nodes.input.focus()
|
||||
window.focus()
|
||||
setTimeout ->
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
notif.onshow = ->
|
||||
setTimeout ->
|
||||
notif.close()
|
||||
, 7 * $.SECOND
|
||||
|
||||
unless Conf['Persistent QR'] or QR.cooldown.auto
|
||||
QR.close()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user