Merge branch 'v3' into Av2

Conflicts:
	4chan-X.user.js
	appchan-x.meta.js
	css/style.css
	package.json
	src/features.coffee
	src/metadata.js
	src/qr.coffee
This commit is contained in:
Zixaphir 2013-04-12 20:10:50 -07:00
commit 929d8b0c7e
9 changed files with 9102 additions and 88 deletions

8996
4chan-X.user.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,11 @@
### 3.0.4 - *2013-04-11*
- More minor fixes.
### 3.0.3 - *2013-04-10*
- Minor fixes.
### 3.0.2 - *2013-04-09* ### 3.0.2 - *2013-04-09*
- Added a setting in the Header's menu to move it at the bottom of the screen. - Added a setting in the Header's menu to move it at the bottom of the screen.

View File

@ -2,9 +2,8 @@
// @name appchan x // @name appchan x
// @version 2.0.0 // @version 2.0.0
// @namespace zixaphir // @namespace zixaphir
// @description Cross-browser userscript for maximum lurking on 4chan. // @description The most comprehensive 4chan userscript.
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com> // @copyright 2012-2013 Zixaphir <zixaphirmoxphar@gmail.com>
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
// @license MIT; http://en.wikipedia.org/wiki/Mit_license // @license MIT; http://en.wikipedia.org/wiki/Mit_license
// @match *://api.4chan.org/* // @match *://api.4chan.org/*
// @match *://boards.4chan.org/* // @match *://boards.4chan.org/*

View File

