diff --git a/LICENSE b/LICENSE
index ba5abcb23..671794a8b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
/*
-* appchan x - Version 2.9.43 - 2015-01-08
+* appchan x - Version 2.9.43 - 2015-01-09
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
diff --git a/builds/appchan-x.user.js b/builds/appchan-x.user.js
index 4f6c9fabb..1bb01d7a2 100644
--- a/builds/appchan-x.user.js
+++ b/builds/appchan-x.user.js
@@ -27,7 +27,7 @@
// ==/UserScript==
/*
-* appchan x - Version 2.9.43 - 2015-01-08
+* appchan x - Version 2.9.43 - 2015-01-09
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
@@ -7612,13 +7612,13 @@
}
};
thisPost = {
- el: UI.checkbox('thisPost', ' This post', true)
+ el: UI.checkbox('thisPost', 'This post', true)
};
replies = {
- el: UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding'])
+ el: UI.checkbox('replies', 'Hide replies', Conf['Recursive Hiding'])
};
makeStub = {
- el: UI.checkbox('makeStub', ' Make stub', Conf['Stubs'])
+ el: UI.checkbox('makeStub', 'Make stub', Conf['Stubs'])
};
Menu.menu.addEntry({
el: $.el('div', {
@@ -7648,14 +7648,14 @@
}
};
thisPost = {
- el: UI.checkbox('thisPost', ' This post', false),
+ el: UI.checkbox('thisPost', 'This post', false),
open: function(post) {
this.el.firstChild.checked = post.isHidden;
return true;
}
};
replies = {
- el: UI.checkbox('replies', ' Show replies', false),
+ el: UI.checkbox('replies', 'Show replies', false),
open: function(post) {
var data;
data = PostHiding.db.get({
@@ -17204,7 +17204,7 @@
Settings = {
init: function() {
- var addSection, arr, check, el, settings, _i, _len, _ref;
+ var add, check, el, settings;
el = $.el('a', {
className: 'settings-link',
title: 'Appchan X Settings',
@@ -17216,12 +17216,16 @@
el: el,
order: 1
});
- addSection = this.addSection;
- _ref = [['style', 'Style'], ['themes', 'Themes'], ['mascots', 'Mascots'], ['main', 'Script'], ['filter', 'Filter'], ['sauce', 'Sauce'], ['advanced', 'Advanced'], ['keybinds', 'Keybinds']];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- arr = _ref[_i];
- addSection(arr[1], Settings[arr[0]]);
- }
+ add = this.addSection;
+ add('Style', this.style);
+ add('Themes', this.themes);
+ add('Mascots', this.mascots);
+ add('Main', this.main);
+ add('Filter', this.filter);
+ add('Sauce', this.sauce);
+ add('Advanced', this.advanced);
+ add('Keybinds', this.keybinds);
+ $.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
return Settings.open(e.detail);
});
@@ -17295,9 +17299,13 @@
return $.event('OpenSettings', null, dialog);
},
close: function() {
+ var _ref;
if (!Settings.dialog) {
return;
}
+ if ((_ref = d.activeElement) != null) {
+ _ref.blur();
+ }
$.rm(Settings.overlay);
$.rm(Settings.dialog);
delete Settings.overlay;
@@ -17305,7 +17313,10 @@
},
sections: [],
addSection: function(title, open) {
- var hyphenatedTitle;
+ var hyphenatedTitle, _ref;
+ if (typeof title !== 'string') {
+ _ref = title.detail, title = _ref.title, open = _ref.open;
+ }
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
return Settings.sections.push({
title: title,
@@ -17327,27 +17338,45 @@
return $.event('OpenSettings', null, section);
},
main: function(section) {
- var arr, button, description, div, fs, input, inputs, items, key, obj, _ref;
+ var arr, button, container, containers, description, div, fs, input, inputs, items, key, level, obj, _ref;
items = {};
inputs = {};
_ref = Config.main;
for (key in _ref) {
obj = _ref[key];
fs = $.el('fieldset', {
- innerHTML: "" + key + " "
+ innerHTML: "" + E(key) + " "
});
+ containers = [fs];
for (key in obj) {
arr = obj[key];
description = arr[1];
- div = $.el('div', {
- innerHTML: " " + key + "" + description + " "
- });
+ div = $.el('div');
+ $.add(div, [
+ UI.checkbox(key, key, false), $.el('span', {
+ "class": 'description',
+ textContent: ": " + description
+ })
+ ]);
input = $('input', div);
$.on($('label', div), 'mouseover', Settings.mouseover);
- $.on(input, 'change', $.cb.checked);
+ $.on(input, 'change', function() {
+ this.parentNode.parentNode.dataset.checked = this.checked;
+ return $.cb.checked.call(this);
+ });
items[key] = Conf[key];
inputs[key] = input;
- $.add(fs, div);
+ level = arr[2] || 0;
+ if (containers.length <= level) {
+ container = $.el('div', {
+ className: 'suboption-list'
+ });
+ $.add(containers[containers.length - 1].lastElementChild, container);
+ containers[level] = container;
+ } else if (containers.length > level + 1) {
+ containers.splice(level + 1, containers.length - (level + 1));
+ }
+ $.add(containers[level], div);
}
Rice.nodes(fs);
$.add(section, fs);
@@ -17357,10 +17386,11 @@
for (key in items) {
val = items[key];
inputs[key].checked = val;
+ inputs[key].parentNode.parentNode.dataset.checked = val;
}
});
div = $.el('div', {
- innerHTML: ": Clear manually-hidden threads and posts on all boards. Reload the page to apply."
+ innerHTML: ": Clear manually-hidden threads and posts on all boards. Reload the page to apply."
});
button = $('button', div);
$.get('hiddenPosts', {}, function(_arg) {
@@ -17412,6 +17442,7 @@
return;
}
if (!confirm('Your current settings will be entirely overwritten, are you sure?')) {
+ new Notice('info', "Import aborted.", 1);
return;
}
reader = new FileReader();
@@ -17419,14 +17450,13 @@
var err;
try {
Settings.loadSettings(JSON.parse(e.target.result));
+ if (confirm('Import successful. Reload now?')) {
+ return window.location.reload();
+ }
} catch (_error) {
err = _error;
alert('Import failed due to an error.');
- c.error(err.stack);
- return;
- }
- if (confirm('Import successful. Reload now?')) {
- return window.location.reload();
+ return c.error(err.stack);
}
};
return reader.readAsText(file);
@@ -17477,9 +17507,10 @@
$.add(div, ta);
return;
}
- return $.extend(div, {
+ $.extend(div, {
innerHTML: "Filter is disabled.
\r\rUse regular expressions , one per line. \rLines starting with a # will be ignored. \rFor example, /weeaboo/i will filter posts containing the string `weeaboo`, case-insensitive. \rMD5 filtering uses exact string matching, not regular expressions.\r
\rYou can use these settings with each regular expression, separate them with semicolons:\r\rPer boards, separate them with commas. It is global if not specified. \rFor example: boards:a,jp;.\r \r\rFilter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default). \rFor example: op:only;, op:no; or op:yes;.\r \r\rOverrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`). \rFor example: stub:yes; or stub:no;.\r \r\rHighlight instead of hiding. You can specify a class name to use with a userstyle. \rFor example: highlight; or highlight:wallpaper;.\r \r\rHighlighted OPs will have their threads put on top of the board index by default. \rFor example: top:yes; or top:no;.\r \r \r"
});
+ return $('.warning', div).hidden = Conf['Filter'];
},
sauce: function(section) {
var ta;
@@ -17488,33 +17519,25 @@
});
ta = $('textarea', section);
$.get('sauces', Conf['sauces'], function(item) {
- return ta.value = item['sauces'].replace(/\$\d/g, function(c) {
- switch (c) {
- case '$1':
- return '%TURL';
- case '$2':
- return '%URL';
- case '$3':
- return '%MD5';
- case '$4':
- return '%board';
- default:
- return c;
- }
- });
+ return ta.value = item['sauces'];
});
return $.on(ta, 'change', $.cb.value);
},
advanced: function(section) {
- var archBoards, boardID, boardOptions, boardSelect, boards, event, files, i, input, inputs, item, items, name, o, row, rows, software, ta, table, withCredentials, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
+ var archBoards, boardID, boardOptions, boardSelect, boards, customCSS, event, files, i, input, inputs, interval, item, items, name, o, row, rows, software, ta, table, warning, withCredentials, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _len6, _m, _n, _o, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
$.extend(section, {
innerHTML: "\rArchiver \r404 Redirect is disabled.
\r
\r\r\rThread redirection \rPost fetching \rFile redirection \r \r \r
\rDisabled selections indicate that only one archive is available for that board and redirection type. \r \r\rCustom Board Navigation \r
\rNew lines will be converted into spaces. \rIn the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
\rBoard link: g
\rTitle link: g-title
\rBoard link (Replace with title when on that board): g-replace
\rFull text link: g-full
\rCustom text link: g-text:\"Install Gentoo\"
\rExternal link: external-text:\"Google\",\"http://www.google.com\"
\rIndex mode: g-mode:\"type\" where type is paged, all threads or catalog
\rIndex sort: g-sort:\"type\" where type is bump order, last reply, creation date, reply count or file count
Combinations are possible: g-text:\"VIP Catalog\"-mode:\"catalog\"-sort:\"creation date\"\rFull board list toggle: toggle-all
\r \r\r[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h-mode:\"catalog\"-sort:\"file count\"] [t-text:\"Piracy\"] \rwill give you \r[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy] \rif you are on /g/.\r
\r \r\rTime Formatting is disabled. \r :
\r\rDay: %a, %A, %d, %e
\rMonth: %m, %b, %B
\rYear: %y, %Y
\rHour: %k, %H, %l, %I, %p, %P
\rMinute: %M
\rSecond: %S
\r \r\rQuote Backlinks formatting is disabled. \r :
\r \r\rFile Info Formatting is disabled. \r :
\rLink: %l (truncated), %L (untruncated), %T (Unix timestamp)
\rOriginal file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
\rSpoiler indicator: %p
\rSize: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
\rResolution: %r (Displays 'PDF' for PDF files)
\r \r\rQuick Reply Personas \r\r\rOne item per line. \rItems will be added in the relevant input's auto-completion list. \rPassword items will always be used, since there is no password input. \rLines starting with a # will be ignored.\r
\rYou can use these settings with each item, separate them with semicolons:\rPossible items are: name, options (or equivalently email), subject and password. \rWrap values of items with quotes, like this: options:\"sage\". \rForce values as defaults with the always keyword, for example: options:\"sage\";always. \rSelect specific boards for an item, separated with commas, for example: options:\"sage\";boards:jp;always. \r \r \r\rUnread Favicon is disabled. \r\rferongr \rxat- \rMayhem \r4chanJS \rOriginal \rMetro \r \r \r \r\rThread Updater is disabled. \r\rInterval: \r
\r \r\r Custom CSS \r\rApply CSS \r\r
\r \r"
});
+ _ref = $$('.warning', section);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ warning = _ref[_i];
+ warning.hidden = Conf[warning.dataset.feature];
+ }
items = {};
inputs = {};
- _ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- name = _ref[_i];
+ _ref1 = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ name = _ref1[_j];
input = $("[name='" + name + "']", section);
items[name] = Conf[name];
inputs[name] = input;
@@ -17540,15 +17563,20 @@
}
return Rice.nodes(section);
});
- $.on($('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval);
- $.on($('input[name="Custom CSS"]', section), 'change', Settings.togglecss);
- $.on($.id('apply-css'), 'click', Settings.usercss);
+ interval = $('input[name="Interval"]', section);
+ customCSS = $('input[name="Custom CSS"]', section);
+ interval.value = Conf['Interval'];
+ customCSS.checked = Conf['Custom CSS'];
+ inputs['usercss'].disabled = !Conf['Custom CSS'];
+ $.on(interval, 'change', ThreadUpdater.cb.interval);
+ $.on(customCSS, 'change', Settings.togglecss);
+ $.on($('#apply-css', section), 'click', Settings.usercss);
archBoards = {};
- _ref1 = Redirect.archives;
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- _ref2 = _ref1[_j], name = _ref2.name, boards = _ref2.boards, files = _ref2.files, software = _ref2.software, withCredentials = _ref2.withCredentials;
- for (_k = 0, _len2 = boards.length; _k < _len2; _k++) {
- boardID = boards[_k];
+ _ref2 = Redirect.archives;
+ for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+ _ref3 = _ref2[_k], name = _ref3.name, boards = _ref3.boards, files = _ref3.files, software = _ref3.software, withCredentials = _ref3.withCredentials;
+ for (_l = 0, _len3 = boards.length; _l < _len3; _l++) {
+ boardID = boards[_l];
o = archBoards[boardID] || (archBoards[boardID] = {
thread: [[], []],
post: [[], []],
@@ -17566,9 +17594,9 @@
}
for (boardID in archBoards) {
o = archBoards[boardID];
- _ref3 = ['thread', 'post', 'file'];
- for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
- item = _ref3[_l];
+ _ref4 = ['thread', 'post', 'file'];
+ for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
+ item = _ref4[_m];
if (o[item][0].length === 0 && o[item][1].length !== 0) {
o[item][0].push('disabled');
}
@@ -17577,9 +17605,9 @@
}
rows = [];
boardOptions = [];
- _ref4 = Object.keys(archBoards).sort();
- for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
- boardID = _ref4[_m];
+ _ref5 = Object.keys(archBoards).sort();
+ for (_n = 0, _len5 = _ref5.length; _n < _len5; _n++) {
+ boardID = _ref5[_n];
row = $.el('tr', {
className: "board-" + boardID
});
@@ -17590,13 +17618,14 @@
selected: boardID === g.BOARD.ID
}));
o = archBoards[boardID];
- _ref5 = ['thread', 'post', 'file'];
- for (_n = 0, _len5 = _ref5.length; _n < _len5; _n++) {
- item = _ref5[_n];
+ _ref6 = ['thread', 'post', 'file'];
+ for (_o = 0, _len6 = _ref6.length; _o < _len6; _o++) {
+ item = _ref6[_o];
$.add(row, Settings.addArchiveCell(boardID, o, item));
}
rows.push(row);
}
+ rows[0].hidden = !g.BOARD.ID in archBoards;
$.add($('tbody', section), rows);
boardSelect = $('#archive-board-select', section);
$.add(boardSelect, boardOptions);
@@ -17638,7 +17667,9 @@
value: archive
}));
}
- td.innerHTML = ' ';
+ $.extend(td, {
+ innerHTML: " "
+ });
select = td.firstElementChild;
if (!(select.disabled = length === 1)) {
select.setAttribute('data-boardid', boardID);
@@ -17665,7 +17696,12 @@
return this.nextElementSibling.textContent = Time.format(this.value, new Date());
},
backlink: function() {
- return this.nextElementSibling.textContent = this.value.replace(/%id/g, '123456789');
+ return this.nextElementSibling.textContent = this.value.replace(/%(?:id|%)/g, function(x) {
+ return {
+ '%id': '123456789',
+ '%%': '%'
+ }[x];
+ });
},
fileInfo: function() {
var data;
@@ -17678,21 +17714,25 @@
sizeInBytes: 276 * 1024,
dimensions: '1280x720',
isImage: true,
- isVideo: false,
isSpoiler: true
}
};
- return this.nextElementSibling.innerHTML = FileInfo.format(this.value, data);
+ return FileInfo.format(this.value, data, this.nextElementSibling);
},
favicon: function() {
- Favicon.init();
+ var img;
+ Favicon["switch"]();
if (g.VIEW === 'thread' && Conf['Unread Favicon']) {
Unread.update();
}
- return $.id('favicon-preview').innerHTML = " \n \n \n ";
+ img = this.nextElementSibling.children;
+ img[0].src = Favicon["default"];
+ img[1].src = Favicon.unreadSFW;
+ img[2].src = Favicon.unreadNSFW;
+ return img[3].src = Favicon.unreadDead;
},
togglecss: function() {
- if ($('textarea', this.parentNode.parentNode).disabled = !this.checked) {
+ if ($('textarea[name=usercss]', $.x('ancestor::fieldset[1]', this)).disabled = !this.checked) {
CustomCSS.rmStyle();
} else {
CustomCSS.addStyle();
@@ -17707,6 +17747,7 @@
$.extend(section, {
innerHTML: "Keybinds are disabled.
\rAllowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
\rPress Backspace to disable a keybind.
\r"
});
+ $('.warning', section).hidden = Conf['Keybinds'];
tbody = $('tbody', section);
items = {};
inputs = {};
@@ -17714,7 +17755,7 @@
for (key in _ref) {
arr = _ref[key];
tr = $.el('tr', {
- innerHTML: "
" + arr[1] + " "
+ innerHTML: "" + E(arr[1]) + " "
});
input = $('input', tr);
input.name = key;
@@ -17747,7 +17788,7 @@
return $.cb.value.call(this);
},
style: function(section) {
- var arr, description, div, fs, html, input, inputs, items, key, name, nodes, obj, type, value, _i, _len, _ref;
+ var arr, description, div, fs, html, input, inputs, items, key, name, nodes, obj, span, type, value, _i, _len, _ref;
nodes = $.frag();
items = {};
inputs = {};
@@ -17765,7 +17806,9 @@
});
if (type) {
if (type === 'text') {
- div.innerHTML = "" + key + "
" + description + "
";
+ $.extend(div, {
+ innerHTML: "" + E(key) + "
" + E(description) + "
"
+ });
input = $("input", div);
} else {
html = "" + key + "
" + description + "
";
@@ -17778,7 +17821,12 @@
input = $("select", div);
}
} else {
- div.innerHTML = " " + key + "
" + description + " ";
+ span = $.el('span', {
+ "class": 'description',
+ textContent: description
+ });
+ span.style.display = 'none';
+ $.add(div, [UI.checkbox(key, key), span]);
input = $('input', div);
}
items[key] = Conf[key];
@@ -17839,8 +17887,10 @@
}
div = $.el('div', {
className: "theme " + (name === Conf[g.THEMESTRING] ? 'selectedtheme' : ''),
- id: name,
- innerHTML: ""
+ id: name
+ });
+ $.extend(div, {
+ innerHTML: ""
});
div.style.backgroundColor = theme['Background Color'];
_ref = $$('a[data-color]', div);
@@ -17857,8 +17907,10 @@
$.add(suboptions, div);
}
div = $.el('div', {
- id: 'addthemes',
- innerHTML: "New Theme \n/\nImport Theme \n/\nUndelete Theme "
+ id: 'addthemes'
+ });
+ $.extend(div, {
+ innerHTML: "New Theme \r/\rImport Theme \r \r/\rUndelete Theme "
});
$.on($("#newtheme", div), 'click', function() {
ThemeTools.init("untitled");
@@ -17886,8 +17938,10 @@
}
div = $.el('div', {
id: name,
- className: theme,
- innerHTML: "\n " + name + "\n \n " + theme['Author'] + "\n \n (SAGE)\n \n " + theme['Author Tripcode'] + "\n \n 20XX.01.01 12:00\n \n No.27583594\n \n >>27582902\n \n I forgive you for using VLC to open me. ;__;\n "
+ className: theme
+ });
+ $.extend(div, {
+ innerHTML: "\r
\r
\r" + name + "\r \r
\r" + theme['Author'] + "\r \r
\r(SAGE)\r \r
\r" + theme['Author Tripcode'] + "\r \r
\r20XX.01.01 12:00\r \r
\rNo.27583594\r \r
\r
\r\r>>27582902\r \r \rI forgive you for using VLC to open me. ;__;\r \r
"
});
$.on(div, 'click', cb.restore);
$.add(suboptions, div);
@@ -17942,15 +17996,17 @@
});
mascotHide = $.el("div", {
id: "mascot_hide",
- className: "reply",
- innerHTML: "Hide Categories
"
+ className: "reply"
+ }, {
+ innerHTML: "Hide Categories
"
});
keys = Object.keys(Mascots);
keys.sort();
if (mode === 'default') {
mascotoptions = $.el('div', {
- id: 'mascot-options',
- innerHTML: "Edit Delete Export "
+ id: 'mascot-options'
+ }, {
+ innerHTML: "Edit Delete Export "
});
$.on($('.edit', mascotoptions), 'click', cb.edit);
$.on($('.delete', mascotoptions), 'click', cb["delete"]);
@@ -17967,14 +18023,13 @@
menu = $('div', mascotHide);
categories[name] = div = $.el("div", {
id: name,
- className: "mascots-container",
- innerHTML: "",
+ className: "mascots-container"
+ }, {
+ innerHTML: ""
+ }, {
hidden: __indexOf.call(Conf["Hidden Categories"], name) >= 0
});
- option = $.el("label", {
- name: name,
- innerHTML: " = 0 ? 'checked' : '') + ">" + name
- });
+ option = UI.checkbox(name, name, __indexOf.call(Conf["Hidden Categories"], name) >= 0);
$.on($('input', option), 'change', cb.category);
$.add(suboptions, div);
$.add(menu, option);
@@ -17987,16 +18042,20 @@
mascot = Mascots[name];
mascotEl = $.el('div', {
id: name,
- className: __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 ? 'mascot enabled' : 'mascot',
- innerHTML: "" + (name.replace(/_/g, " ")) + "
"
+ className: __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 ? 'mascot enabled' : 'mascot'
+ });
+ $.extend(div, {
+ innerHTML: "" + (name.replace(/_/g, ' ')) + "
\r"
});
$.on(mascotEl, 'click', cb.select);
$.on(mascotEl, 'mouseover', addoptions);
$.add(categories[mascot.category] || categories[MascotTools.categories[0]], mascotEl);
}
batchmascots = $.el('div', {
- id: "mascots_batch",
- innerHTML: " Clear All \n/\nSelect All \n/\nAdd Mascot \n/\nImport Mascot \n/\nUndelete Mascots \n/\nGet More Mascots! "
+ id: "mascots_batch"
+ });
+ $.extend(batchmascots, {
+ innerHTML: "Clear All \r/\rSelect All \r/\rAdd Mascot \r/\rImport Mascot \r/\rUndelete Mascots \r/\rGet More Mascots! "
});
$.on($('#clear', batchmascots), 'click', function() {
var enabledMascots, _k, _len2;
@@ -18050,15 +18109,18 @@
mascot = Mascots[name];
mascotEl = $.el('div', {
className: 'mascot',
- id: name,
- innerHTML: "" + (name.replace(/_/g, " ")) + "
"
+ id: name
+ });
+ $.extend(mascotEl, {
+ innerHTML: "
" + (name.replace(/_/g, ' ')) + "
\r
"
});
$.on(mascotEl, 'click', cb.restore);
$.add(container, mascotEl);
}
$.add(suboptions, container);
batchmascots = $.el('div', {
- id: "mascots_batch",
+ id: "mascots_batch"
+ }, {
innerHTML: "
Return "
});
$.on($('#return', batchmascots), 'click', function() {
diff --git a/builds/crx/script.js b/builds/crx/script.js
index 54680a7c3..c00c1d1b6 100644
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -1,6 +1,6 @@
// Generated by CoffeeScript
/*
-* appchan x - Version 2.9.43 - 2015-01-08
+* appchan x - Version 2.9.43 - 2015-01-09
*
* Licensed under the MIT license.
* https://github.com/zixaphir/appchan-x/blob/master/LICENSE
@@ -7657,13 +7657,13 @@
}
};
thisPost = {
- el: UI.checkbox('thisPost', ' This post', true)
+ el: UI.checkbox('thisPost', 'This post', true)
};
replies = {
- el: UI.checkbox('replies', ' Hide replies', Conf['Recursive Hiding'])
+ el: UI.checkbox('replies', 'Hide replies', Conf['Recursive Hiding'])
};
makeStub = {
- el: UI.checkbox('makeStub', ' Make stub', Conf['Stubs'])
+ el: UI.checkbox('makeStub', 'Make stub', Conf['Stubs'])
};
Menu.menu.addEntry({
el: $.el('div', {
@@ -7693,14 +7693,14 @@
}
};
thisPost = {
- el: UI.checkbox('thisPost', ' This post', false),
+ el: UI.checkbox('thisPost', 'This post', false),
open: function(post) {
this.el.firstChild.checked = post.isHidden;
return true;
}
};
replies = {
- el: UI.checkbox('replies', ' Show replies', false),
+ el: UI.checkbox('replies', 'Show replies', false),
open: function(post) {
var data;
data = PostHiding.db.get({
@@ -17227,7 +17227,7 @@
Settings = {
init: function() {
- var addSection, arr, check, el, settings, _i, _len, _ref;
+ var add, check, el, settings;
el = $.el('a', {
className: 'settings-link',
title: 'Appchan X Settings',
@@ -17239,12 +17239,16 @@
el: el,
order: 1
});
- addSection = this.addSection;
- _ref = [['style', 'Style'], ['themes', 'Themes'], ['mascots', 'Mascots'], ['main', 'Script'], ['filter', 'Filter'], ['sauce', 'Sauce'], ['advanced', 'Advanced'], ['keybinds', 'Keybinds']];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- arr = _ref[_i];
- addSection(arr[1], Settings[arr[0]]);
- }
+ add = this.addSection;
+ add('Style', this.style);
+ add('Themes', this.themes);
+ add('Mascots', this.mascots);
+ add('Main', this.main);
+ add('Filter', this.filter);
+ add('Sauce', this.sauce);
+ add('Advanced', this.advanced);
+ add('Keybinds', this.keybinds);
+ $.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
return Settings.open(e.detail);
});
@@ -17318,9 +17322,13 @@
return $.event('OpenSettings', null, dialog);
},
close: function() {
+ var _ref;
if (!Settings.dialog) {
return;
}
+ if ((_ref = d.activeElement) != null) {
+ _ref.blur();
+ }
$.rm(Settings.overlay);
$.rm(Settings.dialog);
delete Settings.overlay;
@@ -17328,7 +17336,10 @@
},
sections: [],
addSection: function(title, open) {
- var hyphenatedTitle;
+ var hyphenatedTitle, _ref;
+ if (typeof title !== 'string') {
+ _ref = title.detail, title = _ref.title, open = _ref.open;
+ }
hyphenatedTitle = title.toLowerCase().replace(/\s+/g, '-');
return Settings.sections.push({
title: title,
@@ -17350,27 +17361,45 @@
return $.event('OpenSettings', null, section);
},
main: function(section) {
- var arr, button, description, div, fs, input, inputs, items, key, obj, _ref;
+ var arr, button, container, containers, description, div, fs, input, inputs, items, key, level, obj, _ref;
items = {};
inputs = {};
_ref = Config.main;
for (key in _ref) {
obj = _ref[key];
fs = $.el('fieldset', {
- innerHTML: "
" + key + " "
+ innerHTML: "
" + E(key) + " "
});
+ containers = [fs];
for (key in obj) {
arr = obj[key];
description = arr[1];
- div = $.el('div', {
- innerHTML: "
" + key + "" + description + " "
- });
+ div = $.el('div');
+ $.add(div, [
+ UI.checkbox(key, key, false), $.el('span', {
+ "class": 'description',
+ textContent: ": " + description
+ })
+ ]);
input = $('input', div);
$.on($('label', div), 'mouseover', Settings.mouseover);
- $.on(input, 'change', $.cb.checked);
+ $.on(input, 'change', function() {
+ this.parentNode.parentNode.dataset.checked = this.checked;
+ return $.cb.checked.call(this);
+ });
items[key] = Conf[key];
inputs[key] = input;
- $.add(fs, div);
+ level = arr[2] || 0;
+ if (containers.length <= level) {
+ container = $.el('div', {
+ className: 'suboption-list'
+ });
+ $.add(containers[containers.length - 1].lastElementChild, container);
+ containers[level] = container;
+ } else if (containers.length > level + 1) {
+ containers.splice(level + 1, containers.length - (level + 1));
+ }
+ $.add(containers[level], div);
}
Rice.nodes(fs);
$.add(section, fs);
@@ -17380,10 +17409,11 @@
for (key in items) {
val = items[key];
inputs[key].checked = val;
+ inputs[key].parentNode.parentNode.dataset.checked = val;
}
});
div = $.el('div', {
- innerHTML: "
: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
+ innerHTML: ": Clear manually-hidden threads and posts on all boards. Reload the page to apply."
});
button = $('button', div);
$.get('hiddenPosts', {}, function(_arg) {
@@ -17433,6 +17463,7 @@
return;
}
if (!confirm('Your current settings will be entirely overwritten, are you sure?')) {
+ new Notice('info', "Import aborted.", 1);
return;
}
reader = new FileReader();
@@ -17440,14 +17471,13 @@
var err;
try {
Settings.loadSettings(JSON.parse(e.target.result));
+ if (confirm('Import successful. Reload now?')) {
+ return window.location.reload();
+ }
} catch (_error) {
err = _error;
alert('Import failed due to an error.');
- c.error(err.stack);
- return;
- }
- if (confirm('Import successful. Reload now?')) {
- return window.location.reload();
+ return c.error(err.stack);
}
};
return reader.readAsText(file);
@@ -17498,9 +17528,10 @@
$.add(div, ta);
return;
}
- return $.extend(div, {
+ $.extend(div, {
innerHTML: "Filter is disabled.
\r\rUse regular expressions , one per line. \rLines starting with a # will be ignored. \rFor example, /weeaboo/i will filter posts containing the string `weeaboo`, case-insensitive. \rMD5 filtering uses exact string matching, not regular expressions.\r
\rYou can use these settings with each regular expression, separate them with semicolons:\r\rPer boards, separate them with commas. It is global if not specified. \rFor example: boards:a,jp;.\r \r\rFilter OPs only along with their threads (`only`), replies only (`no`), or both (`yes`, this is default). \rFor example: op:only;, op:no; or op:yes;.\r \r\rOverrule the `Show Stubs` setting if specified: create a stub (`yes`) or not (`no`). \rFor example: stub:yes; or stub:no;.\r \r\rHighlight instead of hiding. You can specify a class name to use with a userstyle. \rFor example: highlight; or highlight:wallpaper;.\r \r\rHighlighted OPs will have their threads put on top of the board index by default. \rFor example: top:yes; or top:no;.\r \r \r"
});
+ return $('.warning', div).hidden = Conf['Filter'];
},
sauce: function(section) {
var ta;
@@ -17509,33 +17540,25 @@
});
ta = $('textarea', section);
$.get('sauces', Conf['sauces'], function(item) {
- return ta.value = item['sauces'].replace(/\$\d/g, function(c) {
- switch (c) {
- case '$1':
- return '%TURL';
- case '$2':
- return '%URL';
- case '$3':
- return '%MD5';
- case '$4':
- return '%board';
- default:
- return c;
- }
- });
+ return ta.value = item['sauces'];
});
return $.on(ta, 'change', $.cb.value);
},
advanced: function(section) {
- var archBoards, boardID, boardOptions, boardSelect, boards, event, files, i, input, inputs, item, items, name, o, row, rows, software, ta, table, withCredentials, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
+ var archBoards, boardID, boardOptions, boardSelect, boards, customCSS, event, files, i, input, inputs, interval, item, items, name, o, row, rows, software, ta, table, warning, withCredentials, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _len6, _m, _n, _o, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
$.extend(section, {
innerHTML: "\rArchiver \r404 Redirect is disabled.
\r
\r\r\rThread redirection \rPost fetching \rFile redirection \r \r \r
\rDisabled selections indicate that only one archive is available for that board and redirection type. \r \r\rCustom Board Navigation \r
\rNew lines will be converted into spaces. \rIn the following examples for /g/, g can be changed to a different board ID (a, b, etc...), the current board (current), or the Twitter link (@).
\rBoard link: g
\rTitle link: g-title
\rBoard link (Replace with title when on that board): g-replace
\rFull text link: g-full
\rCustom text link: g-text:\"Install Gentoo\"
\rExternal link: external-text:\"Google\",\"http://www.google.com\"
\rIndex mode: g-mode:\"type\" where type is paged, all threads or catalog
\rIndex sort: g-sort:\"type\" where type is bump order, last reply, creation date, reply count or file count
Combinations are possible: g-text:\"VIP Catalog\"-mode:\"catalog\"-sort:\"creation date\" \rFull board list toggle: toggle-all
\r \r\r[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h-mode:\"catalog\"-sort:\"file count\"] [t-text:\"Piracy\"] \rwill give you \r[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy] \rif you are on /g/.\r
\r\r\rTime Formatting is disabled. \r :
\r\rDay: %a, %A, %d, %e
\rMonth: %m, %b, %B
\rYear: %y, %Y
\rHour: %k, %H, %l, %I, %p, %P
\rMinute: %M
\rSecond: %S
\r \r\rQuote Backlinks formatting is disabled. \r :
\r \r\rFile Info Formatting is disabled. \r :
\rLink: %l (truncated), %L (untruncated), %T (Unix timestamp)
\rOriginal file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
\rSpoiler indicator: %p
\rSize: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
\rResolution: %r (Displays 'PDF' for PDF files)
\r \r\rQuick Reply Personas \r\r\rOne item per line. \rItems will be added in the relevant input's auto-completion list. \rPassword items will always be used, since there is no password input. \rLines starting with a # will be ignored.\r
\rYou can use these settings with each item, separate them with semicolons:\rPossible items are: name, options (or equivalently email), subject and password. \rWrap values of items with quotes, like this: options:\"sage\". \rForce values as defaults with the always keyword, for example: options:\"sage\";always. \rSelect specific boards for an item, separated with commas, for example: options:\"sage\";boards:jp;always. \r \r \r\rUnread Favicon is disabled. \r\rferongr \rxat- \rMayhem \r4chanJS \rOriginal \rMetro \r \r \r \r\rThread Updater is disabled. \r\rInterval: \r
\r \r\r Custom CSS \r\rApply CSS \r\r
\r \r"
});
+ _ref = $$('.warning', section);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ warning = _ref[_i];
+ warning.hidden = Conf[warning.dataset.feature];
+ }
items = {};
inputs = {};
- _ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- name = _ref[_i];
+ _ref1 = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss'];
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ name = _ref1[_j];
input = $("[name='" + name + "']", section);
items[name] = Conf[name];
inputs[name] = input;
@@ -17561,15 +17584,20 @@
}
return Rice.nodes(section);
});
- $.on($('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval);
- $.on($('input[name="Custom CSS"]', section), 'change', Settings.togglecss);
- $.on($.id('apply-css'), 'click', Settings.usercss);
+ interval = $('input[name="Interval"]', section);
+ customCSS = $('input[name="Custom CSS"]', section);
+ interval.value = Conf['Interval'];
+ customCSS.checked = Conf['Custom CSS'];
+ inputs['usercss'].disabled = !Conf['Custom CSS'];
+ $.on(interval, 'change', ThreadUpdater.cb.interval);
+ $.on(customCSS, 'change', Settings.togglecss);
+ $.on($('#apply-css', section), 'click', Settings.usercss);
archBoards = {};
- _ref1 = Redirect.archives;
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- _ref2 = _ref1[_j], name = _ref2.name, boards = _ref2.boards, files = _ref2.files, software = _ref2.software, withCredentials = _ref2.withCredentials;
- for (_k = 0, _len2 = boards.length; _k < _len2; _k++) {
- boardID = boards[_k];
+ _ref2 = Redirect.archives;
+ for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+ _ref3 = _ref2[_k], name = _ref3.name, boards = _ref3.boards, files = _ref3.files, software = _ref3.software, withCredentials = _ref3.withCredentials;
+ for (_l = 0, _len3 = boards.length; _l < _len3; _l++) {
+ boardID = boards[_l];
o = archBoards[boardID] || (archBoards[boardID] = {
thread: [[], []],
post: [[], []],
@@ -17587,9 +17615,9 @@
}
for (boardID in archBoards) {
o = archBoards[boardID];
- _ref3 = ['thread', 'post', 'file'];
- for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
- item = _ref3[_l];
+ _ref4 = ['thread', 'post', 'file'];
+ for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
+ item = _ref4[_m];
if (o[item][0].length === 0 && o[item][1].length !== 0) {
o[item][0].push('disabled');
}
@@ -17598,9 +17626,9 @@
}
rows = [];
boardOptions = [];
- _ref4 = Object.keys(archBoards).sort();
- for (_m = 0, _len4 = _ref4.length; _m < _len4; _m++) {
- boardID = _ref4[_m];
+ _ref5 = Object.keys(archBoards).sort();
+ for (_n = 0, _len5 = _ref5.length; _n < _len5; _n++) {
+ boardID = _ref5[_n];
row = $.el('tr', {
className: "board-" + boardID
});
@@ -17611,13 +17639,14 @@
selected: boardID === g.BOARD.ID
}));
o = archBoards[boardID];
- _ref5 = ['thread', 'post', 'file'];
- for (_n = 0, _len5 = _ref5.length; _n < _len5; _n++) {
- item = _ref5[_n];
+ _ref6 = ['thread', 'post', 'file'];
+ for (_o = 0, _len6 = _ref6.length; _o < _len6; _o++) {
+ item = _ref6[_o];
$.add(row, Settings.addArchiveCell(boardID, o, item));
}
rows.push(row);
}
+ rows[0].hidden = !g.BOARD.ID in archBoards;
$.add($('tbody', section), rows);
boardSelect = $('#archive-board-select', section);
$.add(boardSelect, boardOptions);
@@ -17659,7 +17688,9 @@
value: archive
}));
}
- td.innerHTML = ' ';
+ $.extend(td, {
+ innerHTML: " "
+ });
select = td.firstElementChild;
if (!(select.disabled = length === 1)) {
select.setAttribute('data-boardid', boardID);
@@ -17686,7 +17717,12 @@
return this.nextElementSibling.textContent = Time.format(this.value, new Date());
},
backlink: function() {
- return this.nextElementSibling.textContent = this.value.replace(/%id/g, '123456789');
+ return this.nextElementSibling.textContent = this.value.replace(/%(?:id|%)/g, function(x) {
+ return {
+ '%id': '123456789',
+ '%%': '%'
+ }[x];
+ });
},
fileInfo: function() {
var data;
@@ -17699,21 +17735,25 @@
sizeInBytes: 276 * 1024,
dimensions: '1280x720',
isImage: true,
- isVideo: false,
isSpoiler: true
}
};
- return this.nextElementSibling.innerHTML = FileInfo.format(this.value, data);
+ return FileInfo.format(this.value, data, this.nextElementSibling);
},
favicon: function() {
- Favicon.init();
+ var img;
+ Favicon["switch"]();
if (g.VIEW === 'thread' && Conf['Unread Favicon']) {
Unread.update();
}
- return $.id('favicon-preview').innerHTML = " \n \n \n ";
+ img = this.nextElementSibling.children;
+ img[0].src = Favicon["default"];
+ img[1].src = Favicon.unreadSFW;
+ img[2].src = Favicon.unreadNSFW;
+ return img[3].src = Favicon.unreadDead;
},
togglecss: function() {
- if ($('textarea', this.parentNode.parentNode).disabled = !this.checked) {
+ if ($('textarea[name=usercss]', $.x('ancestor::fieldset[1]', this)).disabled = !this.checked) {
CustomCSS.rmStyle();
} else {
CustomCSS.addStyle();
@@ -17728,6 +17768,7 @@
$.extend(section, {
innerHTML: "Keybinds are disabled.
\rAllowed keys: a-z , 0-9 , Ctrl , Shift , Alt , Meta , Enter , Esc , Up , Down , Right , Left .
\rPress Backspace to disable a keybind.
\r"
});
+ $('.warning', section).hidden = Conf['Keybinds'];
tbody = $('tbody', section);
items = {};
inputs = {};
@@ -17735,7 +17776,7 @@
for (key in _ref) {
arr = _ref[key];
tr = $.el('tr', {
- innerHTML: "" + arr[1] + " "
+ innerHTML: "" + E(arr[1]) + " "
});
input = $('input', tr);
input.name = key;
@@ -17768,7 +17809,7 @@
return $.cb.value.call(this);
},
style: function(section) {
- var arr, description, div, fs, html, input, inputs, items, key, name, nodes, obj, type, value, _i, _len, _ref;
+ var arr, description, div, fs, html, input, inputs, items, key, name, nodes, obj, span, type, value, _i, _len, _ref;
nodes = $.frag();
items = {};
inputs = {};
@@ -17786,7 +17827,9 @@
});
if (type) {
if (type === 'text') {
- div.innerHTML = "" + key + "
" + description + "
";
+ $.extend(div, {
+ innerHTML: "" + E(key) + "
" + E(description) + "
"
+ });
input = $("input", div);
} else {
html = "" + key + "
" + description + "
";
@@ -17799,7 +17842,12 @@
input = $("select", div);
}
} else {
- div.innerHTML = " " + key + "
" + description + " ";
+ span = $.el('span', {
+ "class": 'description',
+ textContent: description
+ });
+ span.style.display = 'none';
+ $.add(div, [UI.checkbox(key, key), span]);
input = $('input', div);
}
items[key] = Conf[key];
@@ -17860,8 +17908,10 @@
}
div = $.el('div', {
className: "theme " + (name === Conf[g.THEMESTRING] ? 'selectedtheme' : ''),
- id: name,
- innerHTML: ""
+ id: name
+ });
+ $.extend(div, {
+ innerHTML: ""
});
div.style.backgroundColor = theme['Background Color'];
_ref = $$('a[data-color]', div);
@@ -17878,8 +17928,10 @@
$.add(suboptions, div);
}
div = $.el('div', {
- id: 'addthemes',
- innerHTML: "New Theme \n/\nImport Theme \n/\nUndelete Theme "
+ id: 'addthemes'
+ });
+ $.extend(div, {
+ innerHTML: "New Theme \r/\rImport Theme \r \r/\rUndelete Theme "
});
$.on($("#newtheme", div), 'click', function() {
ThemeTools.init("untitled");
@@ -17907,8 +17959,10 @@
}
div = $.el('div', {
id: name,
- className: theme,
- innerHTML: "\n " + name + "\n \n " + theme['Author'] + "\n \n (SAGE)\n \n " + theme['Author Tripcode'] + "\n \n 20XX.01.01 12:00\n \n No.27583594\n \n >>27582902\n \n I forgive you for using VLC to open me. ;__;\n "
+ className: theme
+ });
+ $.extend(div, {
+ innerHTML: "\r
\r
\r" + name + "\r \r
\r" + theme['Author'] + "\r \r
\r(SAGE)\r \r
\r" + theme['Author Tripcode'] + "\r \r
\r20XX.01.01 12:00\r \r
\rNo.27583594\r \r
\r
\r\r>>27582902\r \r \rI forgive you for using VLC to open me. ;__;\r \r
"
});
$.on(div, 'click', cb.restore);
$.add(suboptions, div);
@@ -17963,15 +18017,17 @@
});
mascotHide = $.el("div", {
id: "mascot_hide",
- className: "reply",
- innerHTML: "Hide Categories
"
+ className: "reply"
+ }, {
+ innerHTML: "Hide Categories
"
});
keys = Object.keys(Mascots);
keys.sort();
if (mode === 'default') {
mascotoptions = $.el('div', {
- id: 'mascot-options',
- innerHTML: "Edit Delete Export "
+ id: 'mascot-options'
+ }, {
+ innerHTML: "Edit Delete Export "
});
$.on($('.edit', mascotoptions), 'click', cb.edit);
$.on($('.delete', mascotoptions), 'click', cb["delete"]);
@@ -17988,14 +18044,13 @@
menu = $('div', mascotHide);
categories[name] = div = $.el("div", {
id: name,
- className: "mascots-container",
- innerHTML: "",
+ className: "mascots-container"
+ }, {
+ innerHTML: ""
+ }, {
hidden: __indexOf.call(Conf["Hidden Categories"], name) >= 0
});
- option = $.el("label", {
- name: name,
- innerHTML: " = 0 ? 'checked' : '') + ">" + name
- });
+ option = UI.checkbox(name, name, __indexOf.call(Conf["Hidden Categories"], name) >= 0);
$.on($('input', option), 'change', cb.category);
$.add(suboptions, div);
$.add(menu, option);
@@ -18008,16 +18063,20 @@
mascot = Mascots[name];
mascotEl = $.el('div', {
id: name,
- className: __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 ? 'mascot enabled' : 'mascot',
- innerHTML: "" + (name.replace(/_/g, " ")) + "
"
+ className: __indexOf.call(Conf[g.MASCOTSTRING], name) >= 0 ? 'mascot enabled' : 'mascot'
+ });
+ $.extend(div, {
+ innerHTML: "" + (name.replace(/_/g, ' ')) + "
\r"
});
$.on(mascotEl, 'click', cb.select);
$.on(mascotEl, 'mouseover', addoptions);
$.add(categories[mascot.category] || categories[MascotTools.categories[0]], mascotEl);
}
batchmascots = $.el('div', {
- id: "mascots_batch",
- innerHTML: " Clear All \n/\nSelect All \n/\nAdd Mascot \n/\nImport Mascot \n/\nUndelete Mascots \n/\nGet More Mascots! "
+ id: "mascots_batch"
+ });
+ $.extend(batchmascots, {
+ innerHTML: "Clear All \r/\rSelect All \r/\rAdd Mascot \r/\rImport Mascot \r/\rUndelete Mascots \r/\rGet More Mascots! "
});
$.on($('#clear', batchmascots), 'click', function() {
var enabledMascots, _k, _len2;
@@ -18071,15 +18130,18 @@
mascot = Mascots[name];
mascotEl = $.el('div', {
className: 'mascot',
- id: name,
- innerHTML: "" + (name.replace(/_/g, " ")) + "
"
+ id: name
+ });
+ $.extend(mascotEl, {
+ innerHTML: "
" + (name.replace(/_/g, ' ')) + "
\r
"
});
$.on(mascotEl, 'click', cb.restore);
$.add(container, mascotEl);
}
$.add(suboptions, container);
batchmascots = $.el('div', {
- id: "mascots_batch",
+ id: "mascots_batch"
+ }, {
innerHTML: "
Return "
});
$.on($('#return', batchmascots), 'click', function() {
diff --git a/src/Filtering/PostHiding.coffee b/src/Filtering/PostHiding.coffee
index 9a69c12ea..72a6e1bc0 100644
--- a/src/Filtering/PostHiding.coffee
+++ b/src/Filtering/PostHiding.coffee
@@ -83,9 +83,9 @@ PostHiding =
@cb = -> PostHiding.menu.hide post
$.on @el, 'click', @cb
true
- thisPost = el: UI.checkbox 'thisPost', ' This post', true
- replies = el: UI.checkbox 'replies', ' Hide replies', Conf['Recursive Hiding']
- makeStub = el: UI.checkbox 'makeStub', ' Make stub', Conf['Stubs']
+ thisPost = el: UI.checkbox 'thisPost', 'This post', true
+ replies = el: UI.checkbox 'replies', 'Hide replies', Conf['Recursive Hiding']
+ makeStub = el: UI.checkbox 'makeStub', 'Make stub', Conf['Stubs']
Menu.menu.addEntry
el: $.el 'div',
@@ -104,12 +104,12 @@ PostHiding =
$.on @el, 'click', @cb
true
thisPost =
- el: UI.checkbox 'thisPost', ' This post', false
+ el: UI.checkbox 'thisPost', 'This post', false
open: (post) ->
@el.firstChild.checked = post.isHidden
true
replies =
- el: UI.checkbox 'replies', ' Show replies', false
+ el: UI.checkbox 'replies', 'Show replies', false
open: (post) ->
data = PostHiding.db.get {boardID: post.board.ID, threadID: post.thread.ID, postID: post.ID}
@el.firstChild.checked = if 'hideRecursively' of data then data.hideRecursively else Conf['Recursive Hiding']
diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee
index 246580c82..5c1822c1e 100755
--- a/src/General/Settings.coffee
+++ b/src/General/Settings.coffee
@@ -12,18 +12,18 @@ Settings =
el: el
order: 1
- {addSection} = @
- addSection arr[1], Settings[arr[0]] for arr in [
- ['style', 'Style']
- ['themes', 'Themes']
- ['mascots', 'Mascots']
- ['main', 'Script']
- ['filter', 'Filter']
- ['sauce', 'Sauce']
- ['advanced', 'Advanced']
- ['keybinds', 'Keybinds']
- ]
+ add = @addSection
+
+ add 'Style', @style
+ add 'Themes', @themes
+ add 'Mascots', @mascots
+ add 'Main', @main
+ add 'Filter', @filter
+ add 'Sauce', @sauce
+ add 'Advanced', @advanced
+ add 'Keybinds', @keybinds
+ $.on d, 'AddSettingsSection', Settings.addSection
$.on d, 'OpenSettings', (e) -> Settings.open e.detail
settings = JSON.parse(localStorage.getItem '4chan-settings') or {}
@@ -84,6 +84,8 @@ Settings =
close: ->
return unless Settings.dialog
+ # Unfocus current field to trigger change event.
+ d.activeElement?.blur()
$.rm Settings.overlay
$.rm Settings.dialog
delete Settings.overlay
@@ -92,6 +94,8 @@ Settings =
sections: []
addSection: (title, open) ->
+ if typeof title isnt 'string'
+ {title, open} = title.detail
hyphenatedTitle = title.toLowerCase().replace /\s+/g, '-'
Settings.sections.push {title, hyphenatedTitle, open}
@@ -111,27 +115,41 @@ Settings =
inputs = {}
for key, obj of Config.main
fs = $.el 'fieldset',
- innerHTML: "
#{key} "
+ <%= html('
${key} ') %>
+ containers = [fs]
for key, arr of obj
description = arr[1]
- div = $.el 'div',
- innerHTML: "
#{key}#{description} "
+ div = $.el 'div'
+ $.add div, [
+ UI.checkbox key, key, false
+ $.el 'span', class: 'description', textContent: ": #{description}"
+ ]
input = $ 'input', div
$.on $('label', div), 'mouseover', Settings.mouseover
- $.on input, 'change', $.cb.checked
+ $.on input, 'change', ->
+ @parentNode.parentNode.dataset.checked = @checked
+ $.cb.checked.call @
items[key] = Conf[key]
inputs[key] = input
- $.add fs, div
+ level = arr[2] or 0
+ if containers.length <= level
+ container = $.el 'div', className: 'suboption-list'
+ $.add containers[containers.length-1].lastElementChild, container
+ containers[level] = container
+ else if containers.length > level+1
+ containers.splice level+1, containers.length - (level+1)
+ $.add containers[level], div
Rice.nodes fs
$.add section, fs
$.get items, (items) ->
for key, val of items
inputs[key].checked = val
+ inputs[key].parentNode.parentNode.dataset.checked = val
return
div = $.el 'div',
- innerHTML: "
: Clear manually-hidden threads and posts on all boards. Reload the page to apply."
+ <%= html(': Clear manually-hidden threads and posts on all boards. Reload the page to apply.') %>
button = $ 'button', div
$.get 'hiddenPosts', {}, ({hiddenPosts}) ->
hiddenNum = 0
@@ -163,18 +181,19 @@ Settings =
onImport: ->
return unless file = @files[0]
- return unless confirm 'Your current settings will be entirely overwritten, are you sure?'
+ unless confirm 'Your current settings will be entirely overwritten, are you sure?'
+ new Notice 'info', "Import aborted.", 1
+ return
reader = new FileReader()
reader.onload = (e) ->
try
Settings.loadSettings JSON.parse e.target.result
+ if confirm 'Import successful. Reload now?'
+ window.location.reload()
catch err
alert 'Import failed due to an error.'
c.error err.stack
- return
- if confirm 'Import successful. Reload now?'
- window.location.reload()
reader.readAsText file
loadSettings: (data) ->
@@ -207,28 +226,19 @@ Settings =
$.add div, ta
return
$.extend div, <%= importHTML('Settings/Filter-guide') %>
+ $('.warning', div).hidden = Conf['Filter']
sauce: (section) ->
$.extend section, <%= importHTML('Settings/Sauce') %>
ta = $ 'textarea', section
$.get 'sauces', Conf['sauces'], (item) ->
- # XXX remove .replace func after 31-7-2013 (v1 transitioning)
- ta.value = item['sauces'].replace /\$\d/g, (c) ->
- switch c
- when '$1'
- '%TURL'
- when '$2'
- '%URL'
- when '$3'
- '%MD5'
- when '$4'
- '%board'
- else
- c
+ ta.value = item['sauces']
$.on ta, 'change', $.cb.value
advanced: (section) ->
$.extend section, <%= importHTML('Settings/Advanced') %>
+ warning.hidden = Conf[warning.dataset.feature] for warning in $$ '.warning', section
+
items = {}
inputs = {}
for name in ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'usercss']
@@ -256,9 +266,16 @@ Settings =
Settings[key].call input
Rice.nodes section
- $.on $('input[name=Interval]', section), 'change', ThreadUpdater.cb.interval
- $.on $('input[name="Custom CSS"]', section), 'change', Settings.togglecss
- $.on $.id('apply-css'), 'click', Settings.usercss
+ interval = $ 'input[name="Interval"]', section
+ customCSS = $ 'input[name="Custom CSS"]', section
+
+ interval.value = Conf['Interval']
+ customCSS.checked = Conf['Custom CSS']
+ inputs['usercss'].disabled = !Conf['Custom CSS']
+
+ $.on interval, 'change', ThreadUpdater.cb.interval
+ $.on customCSS, 'change', Settings.togglecss
+ $.on $('#apply-css', section), 'click', Settings.usercss
archBoards = {}
for {name, boards, files, software, withCredentials} in Redirect.archives
@@ -293,6 +310,8 @@ Settings =
$.add row, Settings.addArchiveCell boardID, o, item for item in ['thread', 'post', 'file']
rows.push row
+ rows[0].hidden = not g.BOARD.ID of archBoards
+
$.add $('tbody', section), rows
boardSelect = $('#archive-board-select', section)
@@ -327,7 +346,7 @@ Settings =
textContent: archive
value: archive
- td.innerHTML = ' '
+ $.extend td, <%= html(' ') %>
select = td.firstElementChild
unless select.disabled = length is 1
# XXX GM can't into datasets
@@ -350,7 +369,7 @@ Settings =
@nextElementSibling.textContent = Time.format @value, new Date()
backlink: ->
- @nextElementSibling.textContent = @value.replace /%id/g, '123456789'
+ @nextElementSibling.textContent = @value.replace /%(?:id|%)/g, (x) -> {'%id': '123456789', '%%': '%'}[x]
fileInfo: ->
data =
@@ -362,22 +381,20 @@ Settings =
sizeInBytes: 276 * 1024
dimensions: '1280x720'
isImage: true
- isVideo: false
isSpoiler: true
- @nextElementSibling.innerHTML = FileInfo.format @value, data
+ FileInfo.format @value, data, @nextElementSibling
favicon: ->
- Favicon.init()
+ Favicon.switch()
Unread.update() if g.VIEW is 'thread' and Conf['Unread Favicon']
- $.id('favicon-preview').innerHTML = """
-
-
-
-
- """
+ img = @nextElementSibling.children
+ img[0].src = Favicon.default
+ img[1].src = Favicon.unreadSFW
+ img[2].src = Favicon.unreadNSFW
+ img[3].src = Favicon.unreadDead
togglecss: ->
- if $('textarea', @parentNode.parentNode).disabled = !@checked
+ if $('textarea[name=usercss]', $.x 'ancestor::fieldset[1]', @).disabled = !@checked
CustomCSS.rmStyle()
else
CustomCSS.addStyle()
@@ -388,13 +405,14 @@ Settings =
keybinds: (section) ->
$.extend section, <%= importHTML('Settings/Keybinds') %>
+ $('.warning', section).hidden = Conf['Keybinds']
tbody = $ 'tbody', section
items = {}
inputs = {}
for key, arr of Config.hotkeys
tr = $.el 'tr',
- innerHTML: " #{arr[1]} "
+ <%= html('
${arr[1]} ') %>
input = $ 'input', tr
input.name = key
input.spellcheck = false
@@ -437,7 +455,7 @@ Settings =
if type is 'text'
- div.innerHTML = "
#{key}
#{description}
"
+ $.extend div, <%= html('
${key}
${description}
') %>
input = $ "input", div
else
@@ -450,8 +468,17 @@ Settings =
input = $ "select", div
else
+ span = $.el 'span',
+ class: 'description'
+ textContent: description
+
+ span.style.display = 'none'
- div.innerHTML = "
#{key}
#{description} "
+ $.add div, [
+ UI.checkbox key, key
+ span
+ ]
+
input = $ 'input', div
items[key] = Conf[key]
@@ -507,7 +534,8 @@ Settings =
div = $.el 'div',
className: "theme #{if name is Conf[g.THEMESTRING] then 'selectedtheme' else ''}"
id: name
- innerHTML: """<%= grunt.file.read('src/General/html/Settings/Theme.html').replace(/>\s+<').trim() %>"""
+
+ $.extend div, <%= importHTML('Settings/Theme') %>
div.style.backgroundColor = theme['Background Color']
@@ -526,7 +554,8 @@ Settings =
div = $.el 'div',
id: 'addthemes'
- innerHTML: """<%= grunt.file.read('src/General/html/Settings/Batch-Theme.html').replace(/>\s+<').trim() %>"""
+
+ $.extend div, <%= importHTML('Settings/Batch-Theme') %>
$.on $("#newtheme", div), 'click', ->
ThemeTools.init "untitled"
@@ -556,7 +585,8 @@ Settings =
div = $.el 'div',
id: name
className: theme
- innerHTML: """<%= grunt.file.read('src/General/html/Settings/Deleted-Theme.html').replace(/>\s+<').trim() %>"""
+
+ $.extend div, <%= importHTML('Settings/Deleted-Theme') %>
$.on div, 'click', cb.restore
@@ -611,7 +641,7 @@ Settings =
mascotHide = $.el "div",
id: "mascot_hide"
className: "reply"
- innerHTML: "Hide Categories
"
+ <%= html('Hide Categories
') %>
keys = Object.keys Mascots
keys.sort()
@@ -619,7 +649,7 @@ Settings =
if mode is 'default'
mascotoptions = $.el 'div',
id: 'mascot-options'
- innerHTML: """
Edit Delete Export """
+ <%= html('
Edit Delete Export ') %>
$.on $('.edit', mascotoptions), 'click', cb.edit
$.on $('.delete', mascotoptions), 'click', cb.delete
@@ -635,12 +665,10 @@ Settings =
categories[name] = div = $.el "div",
id: name
className: "mascots-container"
- innerHTML: ""
+ <%= html('') %>
hidden: name in Conf["Hidden Categories"]
- option = $.el "label",
- name: name
- innerHTML: "
#{name}"
+ option = UI.checkbox name, name, name in Conf["Hidden Categories"]
$.on $('input', option), 'change', cb.category
@@ -653,7 +681,8 @@ Settings =
mascotEl = $.el 'div',
id: name
className: if name in Conf[g.MASCOTSTRING] then 'mascot enabled' else 'mascot'
- innerHTML: "<%= grunt.file.read('src/General/html/Settings/Mascot.html') %>"
+
+ $.extend div, <%= importHTML('Settings/Mascot') %>
$.on mascotEl, 'click', cb.select
$.on mascotEl, 'mouseover', addoptions
@@ -662,7 +691,8 @@ Settings =
batchmascots = $.el 'div',
id: "mascots_batch"
- innerHTML: """<%= grunt.file.read('src/General/html/Settings/Batch-Mascot.html') %>"""
+
+ $.extend batchmascots, <%= importHTML('Settings/Batch-Mascot') %>
$.on $('#clear', batchmascots), 'click', ->
enabledMascots = JSON.parse(JSON.stringify(Conf[g.MASCOTSTRING]))
@@ -704,10 +734,8 @@ Settings =
mascotEl = $.el 'div',
className: 'mascot'
id: name
- innerHTML: "
-
#{name.replace /_/g, " "}
-
-"
+
+ $.extend mascotEl, <%= importHTML('Settings/Mascot') %>
$.on mascotEl, 'click', cb.restore
@@ -717,7 +745,7 @@ Settings =
batchmascots = $.el 'div',
id: "mascots_batch"
- innerHTML: """
Return """
+ <%= html('
Return ') %>
$.on $('#return', batchmascots), 'click', ->
mascots =
diff --git a/src/General/html/Settings/Mascot.html b/src/General/html/Settings/Mascot.html
index 12d8e25e2..a16a61a49 100644
--- a/src/General/html/Settings/Mascot.html
+++ b/src/General/html/Settings/Mascot.html
@@ -1,2 +1,2 @@
-
#{name.replace /_/g, " "}
-
\ No newline at end of file
+
#{name.replace /_/g, ' '}
+
\ No newline at end of file