@ -2,9 +2,8 @@
// @name appchan x // @name appchan x
// @version 2.0.0 // @version 2.0.0
// @namespace zixaphir // @namespace zixaphir
// @description Cross-browser userscript for maximum lurking on 4chan. // @description The most comprehensive 4chan userscript.
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com> // @copyright 2012-2013 Zixaphir <zixaphirmoxphar@gmail.com>
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
// @license MIT; http://en.wikipedia.org/wiki/Mit_license // @license MIT; http://en.wikipedia.org/wiki/Mit_license
// @match *://api.4chan.org/* // @match *://api.4chan.org/*
// @match *://boards.4chan.org/* // @match *://boards.4chan.org/*
@ -2435,7 +2434,7 @@
var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove; var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove;
dialog = function(id, position, html) { dialog = function(id, position, html) {
var el, move; var child, el, move, _i, _len, _ref;
el = $.el('div', { el = $.el('div', {
className: 'dialog', className: 'dialog',
@ -2445,6 +2444,16 @@
el.style.cssText = localStorage.getItem("" + g.NAMESPACE + id + ".position") || position; el.style.cssText = localStorage.getItem("" + g.NAMESPACE + id + ".position") || position;
move = $('.move', el); move = $('.move', el);
$.on(move, 'touchstart mousedown', dragstart); $.on(move, 'touchstart mousedown', dragstart);
_ref = move.children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i];
if (!child.tagName) {
continue;
}
$.on(child, 'touchstart mousedown', function(e) {
return e.stopPropagation();
});
}
return el; return el;
}; };
Menu = (function() { Menu = (function() {
@ -5980,6 +5989,7 @@
id: 'hoverUI' id: 'hoverUI'
}); });
$.on(window, 'load hashchange', Header.hashScroll); $.on(window, 'load hashchange', Header.hashScroll);
$.on(d, 'CreateNotification', this.createNotification);
$.asap((function() { $.asap((function() {
return d.body; return d.body;
}), function() { }), function() {
@ -6114,6 +6124,15 @@
}); });
$.add(shortcut, [$.tn(' ['), el, $.tn(']')]); $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
return $.add(Header.shortcuts, shortcut); return $.add(Header.shortcuts, shortcut);
},
createNotification: function(e) {
var cb, content, lifetime, notif, type, _ref;
_ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
notif = new Notification(type, content, lifetime);
if (cb) {
return cb(notif);
}
} }
}; };
@ -6554,7 +6573,7 @@
}; };
}, },
makeFilter: function() { makeFilter: function() {
var re, section, select, ta, tl, type, value; var re, type, value;
type = this.dataset.type; type = this.dataset.type;
value = Filter[type](Filter.menu.post); value = Filter[type](Filter.menu.post);
@ -6568,25 +6587,22 @@
} }
}); });
re = ['uniqueID', 'MD5'].contains(type) ? "/" + re + "/" : "/^" + re + "$/"; re = ['uniqueID', 'MD5'].contains(type) ? "/" + re + "/" : "/^" + re + "$/";
if (!Filter.menu.post.isReply) { return $.get(type, Conf[type], function(item) {
re += ';op:yes'; var save, section, select, ta, tl;
}
$.get(type, '', function(item) {
var save;
save = item[type]; save = item[type];
save = save ? "" + save + "\n" + re : re; save = save ? "" + save + "\n" + re : re;
return $.set(type, save); $.set(type, save);
Settings.open('Filter');
section = $('.section-container');
select = $('select[name=filter]', section);
select.value = type;
Settings.selectFilter.call(select);
ta = $('textarea', section);
tl = ta.textLength;
ta.setSelectionRange(tl, tl);
return ta.focus();
}); });
Settings.open('Filter');
section = $('.section-container');
select = $('select[name=filter]', section);
select.value = type;
Settings.selectFilter.call(select);
ta = $('textarea', section);
tl = ta.textLength;
ta.setSelectionRange(tl, tl);
return ta.focus();
} }
} }
}; };
@ -7548,7 +7564,7 @@
}); });
}, },
keydown: function(e) { keydown: function(e) {
var form, key, notification, notifications, target, thread, threadRoot, _i, _len; var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
if (!(key = Keybinds.keyCode(e))) { if (!(key = Keybinds.keyCode(e))) {
return; return;
@ -7560,7 +7576,9 @@
} }
} }
threadRoot = Nav.getThread(); threadRoot = Nav.getThread();
thread = Get.postFromNode($('.op', threadRoot)).thread; if (op = $('.op', threadRoot)) {
thread = Get.postFromNode(op).thread;
}
switch (key) { switch (key) {
case Conf['Toggle board list']: case Conf['Toggle board list']:
if (Conf['Custom Board Navigation']) { if (Conf['Custom Board Navigation']) {
@ -9107,7 +9125,7 @@
_ref = [post].concat(post.clones); _ref = [post].concat(post.clones);
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
singlePost = _ref[_i]; singlePost = _ref[_i];
singlePost.nodes.date.textContent = relative; singlePost.nodes.date.firstChild.textContent = relative;
} }
return setOwnTimeout(diff); return setOwnTimeout(diff);
}; };
@ -9419,11 +9437,8 @@
if (!(rect.top <= 0 || rect.left <= 0)) { if (!(rect.top <= 0 || rect.left <= 0)) {
return; return;
} }
top = rect.top; headRect = Header.bar.getBoundingClientRect();
if (!Conf['Bottom header']) { top = rect.top - headRect.top - headRect.height;
headRect = Header.bar.getBoundingClientRect();
top += -headRect.top - headRect.height;
}
root = $.engine === 'webkit' ? d.body : doc; root = $.engine === 'webkit' ? d.body : doc;
if (rect.top < 0) { if (rect.top < 0) {
root.scrollTop += top; root.scrollTop += top;
@ -11527,10 +11542,8 @@
return QR.fileInput(files); return QR.fileInput(files);
}, },
openFileInput: function(e) { openFileInput: function(e) {
if (e.keyCode) { if (e.keyCode && e.keyCode !== 32) {
if (e.keyCode !== 32) { return;
return;
}
} }
return QR.nodes.fileInput.click(); return QR.nodes.fileInput.click();
}, },
@ -12102,7 +12115,7 @@
dialog: function() { dialog: function() {
var dialog, mimeTypes, name, nodes, thread, _i, _len, _ref; var dialog, mimeTypes, name, nodes, thread, _i, _len, _ref;
dialog = UI.dialog('qr', 'top:0;right:0;', "<div id=qrtab>\n <input type=checkbox id=autohide title=Auto-hide> Post Form\n <span class=move></span>\n <a href=javascript:; class=close title=Close>×</a>\n</div>\n<form>\n <div class=persona>\n <input id=dump-button type=button title='Dump list' value=+ tabindex=0>\n <input name=name data-name=name title=Name placeholder=Name class=field size=1 tabindex=10>\n <input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1 tabindex=20>\n <input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1 tabindex=30>\n </div>\n <div class=textarea>\n <textarea data-name=com title=Comment placeholder=Comment class=field tabindex=40></textarea>\n <span id=char-count></span>\n </div>\n <div id=dump-list-container>\n <div id=dump-list></div>\n <a id=add-post href=javascript:; title=\"Add a post\" tabindex=50>+</a>\n </div>\n <div id=file-n-submit>\n <span id=qr-filename-container class=field tabindex=60>\n <span id=qr-no-file>No selected file</span>\n <span id=qr-filename></span>\n <a id=qr-filerm href=javascript:; title='Remove file' tabindex=80>×</a>\n </span>\n <input type=submit tabindex=70>\n </div>\n <input type=file multiple>\n <div id=qr-thread-select>\n <select title='Create a new thread / Reply'>\n <option value=new>New thread</option>\n </select>\n </div>\n <label id=qr-spoiler-label>\n <input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?\n </label>\n</form>".replace(/>\s+</g, '><')); dialog = UI.dialog('qr', 'top:0;right:0;', "<div id=qrtab class=move>\n <input type=checkbox id=autohide title=Auto-hide> Post Form\n <a href=javascript:; class=close title=Close>×</a>\n</div>\n<form>\n <div class=persona>\n <input id=dump-button type=button title='Dump list' value=+ tabindex=0>\n <input name=name data-name=name title=Name placeholder=Name class=field size=1 tabindex=10>\n <input name=email data-name=email title=E-mail placeholder=E-mail class=field size=1 tabindex=20>\n <input name=sub data-name=sub title=Subject placeholder=Subject class=field size=1 tabindex=30>\n </div>\n <div class=textarea>\n <textarea data-name=com title=Comment placeholder=Comment class=field tabindex=40></textarea>\n <span id=char-count></span>\n </div>\n <div id=dump-list-container>\n <div id=dump-list></div>\n <a id=add-post href=javascript:; title=\"Add a post\" tabindex=50>+</a>\n </div>\n <div id=file-n-submit>\n <span id=qr-filename-container class=field tabindex=60>\n <span id=qr-no-file>No selected file</span>\n <span id=qr-filename></span>\n <a id=qr-filerm href=javascript:; title='Remove file' tabindex=80>×</a>\n </span>\n <input type=submit tabindex=70>\n </div>\n <input type=file multiple>\n <label id=qr-spoiler-label>\n <input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?\n </label>\n</form>".replace(/>\s+</g, '><'));
QR.nodes = nodes = { QR.nodes = nodes = {
el: dialog, el: dialog,
move: $('.move', dialog), move: $('.move', dialog),
@ -12123,7 +12136,6 @@
filename: $('#qr-filename', dialog), filename: $('#qr-filename', dialog),
fileRM: $('#qr-filerm', dialog), fileRM: $('#qr-filerm', dialog),
spoiler: $('#qr-file-spoiler', dialog), spoiler: $('#qr-file-spoiler', dialog),
spoilerPar: $('#qr-spoiler-label', dialog),
status: $('[type=submit]', dialog), status: $('[type=submit]', dialog),
fileInput: $('[type=file]', dialog) fileInput: $('[type=file]', dialog)
}; };
@ -12146,7 +12158,7 @@
nodes.fileInput.accept = "text/*, " + mimeTypes; nodes.fileInput.accept = "text/*, " + mimeTypes;
} }
QR.spoiler = !!$('input[name=spoiler]'); QR.spoiler = !!$('input[name=spoiler]');
nodes.spoilerPar.hidden = !QR.spoiler; nodes.spoiler.parentElement.hidden = !QR.spoiler;
if (g.BOARD.ID === 'f') { if (g.BOARD.ID === 'f') {
nodes.flashTag = $.el('select', { nodes.flashTag = $.el('select', {
name: 'filetag', name: 'filetag',
@ -12160,7 +12172,6 @@
textContent: "Thread No." + thread textContent: "Thread No." + thread
})); }));
} }
$.add(nodes.threadPar, nodes.thread);
QR.resetThreadSelector(); QR.resetThreadSelector();
$.on(nodes.filename.parentNode, 'click keyup', QR.openFileInput); $.on(nodes.filename.parentNode, 'click keyup', QR.openFileInput);
$.on(nodes.autohide, 'change', QR.toggleHide); $.on(nodes.autohide, 'change', QR.toggleHide);
@ -12202,7 +12213,7 @@
return $.event('QRDialogCreation', null, dialog); return $.event('QRDialogCreation', null, dialog);
}, },
submit: function(e) { submit: function(e) {
var callbacks, challenge, err, filetag, m, opts, post, postData, response, textOnly, threadID, _ref; var callbacks, challenge, err, filetag, m, opts, post, postData, response, textOnly, thread, threadID, _ref;
if (e != null) { if (e != null) {
e.preventDefault(); e.preventDefault();
@ -12222,6 +12233,7 @@
filetag = QR.nodes.flashTag.value; filetag = QR.nodes.flashTag.value;
} }
threadID = QR.nodes.thread.value; threadID = QR.nodes.thread.value;
thread = g.BOARD.threads[threadID];
if (threadID === 'new') { if (threadID === 'new') {
threadID = null; threadID = null;
if (['vg', 'q'].contains(g.BOARD.ID) && !post.sub) { if (['vg', 'q'].contains(g.BOARD.ID) && !post.sub) {
@ -12233,7 +12245,7 @@
err = 'You can\'t reply to this thread anymore.'; err = 'You can\'t reply to this thread anymore.';
} else if (!(post.com || post.file)) { } else if (!(post.com || post.file)) {
err = 'No file selected.'; err = 'No file selected.';
} else if (post.file && g.BOARD.threads[threadID].fileLimit) { } else if (post.file && thread.fileLimit && !thread.isSticky) {
err = 'Max limit of image replies has been reached.'; err = 'Max limit of image replies has been reached.';
} }
if (QR.captcha.isEnabled && !err) { if (QR.captcha.isEnabled && !err) {

View File

@ -7,6 +7,10 @@ UI = do ->
el.style.cssText = localStorage.getItem("#{g.NAMESPACE}#{id}.position") or position el.style.cssText = localStorage.getItem("#{g.NAMESPACE}#{id}.position") or position
move = $ '.move', el move = $ '.move', el
$.on move, 'touchstart mousedown', dragstart $.on move, 'touchstart mousedown', dragstart
for child in move.children
continue unless child.tagName
$.on child, 'touchstart mousedown', (e) ->
e.stopPropagation()
el el
class Menu class Menu

View File

@ -20,9 +20,9 @@
"grunt": "~0.4.1", "grunt": "~0.4.1",
"grunt-bump": "~0.0.0", "grunt-bump": "~0.0.0",
"grunt-contrib-clean": "~0.4.0", "grunt-contrib-clean": "~0.4.0",
"grunt-contrib-coffee": "~0.6.5", "grunt-contrib-coffee": "~0.6.6",
"grunt-contrib-compress": "~0.4.7", "grunt-contrib-compress": "~0.4.9",
"grunt-contrib-concat": "~0.1.3", "grunt-contrib-concat": "~0.2.0",
"grunt-contrib-copy": "~0.4.1", "grunt-contrib-copy": "~0.4.1",
"grunt-contrib-watch": "~0.3.1", "grunt-contrib-watch": "~0.3.1",
"grunt-exec": "~0.4.0" "grunt-exec": "~0.4.0"

View File

@ -9,6 +9,8 @@ Header =
$.on window, 'load hashchange', Header.hashScroll $.on window, 'load hashchange', Header.hashScroll
$.on d, 'CreateNotification', @createNotification
$.asap (-> d.body), -> $.asap (-> d.body), ->
return unless Main.isThisPageLegit() return unless Main.isThisPageLegit()
# Wait for #boardNavMobile instead of #boardNavDesktop, # Wait for #boardNavMobile instead of #boardNavDesktop,
@ -107,6 +109,11 @@ Header =
$.add shortcut, [$.tn(' ['), el, $.tn(']')] $.add shortcut, [$.tn(' ['), el, $.tn(']')]
$.add Header.shortcuts, shortcut $.add Header.shortcuts, shortcut
createNotification: (e) ->
{type, content, lifetime, cb} = e.detail
notif = new Notification type, content, lifetime
cb notif if cb
class Notification class Notification
constructor: (type, content, @timeout) -> constructor: (type, content, @timeout) ->
@add = add.bind @ @add = add.bind @
@ -506,16 +513,13 @@ Filter =
else else
"\\#{c}" "\\#{c}"
re = re = if ['uniqueID', 'MD5'].contains type
if ['uniqueID', 'MD5'].contains type "/#{re}/"
"/#{re}/" else
else "/^#{re}$/"
"/^#{re}$/"
unless Filter.menu.post.isReply
re += ';op:yes'
# Add a new line before the regexp unless the text is empty. # Add a new line before the regexp unless the text is empty.
$.get type, '', (item) -> $.get type, Conf[type], (item) ->
save = item[type] save = item[type]
save = save =
if save if save
@ -524,16 +528,16 @@ Filter =
re re
$.set type, save $.set type, save
# Open the settings and display & focus the relevant filter textarea. # Open the settings and display & focus the relevant filter textarea.
Settings.open 'Filter' Settings.open 'Filter'
section = $ '.section-container' section = $ '.section-container'
select = $ 'select[name=filter]', section select = $ 'select[name=filter]', section
select.value = type select.value = type
Settings.selectFilter.call select Settings.selectFilter.call select
ta = $ 'textarea', section ta = $ 'textarea', section
tl = ta.textLength tl = ta.textLength
ta.setSelectionRange tl, tl ta.setSelectionRange tl, tl
ta.focus() ta.focus()
ThreadHiding = ThreadHiding =
init: -> init: ->
@ -1205,7 +1209,8 @@ Keybinds =
return unless /(Esc|Alt|Ctrl|Meta)/.test key return unless /(Esc|Alt|Ctrl|Meta)/.test key
threadRoot = Nav.getThread() threadRoot = Nav.getThread()
thread = Get.postFromNode($('.op', threadRoot)).thread if op = $ '.op', threadRoot
thread = Get.postFromNode(op).thread
switch key switch key
# QR & Options # QR & Options
when Conf['Toggle board list'] when Conf['Toggle board list']
@ -2550,7 +2555,7 @@ RelativeDates =
diff = now - date diff = now - date
relative = RelativeDates.relative diff, now, date relative = RelativeDates.relative diff, now, date
for singlePost in [post].concat post.clones for singlePost in [post].concat post.clones
singlePost.nodes.date.textContent = relative singlePost.nodes.date.firstChild.textContent = relative
setOwnTimeout diff setOwnTimeout diff
markStale = -> RelativeDates.stale.push update markStale = -> RelativeDates.stale.push update
@ -2751,10 +2756,8 @@ ImageExpand =
return unless rect.top <= 0 or rect.left <= 0 return unless rect.top <= 0 or rect.left <= 0
# Scroll back to the thumbnail when contracting the image # Scroll back to the thumbnail when contracting the image
# to avoid being left miles away from the relevant post. # to avoid being left miles away from the relevant post.
{top} = rect headRect = Header.bar.getBoundingClientRect()
unless Conf['Bottom header'] top = rect.top - headRect.top - headRect.height
headRect = Header.bar.getBoundingClientRect()
top += - headRect.top - headRect.height
root = if $.engine is 'webkit' then d.body else doc root = if $.engine is 'webkit' then d.body else doc
root.scrollTop += top if rect.top < 0 root.scrollTop += top if rect.top < 0
root.scrollLeft = 0 if rect.left < 0 root.scrollLeft = 0 if rect.left < 0

View File

@ -2,9 +2,8 @@
// @name <%= meta.name %> // @name <%= meta.name %>
// @version <%= version %> // @version <%= version %>
// @namespace <%= meta.namespace %> // @namespace <%= meta.namespace %>
// @description Cross-browser userscript for maximum lurking on 4chan. // @description <%= description %>
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com> // @copyright 2012-2013 Zixaphir <zixaphirmoxphar@gmail.com>
// @copyright 2012-<%= grunt.template.today('yyyy') %> Nicolas Stepien <stepien.nicolas@gmail.com>
// @license MIT; http://en.wikipedia.org/wiki/Mit_license // @license MIT; http://en.wikipedia.org/wiki/Mit_license
<%= <%=
meta.matches.map(function(match) { meta.matches.map(function(match) {

View File

@ -322,10 +322,9 @@ QR =
return unless files.length return unless files.length
QR.open() QR.open()
QR.fileInput files QR.fileInput files
openFileInput: (e) -> openFileInput: (e) ->
if e.keyCode return if e.keyCode and e.keyCode isnt 32
return unless e.keyCode is 32
QR.nodes.fileInput.click() QR.nodes.fileInput.click()
fileInput: (files) -> fileInput: (files) ->
@ -653,8 +652,9 @@ QR =
$.on imgContainer, 'click', @reload.bind @ $.on imgContainer, 'click', @reload.bind @
$.on input, 'keydown', @keydown.bind @ $.on input, 'keydown', @keydown.bind @
$.on input, 'focus', -> $.addClass QR.nodes.el, 'focus' $.on input, 'focus', -> $.addClass QR.nodes.el, 'focus'
$.on input, 'blur', -> $.rmClass QR.nodes.el, 'focus' $.on input, 'blur', -> $.rmClass QR.nodes.el, 'focus'
$.get 'captchas', [], (item) => $.get 'captchas', [], (item) =>
@sync item['captchas'] @sync item['captchas']
$.sync 'captchas', @sync $.sync 'captchas', @sync
@ -740,9 +740,8 @@ QR =
dialog: -> dialog: ->
dialog = UI.dialog 'qr', 'top:0;right:0;', """ dialog = UI.dialog 'qr', 'top:0;right:0;', """
<div id=qrtab> <div id=qrtab class=move>
<input type=checkbox id=autohide title=Auto-hide> Post Form <input type=checkbox id=autohide title=Auto-hide> Post Form
<span class=move></span>
<a href=javascript:; class=close title=Close>×</a> <a href=javascript:; class=close title=Close>×</a>
</div> </div>
<form> <form>
@ -769,11 +768,6 @@ QR =
<input type=submit tabindex=70> <input type=submit tabindex=70>
</div> </div>
<input type=file multiple> <input type=file multiple>
<div id=qr-thread-select>
<select title='Create a new thread / Reply'>
<option value=new>New thread</option>
</select>
</div>
<label id=qr-spoiler-label> <label id=qr-spoiler-label>
<input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler? <input type=checkbox id=qr-file-spoiler title='Spoiler image' tabindex=90>Spoiler?
</label> </label>
@ -800,7 +794,6 @@ QR =
filename: $ '#qr-filename', dialog filename: $ '#qr-filename', dialog
fileRM: $ '#qr-filerm', dialog fileRM: $ '#qr-filerm', dialog
spoiler: $ '#qr-file-spoiler', dialog spoiler: $ '#qr-file-spoiler', dialog
spoilerPar: $ '#qr-spoiler-label', dialog
status: $ '[type=submit]', dialog status: $ '[type=submit]', dialog
fileInput: $ '[type=file]', dialog fileInput: $ '[type=file]', dialog
@ -822,7 +815,7 @@ QR =
nodes.fileInput.accept = "text/*, #{mimeTypes}" if $.engine isnt 'presto' # Opera's accept attribute is fucked up nodes.fileInput.accept = "text/*, #{mimeTypes}" if $.engine isnt 'presto' # Opera's accept attribute is fucked up
QR.spoiler = !!$ 'input[name=spoiler]' QR.spoiler = !!$ 'input[name=spoiler]'
nodes.spoilerPar.hidden = !QR.spoiler nodes.spoiler.parentElement.hidden = !QR.spoiler
if g.BOARD.ID is 'f' if g.BOARD.ID is 'f'
nodes.flashTag = $.el 'select', nodes.flashTag = $.el 'select',
@ -843,10 +836,9 @@ QR =
$.add nodes.thread, $.el 'option', $.add nodes.thread, $.el 'option',
value: thread value: thread
textContent: "Thread No.#{thread}" textContent: "Thread No.#{thread}"
$.add nodes.threadPar, nodes.thread
QR.resetThreadSelector() QR.resetThreadSelector()
$.on nodes.filename.parentNode, 'click keyup', QR.openFileInput $.on nodes.filename.parentNode, 'click keyup', QR.openFileInput
$.on nodes.autohide, 'change', QR.toggleHide $.on nodes.autohide, 'change', QR.toggleHide
$.on nodes.close, 'click', QR.close $.on nodes.close, 'click', QR.close
@ -895,6 +887,7 @@ QR =
if g.BOARD.ID is 'f' if g.BOARD.ID is 'f'
filetag = QR.nodes.flashTag.value filetag = QR.nodes.flashTag.value
threadID = QR.nodes.thread.value threadID = QR.nodes.thread.value
thread = g.BOARD.threads[threadID]
# prevent errors # prevent errors
if threadID is 'new' if threadID is 'new'
@ -907,7 +900,7 @@ QR =
err = 'You can\'t reply to this thread anymore.' err = 'You can\'t reply to this thread anymore.'
else unless post.com or post.file else unless post.com or post.file
err = 'No file selected.' err = 'No file selected.'
else if post.file and g.BOARD.threads[threadID].fileLimit else if post.file and thread.fileLimit and !thread.isSticky
err = 'Max limit of image replies has been reached.' err = 'Max limit of image replies has been reached.'
if QR.captcha.isEnabled and !err if QR.captcha.isEnabled and !err