diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a402a0a9..e462f6e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ### v1.14.11 +**v1.14.11.1** *(2019-08-03)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.11.1/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.11.1/builds/4chan-X-noupdate.crx)] +- Security improvements. +- Fix 2captcha on Chrome extension. #2375 +- Minor bugfixes. + **v1.14.11.0** *(2019-07-24)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.11.0/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.11.0/builds/4chan-X-noupdate.crx)] - Based on v1.14.10.3. - Make applicable keybinds work on Tinyboard/vichan. #2171 diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx index 0798fd49f..3968fee23 100644 Binary files a/builds/4chan-X-beta.crx and b/builds/4chan-X-beta.crx differ diff --git a/builds/4chan-X-beta.meta.js b/builds/4chan-X-beta.meta.js index c57f1f943..8f13c6570 100644 --- a/builds/4chan-X-beta.meta.js +++ b/builds/4chan-X-beta.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X beta -// @version 1.14.11.0 +// @version 1.14.11.1 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X diff --git a/builds/4chan-X-beta.user.js b/builds/4chan-X-beta.user.js index 8df3793b1..772067743 100644 --- a/builds/4chan-X-beta.user.js +++ b/builds/4chan-X-beta.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X beta -// @version 1.14.11.0 +// @version 1.14.11.1 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -188,7 +188,7 @@ var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, CSS var Conf, E, c, d, doc, docSet, g; -Conf = {}; +Conf = Object.create(null); c = console; d = document; doc = d.documentElement; @@ -199,10 +199,10 @@ docSet = function() { }; g = { - VERSION: '1.14.11.0', + VERSION: '1.14.11.1', NAMESPACE: '4chan X.', - sites: {}, - boards: {} + sites: Object.create(null), + boards: Object.create(null) }; E = (function() { @@ -4687,7 +4687,7 @@ sub: function(css) { var sel = variables; for (var i = 0; i < words.length; i++) { if (typeof sel !== 'object') return ':not(*)'; - sel = sel[words[i]]; + sel = $.getOwn(sel, words[i]); } if (typeof sel !== 'string') return ':not(*)'; return sel; @@ -4754,6 +4754,46 @@ $ = (function() { } }; + $.dict = function() { + return Object.create(null); + }; + + $.dict.clone = function(obj) { + var arr, i, j, key, map, ref, val; + if (typeof obj !== 'object' || obj === null) { + return obj; + } else if (obj instanceof Array) { + arr = []; + for (i = j = 0, ref = obj.length; j < ref; i = j += 1) { + arr.push($.dict.clone(obj[i])); + } + return arr; + } else { + map = Object.create(null); + for (key in obj) { + val = obj[key]; + map[key] = $.dict.clone(val); + } + return map; + } + }; + + $.dict.json = function(str) { + return $.dict.clone(JSON.parse(str)); + }; + + $.hasOwn = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + }; + + $.getOwn = function(obj, key) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return obj[key]; + } else { + return void 0; + } + }; + $.ajax = (function() { var pageXHR; if (window.wrappedJSObject && !XMLHttpRequest.wrappedJSObject) { @@ -4808,7 +4848,7 @@ $ = (function() { }; })(); - $.lastModified = {}; + $.lastModified = $.dict(); $.whenModified = function(url, bucket, cb, options) { var ajax, headers, params, r, ref, t, timeout, url0; @@ -4827,14 +4867,14 @@ $ = (function() { if (params.length) { url += '?' + params.join('&'); } - headers = {}; + headers = $.dict(); if ((t = (ref = $.lastModified[bucket]) != null ? ref[url0] : void 0) != null) { headers['If-Modified-Since'] = t; } r = (ajax || $.ajax)(url, { onloadend: function() { var base; - ((base = $.lastModified)[bucket] || (base[bucket] = {}))[url0] = this.getResponseHeader('Last-Modified'); + ((base = $.lastModified)[bucket] || (base[bucket] = $.dict()))[url0] = this.getResponseHeader('Last-Modified'); return cb.call(this); }, timeout: timeout, @@ -4845,7 +4885,7 @@ $ = (function() { (function() { var reqs; - reqs = {}; + reqs = $.dict(); $.cache = function(url, cb, options) { var ajax, onloadend, req; if (options == null) { @@ -4903,12 +4943,16 @@ $ = (function() { $.cb = { checked: function() { - $.set(this.name, this.checked); - return Conf[this.name] = this.checked; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.checked); + return Conf[this.name] = this.checked; + } }, value: function() { - $.set(this.name, this.value.trim()); - return Conf[this.name] = this.value; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.value.trim()); + return Conf[this.name] = this.value; + } } }; @@ -5281,11 +5325,11 @@ $ = (function() { $.hasStorage = (function() { try { - if (localStorage[g.NAMESPACE + 'hasStorage'] === 'true') { + if (localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true') { return true; } - localStorage[g.NAMESPACE + 'hasStorage'] = 'true'; - return localStorage[g.NAMESPACE + 'hasStorage'] === 'true'; + localStorage.setItem(g.NAMESPACE + 'hasStorage', 'true'); + return localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true'; } catch (error) { return false; } @@ -5293,7 +5337,7 @@ $ = (function() { $.item = function(key, val) { var item; - item = {}; + item = $.dict(); item[key] = val; return item; }; @@ -5308,7 +5352,7 @@ $ = (function() { }; }; - $.syncing = {}; + $.syncing = $.dict(); $.securityCheck = function(data) { if (location.protocol !== 'https:') { @@ -5325,7 +5369,7 @@ $ = (function() { for (key in ref) { val = ref[key]; if ((cb = $.syncing[key])) { - results.push(cb(JSON.parse(JSON.stringify(val)), key)); + results.push(cb($.dict.json(JSON.stringify(val)), key)); } } return results; @@ -5349,7 +5393,7 @@ $ = (function() { return results; })()).then(function() { var items, j, key, len; - items = {}; + items = $.dict(); for (j = 0, len = keys.length; j < len; j++) { key = keys[j]; items[key] = void 0; @@ -5374,7 +5418,7 @@ $ = (function() { for (i = j = 0, len = values.length; j < len; i = ++j) { val = values[i]; if (val) { - items[keys[i]] = JSON.parse(val); + items[keys[i]] = $.dict.json(val); } } return cb(items); @@ -5416,7 +5460,7 @@ $ = (function() { }; } else if ($.hasStorage) { $.getValue = function(key) { - return localStorage[key]; + return localStorage.getItem(key); }; $.listValues = function() { var key, results; @@ -5438,13 +5482,13 @@ $ = (function() { $.setValue = GM_setValue; $.deleteValue = GM_deleteValue; } else if (typeof GM_deleteValue !== "undefined" && GM_deleteValue !== null) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { GM_setValue(key, val); if (key in $.syncing) { $.oldValue[key] = val; if ($.hasStorage) { - return localStorage[key] = val; + return localStorage.setItem(key, val); } } }; @@ -5461,12 +5505,12 @@ $ = (function() { $.cantSync = true; } } else if ($.hasStorage) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { if (key in $.syncing) { $.oldValue[key] = val; } - return localStorage[key] = val; + return localStorage.setItem(key, val); }; $.deleteValue = function(key) { if (key in $.syncing) { @@ -5484,7 +5528,7 @@ $ = (function() { return $.syncing[key] = GM_addValueChangeListener(g.NAMESPACE + key, function(key2, oldValue, newValue, remote) { if (remote) { if (newValue !== void 0) { - newValue = JSON.parse(newValue); + newValue = $.dict.json(newValue); } return cb(newValue, key); } @@ -5510,7 +5554,7 @@ $ = (function() { return; } $.oldValue[key] = newValue; - return cb(JSON.parse(newValue), key.slice(g.NAMESPACE.length)); + return cb($.dict.json(newValue), key.slice(g.NAMESPACE.length)); } else { if ($.oldValue[key] == null) { return; @@ -5550,7 +5594,7 @@ $ = (function() { for (key in items) { if ((val2 = $.getValue(g.NAMESPACE + key))) { try { - items[key] = JSON.parse(val2); + items[key] = $.dict.json(val2); } catch (error) { err = error; if (!/^(?:undefined)*$/.test(val2)) { @@ -5610,7 +5654,7 @@ CrossOrigin = (function() { binary: function(url, cb, headers) { var fallback, gmOptions; if (headers == null) { - headers = {}; + headers = $.dict(); } url = url.replace(/^((?:https?:)?\/\/(?:\w+\.)?(?:4chan|4channel|4cdn)\.org)\/adv\//, '$1//adv/'); fallback = function() { @@ -5679,7 +5723,7 @@ CrossOrigin = (function() { name = match.replace(/\\"/g, '"'); } if (/^text\/plain;\s*charset=x-user-defined$/i.test(mime)) { - mime = QR.typeFromExtension[name.match(/[^.]*$/)[0].toLowerCase()] || 'application/octet-stream'; + mime = $.getOwn(QR.typeFromExtension, name.match(/[^.]*$/)[0].toLowerCase()) || 'application/octet-stream'; } blob = new Blob([data], { type: mime @@ -5700,9 +5744,9 @@ CrossOrigin = (function() { Request.prototype.responseHeaderString = null; Request.prototype.getResponseHeader = function(headerName) { - var header, i, j, key, len, ref, ref1, val; + var header, i, j, key, len, ref, ref1, ref2, val; if ((this.responseHeaders == null) && (this.responseHeaderString != null)) { - this.responseHeaders = {}; + this.responseHeaders = $.dict(); ref = this.responseHeaderString.split('\r\n'); for (j = 0, len = ref.length; j < len; j++) { header = ref[j]; @@ -5713,7 +5757,7 @@ CrossOrigin = (function() { } } } - return (ref1 = (this.responseHeaders || {})[headerName.toLowerCase()]) != null ? ref1 : null; + return (ref1 = (ref2 = this.responseHeaders) != null ? ref2[headerName.toLowerCase()] : void 0) != null ? ref1 : null; }; Request.prototype.abort = function() {}; @@ -5971,7 +6015,7 @@ CatalogThreadNative = (function() { this.boardID = this.nodes.thumb.parentNode.pathname.split(/\/+/)[1]; this.board = g.boards[this.boardID] || new Board(this.boardID); this.ID = this.threadID = +(root.dataset.id || root.id).match(/\d*$/)[0]; - this.thread = this.board.threads[this.ID] || new Thread(this.ID, this.board); + this.thread = this.board.threads.get(this.ID) || new Thread(this.ID, this.board); } return CatalogThreadNative; @@ -6009,15 +6053,15 @@ Connection = (function() { }; Connection.prototype.onMessage = function(e) { - var base, data, type, value; + var data, type, value; if (!(e.source === this.targetWindow() && e.origin === this.origin && typeof e.data === 'string' && e.data.slice(0, g.NAMESPACE.length) === g.NAMESPACE)) { return; } data = JSON.parse(e.data.slice(g.NAMESPACE.length)); for (type in data) { value = data[type]; - if (typeof (base = this.cb)[type] === "function") { - base[type](value); + if ($.hasOwn(this.cb, type)) { + this.cb[type](value); } } }; @@ -6071,7 +6115,7 @@ DataBoard = (function() { delete this.data.lastChecked; } return (base = this.data)[name = g.SITE.ID] || (base[name] = { - boards: {} + boards: $.dict() }); }; @@ -6081,7 +6125,7 @@ DataBoard = (function() { change(); this.changes.push(change); return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var i, len, needSync, ref; @@ -6113,7 +6157,7 @@ DataBoard = (function() { DataBoard.prototype.forceSync = function(cb) { return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var change, i, len, ref; @@ -6201,12 +6245,12 @@ DataBoard = (function() { siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, postID = arg.postID, val = arg.val; siteID || (siteID = g.SITE.ID); (base = this.data)[siteID] || (base[siteID] = { - boards: {} + boards: $.dict() }); if (postID !== void 0) { - return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = {})))[threadID] || (base1[threadID] = {}))[postID] = val; + return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = $.dict())))[threadID] || (base1[threadID] = $.dict()))[postID] = val; } else if (threadID !== void 0) { - return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = {}))[threadID] = val; + return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = $.dict()))[threadID] = val; } else { return this.data[siteID].boards[boardID] = val; } @@ -6223,7 +6267,7 @@ DataBoard = (function() { boardID: boardID, threadID: threadID, postID: postID, - defaultValue: {} + defaultValue: $.dict() }); for (key in val) { subVal = val[key]; @@ -6338,7 +6382,7 @@ DataBoard = (function() { if (!(board = this.data[siteID].boards[boardID])) { return; } - threads = {}; + threads = $.dict(); if (response1) { for (i = 0, len = response1.length; i < len; i++) { page = response1[i]; @@ -6396,11 +6440,11 @@ Fetcher = (function() { this.postID = postID1; this.root = root; this.quoter = quoter; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } - if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads[this.boardID + "." + this.threadID])) { + if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads.get(this.boardID + "." + this.threadID))) { board = g.boards[this.boardID]; post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true @@ -6459,7 +6503,7 @@ Fetcher = (function() { Fetcher.prototype.fetchedPost = function(req, isCached) { var api, board, k, len, post, posts, status, that, thread; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6503,7 +6547,7 @@ Fetcher = (function() { return; } board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true }); @@ -6532,7 +6576,7 @@ Fetcher = (function() { media = this.response.media; for (key in media) { if (/_link$/.test(key)) { - if (!((ref1 = media[key]) != null ? ref1.match(/^http:\/\//) : void 0)) { + if (!((ref1 = $.getOwn(media, key)) != null ? ref1.match(/^http:\/\//) : void 0)) { delete media[key]; } } @@ -6547,7 +6591,7 @@ Fetcher = (function() { Fetcher.prototype.parseArchivedPost = function(data, url, archive) { var board, comment, greentext, i, j, media_link, o, post, ref, tag, text, text2, thread, thumb_link; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6675,8 +6719,9 @@ Fetcher = (function() { o.file.tag = JSON.parse(data.media.exif).Tag; } } + o.extra = $.dict(); board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.post(o), thread, board, { isFetchedQuote: true }); @@ -6892,9 +6937,9 @@ Post = (function() { this.isDead = false; this.isHidden = false; this.clones = []; - if (g.posts[this.fullID]) { + if (g.posts.get(this.fullID)) { this.isRebuilt = true; - this.clones = g.posts[this.fullID].clones; + this.clones = g.posts.get(this.fullID).clones; ref14 = this.clones; for (k = 0, len1 = ref14.length; k < len1; k++) { clone = ref14[k]; @@ -7463,7 +7508,7 @@ ShimSet = (function() { ShimSet = (function() { function ShimSet() { - this.elements = {}; + this.elements = $.dict(); this.size = 0; } @@ -7534,6 +7579,14 @@ SimpleDict = (function() { } }; + SimpleDict.prototype.get = function(key) { + if (key === 'keys') { + return void 0; + } else { + return $.getOwn(this, key); + } + }; + return SimpleDict; })(); @@ -7551,8 +7604,8 @@ Thread = (function() { }; function Thread(ID, board) { - this.ID = ID; this.board = board; + this.ID = +ID; this.threadID = this.ID; this.boardID = this.board.ID; this.siteID = g.SITE.ID; @@ -7694,7 +7747,7 @@ SW = {}; for (j = 0, len = ref.length; j < len; j++) { script = ref[j]; if ((m = script.textContent.match(/\bvar configRoot=(".*?")/))) { - properties = {}; + properties = $.dict(); try { root = JSON.parse(m[1]); if (root[0] === '/') { @@ -8288,7 +8341,7 @@ SW = {}; Build = { staticPath: '//s.4cdn.org/image/', gifIcon: window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif', - spoilerRange: {}, + spoilerRange: $.dict(), shortFilename: function(filename) { var ext; ext = filename.match(/\.?[^\.]*$/)[0]; @@ -8368,9 +8421,10 @@ SW = {}; }); o.files.push(o.file); } + o.extra = $.dict(); for (key in data) { if (key[0] === 'x') { - o[key] = data[key]; + o.extra[key] = data[key]; } } return o; @@ -8443,10 +8497,10 @@ SW = {}; capcodePlural = 'Verified Users'; capcodeDescription = ''; } else { - capcodeLong = { + capcodeLong = $.getOwn({ 'Admin': 'Administrator', 'Mod': 'Moderator' - }[capcode] || capcode; + }, capcode) || capcode; capcodePlural = capcodeLong + "s"; capcodeDescription = "a 4chan " + capcodeLong; } @@ -8455,7 +8509,7 @@ SW = {}; postLink = url + "#p" + ID; quoteLink = Build.sameThread(boardID, threadID) ? "javascript:quote('" + (+ID) + "');" : url + "#q" + ID; postInfo = { - innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.xa19s) ? " " + E(o.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.xa19l && o.isReply) ? " Like! ×" + E(o.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" + innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.extra.xa19s) ? " " + E(o.extra.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.extra.xa19l && o.isReply) ? " Like! ×" + E(o.extra.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" }; /* File Info */ @@ -8636,7 +8690,7 @@ Site = (function() { var hostname; $.extend(Conf['siteProperties'], Site.defaultProperties); hostname = Site.resolve(); - if (hostname && Conf['siteProperties'][hostname].software in SW) { + if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) { this.set(hostname); cb(); } @@ -8649,7 +8703,7 @@ Site = (function() { } changes.software = software; hostname = location.hostname.replace(/^www\./, ''); - properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = {})); + properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = $.dict())); changed = 0; for (key in changes) { if (!(properties[key] !== changes[key])) { @@ -8676,7 +8730,7 @@ Site = (function() { url = location; } hostname = url.hostname; - while (hostname && !(hostname in Conf['siteProperties'])) { + while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) { hostname = hostname.replace(/^[^.]*\.?/, ''); } if (hostname) { @@ -8700,7 +8754,7 @@ Site = (function() { continue; } software = properties.software; - if (!(software && SW[software])) { + if (!(software && $.hasOwn(SW, software))) { continue; } g.sites[ID] = site = Object.create(SW[software]); @@ -8750,11 +8804,11 @@ Redirect = (function() { selectArchives: function() { var archive, archives, boardID, boards, data, files, id, j, k, key, l, len, len1, len2, name, o, record, ref, ref1, ref2, software, type, uid; o = { - thread: {}, - post: {}, - file: {} + thread: $.dict(), + post: $.dict(), + file: $.dict() }; - archives = {}; + archives = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { data = ref[j]; @@ -8788,7 +8842,7 @@ Redirect = (function() { record = ref2[boardID]; for (type in record) { id = record[type]; - if (!((archive = archives[JSON.stringify(id)]))) { + if (!((archive = archives[JSON.stringify(id)]) && $.hasOwn(o, type))) { continue; } boards = type === 'file' ? archive.files : archive.boards; @@ -8863,7 +8917,7 @@ Redirect = (function() { parse: function(responses, cb) { var archiveUIDs, archives, data, items, j, k, len, len1, ref, response, uid; archives = []; - archiveUIDs = {}; + archiveUIDs = $.dict(); for (j = 0, len = responses.length; j < len; j++) { response = responses[j]; for (k = 0, len1 = response.length; k < len1; k++) { @@ -8872,7 +8926,7 @@ Redirect = (function() { if (uid in archiveUIDs) { $.extend(archiveUIDs[uid], data); } else { - archiveUIDs[uid] = data; + archiveUIDs[uid] = $.dict.clone(data); archives.push(data); } } @@ -8897,7 +8951,7 @@ Redirect = (function() { protocol: function(archive) { var protocol; protocol = location.protocol; - if (!archive[protocol.slice(0, -1)]) { + if (!$.getOwn(archive, protocol.slice(0, -1))) { protocol = protocol === 'https:' ? 'http:' : 'https:'; } return protocol + "//"; @@ -8949,10 +9003,10 @@ Redirect = (function() { boardID = arg.boardID, type = arg.type, value = arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; if (type === 'capcode') { - value = { + value = $.getOwn({ 'Developer': 'dev', 'Verified': 'ver' - }[value] || value.toLowerCase(); + }, value) || value.toLowerCase(); } else if (type === 'image') { value = value.replace(/[+\/=]/g, function(c) { return { @@ -9022,8 +9076,8 @@ Filter = (function() { slice = [].slice; Filter = { - filters: {}, - results: {}, + filters: $.dict(), + results: $.dict(), init: function() { var base, base1, boards, err, excludes, file, filter, hide, hl, i, isstring, j, key, len, len1, line, mask, noti, op, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, regexp, stub, top, type, types; if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'catalog') && Conf['Filter'])) { @@ -9060,15 +9114,15 @@ Filter = (function() { } } op = ((ref4 = filter.match(/(?:^|;)\s*op:(no|only)/)) != null ? ref4[1] : void 0) || ''; - mask = { + mask = $.getOwn({ 'no': 1, 'only': 2 - }[op] || 0; + }, op) || 0; file = ((ref5 = filter.match(/(?:^|;)\s*file:(no|only)/)) != null ? ref5[1] : void 0) || ''; - mask = mask | ({ + mask = mask | ($.getOwn({ 'no': 4, 'only': 8 - }[file] || 0); + }, file) || 0); stub = (function() { var ref6; switch ((ref6 = filter.match(/(?:^|;)\s*stub:(yes|no)/)) != null ? ref6[1] : void 0) { @@ -9136,7 +9190,7 @@ Filter = (function() { if ((boards = Filter.parseBoardsMemo[boardsRaw])) { return boards; } - boards = {}; + boards = $.dict(); siteFilter = ''; ref = boardsRaw.split(','); for (i = 0, len = ref.length; i < len; i++) { @@ -9163,7 +9217,7 @@ Filter = (function() { Filter.parseBoardsMemo[boardsRaw] = boards; return boards; }, - parseBoardsMemo: {}, + parseBoardsMemo: $.dict(), test: function(post, hideable) { var board, filter, hide, hl, i, j, key, len, len1, mask, noti, ref, ref1, ref2, site, stub, top, value; if (hideable == null) { @@ -9251,7 +9305,7 @@ Filter = (function() { if (!(url = typeof (base = g.SITE.urls).catalogJSON === "function" ? base.catalogJSON(g.BOARD) : void 0)) { return; } - Filter.catalogData = {}; + Filter.catalogData = $.dict(); $.ajax(url, { onloadend: Filter.catalogParse }); @@ -9365,7 +9419,7 @@ Filter = (function() { } }, values: function(key, post) { - if (key in Filter.valueF) { + if ($.hasOwn(Filter.valueF, key)) { return Filter.valueF[key](post).filter(function(v) { return v != null; }); @@ -9373,7 +9427,7 @@ Filter = (function() { return [ key.split('+').map(function(k) { var f; - if ((f = Filter.valueF[k])) { + if ((f = $.getOwn(Filter.valueF, k))) { return f(post).map(function(v) { return v || ''; }).join('\n'); @@ -9385,6 +9439,9 @@ Filter = (function() { } }, addFilter: function(type, re, cb) { + if (!$.hasOwn(Config.filter, type)) { + return; + } return $.get(type, Conf[type], function(item) { var save; save = item[type]; @@ -9871,7 +9928,7 @@ Recursive = (function() { indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Recursive = { - recursives: {}, + recursives: $.dict(), init: function() { var ref; if ((ref = g.VIEW) !== 'index' && ref !== 'thread') { @@ -9970,7 +10027,7 @@ ThreadHiding = (function() { } hiddenThreads = ThreadHiding.db.get({ boardID: board.ID, - defaultValue: {} + defaultValue: $.dict() }); for (threadID in hiddenThreads) { hiddenThreads[threadID] = true; @@ -9994,7 +10051,7 @@ ThreadHiding = (function() { var hiddenThreads2, threadID; hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; for (threadID in hiddenThreads2) { - if (!(threadID in ThreadHiding.hiddenThreads)) { + if (!$.hasOwn(ThreadHiding.hiddenThreads, threadID)) { ThreadHiding.db.set({ boardID: g.BOARD.ID, threadID: threadID, @@ -10005,7 +10062,7 @@ ThreadHiding = (function() { } } for (threadID in ThreadHiding.hiddenThreads) { - if (!(threadID in hiddenThreads2)) { + if (!$.hasOwn(hiddenThreads2, threadID)) { ThreadHiding.db["delete"]({ boardID: g.BOARD.ID, threadID: threadID @@ -10194,7 +10251,7 @@ ThreadHiding = (function() { }, toggle: function(thread) { if (!(thread instanceof Thread)) { - thread = g.threads[this.dataset.fullID]; + thread = g.threads.get(this.dataset.fullID); } if (thread.isHidden) { ThreadHiding.show(thread); @@ -10266,7 +10323,7 @@ BoardConfig = (function() { load: function() { var board, boards, err, i, len, ref, ref1, troll_flags; if (this.status === 200 && this.response && this.response.boards) { - boards = {}; + boards = $.dict(); ref = this.response.boards; for (i = 0, len = ref.length; i < len; i++) { board = ref[i]; @@ -10384,7 +10441,7 @@ Get = (function() { return null; } board = root.dataset.board; - return g.threads[(board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])]; + return g.threads.get((board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])); }, threadFromNode: function(node) { return Get.threadFromRoot($.x("ancestor-or-self::" + g.SITE.xpath.thread, node)); @@ -10394,10 +10451,10 @@ Get = (function() { if (root == null) { return null; } - post = g.posts[root.dataset.fullID]; + post = g.posts.get(root.dataset.fullID); index = root.dataset.clone; if (index) { - return post.clones[index]; + return post.clones[+index]; } else { return post; } @@ -10444,7 +10501,7 @@ Get = (function() { ref = post.quotes; for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; - if (qPost = posts[quote]) { + if (qPost = posts.get(quote)) { handleQuotes(qPost, 'backlinks'); } } @@ -11179,7 +11236,7 @@ Index = (function() { }); Header.addShortcut('index-refresh', this.button, 590); entries = []; - this.inputs = inputs = {}; + this.inputs = inputs = $.dict(); ref4 = Config.Index; for (name in ref4) { arr = ref4[name]; @@ -11200,7 +11257,7 @@ Index = (function() { $.on(inputs['Pin Watched Threads'], 'change', this.cb.resort); $.on(inputs['Anchor Hidden Threads'], 'change', this.cb.resort); watchSettings = function(e) { - if ((input = inputs[e.target.name])) { + if ((input = $.getOwn(inputs, e.target.name))) { input.checked = e.target.checked; return $.event('change', null, input); } @@ -11486,10 +11543,10 @@ Index = (function() { }, perBoardSort: function() { var i, k; - Conf['Index Sort'] = this.checked ? {} : ''; + Conf['Index Sort'] = this.checked ? $.dict() : ''; Index.saveSort(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = this.checked ? {} : ''; + Conf["Last Long Reply Thresholds " + i] = this.checked ? $.dict() : ''; Index.saveLastLongThresholds(i); } }, @@ -11653,12 +11710,12 @@ Index = (function() { leftover = []; for (k = 0, len1 = commands.length; k < len1; k++) { command = commands[k]; - if ((mode = Index.hashCommands.mode[command])) { + if ((mode = $.getOwn(Index.hashCommands.mode, command))) { state.mode = mode; } else if (command === 'index') { state.mode = Conf['Previous Index Mode']; state.page = 1; - } else if ((sort = Index.hashCommands.sort[command.replace(/-rev$/, '')])) { + } else if ((sort = $.getOwn(Index.hashCommands.sort, command.replace(/-rev$/, '')))) { state.sort = sort; if (/-rev$/.test(command)) { state.sort += '-rev'; @@ -11972,10 +12029,10 @@ Index = (function() { Index.liveThreadIDs = Index.liveThreadData.map(function(data) { return data.no; }); - Index.liveThreadDict = {}; - Index.threadPosition = {}; - Index.parsedThreads = {}; - Index.replyData = {}; + Index.liveThreadDict = $.dict(); + Index.threadPosition = $.dict(); + Index.parsedThreads = $.dict(); + Index.replyData = $.dict(); ref1 = Index.liveThreadData; for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { data = ref1[i]; @@ -12017,7 +12074,7 @@ Index = (function() { }, isHidden: function(threadID) { var thread; - if ((thread = g.BOARD.threads[threadID]) && thread.OP && !thread.OP.isFetchedQuote) { + if ((thread = g.BOARD.threads.get(threadID)) && thread.OP && !thread.OP.isFetchedQuote) { return thread.isHidden; } else { return Index.parsedThreads[threadID].isHidden; @@ -12035,7 +12092,7 @@ Index = (function() { ID = threadIDs[k]; try { threadData = Index.liveThreadDict[ID]; - if ((thread = g.BOARD.threads[ID])) { + if ((thread = g.BOARD.threads.get(ID))) { isStale = (thread.json !== threadData) && (JSON.stringify(thread.json) !== JSON.stringify(threadData)); if (isStale) { thread.setCount('post', threadData.replies + 1, threadData.bumplimit); @@ -12114,7 +12171,7 @@ Index = (function() { nodes = []; for (l = 0, len2 = lastReplies.length; l < len2; l++) { data = lastReplies[l]; - if ((post = thread.posts[data.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(data.no)) && !post.isFetchedQuote) { nodes.push(post.nodes.root); continue; } @@ -12226,7 +12283,7 @@ Index = (function() { return thread; } }; - lastlongD = {}; + lastlongD = $.dict(); for (k = 0, len1 = liveThreadData.length; k < len1; k++) { thread = liveThreadData[k]; lastlongD[thread.no] = lastlong(thread).no; @@ -12666,8 +12723,8 @@ Settings = (function() { warning(addWarning); } $.add(section, warnings); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); addCheckboxes = function(root, obj) { var arr, container, containers, description, div, input, level, results; containers = [root]; @@ -12737,8 +12794,8 @@ Settings = (function() { }); button = $('button', div); $.get({ - hiddenThreads: {}, - hiddenPosts: {} + hiddenThreads: $.dict(), + hiddenPosts: $.dict() }, function(arg) { var ID, board, hiddenNum, hiddenPosts, hiddenThreads, ref2, ref3, ref4, ref5, site, thread; hiddenThreads = arg.hiddenThreads, hiddenPosts = arg.hiddenPosts; @@ -12783,10 +12840,13 @@ Settings = (function() { }); $.on(button, 'click', function() { this.textContent = 'Hidden: 0'; - return $.get('hiddenThreads', {}, function(arg) { - var boardID, hiddenThreads; + return $.get('hiddenThreads', $.dict(), function(arg) { + var boardID, hiddenThreads, ref2; hiddenThreads = arg.hiddenThreads; if ($.hasStorage && g.SITE.software === 'yotsuba') { + for (boardID in (ref2 = hiddenThreads['4chan.org']) != null ? ref2.boards : void 0) { + localStorage.removeItem("4chan-hide-t-" + boardID); + } for (boardID in hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -12798,7 +12858,7 @@ Settings = (function() { }, "export": function() { var Conf2; - Conf2 = {}; + Conf2 = $.dict(); $.extend(Conf2, Conf); return $.get(Conf2, function(Conf2) { delete Conf2['boardConfig']; @@ -12842,7 +12902,7 @@ Settings = (function() { reader.onload = function(e) { var err; try { - return Settings.loadSettings(JSON.parse(e.target.result), function(err) { + return Settings.loadSettings($.dict.json(e.target.result), function(err) { if (err) { return output.textContent = 'Import failed due to an error.'; } else if (confirm('Import successful. Reload now?')) { @@ -12954,14 +13014,14 @@ Settings = (function() { } if (data.WatchedThreads) { data.Conf['watchedThreads'] = { - boards: {} + boards: $.dict() }; ref1 = data.WatchedThreads; for (boardID in ref1) { threads = ref1[boardID]; for (threadID in threads) { threadData = threads[threadID]; - ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = {}))[threadID] = { + ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = $.dict()))[threadID] = { excerpt: threadData.textContent }; } @@ -12972,7 +13032,7 @@ Settings = (function() { }, upgrade: function(data, version) { var addCSS, addSauces, boardID, boards, changes, compareString, corrupted, db, hostname, j, k, key, l, lastChecked, len, len1, len2, len3, line, list, m, name, record, ref, ref1, ref10, ref11, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rice, set, setD, siteProperties, software, type, uids, val, val2, value; - changes = {}; + changes = $.dict(); set = function(key, value) { return data[key] = changes[key] = value; }; @@ -13056,7 +13116,7 @@ Settings = (function() { record = ref2[boardID]; for (type in record) { name = record[type]; - if (name in uids) { + if ($.hasOwn(uids, name)) { record[type] = uids[name]; } } @@ -13235,7 +13295,7 @@ Settings = (function() { } } if ((data['siteSoftware'] != null) && (data['siteProperties'] == null)) { - siteProperties = {}; + siteProperties = $.dict(); ref10 = data['siteSoftware'].split('\n'); for (m = 0, len3 = ref10.length; m < len3; m++) { line = ref10[m]; @@ -13312,6 +13372,9 @@ Settings = (function() { var div, filterTypes, name, ta; div = this.nextElementSibling; if ((name = this.value) !== 'guide') { + if (!$.hasOwn(Config.filter, name)) { + return; + } $.rmAll(div); ta = $.el('textarea', { name: name, @@ -13360,7 +13423,7 @@ Settings = (function() { warning = ref[j]; warning.hidden = Conf[warning.dataset.feature]; } - inputs = {}; + inputs = $.dict(); ref1 = $$('[name]', section); for (k = 0, len1 = ref1.length; k < len1; k++) { input = ref1[k]; @@ -13371,7 +13434,7 @@ Settings = (function() { Conf['lastarchivecheck'] = 0; return $.id('lastarchivecheck').textContent = 'never'; }); - items = {}; + items = $.dict(); for (name in inputs) { input = inputs[name]; if (!(name !== 'captchaServiceKey' && name !== 'Interval' && name !== 'Custom CSS')) { @@ -13423,7 +13486,7 @@ Settings = (function() { $.on(applyCSS, 'click', function() { return CustomCSS.update(); }); - itemsArchive = {}; + itemsArchive = $.dict(); ref4 = ['archives', 'selectedArchives', 'lastarchivecheck']; for (m = 0, len3 = ref4.length; m < len3; m++) { name = ref4[m]; @@ -13455,7 +13518,7 @@ Settings = (function() { tbody = $('tbody', section); $.rmAll(boardSelect); $.rmAll(tbody); - archBoards = {}; + archBoards = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { ref1 = ref[j], uid = ref1.uid, name = ref1.name, boards = ref1.boards, files = ref1.files, software = ref1.software; @@ -13561,7 +13624,7 @@ Settings = (function() { return function(arg) { var name1, selectedArchives; selectedArchives = arg.selectedArchives; - (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = {}))[_this.dataset.type] = JSON.parse(_this.value); + (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = $.dict()))[_this.dataset.type] = JSON.parse(_this.value); $.set('selectedArchives', selectedArchives); Conf['selectedArchives'] = selectedArchives; return Redirect.selectArchives(); @@ -13588,7 +13651,7 @@ Settings = (function() { var captchaServiceKey; captchaServiceKey = arg.captchaServiceKey; captchaServiceKey[domain] = value; - if (!(value || (domain in Config['captchaServiceKey'][0]))) { + if (!(value || $.hasOwn(Config['captchaServiceKey'][0], domain))) { delete captchaServiceKey[domain]; } Conf['captchaServiceKey'] = captchaServiceKey; @@ -13673,8 +13736,8 @@ Settings = (function() { }); $('.warning', section).hidden = Conf['Keybinds']; tbody = $('tbody', section); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); ref = Config.hotkeys; for (key in ref) { arr = ref[key]; @@ -14247,7 +14310,7 @@ FappeTyme = (function() { }); $.on(indicator, 'click', function() { var check; - check = FappeTyme.nodes[this.parentNode.id.replace('shortcut-', '')]; + check = $.getOwn(FappeTyme.nodes, this.parentNode.id.replace('shortcut-', '')); check.checked = !check.checked; return $.event('change', null, check); }); @@ -14356,7 +14419,7 @@ Gallery = (function() { } Gallery.images = []; nodes = Gallery.nodes = {}; - Gallery.fileIDs = {}; + Gallery.fileIDs = $.dict(); Gallery.slideshow = false; nodes.el = dialog = $.el('div', { id: 'a-gallery' @@ -14471,11 +14534,11 @@ Gallery = (function() { load: function(thumb, errorCB) { var elType, ext, file; ext = thumb.href.match(/\w*$/); - elType = { + elType = $.getOwn({ 'webm': 'video', 'mp4': 'video', 'pdf': 'iframe' - }[ext] || 'img'; + }, ext) || 'img'; file = $.el(elType); $.extend(file.dataset, thumb.dataset); $.on(file, 'error', errorCB); @@ -14525,7 +14588,7 @@ Gallery = (function() { } else { Gallery.cb.stop(); } - if (Conf['Scroll to Post'] && (post = g.posts[file.dataset.post])) { + if (Conf['Scroll to Post'] && (post = g.posts.get(file.dataset.post))) { Header.scrollTo(post.nodes.root); } if (isNaN(oldID) || newID === (oldID + 1) % Gallery.images.length) { @@ -14540,14 +14603,14 @@ Gallery = (function() { if (ImageCommon.isFromArchive(this)) { return; } - post = g.posts[this.dataset.post]; - file = post.files[this.dataset.file]; + post = g.posts.get(this.dataset.post); + file = post.files[+this.dataset.file]; return ImageCommon.error(this, post, file, null, (function(_this) { return function(url) { if (!url) { return; } - Gallery.images[_this.dataset.id].href = url; + Gallery.images[+_this.dataset.id].href = url; if (Gallery.nodes.current === _this) { return _this.src = url; } @@ -14742,7 +14805,7 @@ Gallery = (function() { var containerHeight, containerWidth, current, dim, frame, height, margin, minHeight, ref, ref1, ref2, ref3, style, width; ref = Gallery.nodes, current = ref.current, frame = ref.frame; style = current.style; - if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts[current.dataset.post]) != null ? ref1.file.dimensions : void 0)) { + if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts.get(current.dataset.post)) != null ? ref1.file.dimensions : void 0)) { ref2 = dim.split('x'), width = ref2[0], height = ref2[1]; containerWidth = frame.clientWidth; containerHeight = doc.clientHeight - 25; @@ -15812,7 +15875,7 @@ Metadata = (function() { $.rmClass(this.parentNode, 'error'); $.addClass(this.parentNode, 'loading'); index = this.parentNode.dataset.index; - return CrossOrigin.binary(Get.postFromNode(this).files[index].url, (function(_this) { + return CrossOrigin.binary(Get.postFromNode(this).files[+index].url, (function(_this) { return function(data) { var output, title; $.rmClass(_this.parentNode, 'loading'); @@ -15953,7 +16016,7 @@ Sauce = (function() { if (!(link = link.trim())) { return null; } - parts = {}; + parts = $.dict(); ref = link.split(/;(?=(?:text|boards|types|regexp|sandbox):?)/); for (i = j = 0, len = ref.length; j < len; i = ++j) { part = ref[i]; @@ -15986,7 +16049,7 @@ Sauce = (function() { createSauceLink: function(link, post, file) { var a, base, ext, j, key, len, matches, missing, parts, ref; ext = file.url.match(/[^.]*$/)[0]; - parts = {}; + parts = $.dict(); $.extend(parts, link); if (!(!parts['boards'] || parts['boards'][post.siteID + "/" + post.boardID] || parts['boards'][post.siteID + "/*"])) { return null; @@ -16291,7 +16354,7 @@ Embedding = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'archive') && Conf['Linkify'] && (Conf['Embedding'] || Conf['Link Title'] || Conf['Cover Preview']))) { return; } - this.types = {}; + this.types = $.dict(); ref1 = this.ordered_types; for (j = 0, len = ref1.length; j < len; j++) { type = ref1[j]; @@ -17382,7 +17445,7 @@ DeleteLink = (function() { var DeleteLink; DeleteLink = { - auto: [{}, {}], + auto: [$.dict(), $.dict()], init: function() { var div, fileEl, fileEntry, postEl, postEntry, ref; if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Menu'] && Conf['Delete Link'])) { @@ -17483,7 +17546,7 @@ DeleteLink = (function() { onlyimgdel: fileOnly, pwd: QR.persona.getPassword() }; - form[post.ID] = 'delete'; + form[+post.ID] = 'delete'; return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), { responseType: 'document', withCredentials: true, @@ -17531,7 +17594,7 @@ DeleteLink = (function() { } }, cooldown: { - seconds: {}, + seconds: $.dict(), start: function(post, seconds) { if (DeleteLink.cooldown.seconds[post.fullID] != null) { return; @@ -17887,7 +17950,7 @@ Banner = (function() { } } }, - original: {}, + original: $.dict(), custom: function(child) { var className, data, event, j, len, ref; className = child.className; @@ -18040,7 +18103,7 @@ CatalogLinks = (function() { }, externalParse: function() { var board, boards, excludes, i, len, line, ref, ref1, ref2, url; - CatalogLinks.externalList = {}; + CatalogLinks.externalList = $.dict(); ref = Conf['externalCatalogURLs'].split('\n'); for (i = 0, len = ref.length; i < len; i++) { line = ref[i]; @@ -18049,7 +18112,7 @@ CatalogLinks = (function() { } url = line.split(';')[0]; boards = Filter.parseBoards(((ref1 = line.match(/;boards:([^;]+)/)) != null ? ref1[1] : void 0) || '*'); - excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || {}; + excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || $.dict(); for (board in boards) { if (!(excludes[board] || excludes[board.split('/')[0] + '/*'])) { CatalogLinks.externalList[board] = url; @@ -18250,7 +18313,7 @@ ExpandThread = (function() { slice = [].slice; ExpandThread = { - statuses: {}, + statuses: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Thread Expansion'])) { return; @@ -18398,7 +18461,7 @@ ExpandThread = (function() { if (postData.no === thread.ID) { continue; } - if ((post = thread.posts[postData.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(postData.no)) && !post.isFetchedQuote) { if ('file' in post) { filesCount++; } @@ -18479,7 +18542,7 @@ FileInfo = (function() { var a, i, j, len, len1, output, ref, ref1; output = []; formatString.replace(/%(.)|[^%]+/g, function(s, c) { - output.push(c in FileInfo.formatters ? FileInfo.formatters[c].call(post) : { + output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : { innerHTML: E(s) }); return ''; @@ -18644,10 +18707,10 @@ Fourchan = (function() { if (g.BOARD.config.code_tags) { $.on(window, 'prettyprint:cb', function(e) { var post, pre; - if (!(post = g.posts[e.detail.ID])) { + if (!(post = g.posts.get(e.detail.ID))) { return; } - if (!(pre = $$('.prettyprint', post.nodes.comment)[e.detail.i])) { + if (!(pre = $$('.prettyprint', post.nodes.comment)[+e.detail.i])) { return; } if (!$.hasClass(pre, 'prettyprinted')) { @@ -18764,9 +18827,8 @@ IDColor = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Color User IDs'])) { return; } - this.ids = { - Heaven: [0, 0, 0, '#fff'] - }; + this.ids = $.dict(); + this.ids['Heaven'] = [0, 0, 0, '#fff']; return Callbacks.Post.push({ name: 'Color User IDs', cb: this.node @@ -19452,7 +19514,7 @@ ModContact = (function() { }, node: function() { var links, moveNote, moved; - if (this.isClone || !ModContact.specific[this.info.capcode]) { + if (this.isClone || !$.hasOwn(ModContact.specific, this.info.capcode)) { return; } links = $.el('span', { @@ -19460,7 +19522,7 @@ ModContact = (function() { }); $.extend(links, ModContact.template(this.info.capcode)); $.after(this.nodes.capcode, links); - if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && ModContact.moveNote[moved[1]]) { + if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && $.hasOwn(ModContact.moveNote, moved[1])) { moveNote = $.el('div', { className: 'move-note' }); @@ -19561,7 +19623,7 @@ Nav = (function() { getThread: function() { var i, len, ref, thread, threadRoot; if (g.VIEW === 'thread') { - return g.threads[g.BOARD + "." + g.THREADID].nodes.root; + return g.threads.get(g.BOARD + "." + g.THREADID).nodes.root; } if ($.hasClass(doc, 'catalog-mode')) { return; @@ -19953,7 +20015,7 @@ RelativeDates = (function() { if (indexOf.call(RelativeDates.stale, data) >= 0) { return; } - if (data instanceof Post && !g.posts[data.fullID]) { + if (data instanceof Post && !g.posts.get(data.fullID)) { return; } if (data instanceof Element && !doc.contains(data)) { @@ -20218,7 +20280,7 @@ Time = (function() { }, format: function(formatString, date) { return formatString.replace(/%(.)/g, function(s, c) { - if (c in Time.formatters) { + if ($.hasOwn(Time.formatters, c)) { return Time.formatters[c].call(date); } else { return s; @@ -20412,7 +20474,8 @@ Favicon = (function() { '4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAD/AABmZmYA/wBD99DBAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAAul8NnZ2f/AAD7B+mqAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAABmzDNmZmb/AAC8/wCMAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII='], Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'], 'Metro': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAC/AABrZQDiAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAC/AAD///8dAAApAABsAAAHAAA4AACQAAAsAABMCpCvAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAA1/GhpCidAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAAA1/H///8AISUALzQAeokACAkAQEcAorYAMTcE9WFNAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAABV/wErM5hwAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAABV/wH///8NKAASOAAwkQADCgAZTABAwQATOwC5e3VGAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII='] - }[Conf['favicon']]; + }; + items = $.getOwn(items, Conf['favicon']); f = Favicon; t = 'data:image/png;base64,'; i = 0; @@ -20470,13 +20533,13 @@ MarkNewIPs = (function() { i = MarkNewIPs.ipCount; for (j = 0, len = newPosts.length; j < len; j++) { fullID = newPosts[j]; - MarkNewIPs.markNew(g.posts[fullID], ++i); + MarkNewIPs.markNew(g.posts.get(fullID), ++i); } break; case -deletedPosts.length: for (k = 0, len1 = newPosts.length; k < len1; k++) { fullID = newPosts[k]; - MarkNewIPs.markOld(g.posts[fullID]); + MarkNewIPs.markOld(g.posts.get(fullID)); } } MarkNewIPs.ipCount = ipCount; @@ -20603,7 +20666,7 @@ ReplyPruning = (function() { for (i = 0, len = ref.length; i < len; i++) { fullID = ref[i]; ReplyPruning.total++; - if (g.posts[fullID].file) { + if (g.posts.get(fullID).file) { ReplyPruning.totalFiles++; } } @@ -20616,7 +20679,7 @@ ReplyPruning = (function() { posts = ReplyPruning.thread.posts; if (ReplyPruning.hidden < hidden2) { while (ReplyPruning.hidden < hidden2 && ReplyPruning.position < posts.keys.length) { - post = posts[posts.keys[ReplyPruning.position++]]; + post = posts.get(posts.keys[ReplyPruning.position++]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.summary.nextSibling) && node !== post.nodes.root) { $.add(ReplyPruning.container, node); @@ -20631,7 +20694,7 @@ ReplyPruning = (function() { } else if (ReplyPruning.hidden > hidden2) { frag = $.frag(); while (ReplyPruning.hidden > hidden2 && ReplyPruning.position > 0) { - post = posts[posts.keys[--ReplyPruning.position]]; + post = posts.get(posts.keys[--ReplyPruning.position]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.container.lastChild) && node !== post.nodes.root) { $.prepend(frag, node); @@ -20726,7 +20789,7 @@ ThreadStats = (function() { posts = ThreadStats.thread.posts; n = posts.keys.length; for (i = j = ref = ThreadStats.postIndex, ref1 = n; j < ref1; i = j += 1) { - post = posts[posts.keys[i]]; + post = posts.get(posts.keys[i]); if (!post.isFetchedQuote) { ThreadStats.postCount++; ThreadStats.fileCount += post.files.length; @@ -20831,7 +20894,7 @@ ThreadStats = (function() { } }, retry: function() { - if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts[ThreadStats.thread.lastPost].info.date > ThreadStats.lastPageUpdate)) { + if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts.get(ThreadStats.thread.lastPost).info.date > ThreadStats.lastPageUpdate)) { return; } clearTimeout(ThreadStats.timeout); @@ -21157,7 +21220,7 @@ ThreadUpdater = (function() { thread = ThreadUpdater.thread; board = thread.board; ref = ThreadUpdater.postIDs, lastPost = ref[ref.length - 1]; - if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts[lastPost].info.date < 30 * $.SECOND) { + if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts.get(lastPost).info.date < 30 * $.SECOND) { return; } g.SITE.Build.spoilerRange[board] = OP.custom_spoiler; @@ -21183,7 +21246,7 @@ ThreadUpdater = (function() { if (ID <= lastPost) { continue; } - if ((post = thread.posts[ID]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(ID)) && !post.isFetchedQuote) { post.resurrect(); continue; } @@ -21201,7 +21264,7 @@ ThreadUpdater = (function() { if (!(indexOf.call(index, ID) < 0)) { continue; } - thread.posts[ID].kill(); + thread.posts.get(ID).kill(); deletedPosts.push(board + "." + ID); } ThreadUpdater.postIDs = index; @@ -21212,7 +21275,7 @@ ThreadUpdater = (function() { if (!(!(indexOf.call(files, ID) >= 0 || (ref3 = board + "." + ID, indexOf.call(deletedPosts, ref3) >= 0)))) { continue; } - thread.posts[ID].kill(true); + thread.posts.get(ID).kill(true); deletedFiles.push(board + "." + ID); } ThreadUpdater.fileIDs = files; @@ -21517,7 +21580,7 @@ ThreadWatcher = (function() { return ThreadWatcher.addRaw(boardID, threadID, {}, cb); } } else if (Conf['Auto Watch Reply']) { - return ThreadWatcher.add(g.threads[boardID + '.' + threadID] || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); + return ThreadWatcher.add(g.threads.get(boardID + '.' + threadID) || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); } }, onIndexUpdate: function(e) { @@ -21571,7 +21634,7 @@ ThreadWatcher = (function() { }, onThreadRefresh: function(e) { var thread; - thread = g.threads[e.detail.threadID]; + thread = g.threads.get(e.detail.threadID); if (!(e.detail[404] && ThreadWatcher.isWatched(thread))) { return; } @@ -21634,7 +21697,7 @@ ThreadWatcher = (function() { }, initLastModified: function() { var base, boardID, boards, data, date, lm, ref, ref1, siteID, url; - lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = {})); + lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = $.dict())); ref = ThreadWatcher.dbLM.data; for (siteID in ref) { boards = ref[siteID]; @@ -21773,7 +21836,7 @@ ThreadWatcher = (function() { boardID: boardID, val: $.item(url, lmDate) }); - threads = {}; + threads = $.dict(); pageLength = 0; nThreads = 0; oldest = null; @@ -22056,7 +22119,7 @@ ThreadWatcher = (function() { }, setPrefixes: function(threads) { var conflicts, conflicts2, j, k, len, len1, len2, prefix, prefixes, siteID, siteID2; - prefixes = {}; + prefixes = $.dict(); for (j = 0, len1 = threads.length; j < len1; j++) { siteID = threads[j].siteID; if (siteID in prefixes) { @@ -22090,7 +22153,7 @@ ThreadWatcher = (function() { ThreadWatcher.setPrefixes(threads); for (j = 0, len1 = threads.length; j < len1; j++) { ref = threads[j], siteID = ref.siteID, boardID = ref.boardID, threadID = ref.threadID, data = ref.data; - if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads[boardID + "." + threadID]) && thread.OP) { + if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads.get(boardID + "." + threadID)) && thread.OP) { ThreadWatcher.db.extend({ boardID: boardID, threadID: threadID, @@ -22257,7 +22320,7 @@ ThreadWatcher = (function() { oldData = ThreadWatcher.db.get({ boardID: boardID, threadID: threadID, - defaultValue: {} + defaultValue: $.dict() }); delete oldData.last; delete oldData.modified; @@ -22325,7 +22388,7 @@ ThreadWatcher = (function() { } }); return $.on(entryEl, 'click', function() { - return ThreadWatcher.toggle(g.threads[g.BOARD + "." + g.THREADID]); + return ThreadWatcher.toggle(g.threads.get(g.BOARD + "." + g.THREADID)); }); }, addMenuEntries: function() { @@ -22548,7 +22611,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (ID > Unread.lastReadPost) { break; } @@ -22670,7 +22733,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (Unread.posts.has(ID)) { break; } @@ -22760,9 +22823,9 @@ UnreadIndex = (function() { var UnreadIndex; UnreadIndex = { - lastReadPost: {}, - hr: {}, - markReadLink: {}, + lastReadPost: $.dict(), + hr: $.dict(), + markReadLink: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Remember Last Read Post'] && Conf['Unread Line in Index'])) { return; @@ -22794,7 +22857,7 @@ UnreadIndex = (function() { results = []; for (i = 0, len = ref.length; i < len; i++) { threadID = ref[i]; - thread = g.threads[threadID]; + thread = g.threads.get(threadID); results.push(UnreadIndex.update(thread)); } return results; @@ -22922,14 +22985,10 @@ Captcha = {}; haveCookie: function() { return /\b_ct=/.test(d.cookie) && QR.posts[0].thread !== 'new'; }, - getOne: function(isReply) { - var captcha, i; + getOne: function() { + var captcha; this.clear(); - i = this.captchas.findIndex(function(x) { - return isReply || (x.challenge == null); - }); - if (i >= 0) { - captcha = this.captchas.splice(i, 1)[0]; + if ((captcha = this.captchas.shift())) { this.count(); return captcha; } else { @@ -23186,12 +23245,12 @@ Captcha = {}; } else if (n !== 9 && (i = this.imageKeys16.indexOf(key)) >= 0 && i % 4 < w && (img = this.images[n - (4 - Math.floor(i / 4)) * w + (i % 4)])) { img.click(); verify.focus(); - } else if (dx = { + } else if (dx = $.getOwn({ 'Up': n, 'Down': w, 'Left': last, 'Right': 1 - }[key]) { + }, key)) { x = (x + dx) % (n + w); if ((n < x && x < last)) { x = dx === last ? n : last; @@ -23310,7 +23369,6 @@ Captcha = {}; } }, requestCaptcha: function(e) { - var key, url; if (!this.isEnabled()) { return; } @@ -23327,6 +23385,10 @@ Captcha = {}; this.pending = true; this.aborted = false; e.preventDefault(); + return CrossOrigin.permission(this.requestCaptcha2.bind(this), this.noCaptcha.bind(this, 'Permission denied'), [Conf['captchaServiceDomain'] + "/*"]); + }, + requestCaptcha2: function() { + var key, url; key = Conf['captchaServiceKey'][Conf['captchaServiceDomain']]; if (!(key && /\S/.test(key))) { return this.noCaptcha('API key not set'); @@ -23384,7 +23446,7 @@ Captcha = {}; if (this.aborted) { return; } - error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'; + error || (error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'); error = "Failed to retrieve captcha: " + error; return $.event('NoCaptcha', { error: error @@ -23927,7 +23989,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { return QR.abort(); } else { return QR.status(); @@ -24114,7 +24176,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { value = 'Dead'; disabled = true; QR.cooldown.auto = false; @@ -24303,7 +24365,7 @@ QR = (function() { blob = new Blob([file], { type: type }); - blob.name = Conf['pastedname'] + "." + (QR.extensionFromType[type] || 'jpg'); + blob.name = Conf['pastedname'] + "." + ($.getOwn(QR.extensionFromType, type) || 'jpg'); QR.open(); QR.handleFiles([blob]); $.addClass(QR.nodes.el, 'dump'); @@ -24612,7 +24674,7 @@ QR = (function() { post = QR.posts[0]; post.forceSave(); threadID = post.thread; - thread = g.BOARD.threads[threadID]; + thread = g.BOARD.threads.get(threadID); if (g.BOARD.ID === 'f' && threadID === 'new') { filetag = QR.nodes.flashTag.value; } @@ -24623,7 +24685,7 @@ QR = (function() { } else if (!(!!g.BOARD.config.text_only || post.file)) { err = 'No file selected.'; } - } else if (g.BOARD.threads[threadID].isClosed) { + } else if (g.BOARD.threads.get(threadID).isClosed) { err = 'You can\'t reply to this thread anymore.'; } else if (!(post.com || post.file)) { err = 'No comment or file.'; @@ -24889,7 +24951,7 @@ QR = (function() { return; } this.data = Conf['cooldowns']; - this.changes = {}; + this.changes = $.dict(); return $.sync('cooldowns', this.sync); }, setup: function() { @@ -24916,7 +24978,7 @@ QR = (function() { return QR.cooldown.count(); }, sync: function(data) { - QR.cooldown.data = data || {}; + QR.cooldown.data = data || $.dict(); return QR.cooldown.start(); }, add: function(threadID, postID) { @@ -24967,7 +25029,7 @@ QR = (function() { if (!QR.cooldown.data) { return; } - cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = {})); + cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = $.dict())); for (id in cooldowns) { cooldown = cooldowns[id]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -24981,7 +25043,7 @@ QR = (function() { if (!(QR.cooldown.data && Conf['Cooldown'])) { return 0; } - cooldowns = QR.cooldown.data[post.board.ID] || {}; + cooldowns = QR.cooldown.data[post.board.ID] || $.dict(); for (start in cooldowns) { cooldown = cooldowns[start]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -25005,7 +25067,7 @@ QR = (function() { }, mergeChange: function(data, scope, id, value) { if (value) { - return (data[scope] || (data[scope] = {}))[id] = value; + return (data[scope] || (data[scope] = $.dict()))[id] = value; } else if (scope in data) { delete data[scope][id]; if (Object.keys(data[scope]).length === 0) { @@ -25016,7 +25078,7 @@ QR = (function() { set: function(scope, id, value) { var base; QR.cooldown.mergeChange(QR.cooldown.data, scope, id, value); - return ((base = QR.cooldown.changes)[scope] || (base[scope] = {}))[id] = value; + return ((base = QR.cooldown.changes)[scope] || (base[scope] = $.dict()))[id] = value; }, save: function() { var changes; @@ -25024,7 +25086,7 @@ QR = (function() { if (!Object.keys(changes).length) { return; } - return $.get('cooldowns', {}, function(arg) { + return $.get('cooldowns', $.dict(), function(arg) { var cooldowns, id, ref, scope, value; cooldowns = arg.cooldowns; for (scope in QR.cooldown.changes) { @@ -25036,7 +25098,7 @@ QR = (function() { QR.cooldown.data = cooldowns; } return $.set('cooldowns', cooldowns, function() { - return QR.cooldown.changes = {}; + return QR.cooldown.changes = $.dict(); }); }); }, @@ -25054,7 +25116,7 @@ QR = (function() { ref1 = [g.BOARD.ID, 'global']; for (i = 0, len = ref1.length; i < len; i++) { scope = ref1[i]; - cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = {})); + cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = $.dict())); for (start in cooldowns) { cooldown = cooldowns[start]; start = +start; @@ -25606,6 +25668,9 @@ QR = (function() { return; } name = input.dataset.name; + if (name !== 'thread' && name !== 'name' && name !== 'email' && name !== 'sub' && name !== 'com' && name !== 'filename' && name !== 'flag') { + return; + } prev = this[name]; this[name] = input.value || input.dataset["default"] || null; switch (name) { @@ -25927,7 +25992,7 @@ QR = (function() { _Class.prototype.saveFilename = function() { this.file.newName = (this.filename || '').replace(/[\/\\]/g, '-'); if (!QR.validExtension.test(this.filename)) { - return this.file.newName += "." + (QR.extensionFromType[this.file.type] || 'jpg'); + return this.file.newName += "." + ($.getOwn(QR.extensionFromType, this.file.type) || 'jpg'); } }; @@ -26031,7 +26096,7 @@ QuoteBacklink = (function() { var QuoteBacklink; QuoteBacklink = { - containers: {}, + containers: $.dict(), init: function() { var ref; if (((ref = g.VIEW) !== 'index' && ref !== 'thread') || !Conf['Quote Backlinks']) { @@ -26074,7 +26139,7 @@ QuoteBacklink = (function() { for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; containers = [QuoteBacklink.getContainer(quote)]; - if ((post = g.posts[quote]) && post.nodes.backlinkContainer) { + if ((post = g.posts.get(quote)) && post.nodes.backlinkContainer) { ref1 = post.clones; for (j = 0, len1 = ref1.length; j < len1; j++) { clone = ref1[j]; @@ -26230,7 +26295,7 @@ QuoteInline = (function() { return; } ref = Get.postDataFromLink(this), boardID = ref.boardID, threadID = ref.threadID, postID = ref.postID; - if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts[boardID + "." + postID]) != null ? ref1.nodes.root.offsetParent : void 0)) { + if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts.get(boardID + "." + postID)) != null ? ref1.nodes.root.offsetParent : void 0)) { return; } if ($.hasClass(doc, 'catalog-mode')) { @@ -26268,7 +26333,7 @@ QuoteInline = (function() { qroot = $.x('ancestor::*[contains(@class,"postContainer")][1]', root); $.addClass(qroot, 'hasInline'); new Fetcher(boardID, threadID, postID, inline, quoter); - if (!((post = g.posts[boardID + "." + postID]) && context.thread === post.thread)) { + if (!((post = g.posts.get(boardID + "." + postID)) && context.thread === post.thread)) { return; } if (isBacklink && Conf['Forward Hiding']) { @@ -26295,9 +26360,9 @@ QuoteInline = (function() { if (!(el = root.firstElementChild)) { return; } - post = g.posts[boardID + "." + postID]; + post = g.posts.get(boardID + "." + postID); post.rmClone(el.dataset.clone); - if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads[boardID + "." + threadID] && !--post.forwarded) { + if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads.get(boardID + "." + threadID) && !--post.forwarded) { delete post.forwarded; $.rmClass(post.nodes.root, 'forwarded'); } @@ -26423,7 +26488,7 @@ QuotePreview = (function() { endEvents: 'mouseout click', cb: QuotePreview.mouseout }); - if (Conf['Quote Highlighting'] && (origin = g.posts[boardID + "." + postID])) { + if (Conf['Quote Highlighting'] && (origin = g.posts.get(boardID + "." + postID))) { posts = [origin].concat(origin.clones); posts.pop(); for (i = 0, len = posts.length; i < len; i++) { @@ -26479,7 +26544,7 @@ QuoteStrikeThrough = (function() { for (i = 0, len = ref.length; i < len; i++) { quotelink = ref[i]; ref1 = Get.postDataFromLink(quotelink), boardID = ref1.boardID, postID = ref1.postID; - if ((ref2 = g.posts[boardID + "." + postID]) != null ? ref2.isHidden : void 0) { + if ((ref2 = g.posts.get(boardID + "." + postID)) != null ? ref2.isHidden : void 0) { $.addClass(quotelink, 'filtered'); } } @@ -26536,9 +26601,9 @@ QuoteThreading = cb: this.node }); }, - parent: {}, - children: {}, - inserted: {}, + parent: $.dict(), + children: $.dict(), + inserted: $.dict(), toggleThreading: function() { return this.setThreadingState(!Conf['Thread Quotes']); }, @@ -26580,7 +26645,7 @@ QuoteThreading = ref = this.quotes; for (j = 0, len = ref.length; j < len; j++) { quote = ref[j]; - if (parent = g.posts[quote]) { + if (parent = g.posts.get(quote)) { if (!parent.isFetchedQuote && parent.isReply && parent.ID < this.ID) { parents.add(parent.ID); if (!lastParent || parent.ID > lastParent.ID) { @@ -26688,7 +26753,7 @@ QuoteThreading = } else { nodes = []; Unread.order = new RandomAccessList(); - QuoteThreading.inserted = {}; + QuoteThreading.inserted = $.dict(); posts.forEach(function(post) { if (post.isFetchedQuote) { return; @@ -26990,7 +27055,7 @@ Quotify = (function() { } boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID; quoteID = boardID + "." + postID; - if (post = g.posts[quoteID]) { + if (post = g.posts.get(quoteID)) { if (!post.isDead) { a = $.el('a', { href: g.SITE.Build.postURL(boardID, post.thread.ID, postID), @@ -27119,7 +27184,7 @@ Main = (function() { flatten = function(parent, obj) { var key, val; if (obj instanceof Array) { - Conf[parent] = obj[0]; + Conf[parent] = $.dict.clone(obj[0]); } else if (typeof obj === 'object') { for (key in obj) { val = obj[key]; @@ -27150,9 +27215,9 @@ Main = (function() { ref2 = DataBoard.keys; for (j = 0, len = ref2.length; j < len; j++) { db = ref2[j]; - Conf[db] = {}; + Conf[db] = $.dict(); } - Conf['customTitles'] = { + Conf['customTitles'] = $.dict.clone({ '4chan.org': { boards: { 'qa': { @@ -27163,18 +27228,18 @@ Main = (function() { } } } - }; + }); Conf['boardConfig'] = { - boards: {} + boards: $.dict() }; Conf['archives'] = Redirect.archives; - Conf['selectedArchives'] = {}; - Conf['cooldowns'] = {}; - Conf['Index Sort'] = {}; + Conf['selectedArchives'] = $.dict(); + Conf['cooldowns'] = $.dict(); + Conf['Index Sort'] = $.dict(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = {}; + Conf["Last Long Reply Thresholds " + i] = $.dict(); } - Conf['siteProperties'] = {}; + Conf['siteProperties'] = $.dict(); Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; @@ -27195,7 +27260,7 @@ Main = (function() { return $.addCSP("script-src " + (jsWhitelist.replace(/^#.*$/mg, '').replace(/[\s;]+/g, ' ').trim())); }); } - items = {}; + items = $.dict(); for (key in Conf) { items[key] = void 0; } @@ -27535,7 +27600,7 @@ Main = (function() { threadRoot = threadRoots[j]; boardObj = (boardID = threadRoot.dataset.board) ? (boardID = encodeURIComponent(boardID), g.boards[boardID] || new Board(boardID)) : g.BOARD; threadID = +threadRoot.id.match(/\d*$/)[0]; - if (!threadID || ((ref = boardObj.threads[threadID]) != null ? ref.nodes.root : void 0)) { + if (!threadID || ((ref = boardObj.threads.get(threadID)) != null ? ref.nodes.root : void 0)) { return; } thread = new Thread(threadID, boardObj); diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx index 80e93b35c..205c68a46 100644 Binary files a/builds/4chan-X-noupdate.crx and b/builds/4chan-X-noupdate.crx differ diff --git a/builds/4chan-X-noupdate.user.js b/builds/4chan-X-noupdate.user.js index f8b8b10d4..3edbff31f 100644 --- a/builds/4chan-X-noupdate.user.js +++ b/builds/4chan-X-noupdate.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.14.11.0 +// @version 1.14.11.1 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -188,7 +188,7 @@ var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, CSS var Conf, E, c, d, doc, docSet, g; -Conf = {}; +Conf = Object.create(null); c = console; d = document; doc = d.documentElement; @@ -199,10 +199,10 @@ docSet = function() { }; g = { - VERSION: '1.14.11.0', + VERSION: '1.14.11.1', NAMESPACE: '4chan X.', - sites: {}, - boards: {} + sites: Object.create(null), + boards: Object.create(null) }; E = (function() { @@ -4687,7 +4687,7 @@ sub: function(css) { var sel = variables; for (var i = 0; i < words.length; i++) { if (typeof sel !== 'object') return ':not(*)'; - sel = sel[words[i]]; + sel = $.getOwn(sel, words[i]); } if (typeof sel !== 'string') return ':not(*)'; return sel; @@ -4754,6 +4754,46 @@ $ = (function() { } }; + $.dict = function() { + return Object.create(null); + }; + + $.dict.clone = function(obj) { + var arr, i, j, key, map, ref, val; + if (typeof obj !== 'object' || obj === null) { + return obj; + } else if (obj instanceof Array) { + arr = []; + for (i = j = 0, ref = obj.length; j < ref; i = j += 1) { + arr.push($.dict.clone(obj[i])); + } + return arr; + } else { + map = Object.create(null); + for (key in obj) { + val = obj[key]; + map[key] = $.dict.clone(val); + } + return map; + } + }; + + $.dict.json = function(str) { + return $.dict.clone(JSON.parse(str)); + }; + + $.hasOwn = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + }; + + $.getOwn = function(obj, key) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return obj[key]; + } else { + return void 0; + } + }; + $.ajax = (function() { var pageXHR; if (window.wrappedJSObject && !XMLHttpRequest.wrappedJSObject) { @@ -4808,7 +4848,7 @@ $ = (function() { }; })(); - $.lastModified = {}; + $.lastModified = $.dict(); $.whenModified = function(url, bucket, cb, options) { var ajax, headers, params, r, ref, t, timeout, url0; @@ -4827,14 +4867,14 @@ $ = (function() { if (params.length) { url += '?' + params.join('&'); } - headers = {}; + headers = $.dict(); if ((t = (ref = $.lastModified[bucket]) != null ? ref[url0] : void 0) != null) { headers['If-Modified-Since'] = t; } r = (ajax || $.ajax)(url, { onloadend: function() { var base; - ((base = $.lastModified)[bucket] || (base[bucket] = {}))[url0] = this.getResponseHeader('Last-Modified'); + ((base = $.lastModified)[bucket] || (base[bucket] = $.dict()))[url0] = this.getResponseHeader('Last-Modified'); return cb.call(this); }, timeout: timeout, @@ -4845,7 +4885,7 @@ $ = (function() { (function() { var reqs; - reqs = {}; + reqs = $.dict(); $.cache = function(url, cb, options) { var ajax, onloadend, req; if (options == null) { @@ -4903,12 +4943,16 @@ $ = (function() { $.cb = { checked: function() { - $.set(this.name, this.checked); - return Conf[this.name] = this.checked; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.checked); + return Conf[this.name] = this.checked; + } }, value: function() { - $.set(this.name, this.value.trim()); - return Conf[this.name] = this.value; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.value.trim()); + return Conf[this.name] = this.value; + } } }; @@ -5281,11 +5325,11 @@ $ = (function() { $.hasStorage = (function() { try { - if (localStorage[g.NAMESPACE + 'hasStorage'] === 'true') { + if (localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true') { return true; } - localStorage[g.NAMESPACE + 'hasStorage'] = 'true'; - return localStorage[g.NAMESPACE + 'hasStorage'] === 'true'; + localStorage.setItem(g.NAMESPACE + 'hasStorage', 'true'); + return localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true'; } catch (error) { return false; } @@ -5293,7 +5337,7 @@ $ = (function() { $.item = function(key, val) { var item; - item = {}; + item = $.dict(); item[key] = val; return item; }; @@ -5308,7 +5352,7 @@ $ = (function() { }; }; - $.syncing = {}; + $.syncing = $.dict(); $.securityCheck = function(data) { if (location.protocol !== 'https:') { @@ -5325,7 +5369,7 @@ $ = (function() { for (key in ref) { val = ref[key]; if ((cb = $.syncing[key])) { - results.push(cb(JSON.parse(JSON.stringify(val)), key)); + results.push(cb($.dict.json(JSON.stringify(val)), key)); } } return results; @@ -5349,7 +5393,7 @@ $ = (function() { return results; })()).then(function() { var items, j, key, len; - items = {}; + items = $.dict(); for (j = 0, len = keys.length; j < len; j++) { key = keys[j]; items[key] = void 0; @@ -5374,7 +5418,7 @@ $ = (function() { for (i = j = 0, len = values.length; j < len; i = ++j) { val = values[i]; if (val) { - items[keys[i]] = JSON.parse(val); + items[keys[i]] = $.dict.json(val); } } return cb(items); @@ -5416,7 +5460,7 @@ $ = (function() { }; } else if ($.hasStorage) { $.getValue = function(key) { - return localStorage[key]; + return localStorage.getItem(key); }; $.listValues = function() { var key, results; @@ -5438,13 +5482,13 @@ $ = (function() { $.setValue = GM_setValue; $.deleteValue = GM_deleteValue; } else if (typeof GM_deleteValue !== "undefined" && GM_deleteValue !== null) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { GM_setValue(key, val); if (key in $.syncing) { $.oldValue[key] = val; if ($.hasStorage) { - return localStorage[key] = val; + return localStorage.setItem(key, val); } } }; @@ -5461,12 +5505,12 @@ $ = (function() { $.cantSync = true; } } else if ($.hasStorage) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { if (key in $.syncing) { $.oldValue[key] = val; } - return localStorage[key] = val; + return localStorage.setItem(key, val); }; $.deleteValue = function(key) { if (key in $.syncing) { @@ -5484,7 +5528,7 @@ $ = (function() { return $.syncing[key] = GM_addValueChangeListener(g.NAMESPACE + key, function(key2, oldValue, newValue, remote) { if (remote) { if (newValue !== void 0) { - newValue = JSON.parse(newValue); + newValue = $.dict.json(newValue); } return cb(newValue, key); } @@ -5510,7 +5554,7 @@ $ = (function() { return; } $.oldValue[key] = newValue; - return cb(JSON.parse(newValue), key.slice(g.NAMESPACE.length)); + return cb($.dict.json(newValue), key.slice(g.NAMESPACE.length)); } else { if ($.oldValue[key] == null) { return; @@ -5550,7 +5594,7 @@ $ = (function() { for (key in items) { if ((val2 = $.getValue(g.NAMESPACE + key))) { try { - items[key] = JSON.parse(val2); + items[key] = $.dict.json(val2); } catch (error) { err = error; if (!/^(?:undefined)*$/.test(val2)) { @@ -5610,7 +5654,7 @@ CrossOrigin = (function() { binary: function(url, cb, headers) { var fallback, gmOptions; if (headers == null) { - headers = {}; + headers = $.dict(); } url = url.replace(/^((?:https?:)?\/\/(?:\w+\.)?(?:4chan|4channel|4cdn)\.org)\/adv\//, '$1//adv/'); fallback = function() { @@ -5679,7 +5723,7 @@ CrossOrigin = (function() { name = match.replace(/\\"/g, '"'); } if (/^text\/plain;\s*charset=x-user-defined$/i.test(mime)) { - mime = QR.typeFromExtension[name.match(/[^.]*$/)[0].toLowerCase()] || 'application/octet-stream'; + mime = $.getOwn(QR.typeFromExtension, name.match(/[^.]*$/)[0].toLowerCase()) || 'application/octet-stream'; } blob = new Blob([data], { type: mime @@ -5700,9 +5744,9 @@ CrossOrigin = (function() { Request.prototype.responseHeaderString = null; Request.prototype.getResponseHeader = function(headerName) { - var header, i, j, key, len, ref, ref1, val; + var header, i, j, key, len, ref, ref1, ref2, val; if ((this.responseHeaders == null) && (this.responseHeaderString != null)) { - this.responseHeaders = {}; + this.responseHeaders = $.dict(); ref = this.responseHeaderString.split('\r\n'); for (j = 0, len = ref.length; j < len; j++) { header = ref[j]; @@ -5713,7 +5757,7 @@ CrossOrigin = (function() { } } } - return (ref1 = (this.responseHeaders || {})[headerName.toLowerCase()]) != null ? ref1 : null; + return (ref1 = (ref2 = this.responseHeaders) != null ? ref2[headerName.toLowerCase()] : void 0) != null ? ref1 : null; }; Request.prototype.abort = function() {}; @@ -5971,7 +6015,7 @@ CatalogThreadNative = (function() { this.boardID = this.nodes.thumb.parentNode.pathname.split(/\/+/)[1]; this.board = g.boards[this.boardID] || new Board(this.boardID); this.ID = this.threadID = +(root.dataset.id || root.id).match(/\d*$/)[0]; - this.thread = this.board.threads[this.ID] || new Thread(this.ID, this.board); + this.thread = this.board.threads.get(this.ID) || new Thread(this.ID, this.board); } return CatalogThreadNative; @@ -6009,15 +6053,15 @@ Connection = (function() { }; Connection.prototype.onMessage = function(e) { - var base, data, type, value; + var data, type, value; if (!(e.source === this.targetWindow() && e.origin === this.origin && typeof e.data === 'string' && e.data.slice(0, g.NAMESPACE.length) === g.NAMESPACE)) { return; } data = JSON.parse(e.data.slice(g.NAMESPACE.length)); for (type in data) { value = data[type]; - if (typeof (base = this.cb)[type] === "function") { - base[type](value); + if ($.hasOwn(this.cb, type)) { + this.cb[type](value); } } }; @@ -6071,7 +6115,7 @@ DataBoard = (function() { delete this.data.lastChecked; } return (base = this.data)[name = g.SITE.ID] || (base[name] = { - boards: {} + boards: $.dict() }); }; @@ -6081,7 +6125,7 @@ DataBoard = (function() { change(); this.changes.push(change); return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var i, len, needSync, ref; @@ -6113,7 +6157,7 @@ DataBoard = (function() { DataBoard.prototype.forceSync = function(cb) { return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var change, i, len, ref; @@ -6201,12 +6245,12 @@ DataBoard = (function() { siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, postID = arg.postID, val = arg.val; siteID || (siteID = g.SITE.ID); (base = this.data)[siteID] || (base[siteID] = { - boards: {} + boards: $.dict() }); if (postID !== void 0) { - return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = {})))[threadID] || (base1[threadID] = {}))[postID] = val; + return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = $.dict())))[threadID] || (base1[threadID] = $.dict()))[postID] = val; } else if (threadID !== void 0) { - return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = {}))[threadID] = val; + return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = $.dict()))[threadID] = val; } else { return this.data[siteID].boards[boardID] = val; } @@ -6223,7 +6267,7 @@ DataBoard = (function() { boardID: boardID, threadID: threadID, postID: postID, - defaultValue: {} + defaultValue: $.dict() }); for (key in val) { subVal = val[key]; @@ -6338,7 +6382,7 @@ DataBoard = (function() { if (!(board = this.data[siteID].boards[boardID])) { return; } - threads = {}; + threads = $.dict(); if (response1) { for (i = 0, len = response1.length; i < len; i++) { page = response1[i]; @@ -6396,11 +6440,11 @@ Fetcher = (function() { this.postID = postID1; this.root = root; this.quoter = quoter; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } - if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads[this.boardID + "." + this.threadID])) { + if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads.get(this.boardID + "." + this.threadID))) { board = g.boards[this.boardID]; post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true @@ -6459,7 +6503,7 @@ Fetcher = (function() { Fetcher.prototype.fetchedPost = function(req, isCached) { var api, board, k, len, post, posts, status, that, thread; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6503,7 +6547,7 @@ Fetcher = (function() { return; } board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true }); @@ -6532,7 +6576,7 @@ Fetcher = (function() { media = this.response.media; for (key in media) { if (/_link$/.test(key)) { - if (!((ref1 = media[key]) != null ? ref1.match(/^http:\/\//) : void 0)) { + if (!((ref1 = $.getOwn(media, key)) != null ? ref1.match(/^http:\/\//) : void 0)) { delete media[key]; } } @@ -6547,7 +6591,7 @@ Fetcher = (function() { Fetcher.prototype.parseArchivedPost = function(data, url, archive) { var board, comment, greentext, i, j, media_link, o, post, ref, tag, text, text2, thread, thumb_link; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6675,8 +6719,9 @@ Fetcher = (function() { o.file.tag = JSON.parse(data.media.exif).Tag; } } + o.extra = $.dict(); board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.post(o), thread, board, { isFetchedQuote: true }); @@ -6892,9 +6937,9 @@ Post = (function() { this.isDead = false; this.isHidden = false; this.clones = []; - if (g.posts[this.fullID]) { + if (g.posts.get(this.fullID)) { this.isRebuilt = true; - this.clones = g.posts[this.fullID].clones; + this.clones = g.posts.get(this.fullID).clones; ref14 = this.clones; for (k = 0, len1 = ref14.length; k < len1; k++) { clone = ref14[k]; @@ -7463,7 +7508,7 @@ ShimSet = (function() { ShimSet = (function() { function ShimSet() { - this.elements = {}; + this.elements = $.dict(); this.size = 0; } @@ -7534,6 +7579,14 @@ SimpleDict = (function() { } }; + SimpleDict.prototype.get = function(key) { + if (key === 'keys') { + return void 0; + } else { + return $.getOwn(this, key); + } + }; + return SimpleDict; })(); @@ -7551,8 +7604,8 @@ Thread = (function() { }; function Thread(ID, board) { - this.ID = ID; this.board = board; + this.ID = +ID; this.threadID = this.ID; this.boardID = this.board.ID; this.siteID = g.SITE.ID; @@ -7694,7 +7747,7 @@ SW = {}; for (j = 0, len = ref.length; j < len; j++) { script = ref[j]; if ((m = script.textContent.match(/\bvar configRoot=(".*?")/))) { - properties = {}; + properties = $.dict(); try { root = JSON.parse(m[1]); if (root[0] === '/') { @@ -8288,7 +8341,7 @@ SW = {}; Build = { staticPath: '//s.4cdn.org/image/', gifIcon: window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif', - spoilerRange: {}, + spoilerRange: $.dict(), shortFilename: function(filename) { var ext; ext = filename.match(/\.?[^\.]*$/)[0]; @@ -8368,9 +8421,10 @@ SW = {}; }); o.files.push(o.file); } + o.extra = $.dict(); for (key in data) { if (key[0] === 'x') { - o[key] = data[key]; + o.extra[key] = data[key]; } } return o; @@ -8443,10 +8497,10 @@ SW = {}; capcodePlural = 'Verified Users'; capcodeDescription = ''; } else { - capcodeLong = { + capcodeLong = $.getOwn({ 'Admin': 'Administrator', 'Mod': 'Moderator' - }[capcode] || capcode; + }, capcode) || capcode; capcodePlural = capcodeLong + "s"; capcodeDescription = "a 4chan " + capcodeLong; } @@ -8455,7 +8509,7 @@ SW = {}; postLink = url + "#p" + ID; quoteLink = Build.sameThread(boardID, threadID) ? "javascript:quote('" + (+ID) + "');" : url + "#q" + ID; postInfo = { - innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.xa19s) ? " " + E(o.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.xa19l && o.isReply) ? " Like! ×" + E(o.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" + innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.extra.xa19s) ? " " + E(o.extra.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.extra.xa19l && o.isReply) ? " Like! ×" + E(o.extra.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" }; /* File Info */ @@ -8636,7 +8690,7 @@ Site = (function() { var hostname; $.extend(Conf['siteProperties'], Site.defaultProperties); hostname = Site.resolve(); - if (hostname && Conf['siteProperties'][hostname].software in SW) { + if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) { this.set(hostname); cb(); } @@ -8649,7 +8703,7 @@ Site = (function() { } changes.software = software; hostname = location.hostname.replace(/^www\./, ''); - properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = {})); + properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = $.dict())); changed = 0; for (key in changes) { if (!(properties[key] !== changes[key])) { @@ -8676,7 +8730,7 @@ Site = (function() { url = location; } hostname = url.hostname; - while (hostname && !(hostname in Conf['siteProperties'])) { + while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) { hostname = hostname.replace(/^[^.]*\.?/, ''); } if (hostname) { @@ -8700,7 +8754,7 @@ Site = (function() { continue; } software = properties.software; - if (!(software && SW[software])) { + if (!(software && $.hasOwn(SW, software))) { continue; } g.sites[ID] = site = Object.create(SW[software]); @@ -8750,11 +8804,11 @@ Redirect = (function() { selectArchives: function() { var archive, archives, boardID, boards, data, files, id, j, k, key, l, len, len1, len2, name, o, record, ref, ref1, ref2, software, type, uid; o = { - thread: {}, - post: {}, - file: {} + thread: $.dict(), + post: $.dict(), + file: $.dict() }; - archives = {}; + archives = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { data = ref[j]; @@ -8788,7 +8842,7 @@ Redirect = (function() { record = ref2[boardID]; for (type in record) { id = record[type]; - if (!((archive = archives[JSON.stringify(id)]))) { + if (!((archive = archives[JSON.stringify(id)]) && $.hasOwn(o, type))) { continue; } boards = type === 'file' ? archive.files : archive.boards; @@ -8863,7 +8917,7 @@ Redirect = (function() { parse: function(responses, cb) { var archiveUIDs, archives, data, items, j, k, len, len1, ref, response, uid; archives = []; - archiveUIDs = {}; + archiveUIDs = $.dict(); for (j = 0, len = responses.length; j < len; j++) { response = responses[j]; for (k = 0, len1 = response.length; k < len1; k++) { @@ -8872,7 +8926,7 @@ Redirect = (function() { if (uid in archiveUIDs) { $.extend(archiveUIDs[uid], data); } else { - archiveUIDs[uid] = data; + archiveUIDs[uid] = $.dict.clone(data); archives.push(data); } } @@ -8897,7 +8951,7 @@ Redirect = (function() { protocol: function(archive) { var protocol; protocol = location.protocol; - if (!archive[protocol.slice(0, -1)]) { + if (!$.getOwn(archive, protocol.slice(0, -1))) { protocol = protocol === 'https:' ? 'http:' : 'https:'; } return protocol + "//"; @@ -8949,10 +9003,10 @@ Redirect = (function() { boardID = arg.boardID, type = arg.type, value = arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; if (type === 'capcode') { - value = { + value = $.getOwn({ 'Developer': 'dev', 'Verified': 'ver' - }[value] || value.toLowerCase(); + }, value) || value.toLowerCase(); } else if (type === 'image') { value = value.replace(/[+\/=]/g, function(c) { return { @@ -9022,8 +9076,8 @@ Filter = (function() { slice = [].slice; Filter = { - filters: {}, - results: {}, + filters: $.dict(), + results: $.dict(), init: function() { var base, base1, boards, err, excludes, file, filter, hide, hl, i, isstring, j, key, len, len1, line, mask, noti, op, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, regexp, stub, top, type, types; if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'catalog') && Conf['Filter'])) { @@ -9060,15 +9114,15 @@ Filter = (function() { } } op = ((ref4 = filter.match(/(?:^|;)\s*op:(no|only)/)) != null ? ref4[1] : void 0) || ''; - mask = { + mask = $.getOwn({ 'no': 1, 'only': 2 - }[op] || 0; + }, op) || 0; file = ((ref5 = filter.match(/(?:^|;)\s*file:(no|only)/)) != null ? ref5[1] : void 0) || ''; - mask = mask | ({ + mask = mask | ($.getOwn({ 'no': 4, 'only': 8 - }[file] || 0); + }, file) || 0); stub = (function() { var ref6; switch ((ref6 = filter.match(/(?:^|;)\s*stub:(yes|no)/)) != null ? ref6[1] : void 0) { @@ -9136,7 +9190,7 @@ Filter = (function() { if ((boards = Filter.parseBoardsMemo[boardsRaw])) { return boards; } - boards = {}; + boards = $.dict(); siteFilter = ''; ref = boardsRaw.split(','); for (i = 0, len = ref.length; i < len; i++) { @@ -9163,7 +9217,7 @@ Filter = (function() { Filter.parseBoardsMemo[boardsRaw] = boards; return boards; }, - parseBoardsMemo: {}, + parseBoardsMemo: $.dict(), test: function(post, hideable) { var board, filter, hide, hl, i, j, key, len, len1, mask, noti, ref, ref1, ref2, site, stub, top, value; if (hideable == null) { @@ -9251,7 +9305,7 @@ Filter = (function() { if (!(url = typeof (base = g.SITE.urls).catalogJSON === "function" ? base.catalogJSON(g.BOARD) : void 0)) { return; } - Filter.catalogData = {}; + Filter.catalogData = $.dict(); $.ajax(url, { onloadend: Filter.catalogParse }); @@ -9365,7 +9419,7 @@ Filter = (function() { } }, values: function(key, post) { - if (key in Filter.valueF) { + if ($.hasOwn(Filter.valueF, key)) { return Filter.valueF[key](post).filter(function(v) { return v != null; }); @@ -9373,7 +9427,7 @@ Filter = (function() { return [ key.split('+').map(function(k) { var f; - if ((f = Filter.valueF[k])) { + if ((f = $.getOwn(Filter.valueF, k))) { return f(post).map(function(v) { return v || ''; }).join('\n'); @@ -9385,6 +9439,9 @@ Filter = (function() { } }, addFilter: function(type, re, cb) { + if (!$.hasOwn(Config.filter, type)) { + return; + } return $.get(type, Conf[type], function(item) { var save; save = item[type]; @@ -9871,7 +9928,7 @@ Recursive = (function() { indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Recursive = { - recursives: {}, + recursives: $.dict(), init: function() { var ref; if ((ref = g.VIEW) !== 'index' && ref !== 'thread') { @@ -9970,7 +10027,7 @@ ThreadHiding = (function() { } hiddenThreads = ThreadHiding.db.get({ boardID: board.ID, - defaultValue: {} + defaultValue: $.dict() }); for (threadID in hiddenThreads) { hiddenThreads[threadID] = true; @@ -9994,7 +10051,7 @@ ThreadHiding = (function() { var hiddenThreads2, threadID; hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; for (threadID in hiddenThreads2) { - if (!(threadID in ThreadHiding.hiddenThreads)) { + if (!$.hasOwn(ThreadHiding.hiddenThreads, threadID)) { ThreadHiding.db.set({ boardID: g.BOARD.ID, threadID: threadID, @@ -10005,7 +10062,7 @@ ThreadHiding = (function() { } } for (threadID in ThreadHiding.hiddenThreads) { - if (!(threadID in hiddenThreads2)) { + if (!$.hasOwn(hiddenThreads2, threadID)) { ThreadHiding.db["delete"]({ boardID: g.BOARD.ID, threadID: threadID @@ -10194,7 +10251,7 @@ ThreadHiding = (function() { }, toggle: function(thread) { if (!(thread instanceof Thread)) { - thread = g.threads[this.dataset.fullID]; + thread = g.threads.get(this.dataset.fullID); } if (thread.isHidden) { ThreadHiding.show(thread); @@ -10266,7 +10323,7 @@ BoardConfig = (function() { load: function() { var board, boards, err, i, len, ref, ref1, troll_flags; if (this.status === 200 && this.response && this.response.boards) { - boards = {}; + boards = $.dict(); ref = this.response.boards; for (i = 0, len = ref.length; i < len; i++) { board = ref[i]; @@ -10384,7 +10441,7 @@ Get = (function() { return null; } board = root.dataset.board; - return g.threads[(board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])]; + return g.threads.get((board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])); }, threadFromNode: function(node) { return Get.threadFromRoot($.x("ancestor-or-self::" + g.SITE.xpath.thread, node)); @@ -10394,10 +10451,10 @@ Get = (function() { if (root == null) { return null; } - post = g.posts[root.dataset.fullID]; + post = g.posts.get(root.dataset.fullID); index = root.dataset.clone; if (index) { - return post.clones[index]; + return post.clones[+index]; } else { return post; } @@ -10444,7 +10501,7 @@ Get = (function() { ref = post.quotes; for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; - if (qPost = posts[quote]) { + if (qPost = posts.get(quote)) { handleQuotes(qPost, 'backlinks'); } } @@ -11179,7 +11236,7 @@ Index = (function() { }); Header.addShortcut('index-refresh', this.button, 590); entries = []; - this.inputs = inputs = {}; + this.inputs = inputs = $.dict(); ref4 = Config.Index; for (name in ref4) { arr = ref4[name]; @@ -11200,7 +11257,7 @@ Index = (function() { $.on(inputs['Pin Watched Threads'], 'change', this.cb.resort); $.on(inputs['Anchor Hidden Threads'], 'change', this.cb.resort); watchSettings = function(e) { - if ((input = inputs[e.target.name])) { + if ((input = $.getOwn(inputs, e.target.name))) { input.checked = e.target.checked; return $.event('change', null, input); } @@ -11486,10 +11543,10 @@ Index = (function() { }, perBoardSort: function() { var i, k; - Conf['Index Sort'] = this.checked ? {} : ''; + Conf['Index Sort'] = this.checked ? $.dict() : ''; Index.saveSort(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = this.checked ? {} : ''; + Conf["Last Long Reply Thresholds " + i] = this.checked ? $.dict() : ''; Index.saveLastLongThresholds(i); } }, @@ -11653,12 +11710,12 @@ Index = (function() { leftover = []; for (k = 0, len1 = commands.length; k < len1; k++) { command = commands[k]; - if ((mode = Index.hashCommands.mode[command])) { + if ((mode = $.getOwn(Index.hashCommands.mode, command))) { state.mode = mode; } else if (command === 'index') { state.mode = Conf['Previous Index Mode']; state.page = 1; - } else if ((sort = Index.hashCommands.sort[command.replace(/-rev$/, '')])) { + } else if ((sort = $.getOwn(Index.hashCommands.sort, command.replace(/-rev$/, '')))) { state.sort = sort; if (/-rev$/.test(command)) { state.sort += '-rev'; @@ -11972,10 +12029,10 @@ Index = (function() { Index.liveThreadIDs = Index.liveThreadData.map(function(data) { return data.no; }); - Index.liveThreadDict = {}; - Index.threadPosition = {}; - Index.parsedThreads = {}; - Index.replyData = {}; + Index.liveThreadDict = $.dict(); + Index.threadPosition = $.dict(); + Index.parsedThreads = $.dict(); + Index.replyData = $.dict(); ref1 = Index.liveThreadData; for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { data = ref1[i]; @@ -12017,7 +12074,7 @@ Index = (function() { }, isHidden: function(threadID) { var thread; - if ((thread = g.BOARD.threads[threadID]) && thread.OP && !thread.OP.isFetchedQuote) { + if ((thread = g.BOARD.threads.get(threadID)) && thread.OP && !thread.OP.isFetchedQuote) { return thread.isHidden; } else { return Index.parsedThreads[threadID].isHidden; @@ -12035,7 +12092,7 @@ Index = (function() { ID = threadIDs[k]; try { threadData = Index.liveThreadDict[ID]; - if ((thread = g.BOARD.threads[ID])) { + if ((thread = g.BOARD.threads.get(ID))) { isStale = (thread.json !== threadData) && (JSON.stringify(thread.json) !== JSON.stringify(threadData)); if (isStale) { thread.setCount('post', threadData.replies + 1, threadData.bumplimit); @@ -12114,7 +12171,7 @@ Index = (function() { nodes = []; for (l = 0, len2 = lastReplies.length; l < len2; l++) { data = lastReplies[l]; - if ((post = thread.posts[data.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(data.no)) && !post.isFetchedQuote) { nodes.push(post.nodes.root); continue; } @@ -12226,7 +12283,7 @@ Index = (function() { return thread; } }; - lastlongD = {}; + lastlongD = $.dict(); for (k = 0, len1 = liveThreadData.length; k < len1; k++) { thread = liveThreadData[k]; lastlongD[thread.no] = lastlong(thread).no; @@ -12666,8 +12723,8 @@ Settings = (function() { warning(addWarning); } $.add(section, warnings); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); addCheckboxes = function(root, obj) { var arr, container, containers, description, div, input, level, results; containers = [root]; @@ -12737,8 +12794,8 @@ Settings = (function() { }); button = $('button', div); $.get({ - hiddenThreads: {}, - hiddenPosts: {} + hiddenThreads: $.dict(), + hiddenPosts: $.dict() }, function(arg) { var ID, board, hiddenNum, hiddenPosts, hiddenThreads, ref2, ref3, ref4, ref5, site, thread; hiddenThreads = arg.hiddenThreads, hiddenPosts = arg.hiddenPosts; @@ -12783,10 +12840,13 @@ Settings = (function() { }); $.on(button, 'click', function() { this.textContent = 'Hidden: 0'; - return $.get('hiddenThreads', {}, function(arg) { - var boardID, hiddenThreads; + return $.get('hiddenThreads', $.dict(), function(arg) { + var boardID, hiddenThreads, ref2; hiddenThreads = arg.hiddenThreads; if ($.hasStorage && g.SITE.software === 'yotsuba') { + for (boardID in (ref2 = hiddenThreads['4chan.org']) != null ? ref2.boards : void 0) { + localStorage.removeItem("4chan-hide-t-" + boardID); + } for (boardID in hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -12798,7 +12858,7 @@ Settings = (function() { }, "export": function() { var Conf2; - Conf2 = {}; + Conf2 = $.dict(); $.extend(Conf2, Conf); return $.get(Conf2, function(Conf2) { delete Conf2['boardConfig']; @@ -12842,7 +12902,7 @@ Settings = (function() { reader.onload = function(e) { var err; try { - return Settings.loadSettings(JSON.parse(e.target.result), function(err) { + return Settings.loadSettings($.dict.json(e.target.result), function(err) { if (err) { return output.textContent = 'Import failed due to an error.'; } else if (confirm('Import successful. Reload now?')) { @@ -12954,14 +13014,14 @@ Settings = (function() { } if (data.WatchedThreads) { data.Conf['watchedThreads'] = { - boards: {} + boards: $.dict() }; ref1 = data.WatchedThreads; for (boardID in ref1) { threads = ref1[boardID]; for (threadID in threads) { threadData = threads[threadID]; - ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = {}))[threadID] = { + ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = $.dict()))[threadID] = { excerpt: threadData.textContent }; } @@ -12972,7 +13032,7 @@ Settings = (function() { }, upgrade: function(data, version) { var addCSS, addSauces, boardID, boards, changes, compareString, corrupted, db, hostname, j, k, key, l, lastChecked, len, len1, len2, len3, line, list, m, name, record, ref, ref1, ref10, ref11, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rice, set, setD, siteProperties, software, type, uids, val, val2, value; - changes = {}; + changes = $.dict(); set = function(key, value) { return data[key] = changes[key] = value; }; @@ -13056,7 +13116,7 @@ Settings = (function() { record = ref2[boardID]; for (type in record) { name = record[type]; - if (name in uids) { + if ($.hasOwn(uids, name)) { record[type] = uids[name]; } } @@ -13235,7 +13295,7 @@ Settings = (function() { } } if ((data['siteSoftware'] != null) && (data['siteProperties'] == null)) { - siteProperties = {}; + siteProperties = $.dict(); ref10 = data['siteSoftware'].split('\n'); for (m = 0, len3 = ref10.length; m < len3; m++) { line = ref10[m]; @@ -13312,6 +13372,9 @@ Settings = (function() { var div, filterTypes, name, ta; div = this.nextElementSibling; if ((name = this.value) !== 'guide') { + if (!$.hasOwn(Config.filter, name)) { + return; + } $.rmAll(div); ta = $.el('textarea', { name: name, @@ -13360,7 +13423,7 @@ Settings = (function() { warning = ref[j]; warning.hidden = Conf[warning.dataset.feature]; } - inputs = {}; + inputs = $.dict(); ref1 = $$('[name]', section); for (k = 0, len1 = ref1.length; k < len1; k++) { input = ref1[k]; @@ -13371,7 +13434,7 @@ Settings = (function() { Conf['lastarchivecheck'] = 0; return $.id('lastarchivecheck').textContent = 'never'; }); - items = {}; + items = $.dict(); for (name in inputs) { input = inputs[name]; if (!(name !== 'captchaServiceKey' && name !== 'Interval' && name !== 'Custom CSS')) { @@ -13423,7 +13486,7 @@ Settings = (function() { $.on(applyCSS, 'click', function() { return CustomCSS.update(); }); - itemsArchive = {}; + itemsArchive = $.dict(); ref4 = ['archives', 'selectedArchives', 'lastarchivecheck']; for (m = 0, len3 = ref4.length; m < len3; m++) { name = ref4[m]; @@ -13455,7 +13518,7 @@ Settings = (function() { tbody = $('tbody', section); $.rmAll(boardSelect); $.rmAll(tbody); - archBoards = {}; + archBoards = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { ref1 = ref[j], uid = ref1.uid, name = ref1.name, boards = ref1.boards, files = ref1.files, software = ref1.software; @@ -13561,7 +13624,7 @@ Settings = (function() { return function(arg) { var name1, selectedArchives; selectedArchives = arg.selectedArchives; - (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = {}))[_this.dataset.type] = JSON.parse(_this.value); + (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = $.dict()))[_this.dataset.type] = JSON.parse(_this.value); $.set('selectedArchives', selectedArchives); Conf['selectedArchives'] = selectedArchives; return Redirect.selectArchives(); @@ -13588,7 +13651,7 @@ Settings = (function() { var captchaServiceKey; captchaServiceKey = arg.captchaServiceKey; captchaServiceKey[domain] = value; - if (!(value || (domain in Config['captchaServiceKey'][0]))) { + if (!(value || $.hasOwn(Config['captchaServiceKey'][0], domain))) { delete captchaServiceKey[domain]; } Conf['captchaServiceKey'] = captchaServiceKey; @@ -13673,8 +13736,8 @@ Settings = (function() { }); $('.warning', section).hidden = Conf['Keybinds']; tbody = $('tbody', section); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); ref = Config.hotkeys; for (key in ref) { arr = ref[key]; @@ -14247,7 +14310,7 @@ FappeTyme = (function() { }); $.on(indicator, 'click', function() { var check; - check = FappeTyme.nodes[this.parentNode.id.replace('shortcut-', '')]; + check = $.getOwn(FappeTyme.nodes, this.parentNode.id.replace('shortcut-', '')); check.checked = !check.checked; return $.event('change', null, check); }); @@ -14356,7 +14419,7 @@ Gallery = (function() { } Gallery.images = []; nodes = Gallery.nodes = {}; - Gallery.fileIDs = {}; + Gallery.fileIDs = $.dict(); Gallery.slideshow = false; nodes.el = dialog = $.el('div', { id: 'a-gallery' @@ -14471,11 +14534,11 @@ Gallery = (function() { load: function(thumb, errorCB) { var elType, ext, file; ext = thumb.href.match(/\w*$/); - elType = { + elType = $.getOwn({ 'webm': 'video', 'mp4': 'video', 'pdf': 'iframe' - }[ext] || 'img'; + }, ext) || 'img'; file = $.el(elType); $.extend(file.dataset, thumb.dataset); $.on(file, 'error', errorCB); @@ -14525,7 +14588,7 @@ Gallery = (function() { } else { Gallery.cb.stop(); } - if (Conf['Scroll to Post'] && (post = g.posts[file.dataset.post])) { + if (Conf['Scroll to Post'] && (post = g.posts.get(file.dataset.post))) { Header.scrollTo(post.nodes.root); } if (isNaN(oldID) || newID === (oldID + 1) % Gallery.images.length) { @@ -14540,14 +14603,14 @@ Gallery = (function() { if (ImageCommon.isFromArchive(this)) { return; } - post = g.posts[this.dataset.post]; - file = post.files[this.dataset.file]; + post = g.posts.get(this.dataset.post); + file = post.files[+this.dataset.file]; return ImageCommon.error(this, post, file, null, (function(_this) { return function(url) { if (!url) { return; } - Gallery.images[_this.dataset.id].href = url; + Gallery.images[+_this.dataset.id].href = url; if (Gallery.nodes.current === _this) { return _this.src = url; } @@ -14742,7 +14805,7 @@ Gallery = (function() { var containerHeight, containerWidth, current, dim, frame, height, margin, minHeight, ref, ref1, ref2, ref3, style, width; ref = Gallery.nodes, current = ref.current, frame = ref.frame; style = current.style; - if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts[current.dataset.post]) != null ? ref1.file.dimensions : void 0)) { + if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts.get(current.dataset.post)) != null ? ref1.file.dimensions : void 0)) { ref2 = dim.split('x'), width = ref2[0], height = ref2[1]; containerWidth = frame.clientWidth; containerHeight = doc.clientHeight - 25; @@ -15812,7 +15875,7 @@ Metadata = (function() { $.rmClass(this.parentNode, 'error'); $.addClass(this.parentNode, 'loading'); index = this.parentNode.dataset.index; - return CrossOrigin.binary(Get.postFromNode(this).files[index].url, (function(_this) { + return CrossOrigin.binary(Get.postFromNode(this).files[+index].url, (function(_this) { return function(data) { var output, title; $.rmClass(_this.parentNode, 'loading'); @@ -15953,7 +16016,7 @@ Sauce = (function() { if (!(link = link.trim())) { return null; } - parts = {}; + parts = $.dict(); ref = link.split(/;(?=(?:text|boards|types|regexp|sandbox):?)/); for (i = j = 0, len = ref.length; j < len; i = ++j) { part = ref[i]; @@ -15986,7 +16049,7 @@ Sauce = (function() { createSauceLink: function(link, post, file) { var a, base, ext, j, key, len, matches, missing, parts, ref; ext = file.url.match(/[^.]*$/)[0]; - parts = {}; + parts = $.dict(); $.extend(parts, link); if (!(!parts['boards'] || parts['boards'][post.siteID + "/" + post.boardID] || parts['boards'][post.siteID + "/*"])) { return null; @@ -16291,7 +16354,7 @@ Embedding = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'archive') && Conf['Linkify'] && (Conf['Embedding'] || Conf['Link Title'] || Conf['Cover Preview']))) { return; } - this.types = {}; + this.types = $.dict(); ref1 = this.ordered_types; for (j = 0, len = ref1.length; j < len; j++) { type = ref1[j]; @@ -17382,7 +17445,7 @@ DeleteLink = (function() { var DeleteLink; DeleteLink = { - auto: [{}, {}], + auto: [$.dict(), $.dict()], init: function() { var div, fileEl, fileEntry, postEl, postEntry, ref; if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Menu'] && Conf['Delete Link'])) { @@ -17483,7 +17546,7 @@ DeleteLink = (function() { onlyimgdel: fileOnly, pwd: QR.persona.getPassword() }; - form[post.ID] = 'delete'; + form[+post.ID] = 'delete'; return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), { responseType: 'document', withCredentials: true, @@ -17531,7 +17594,7 @@ DeleteLink = (function() { } }, cooldown: { - seconds: {}, + seconds: $.dict(), start: function(post, seconds) { if (DeleteLink.cooldown.seconds[post.fullID] != null) { return; @@ -17887,7 +17950,7 @@ Banner = (function() { } } }, - original: {}, + original: $.dict(), custom: function(child) { var className, data, event, j, len, ref; className = child.className; @@ -18040,7 +18103,7 @@ CatalogLinks = (function() { }, externalParse: function() { var board, boards, excludes, i, len, line, ref, ref1, ref2, url; - CatalogLinks.externalList = {}; + CatalogLinks.externalList = $.dict(); ref = Conf['externalCatalogURLs'].split('\n'); for (i = 0, len = ref.length; i < len; i++) { line = ref[i]; @@ -18049,7 +18112,7 @@ CatalogLinks = (function() { } url = line.split(';')[0]; boards = Filter.parseBoards(((ref1 = line.match(/;boards:([^;]+)/)) != null ? ref1[1] : void 0) || '*'); - excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || {}; + excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || $.dict(); for (board in boards) { if (!(excludes[board] || excludes[board.split('/')[0] + '/*'])) { CatalogLinks.externalList[board] = url; @@ -18250,7 +18313,7 @@ ExpandThread = (function() { slice = [].slice; ExpandThread = { - statuses: {}, + statuses: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Thread Expansion'])) { return; @@ -18398,7 +18461,7 @@ ExpandThread = (function() { if (postData.no === thread.ID) { continue; } - if ((post = thread.posts[postData.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(postData.no)) && !post.isFetchedQuote) { if ('file' in post) { filesCount++; } @@ -18479,7 +18542,7 @@ FileInfo = (function() { var a, i, j, len, len1, output, ref, ref1; output = []; formatString.replace(/%(.)|[^%]+/g, function(s, c) { - output.push(c in FileInfo.formatters ? FileInfo.formatters[c].call(post) : { + output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : { innerHTML: E(s) }); return ''; @@ -18644,10 +18707,10 @@ Fourchan = (function() { if (g.BOARD.config.code_tags) { $.on(window, 'prettyprint:cb', function(e) { var post, pre; - if (!(post = g.posts[e.detail.ID])) { + if (!(post = g.posts.get(e.detail.ID))) { return; } - if (!(pre = $$('.prettyprint', post.nodes.comment)[e.detail.i])) { + if (!(pre = $$('.prettyprint', post.nodes.comment)[+e.detail.i])) { return; } if (!$.hasClass(pre, 'prettyprinted')) { @@ -18764,9 +18827,8 @@ IDColor = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Color User IDs'])) { return; } - this.ids = { - Heaven: [0, 0, 0, '#fff'] - }; + this.ids = $.dict(); + this.ids['Heaven'] = [0, 0, 0, '#fff']; return Callbacks.Post.push({ name: 'Color User IDs', cb: this.node @@ -19452,7 +19514,7 @@ ModContact = (function() { }, node: function() { var links, moveNote, moved; - if (this.isClone || !ModContact.specific[this.info.capcode]) { + if (this.isClone || !$.hasOwn(ModContact.specific, this.info.capcode)) { return; } links = $.el('span', { @@ -19460,7 +19522,7 @@ ModContact = (function() { }); $.extend(links, ModContact.template(this.info.capcode)); $.after(this.nodes.capcode, links); - if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && ModContact.moveNote[moved[1]]) { + if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && $.hasOwn(ModContact.moveNote, moved[1])) { moveNote = $.el('div', { className: 'move-note' }); @@ -19561,7 +19623,7 @@ Nav = (function() { getThread: function() { var i, len, ref, thread, threadRoot; if (g.VIEW === 'thread') { - return g.threads[g.BOARD + "." + g.THREADID].nodes.root; + return g.threads.get(g.BOARD + "." + g.THREADID).nodes.root; } if ($.hasClass(doc, 'catalog-mode')) { return; @@ -19953,7 +20015,7 @@ RelativeDates = (function() { if (indexOf.call(RelativeDates.stale, data) >= 0) { return; } - if (data instanceof Post && !g.posts[data.fullID]) { + if (data instanceof Post && !g.posts.get(data.fullID)) { return; } if (data instanceof Element && !doc.contains(data)) { @@ -20218,7 +20280,7 @@ Time = (function() { }, format: function(formatString, date) { return formatString.replace(/%(.)/g, function(s, c) { - if (c in Time.formatters) { + if ($.hasOwn(Time.formatters, c)) { return Time.formatters[c].call(date); } else { return s; @@ -20412,7 +20474,8 @@ Favicon = (function() { '4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAD/AABmZmYA/wBD99DBAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAAul8NnZ2f/AAD7B+mqAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAABmzDNmZmb/AAC8/wCMAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII='], Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'], 'Metro': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAC/AABrZQDiAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAC/AAD///8dAAApAABsAAAHAAA4AACQAAAsAABMCpCvAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAA1/GhpCidAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAAA1/H///8AISUALzQAeokACAkAQEcAorYAMTcE9WFNAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAABV/wErM5hwAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAABV/wH///8NKAASOAAwkQADCgAZTABAwQATOwC5e3VGAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII='] - }[Conf['favicon']]; + }; + items = $.getOwn(items, Conf['favicon']); f = Favicon; t = 'data:image/png;base64,'; i = 0; @@ -20470,13 +20533,13 @@ MarkNewIPs = (function() { i = MarkNewIPs.ipCount; for (j = 0, len = newPosts.length; j < len; j++) { fullID = newPosts[j]; - MarkNewIPs.markNew(g.posts[fullID], ++i); + MarkNewIPs.markNew(g.posts.get(fullID), ++i); } break; case -deletedPosts.length: for (k = 0, len1 = newPosts.length; k < len1; k++) { fullID = newPosts[k]; - MarkNewIPs.markOld(g.posts[fullID]); + MarkNewIPs.markOld(g.posts.get(fullID)); } } MarkNewIPs.ipCount = ipCount; @@ -20603,7 +20666,7 @@ ReplyPruning = (function() { for (i = 0, len = ref.length; i < len; i++) { fullID = ref[i]; ReplyPruning.total++; - if (g.posts[fullID].file) { + if (g.posts.get(fullID).file) { ReplyPruning.totalFiles++; } } @@ -20616,7 +20679,7 @@ ReplyPruning = (function() { posts = ReplyPruning.thread.posts; if (ReplyPruning.hidden < hidden2) { while (ReplyPruning.hidden < hidden2 && ReplyPruning.position < posts.keys.length) { - post = posts[posts.keys[ReplyPruning.position++]]; + post = posts.get(posts.keys[ReplyPruning.position++]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.summary.nextSibling) && node !== post.nodes.root) { $.add(ReplyPruning.container, node); @@ -20631,7 +20694,7 @@ ReplyPruning = (function() { } else if (ReplyPruning.hidden > hidden2) { frag = $.frag(); while (ReplyPruning.hidden > hidden2 && ReplyPruning.position > 0) { - post = posts[posts.keys[--ReplyPruning.position]]; + post = posts.get(posts.keys[--ReplyPruning.position]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.container.lastChild) && node !== post.nodes.root) { $.prepend(frag, node); @@ -20726,7 +20789,7 @@ ThreadStats = (function() { posts = ThreadStats.thread.posts; n = posts.keys.length; for (i = j = ref = ThreadStats.postIndex, ref1 = n; j < ref1; i = j += 1) { - post = posts[posts.keys[i]]; + post = posts.get(posts.keys[i]); if (!post.isFetchedQuote) { ThreadStats.postCount++; ThreadStats.fileCount += post.files.length; @@ -20831,7 +20894,7 @@ ThreadStats = (function() { } }, retry: function() { - if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts[ThreadStats.thread.lastPost].info.date > ThreadStats.lastPageUpdate)) { + if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts.get(ThreadStats.thread.lastPost).info.date > ThreadStats.lastPageUpdate)) { return; } clearTimeout(ThreadStats.timeout); @@ -21157,7 +21220,7 @@ ThreadUpdater = (function() { thread = ThreadUpdater.thread; board = thread.board; ref = ThreadUpdater.postIDs, lastPost = ref[ref.length - 1]; - if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts[lastPost].info.date < 30 * $.SECOND) { + if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts.get(lastPost).info.date < 30 * $.SECOND) { return; } g.SITE.Build.spoilerRange[board] = OP.custom_spoiler; @@ -21183,7 +21246,7 @@ ThreadUpdater = (function() { if (ID <= lastPost) { continue; } - if ((post = thread.posts[ID]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(ID)) && !post.isFetchedQuote) { post.resurrect(); continue; } @@ -21201,7 +21264,7 @@ ThreadUpdater = (function() { if (!(indexOf.call(index, ID) < 0)) { continue; } - thread.posts[ID].kill(); + thread.posts.get(ID).kill(); deletedPosts.push(board + "." + ID); } ThreadUpdater.postIDs = index; @@ -21212,7 +21275,7 @@ ThreadUpdater = (function() { if (!(!(indexOf.call(files, ID) >= 0 || (ref3 = board + "." + ID, indexOf.call(deletedPosts, ref3) >= 0)))) { continue; } - thread.posts[ID].kill(true); + thread.posts.get(ID).kill(true); deletedFiles.push(board + "." + ID); } ThreadUpdater.fileIDs = files; @@ -21517,7 +21580,7 @@ ThreadWatcher = (function() { return ThreadWatcher.addRaw(boardID, threadID, {}, cb); } } else if (Conf['Auto Watch Reply']) { - return ThreadWatcher.add(g.threads[boardID + '.' + threadID] || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); + return ThreadWatcher.add(g.threads.get(boardID + '.' + threadID) || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); } }, onIndexUpdate: function(e) { @@ -21571,7 +21634,7 @@ ThreadWatcher = (function() { }, onThreadRefresh: function(e) { var thread; - thread = g.threads[e.detail.threadID]; + thread = g.threads.get(e.detail.threadID); if (!(e.detail[404] && ThreadWatcher.isWatched(thread))) { return; } @@ -21634,7 +21697,7 @@ ThreadWatcher = (function() { }, initLastModified: function() { var base, boardID, boards, data, date, lm, ref, ref1, siteID, url; - lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = {})); + lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = $.dict())); ref = ThreadWatcher.dbLM.data; for (siteID in ref) { boards = ref[siteID]; @@ -21773,7 +21836,7 @@ ThreadWatcher = (function() { boardID: boardID, val: $.item(url, lmDate) }); - threads = {}; + threads = $.dict(); pageLength = 0; nThreads = 0; oldest = null; @@ -22056,7 +22119,7 @@ ThreadWatcher = (function() { }, setPrefixes: function(threads) { var conflicts, conflicts2, j, k, len, len1, len2, prefix, prefixes, siteID, siteID2; - prefixes = {}; + prefixes = $.dict(); for (j = 0, len1 = threads.length; j < len1; j++) { siteID = threads[j].siteID; if (siteID in prefixes) { @@ -22090,7 +22153,7 @@ ThreadWatcher = (function() { ThreadWatcher.setPrefixes(threads); for (j = 0, len1 = threads.length; j < len1; j++) { ref = threads[j], siteID = ref.siteID, boardID = ref.boardID, threadID = ref.threadID, data = ref.data; - if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads[boardID + "." + threadID]) && thread.OP) { + if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads.get(boardID + "." + threadID)) && thread.OP) { ThreadWatcher.db.extend({ boardID: boardID, threadID: threadID, @@ -22257,7 +22320,7 @@ ThreadWatcher = (function() { oldData = ThreadWatcher.db.get({ boardID: boardID, threadID: threadID, - defaultValue: {} + defaultValue: $.dict() }); delete oldData.last; delete oldData.modified; @@ -22325,7 +22388,7 @@ ThreadWatcher = (function() { } }); return $.on(entryEl, 'click', function() { - return ThreadWatcher.toggle(g.threads[g.BOARD + "." + g.THREADID]); + return ThreadWatcher.toggle(g.threads.get(g.BOARD + "." + g.THREADID)); }); }, addMenuEntries: function() { @@ -22548,7 +22611,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (ID > Unread.lastReadPost) { break; } @@ -22670,7 +22733,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (Unread.posts.has(ID)) { break; } @@ -22760,9 +22823,9 @@ UnreadIndex = (function() { var UnreadIndex; UnreadIndex = { - lastReadPost: {}, - hr: {}, - markReadLink: {}, + lastReadPost: $.dict(), + hr: $.dict(), + markReadLink: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Remember Last Read Post'] && Conf['Unread Line in Index'])) { return; @@ -22794,7 +22857,7 @@ UnreadIndex = (function() { results = []; for (i = 0, len = ref.length; i < len; i++) { threadID = ref[i]; - thread = g.threads[threadID]; + thread = g.threads.get(threadID); results.push(UnreadIndex.update(thread)); } return results; @@ -22922,14 +22985,10 @@ Captcha = {}; haveCookie: function() { return /\b_ct=/.test(d.cookie) && QR.posts[0].thread !== 'new'; }, - getOne: function(isReply) { - var captcha, i; + getOne: function() { + var captcha; this.clear(); - i = this.captchas.findIndex(function(x) { - return isReply || (x.challenge == null); - }); - if (i >= 0) { - captcha = this.captchas.splice(i, 1)[0]; + if ((captcha = this.captchas.shift())) { this.count(); return captcha; } else { @@ -23186,12 +23245,12 @@ Captcha = {}; } else if (n !== 9 && (i = this.imageKeys16.indexOf(key)) >= 0 && i % 4 < w && (img = this.images[n - (4 - Math.floor(i / 4)) * w + (i % 4)])) { img.click(); verify.focus(); - } else if (dx = { + } else if (dx = $.getOwn({ 'Up': n, 'Down': w, 'Left': last, 'Right': 1 - }[key]) { + }, key)) { x = (x + dx) % (n + w); if ((n < x && x < last)) { x = dx === last ? n : last; @@ -23310,7 +23369,6 @@ Captcha = {}; } }, requestCaptcha: function(e) { - var key, url; if (!this.isEnabled()) { return; } @@ -23327,6 +23385,10 @@ Captcha = {}; this.pending = true; this.aborted = false; e.preventDefault(); + return CrossOrigin.permission(this.requestCaptcha2.bind(this), this.noCaptcha.bind(this, 'Permission denied'), [Conf['captchaServiceDomain'] + "/*"]); + }, + requestCaptcha2: function() { + var key, url; key = Conf['captchaServiceKey'][Conf['captchaServiceDomain']]; if (!(key && /\S/.test(key))) { return this.noCaptcha('API key not set'); @@ -23384,7 +23446,7 @@ Captcha = {}; if (this.aborted) { return; } - error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'; + error || (error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'); error = "Failed to retrieve captcha: " + error; return $.event('NoCaptcha', { error: error @@ -23927,7 +23989,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { return QR.abort(); } else { return QR.status(); @@ -24114,7 +24176,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { value = 'Dead'; disabled = true; QR.cooldown.auto = false; @@ -24303,7 +24365,7 @@ QR = (function() { blob = new Blob([file], { type: type }); - blob.name = Conf['pastedname'] + "." + (QR.extensionFromType[type] || 'jpg'); + blob.name = Conf['pastedname'] + "." + ($.getOwn(QR.extensionFromType, type) || 'jpg'); QR.open(); QR.handleFiles([blob]); $.addClass(QR.nodes.el, 'dump'); @@ -24612,7 +24674,7 @@ QR = (function() { post = QR.posts[0]; post.forceSave(); threadID = post.thread; - thread = g.BOARD.threads[threadID]; + thread = g.BOARD.threads.get(threadID); if (g.BOARD.ID === 'f' && threadID === 'new') { filetag = QR.nodes.flashTag.value; } @@ -24623,7 +24685,7 @@ QR = (function() { } else if (!(!!g.BOARD.config.text_only || post.file)) { err = 'No file selected.'; } - } else if (g.BOARD.threads[threadID].isClosed) { + } else if (g.BOARD.threads.get(threadID).isClosed) { err = 'You can\'t reply to this thread anymore.'; } else if (!(post.com || post.file)) { err = 'No comment or file.'; @@ -24889,7 +24951,7 @@ QR = (function() { return; } this.data = Conf['cooldowns']; - this.changes = {}; + this.changes = $.dict(); return $.sync('cooldowns', this.sync); }, setup: function() { @@ -24916,7 +24978,7 @@ QR = (function() { return QR.cooldown.count(); }, sync: function(data) { - QR.cooldown.data = data || {}; + QR.cooldown.data = data || $.dict(); return QR.cooldown.start(); }, add: function(threadID, postID) { @@ -24967,7 +25029,7 @@ QR = (function() { if (!QR.cooldown.data) { return; } - cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = {})); + cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = $.dict())); for (id in cooldowns) { cooldown = cooldowns[id]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -24981,7 +25043,7 @@ QR = (function() { if (!(QR.cooldown.data && Conf['Cooldown'])) { return 0; } - cooldowns = QR.cooldown.data[post.board.ID] || {}; + cooldowns = QR.cooldown.data[post.board.ID] || $.dict(); for (start in cooldowns) { cooldown = cooldowns[start]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -25005,7 +25067,7 @@ QR = (function() { }, mergeChange: function(data, scope, id, value) { if (value) { - return (data[scope] || (data[scope] = {}))[id] = value; + return (data[scope] || (data[scope] = $.dict()))[id] = value; } else if (scope in data) { delete data[scope][id]; if (Object.keys(data[scope]).length === 0) { @@ -25016,7 +25078,7 @@ QR = (function() { set: function(scope, id, value) { var base; QR.cooldown.mergeChange(QR.cooldown.data, scope, id, value); - return ((base = QR.cooldown.changes)[scope] || (base[scope] = {}))[id] = value; + return ((base = QR.cooldown.changes)[scope] || (base[scope] = $.dict()))[id] = value; }, save: function() { var changes; @@ -25024,7 +25086,7 @@ QR = (function() { if (!Object.keys(changes).length) { return; } - return $.get('cooldowns', {}, function(arg) { + return $.get('cooldowns', $.dict(), function(arg) { var cooldowns, id, ref, scope, value; cooldowns = arg.cooldowns; for (scope in QR.cooldown.changes) { @@ -25036,7 +25098,7 @@ QR = (function() { QR.cooldown.data = cooldowns; } return $.set('cooldowns', cooldowns, function() { - return QR.cooldown.changes = {}; + return QR.cooldown.changes = $.dict(); }); }); }, @@ -25054,7 +25116,7 @@ QR = (function() { ref1 = [g.BOARD.ID, 'global']; for (i = 0, len = ref1.length; i < len; i++) { scope = ref1[i]; - cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = {})); + cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = $.dict())); for (start in cooldowns) { cooldown = cooldowns[start]; start = +start; @@ -25606,6 +25668,9 @@ QR = (function() { return; } name = input.dataset.name; + if (name !== 'thread' && name !== 'name' && name !== 'email' && name !== 'sub' && name !== 'com' && name !== 'filename' && name !== 'flag') { + return; + } prev = this[name]; this[name] = input.value || input.dataset["default"] || null; switch (name) { @@ -25927,7 +25992,7 @@ QR = (function() { _Class.prototype.saveFilename = function() { this.file.newName = (this.filename || '').replace(/[\/\\]/g, '-'); if (!QR.validExtension.test(this.filename)) { - return this.file.newName += "." + (QR.extensionFromType[this.file.type] || 'jpg'); + return this.file.newName += "." + ($.getOwn(QR.extensionFromType, this.file.type) || 'jpg'); } }; @@ -26031,7 +26096,7 @@ QuoteBacklink = (function() { var QuoteBacklink; QuoteBacklink = { - containers: {}, + containers: $.dict(), init: function() { var ref; if (((ref = g.VIEW) !== 'index' && ref !== 'thread') || !Conf['Quote Backlinks']) { @@ -26074,7 +26139,7 @@ QuoteBacklink = (function() { for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; containers = [QuoteBacklink.getContainer(quote)]; - if ((post = g.posts[quote]) && post.nodes.backlinkContainer) { + if ((post = g.posts.get(quote)) && post.nodes.backlinkContainer) { ref1 = post.clones; for (j = 0, len1 = ref1.length; j < len1; j++) { clone = ref1[j]; @@ -26230,7 +26295,7 @@ QuoteInline = (function() { return; } ref = Get.postDataFromLink(this), boardID = ref.boardID, threadID = ref.threadID, postID = ref.postID; - if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts[boardID + "." + postID]) != null ? ref1.nodes.root.offsetParent : void 0)) { + if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts.get(boardID + "." + postID)) != null ? ref1.nodes.root.offsetParent : void 0)) { return; } if ($.hasClass(doc, 'catalog-mode')) { @@ -26268,7 +26333,7 @@ QuoteInline = (function() { qroot = $.x('ancestor::*[contains(@class,"postContainer")][1]', root); $.addClass(qroot, 'hasInline'); new Fetcher(boardID, threadID, postID, inline, quoter); - if (!((post = g.posts[boardID + "." + postID]) && context.thread === post.thread)) { + if (!((post = g.posts.get(boardID + "." + postID)) && context.thread === post.thread)) { return; } if (isBacklink && Conf['Forward Hiding']) { @@ -26295,9 +26360,9 @@ QuoteInline = (function() { if (!(el = root.firstElementChild)) { return; } - post = g.posts[boardID + "." + postID]; + post = g.posts.get(boardID + "." + postID); post.rmClone(el.dataset.clone); - if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads[boardID + "." + threadID] && !--post.forwarded) { + if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads.get(boardID + "." + threadID) && !--post.forwarded) { delete post.forwarded; $.rmClass(post.nodes.root, 'forwarded'); } @@ -26423,7 +26488,7 @@ QuotePreview = (function() { endEvents: 'mouseout click', cb: QuotePreview.mouseout }); - if (Conf['Quote Highlighting'] && (origin = g.posts[boardID + "." + postID])) { + if (Conf['Quote Highlighting'] && (origin = g.posts.get(boardID + "." + postID))) { posts = [origin].concat(origin.clones); posts.pop(); for (i = 0, len = posts.length; i < len; i++) { @@ -26479,7 +26544,7 @@ QuoteStrikeThrough = (function() { for (i = 0, len = ref.length; i < len; i++) { quotelink = ref[i]; ref1 = Get.postDataFromLink(quotelink), boardID = ref1.boardID, postID = ref1.postID; - if ((ref2 = g.posts[boardID + "." + postID]) != null ? ref2.isHidden : void 0) { + if ((ref2 = g.posts.get(boardID + "." + postID)) != null ? ref2.isHidden : void 0) { $.addClass(quotelink, 'filtered'); } } @@ -26536,9 +26601,9 @@ QuoteThreading = cb: this.node }); }, - parent: {}, - children: {}, - inserted: {}, + parent: $.dict(), + children: $.dict(), + inserted: $.dict(), toggleThreading: function() { return this.setThreadingState(!Conf['Thread Quotes']); }, @@ -26580,7 +26645,7 @@ QuoteThreading = ref = this.quotes; for (j = 0, len = ref.length; j < len; j++) { quote = ref[j]; - if (parent = g.posts[quote]) { + if (parent = g.posts.get(quote)) { if (!parent.isFetchedQuote && parent.isReply && parent.ID < this.ID) { parents.add(parent.ID); if (!lastParent || parent.ID > lastParent.ID) { @@ -26688,7 +26753,7 @@ QuoteThreading = } else { nodes = []; Unread.order = new RandomAccessList(); - QuoteThreading.inserted = {}; + QuoteThreading.inserted = $.dict(); posts.forEach(function(post) { if (post.isFetchedQuote) { return; @@ -26990,7 +27055,7 @@ Quotify = (function() { } boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID; quoteID = boardID + "." + postID; - if (post = g.posts[quoteID]) { + if (post = g.posts.get(quoteID)) { if (!post.isDead) { a = $.el('a', { href: g.SITE.Build.postURL(boardID, post.thread.ID, postID), @@ -27119,7 +27184,7 @@ Main = (function() { flatten = function(parent, obj) { var key, val; if (obj instanceof Array) { - Conf[parent] = obj[0]; + Conf[parent] = $.dict.clone(obj[0]); } else if (typeof obj === 'object') { for (key in obj) { val = obj[key]; @@ -27150,9 +27215,9 @@ Main = (function() { ref2 = DataBoard.keys; for (j = 0, len = ref2.length; j < len; j++) { db = ref2[j]; - Conf[db] = {}; + Conf[db] = $.dict(); } - Conf['customTitles'] = { + Conf['customTitles'] = $.dict.clone({ '4chan.org': { boards: { 'qa': { @@ -27163,18 +27228,18 @@ Main = (function() { } } } - }; + }); Conf['boardConfig'] = { - boards: {} + boards: $.dict() }; Conf['archives'] = Redirect.archives; - Conf['selectedArchives'] = {}; - Conf['cooldowns'] = {}; - Conf['Index Sort'] = {}; + Conf['selectedArchives'] = $.dict(); + Conf['cooldowns'] = $.dict(); + Conf['Index Sort'] = $.dict(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = {}; + Conf["Last Long Reply Thresholds " + i] = $.dict(); } - Conf['siteProperties'] = {}; + Conf['siteProperties'] = $.dict(); Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; @@ -27195,7 +27260,7 @@ Main = (function() { return $.addCSP("script-src " + (jsWhitelist.replace(/^#.*$/mg, '').replace(/[\s;]+/g, ' ').trim())); }); } - items = {}; + items = $.dict(); for (key in Conf) { items[key] = void 0; } @@ -27535,7 +27600,7 @@ Main = (function() { threadRoot = threadRoots[j]; boardObj = (boardID = threadRoot.dataset.board) ? (boardID = encodeURIComponent(boardID), g.boards[boardID] || new Board(boardID)) : g.BOARD; threadID = +threadRoot.id.match(/\d*$/)[0]; - if (!threadID || ((ref = boardObj.threads[threadID]) != null ? ref.nodes.root : void 0)) { + if (!threadID || ((ref = boardObj.threads.get(threadID)) != null ? ref.nodes.root : void 0)) { return; } thread = new Thread(threadID, boardObj); diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx index 8391086f9..28a046201 100644 Binary files a/builds/4chan-X.crx and b/builds/4chan-X.crx differ diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js index 186d1f2dc..dd50574b9 100644 --- a/builds/4chan-X.meta.js +++ b/builds/4chan-X.meta.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.14.11.0 +// @version 1.14.11.1 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 122b71282..5b6e4f0fb 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan X -// @version 1.14.11.0 +// @version 1.14.11.1 // @minGMVer 1.14 // @minFFVer 26 // @namespace 4chan-X @@ -188,7 +188,7 @@ var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, CSS var Conf, E, c, d, doc, docSet, g; -Conf = {}; +Conf = Object.create(null); c = console; d = document; doc = d.documentElement; @@ -199,10 +199,10 @@ docSet = function() { }; g = { - VERSION: '1.14.11.0', + VERSION: '1.14.11.1', NAMESPACE: '4chan X.', - sites: {}, - boards: {} + sites: Object.create(null), + boards: Object.create(null) }; E = (function() { @@ -4687,7 +4687,7 @@ sub: function(css) { var sel = variables; for (var i = 0; i < words.length; i++) { if (typeof sel !== 'object') return ':not(*)'; - sel = sel[words[i]]; + sel = $.getOwn(sel, words[i]); } if (typeof sel !== 'string') return ':not(*)'; return sel; @@ -4754,6 +4754,46 @@ $ = (function() { } }; + $.dict = function() { + return Object.create(null); + }; + + $.dict.clone = function(obj) { + var arr, i, j, key, map, ref, val; + if (typeof obj !== 'object' || obj === null) { + return obj; + } else if (obj instanceof Array) { + arr = []; + for (i = j = 0, ref = obj.length; j < ref; i = j += 1) { + arr.push($.dict.clone(obj[i])); + } + return arr; + } else { + map = Object.create(null); + for (key in obj) { + val = obj[key]; + map[key] = $.dict.clone(val); + } + return map; + } + }; + + $.dict.json = function(str) { + return $.dict.clone(JSON.parse(str)); + }; + + $.hasOwn = function(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + }; + + $.getOwn = function(obj, key) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + return obj[key]; + } else { + return void 0; + } + }; + $.ajax = (function() { var pageXHR; if (window.wrappedJSObject && !XMLHttpRequest.wrappedJSObject) { @@ -4808,7 +4848,7 @@ $ = (function() { }; })(); - $.lastModified = {}; + $.lastModified = $.dict(); $.whenModified = function(url, bucket, cb, options) { var ajax, headers, params, r, ref, t, timeout, url0; @@ -4827,14 +4867,14 @@ $ = (function() { if (params.length) { url += '?' + params.join('&'); } - headers = {}; + headers = $.dict(); if ((t = (ref = $.lastModified[bucket]) != null ? ref[url0] : void 0) != null) { headers['If-Modified-Since'] = t; } r = (ajax || $.ajax)(url, { onloadend: function() { var base; - ((base = $.lastModified)[bucket] || (base[bucket] = {}))[url0] = this.getResponseHeader('Last-Modified'); + ((base = $.lastModified)[bucket] || (base[bucket] = $.dict()))[url0] = this.getResponseHeader('Last-Modified'); return cb.call(this); }, timeout: timeout, @@ -4845,7 +4885,7 @@ $ = (function() { (function() { var reqs; - reqs = {}; + reqs = $.dict(); $.cache = function(url, cb, options) { var ajax, onloadend, req; if (options == null) { @@ -4903,12 +4943,16 @@ $ = (function() { $.cb = { checked: function() { - $.set(this.name, this.checked); - return Conf[this.name] = this.checked; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.checked); + return Conf[this.name] = this.checked; + } }, value: function() { - $.set(this.name, this.value.trim()); - return Conf[this.name] = this.value; + if ($.hasOwn(Conf, this.name)) { + $.set(this.name, this.value.trim()); + return Conf[this.name] = this.value; + } } }; @@ -5281,11 +5325,11 @@ $ = (function() { $.hasStorage = (function() { try { - if (localStorage[g.NAMESPACE + 'hasStorage'] === 'true') { + if (localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true') { return true; } - localStorage[g.NAMESPACE + 'hasStorage'] = 'true'; - return localStorage[g.NAMESPACE + 'hasStorage'] === 'true'; + localStorage.setItem(g.NAMESPACE + 'hasStorage', 'true'); + return localStorage.getItem(g.NAMESPACE + 'hasStorage') === 'true'; } catch (error) { return false; } @@ -5293,7 +5337,7 @@ $ = (function() { $.item = function(key, val) { var item; - item = {}; + item = $.dict(); item[key] = val; return item; }; @@ -5308,7 +5352,7 @@ $ = (function() { }; }; - $.syncing = {}; + $.syncing = $.dict(); $.securityCheck = function(data) { if (location.protocol !== 'https:') { @@ -5325,7 +5369,7 @@ $ = (function() { for (key in ref) { val = ref[key]; if ((cb = $.syncing[key])) { - results.push(cb(JSON.parse(JSON.stringify(val)), key)); + results.push(cb($.dict.json(JSON.stringify(val)), key)); } } return results; @@ -5349,7 +5393,7 @@ $ = (function() { return results; })()).then(function() { var items, j, key, len; - items = {}; + items = $.dict(); for (j = 0, len = keys.length; j < len; j++) { key = keys[j]; items[key] = void 0; @@ -5374,7 +5418,7 @@ $ = (function() { for (i = j = 0, len = values.length; j < len; i = ++j) { val = values[i]; if (val) { - items[keys[i]] = JSON.parse(val); + items[keys[i]] = $.dict.json(val); } } return cb(items); @@ -5416,7 +5460,7 @@ $ = (function() { }; } else if ($.hasStorage) { $.getValue = function(key) { - return localStorage[key]; + return localStorage.getItem(key); }; $.listValues = function() { var key, results; @@ -5438,13 +5482,13 @@ $ = (function() { $.setValue = GM_setValue; $.deleteValue = GM_deleteValue; } else if (typeof GM_deleteValue !== "undefined" && GM_deleteValue !== null) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { GM_setValue(key, val); if (key in $.syncing) { $.oldValue[key] = val; if ($.hasStorage) { - return localStorage[key] = val; + return localStorage.setItem(key, val); } } }; @@ -5461,12 +5505,12 @@ $ = (function() { $.cantSync = true; } } else if ($.hasStorage) { - $.oldValue = {}; + $.oldValue = $.dict(); $.setValue = function(key, val) { if (key in $.syncing) { $.oldValue[key] = val; } - return localStorage[key] = val; + return localStorage.setItem(key, val); }; $.deleteValue = function(key) { if (key in $.syncing) { @@ -5484,7 +5528,7 @@ $ = (function() { return $.syncing[key] = GM_addValueChangeListener(g.NAMESPACE + key, function(key2, oldValue, newValue, remote) { if (remote) { if (newValue !== void 0) { - newValue = JSON.parse(newValue); + newValue = $.dict.json(newValue); } return cb(newValue, key); } @@ -5510,7 +5554,7 @@ $ = (function() { return; } $.oldValue[key] = newValue; - return cb(JSON.parse(newValue), key.slice(g.NAMESPACE.length)); + return cb($.dict.json(newValue), key.slice(g.NAMESPACE.length)); } else { if ($.oldValue[key] == null) { return; @@ -5550,7 +5594,7 @@ $ = (function() { for (key in items) { if ((val2 = $.getValue(g.NAMESPACE + key))) { try { - items[key] = JSON.parse(val2); + items[key] = $.dict.json(val2); } catch (error) { err = error; if (!/^(?:undefined)*$/.test(val2)) { @@ -5610,7 +5654,7 @@ CrossOrigin = (function() { binary: function(url, cb, headers) { var fallback, gmOptions; if (headers == null) { - headers = {}; + headers = $.dict(); } url = url.replace(/^((?:https?:)?\/\/(?:\w+\.)?(?:4chan|4channel|4cdn)\.org)\/adv\//, '$1//adv/'); fallback = function() { @@ -5679,7 +5723,7 @@ CrossOrigin = (function() { name = match.replace(/\\"/g, '"'); } if (/^text\/plain;\s*charset=x-user-defined$/i.test(mime)) { - mime = QR.typeFromExtension[name.match(/[^.]*$/)[0].toLowerCase()] || 'application/octet-stream'; + mime = $.getOwn(QR.typeFromExtension, name.match(/[^.]*$/)[0].toLowerCase()) || 'application/octet-stream'; } blob = new Blob([data], { type: mime @@ -5700,9 +5744,9 @@ CrossOrigin = (function() { Request.prototype.responseHeaderString = null; Request.prototype.getResponseHeader = function(headerName) { - var header, i, j, key, len, ref, ref1, val; + var header, i, j, key, len, ref, ref1, ref2, val; if ((this.responseHeaders == null) && (this.responseHeaderString != null)) { - this.responseHeaders = {}; + this.responseHeaders = $.dict(); ref = this.responseHeaderString.split('\r\n'); for (j = 0, len = ref.length; j < len; j++) { header = ref[j]; @@ -5713,7 +5757,7 @@ CrossOrigin = (function() { } } } - return (ref1 = (this.responseHeaders || {})[headerName.toLowerCase()]) != null ? ref1 : null; + return (ref1 = (ref2 = this.responseHeaders) != null ? ref2[headerName.toLowerCase()] : void 0) != null ? ref1 : null; }; Request.prototype.abort = function() {}; @@ -5971,7 +6015,7 @@ CatalogThreadNative = (function() { this.boardID = this.nodes.thumb.parentNode.pathname.split(/\/+/)[1]; this.board = g.boards[this.boardID] || new Board(this.boardID); this.ID = this.threadID = +(root.dataset.id || root.id).match(/\d*$/)[0]; - this.thread = this.board.threads[this.ID] || new Thread(this.ID, this.board); + this.thread = this.board.threads.get(this.ID) || new Thread(this.ID, this.board); } return CatalogThreadNative; @@ -6009,15 +6053,15 @@ Connection = (function() { }; Connection.prototype.onMessage = function(e) { - var base, data, type, value; + var data, type, value; if (!(e.source === this.targetWindow() && e.origin === this.origin && typeof e.data === 'string' && e.data.slice(0, g.NAMESPACE.length) === g.NAMESPACE)) { return; } data = JSON.parse(e.data.slice(g.NAMESPACE.length)); for (type in data) { value = data[type]; - if (typeof (base = this.cb)[type] === "function") { - base[type](value); + if ($.hasOwn(this.cb, type)) { + this.cb[type](value); } } }; @@ -6071,7 +6115,7 @@ DataBoard = (function() { delete this.data.lastChecked; } return (base = this.data)[name = g.SITE.ID] || (base[name] = { - boards: {} + boards: $.dict() }); }; @@ -6081,7 +6125,7 @@ DataBoard = (function() { change(); this.changes.push(change); return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var i, len, needSync, ref; @@ -6113,7 +6157,7 @@ DataBoard = (function() { DataBoard.prototype.forceSync = function(cb) { return $.get(this.key, { - boards: {} + boards: $.dict() }, (function(_this) { return function(items) { var change, i, len, ref; @@ -6201,12 +6245,12 @@ DataBoard = (function() { siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, postID = arg.postID, val = arg.val; siteID || (siteID = g.SITE.ID); (base = this.data)[siteID] || (base[siteID] = { - boards: {} + boards: $.dict() }); if (postID !== void 0) { - return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = {})))[threadID] || (base1[threadID] = {}))[postID] = val; + return ((base1 = ((base2 = this.data[siteID].boards)[boardID] || (base2[boardID] = $.dict())))[threadID] || (base1[threadID] = $.dict()))[postID] = val; } else if (threadID !== void 0) { - return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = {}))[threadID] = val; + return ((base3 = this.data[siteID].boards)[boardID] || (base3[boardID] = $.dict()))[threadID] = val; } else { return this.data[siteID].boards[boardID] = val; } @@ -6223,7 +6267,7 @@ DataBoard = (function() { boardID: boardID, threadID: threadID, postID: postID, - defaultValue: {} + defaultValue: $.dict() }); for (key in val) { subVal = val[key]; @@ -6338,7 +6382,7 @@ DataBoard = (function() { if (!(board = this.data[siteID].boards[boardID])) { return; } - threads = {}; + threads = $.dict(); if (response1) { for (i = 0, len = response1.length; i < len; i++) { page = response1[i]; @@ -6396,11 +6440,11 @@ Fetcher = (function() { this.postID = postID1; this.root = root; this.quoter = quoter; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } - if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads[this.boardID + "." + this.threadID])) { + if ((post = (ref = Index.replyData) != null ? ref[this.boardID + "." + this.postID] : void 0) && (thread = g.threads.get(this.boardID + "." + this.threadID))) { board = g.boards[this.boardID]; post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true @@ -6459,7 +6503,7 @@ Fetcher = (function() { Fetcher.prototype.fetchedPost = function(req, isCached) { var api, board, k, len, post, posts, status, that, thread; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6503,7 +6547,7 @@ Fetcher = (function() { return; } board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.postFromObject(post, this.boardID), thread, board, { isFetchedQuote: true }); @@ -6532,7 +6576,7 @@ Fetcher = (function() { media = this.response.media; for (key in media) { if (/_link$/.test(key)) { - if (!((ref1 = media[key]) != null ? ref1.match(/^http:\/\//) : void 0)) { + if (!((ref1 = $.getOwn(media, key)) != null ? ref1.match(/^http:\/\//) : void 0)) { delete media[key]; } } @@ -6547,7 +6591,7 @@ Fetcher = (function() { Fetcher.prototype.parseArchivedPost = function(data, url, archive) { var board, comment, greentext, i, j, media_link, o, post, ref, tag, text, text2, thread, thumb_link; - if (post = g.posts[this.boardID + "." + this.postID]) { + if (post = g.posts.get(this.boardID + "." + this.postID)) { this.insert(post); return; } @@ -6675,8 +6719,9 @@ Fetcher = (function() { o.file.tag = JSON.parse(data.media.exif).Tag; } } + o.extra = $.dict(); board = g.boards[this.boardID] || new Board(this.boardID); - thread = g.threads[this.boardID + "." + this.threadID] || new Thread(this.threadID, board); + thread = g.threads.get(this.boardID + "." + this.threadID) || new Thread(this.threadID, board); post = new Post(g.SITE.Build.post(o), thread, board, { isFetchedQuote: true }); @@ -6892,9 +6937,9 @@ Post = (function() { this.isDead = false; this.isHidden = false; this.clones = []; - if (g.posts[this.fullID]) { + if (g.posts.get(this.fullID)) { this.isRebuilt = true; - this.clones = g.posts[this.fullID].clones; + this.clones = g.posts.get(this.fullID).clones; ref14 = this.clones; for (k = 0, len1 = ref14.length; k < len1; k++) { clone = ref14[k]; @@ -7463,7 +7508,7 @@ ShimSet = (function() { ShimSet = (function() { function ShimSet() { - this.elements = {}; + this.elements = $.dict(); this.size = 0; } @@ -7534,6 +7579,14 @@ SimpleDict = (function() { } }; + SimpleDict.prototype.get = function(key) { + if (key === 'keys') { + return void 0; + } else { + return $.getOwn(this, key); + } + }; + return SimpleDict; })(); @@ -7551,8 +7604,8 @@ Thread = (function() { }; function Thread(ID, board) { - this.ID = ID; this.board = board; + this.ID = +ID; this.threadID = this.ID; this.boardID = this.board.ID; this.siteID = g.SITE.ID; @@ -7694,7 +7747,7 @@ SW = {}; for (j = 0, len = ref.length; j < len; j++) { script = ref[j]; if ((m = script.textContent.match(/\bvar configRoot=(".*?")/))) { - properties = {}; + properties = $.dict(); try { root = JSON.parse(m[1]); if (root[0] === '/') { @@ -8288,7 +8341,7 @@ SW = {}; Build = { staticPath: '//s.4cdn.org/image/', gifIcon: window.devicePixelRatio >= 2 ? '@2x.gif' : '.gif', - spoilerRange: {}, + spoilerRange: $.dict(), shortFilename: function(filename) { var ext; ext = filename.match(/\.?[^\.]*$/)[0]; @@ -8368,9 +8421,10 @@ SW = {}; }); o.files.push(o.file); } + o.extra = $.dict(); for (key in data) { if (key[0] === 'x') { - o[key] = data[key]; + o.extra[key] = data[key]; } } return o; @@ -8443,10 +8497,10 @@ SW = {}; capcodePlural = 'Verified Users'; capcodeDescription = ''; } else { - capcodeLong = { + capcodeLong = $.getOwn({ 'Admin': 'Administrator', 'Mod': 'Moderator' - }[capcode] || capcode; + }, capcode) || capcode; capcodePlural = capcodeLong + "s"; capcodeDescription = "a 4chan " + capcodeLong; } @@ -8455,7 +8509,7 @@ SW = {}; postLink = url + "#p" + ID; quoteLink = Build.sameThread(boardID, threadID) ? "javascript:quote('" + (+ID) + "');" : url + "#q" + ID; postInfo = { - innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.xa19s) ? " " + E(o.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.xa19l && o.isReply) ? " Like! ×" + E(o.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" + innerHTML: "
" + ((!o.isReply || boardID === "f" || subject) ? "" + E(subject || "") + " " : "") + "" + ((email) ? "" : "") + "" + E(name) + "" + ((tripcode) ? " " + E(tripcode) + "" : "") + ((o.extra.xa19s) ? " " + E(o.extra.xa19s) + "" : "") + ((pass) ? " " : "") + ((capcode) ? " ## " + E(capcode) + "" : "") + ((email) ? "" : "") + ((boardID === "f" && !o.isReply || capcodeDescription) ? "" : " ") + ((capcodeDescription) ? " \""" : "") + ((uniqueID && !capcode) ? " (ID: " + E(uniqueID) + ")" : "") + ((flagCode) ? " " : "") + ((flagCodeTroll) ? " \""" : "") + " " + E(dateText) + " No." + E(ID) + "" + ((o.extra.xa19l && o.isReply) ? " Like! ×" + E(o.extra.xa19l) + "" : "") + ((o.isSticky) ? " \"Sticky\"" : "") + ((o.isClosed && !o.isArchived) ? " \"Closed\"" : "") + ((o.isArchived) ? " \"Archived\"" : "") + ((!o.isReply && g.VIEW === "index") ? "   [Reply]" : "") + "
" }; /* File Info */ @@ -8636,7 +8690,7 @@ Site = (function() { var hostname; $.extend(Conf['siteProperties'], Site.defaultProperties); hostname = Site.resolve(); - if (hostname && Conf['siteProperties'][hostname].software in SW) { + if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) { this.set(hostname); cb(); } @@ -8649,7 +8703,7 @@ Site = (function() { } changes.software = software; hostname = location.hostname.replace(/^www\./, ''); - properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = {})); + properties = ((base1 = Conf['siteProperties'])[hostname] || (base1[hostname] = $.dict())); changed = 0; for (key in changes) { if (!(properties[key] !== changes[key])) { @@ -8676,7 +8730,7 @@ Site = (function() { url = location; } hostname = url.hostname; - while (hostname && !(hostname in Conf['siteProperties'])) { + while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) { hostname = hostname.replace(/^[^.]*\.?/, ''); } if (hostname) { @@ -8700,7 +8754,7 @@ Site = (function() { continue; } software = properties.software; - if (!(software && SW[software])) { + if (!(software && $.hasOwn(SW, software))) { continue; } g.sites[ID] = site = Object.create(SW[software]); @@ -8750,11 +8804,11 @@ Redirect = (function() { selectArchives: function() { var archive, archives, boardID, boards, data, files, id, j, k, key, l, len, len1, len2, name, o, record, ref, ref1, ref2, software, type, uid; o = { - thread: {}, - post: {}, - file: {} + thread: $.dict(), + post: $.dict(), + file: $.dict() }; - archives = {}; + archives = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { data = ref[j]; @@ -8788,7 +8842,7 @@ Redirect = (function() { record = ref2[boardID]; for (type in record) { id = record[type]; - if (!((archive = archives[JSON.stringify(id)]))) { + if (!((archive = archives[JSON.stringify(id)]) && $.hasOwn(o, type))) { continue; } boards = type === 'file' ? archive.files : archive.boards; @@ -8863,7 +8917,7 @@ Redirect = (function() { parse: function(responses, cb) { var archiveUIDs, archives, data, items, j, k, len, len1, ref, response, uid; archives = []; - archiveUIDs = {}; + archiveUIDs = $.dict(); for (j = 0, len = responses.length; j < len; j++) { response = responses[j]; for (k = 0, len1 = response.length; k < len1; k++) { @@ -8872,7 +8926,7 @@ Redirect = (function() { if (uid in archiveUIDs) { $.extend(archiveUIDs[uid], data); } else { - archiveUIDs[uid] = data; + archiveUIDs[uid] = $.dict.clone(data); archives.push(data); } } @@ -8897,7 +8951,7 @@ Redirect = (function() { protocol: function(archive) { var protocol; protocol = location.protocol; - if (!archive[protocol.slice(0, -1)]) { + if (!$.getOwn(archive, protocol.slice(0, -1))) { protocol = protocol === 'https:' ? 'http:' : 'https:'; } return protocol + "//"; @@ -8949,10 +9003,10 @@ Redirect = (function() { boardID = arg.boardID, type = arg.type, value = arg.value; type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type; if (type === 'capcode') { - value = { + value = $.getOwn({ 'Developer': 'dev', 'Verified': 'ver' - }[value] || value.toLowerCase(); + }, value) || value.toLowerCase(); } else if (type === 'image') { value = value.replace(/[+\/=]/g, function(c) { return { @@ -9022,8 +9076,8 @@ Filter = (function() { slice = [].slice; Filter = { - filters: {}, - results: {}, + filters: $.dict(), + results: $.dict(), init: function() { var base, base1, boards, err, excludes, file, filter, hide, hl, i, isstring, j, key, len, len1, line, mask, noti, op, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, regexp, stub, top, type, types; if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'catalog') && Conf['Filter'])) { @@ -9060,15 +9114,15 @@ Filter = (function() { } } op = ((ref4 = filter.match(/(?:^|;)\s*op:(no|only)/)) != null ? ref4[1] : void 0) || ''; - mask = { + mask = $.getOwn({ 'no': 1, 'only': 2 - }[op] || 0; + }, op) || 0; file = ((ref5 = filter.match(/(?:^|;)\s*file:(no|only)/)) != null ? ref5[1] : void 0) || ''; - mask = mask | ({ + mask = mask | ($.getOwn({ 'no': 4, 'only': 8 - }[file] || 0); + }, file) || 0); stub = (function() { var ref6; switch ((ref6 = filter.match(/(?:^|;)\s*stub:(yes|no)/)) != null ? ref6[1] : void 0) { @@ -9136,7 +9190,7 @@ Filter = (function() { if ((boards = Filter.parseBoardsMemo[boardsRaw])) { return boards; } - boards = {}; + boards = $.dict(); siteFilter = ''; ref = boardsRaw.split(','); for (i = 0, len = ref.length; i < len; i++) { @@ -9163,7 +9217,7 @@ Filter = (function() { Filter.parseBoardsMemo[boardsRaw] = boards; return boards; }, - parseBoardsMemo: {}, + parseBoardsMemo: $.dict(), test: function(post, hideable) { var board, filter, hide, hl, i, j, key, len, len1, mask, noti, ref, ref1, ref2, site, stub, top, value; if (hideable == null) { @@ -9251,7 +9305,7 @@ Filter = (function() { if (!(url = typeof (base = g.SITE.urls).catalogJSON === "function" ? base.catalogJSON(g.BOARD) : void 0)) { return; } - Filter.catalogData = {}; + Filter.catalogData = $.dict(); $.ajax(url, { onloadend: Filter.catalogParse }); @@ -9365,7 +9419,7 @@ Filter = (function() { } }, values: function(key, post) { - if (key in Filter.valueF) { + if ($.hasOwn(Filter.valueF, key)) { return Filter.valueF[key](post).filter(function(v) { return v != null; }); @@ -9373,7 +9427,7 @@ Filter = (function() { return [ key.split('+').map(function(k) { var f; - if ((f = Filter.valueF[k])) { + if ((f = $.getOwn(Filter.valueF, k))) { return f(post).map(function(v) { return v || ''; }).join('\n'); @@ -9385,6 +9439,9 @@ Filter = (function() { } }, addFilter: function(type, re, cb) { + if (!$.hasOwn(Config.filter, type)) { + return; + } return $.get(type, Conf[type], function(item) { var save; save = item[type]; @@ -9871,7 +9928,7 @@ Recursive = (function() { indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Recursive = { - recursives: {}, + recursives: $.dict(), init: function() { var ref; if ((ref = g.VIEW) !== 'index' && ref !== 'thread') { @@ -9970,7 +10027,7 @@ ThreadHiding = (function() { } hiddenThreads = ThreadHiding.db.get({ boardID: board.ID, - defaultValue: {} + defaultValue: $.dict() }); for (threadID in hiddenThreads) { hiddenThreads[threadID] = true; @@ -9994,7 +10051,7 @@ ThreadHiding = (function() { var hiddenThreads2, threadID; hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {}; for (threadID in hiddenThreads2) { - if (!(threadID in ThreadHiding.hiddenThreads)) { + if (!$.hasOwn(ThreadHiding.hiddenThreads, threadID)) { ThreadHiding.db.set({ boardID: g.BOARD.ID, threadID: threadID, @@ -10005,7 +10062,7 @@ ThreadHiding = (function() { } } for (threadID in ThreadHiding.hiddenThreads) { - if (!(threadID in hiddenThreads2)) { + if (!$.hasOwn(hiddenThreads2, threadID)) { ThreadHiding.db["delete"]({ boardID: g.BOARD.ID, threadID: threadID @@ -10194,7 +10251,7 @@ ThreadHiding = (function() { }, toggle: function(thread) { if (!(thread instanceof Thread)) { - thread = g.threads[this.dataset.fullID]; + thread = g.threads.get(this.dataset.fullID); } if (thread.isHidden) { ThreadHiding.show(thread); @@ -10266,7 +10323,7 @@ BoardConfig = (function() { load: function() { var board, boards, err, i, len, ref, ref1, troll_flags; if (this.status === 200 && this.response && this.response.boards) { - boards = {}; + boards = $.dict(); ref = this.response.boards; for (i = 0, len = ref.length; i < len; i++) { board = ref[i]; @@ -10384,7 +10441,7 @@ Get = (function() { return null; } board = root.dataset.board; - return g.threads[(board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])]; + return g.threads.get((board ? encodeURIComponent(board) : g.BOARD.ID) + "." + (root.id.match(/\d*$/)[0])); }, threadFromNode: function(node) { return Get.threadFromRoot($.x("ancestor-or-self::" + g.SITE.xpath.thread, node)); @@ -10394,10 +10451,10 @@ Get = (function() { if (root == null) { return null; } - post = g.posts[root.dataset.fullID]; + post = g.posts.get(root.dataset.fullID); index = root.dataset.clone; if (index) { - return post.clones[index]; + return post.clones[+index]; } else { return post; } @@ -10444,7 +10501,7 @@ Get = (function() { ref = post.quotes; for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; - if (qPost = posts[quote]) { + if (qPost = posts.get(quote)) { handleQuotes(qPost, 'backlinks'); } } @@ -11179,7 +11236,7 @@ Index = (function() { }); Header.addShortcut('index-refresh', this.button, 590); entries = []; - this.inputs = inputs = {}; + this.inputs = inputs = $.dict(); ref4 = Config.Index; for (name in ref4) { arr = ref4[name]; @@ -11200,7 +11257,7 @@ Index = (function() { $.on(inputs['Pin Watched Threads'], 'change', this.cb.resort); $.on(inputs['Anchor Hidden Threads'], 'change', this.cb.resort); watchSettings = function(e) { - if ((input = inputs[e.target.name])) { + if ((input = $.getOwn(inputs, e.target.name))) { input.checked = e.target.checked; return $.event('change', null, input); } @@ -11486,10 +11543,10 @@ Index = (function() { }, perBoardSort: function() { var i, k; - Conf['Index Sort'] = this.checked ? {} : ''; + Conf['Index Sort'] = this.checked ? $.dict() : ''; Index.saveSort(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = this.checked ? {} : ''; + Conf["Last Long Reply Thresholds " + i] = this.checked ? $.dict() : ''; Index.saveLastLongThresholds(i); } }, @@ -11653,12 +11710,12 @@ Index = (function() { leftover = []; for (k = 0, len1 = commands.length; k < len1; k++) { command = commands[k]; - if ((mode = Index.hashCommands.mode[command])) { + if ((mode = $.getOwn(Index.hashCommands.mode, command))) { state.mode = mode; } else if (command === 'index') { state.mode = Conf['Previous Index Mode']; state.page = 1; - } else if ((sort = Index.hashCommands.sort[command.replace(/-rev$/, '')])) { + } else if ((sort = $.getOwn(Index.hashCommands.sort, command.replace(/-rev$/, '')))) { state.sort = sort; if (/-rev$/.test(command)) { state.sort += '-rev'; @@ -11972,10 +12029,10 @@ Index = (function() { Index.liveThreadIDs = Index.liveThreadData.map(function(data) { return data.no; }); - Index.liveThreadDict = {}; - Index.threadPosition = {}; - Index.parsedThreads = {}; - Index.replyData = {}; + Index.liveThreadDict = $.dict(); + Index.threadPosition = $.dict(); + Index.parsedThreads = $.dict(); + Index.replyData = $.dict(); ref1 = Index.liveThreadData; for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { data = ref1[i]; @@ -12017,7 +12074,7 @@ Index = (function() { }, isHidden: function(threadID) { var thread; - if ((thread = g.BOARD.threads[threadID]) && thread.OP && !thread.OP.isFetchedQuote) { + if ((thread = g.BOARD.threads.get(threadID)) && thread.OP && !thread.OP.isFetchedQuote) { return thread.isHidden; } else { return Index.parsedThreads[threadID].isHidden; @@ -12035,7 +12092,7 @@ Index = (function() { ID = threadIDs[k]; try { threadData = Index.liveThreadDict[ID]; - if ((thread = g.BOARD.threads[ID])) { + if ((thread = g.BOARD.threads.get(ID))) { isStale = (thread.json !== threadData) && (JSON.stringify(thread.json) !== JSON.stringify(threadData)); if (isStale) { thread.setCount('post', threadData.replies + 1, threadData.bumplimit); @@ -12114,7 +12171,7 @@ Index = (function() { nodes = []; for (l = 0, len2 = lastReplies.length; l < len2; l++) { data = lastReplies[l]; - if ((post = thread.posts[data.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(data.no)) && !post.isFetchedQuote) { nodes.push(post.nodes.root); continue; } @@ -12226,7 +12283,7 @@ Index = (function() { return thread; } }; - lastlongD = {}; + lastlongD = $.dict(); for (k = 0, len1 = liveThreadData.length; k < len1; k++) { thread = liveThreadData[k]; lastlongD[thread.no] = lastlong(thread).no; @@ -12666,8 +12723,8 @@ Settings = (function() { warning(addWarning); } $.add(section, warnings); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); addCheckboxes = function(root, obj) { var arr, container, containers, description, div, input, level, results; containers = [root]; @@ -12737,8 +12794,8 @@ Settings = (function() { }); button = $('button', div); $.get({ - hiddenThreads: {}, - hiddenPosts: {} + hiddenThreads: $.dict(), + hiddenPosts: $.dict() }, function(arg) { var ID, board, hiddenNum, hiddenPosts, hiddenThreads, ref2, ref3, ref4, ref5, site, thread; hiddenThreads = arg.hiddenThreads, hiddenPosts = arg.hiddenPosts; @@ -12783,10 +12840,13 @@ Settings = (function() { }); $.on(button, 'click', function() { this.textContent = 'Hidden: 0'; - return $.get('hiddenThreads', {}, function(arg) { - var boardID, hiddenThreads; + return $.get('hiddenThreads', $.dict(), function(arg) { + var boardID, hiddenThreads, ref2; hiddenThreads = arg.hiddenThreads; if ($.hasStorage && g.SITE.software === 'yotsuba') { + for (boardID in (ref2 = hiddenThreads['4chan.org']) != null ? ref2.boards : void 0) { + localStorage.removeItem("4chan-hide-t-" + boardID); + } for (boardID in hiddenThreads.boards) { localStorage.removeItem("4chan-hide-t-" + boardID); } @@ -12798,7 +12858,7 @@ Settings = (function() { }, "export": function() { var Conf2; - Conf2 = {}; + Conf2 = $.dict(); $.extend(Conf2, Conf); return $.get(Conf2, function(Conf2) { delete Conf2['boardConfig']; @@ -12842,7 +12902,7 @@ Settings = (function() { reader.onload = function(e) { var err; try { - return Settings.loadSettings(JSON.parse(e.target.result), function(err) { + return Settings.loadSettings($.dict.json(e.target.result), function(err) { if (err) { return output.textContent = 'Import failed due to an error.'; } else if (confirm('Import successful. Reload now?')) { @@ -12954,14 +13014,14 @@ Settings = (function() { } if (data.WatchedThreads) { data.Conf['watchedThreads'] = { - boards: {} + boards: $.dict() }; ref1 = data.WatchedThreads; for (boardID in ref1) { threads = ref1[boardID]; for (threadID in threads) { threadData = threads[threadID]; - ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = {}))[threadID] = { + ((base = data.Conf['watchedThreads'].boards)[boardID] || (base[boardID] = $.dict()))[threadID] = { excerpt: threadData.textContent }; } @@ -12972,7 +13032,7 @@ Settings = (function() { }, upgrade: function(data, version) { var addCSS, addSauces, boardID, boards, changes, compareString, corrupted, db, hostname, j, k, key, l, lastChecked, len, len1, len2, len3, line, list, m, name, record, ref, ref1, ref10, ref11, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rice, set, setD, siteProperties, software, type, uids, val, val2, value; - changes = {}; + changes = $.dict(); set = function(key, value) { return data[key] = changes[key] = value; }; @@ -13056,7 +13116,7 @@ Settings = (function() { record = ref2[boardID]; for (type in record) { name = record[type]; - if (name in uids) { + if ($.hasOwn(uids, name)) { record[type] = uids[name]; } } @@ -13235,7 +13295,7 @@ Settings = (function() { } } if ((data['siteSoftware'] != null) && (data['siteProperties'] == null)) { - siteProperties = {}; + siteProperties = $.dict(); ref10 = data['siteSoftware'].split('\n'); for (m = 0, len3 = ref10.length; m < len3; m++) { line = ref10[m]; @@ -13312,6 +13372,9 @@ Settings = (function() { var div, filterTypes, name, ta; div = this.nextElementSibling; if ((name = this.value) !== 'guide') { + if (!$.hasOwn(Config.filter, name)) { + return; + } $.rmAll(div); ta = $.el('textarea', { name: name, @@ -13360,7 +13423,7 @@ Settings = (function() { warning = ref[j]; warning.hidden = Conf[warning.dataset.feature]; } - inputs = {}; + inputs = $.dict(); ref1 = $$('[name]', section); for (k = 0, len1 = ref1.length; k < len1; k++) { input = ref1[k]; @@ -13371,7 +13434,7 @@ Settings = (function() { Conf['lastarchivecheck'] = 0; return $.id('lastarchivecheck').textContent = 'never'; }); - items = {}; + items = $.dict(); for (name in inputs) { input = inputs[name]; if (!(name !== 'captchaServiceKey' && name !== 'Interval' && name !== 'Custom CSS')) { @@ -13423,7 +13486,7 @@ Settings = (function() { $.on(applyCSS, 'click', function() { return CustomCSS.update(); }); - itemsArchive = {}; + itemsArchive = $.dict(); ref4 = ['archives', 'selectedArchives', 'lastarchivecheck']; for (m = 0, len3 = ref4.length; m < len3; m++) { name = ref4[m]; @@ -13455,7 +13518,7 @@ Settings = (function() { tbody = $('tbody', section); $.rmAll(boardSelect); $.rmAll(tbody); - archBoards = {}; + archBoards = $.dict(); ref = Conf['archives']; for (j = 0, len = ref.length; j < len; j++) { ref1 = ref[j], uid = ref1.uid, name = ref1.name, boards = ref1.boards, files = ref1.files, software = ref1.software; @@ -13561,7 +13624,7 @@ Settings = (function() { return function(arg) { var name1, selectedArchives; selectedArchives = arg.selectedArchives; - (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = {}))[_this.dataset.type] = JSON.parse(_this.value); + (selectedArchives[name1 = _this.dataset.boardid] || (selectedArchives[name1] = $.dict()))[_this.dataset.type] = JSON.parse(_this.value); $.set('selectedArchives', selectedArchives); Conf['selectedArchives'] = selectedArchives; return Redirect.selectArchives(); @@ -13588,7 +13651,7 @@ Settings = (function() { var captchaServiceKey; captchaServiceKey = arg.captchaServiceKey; captchaServiceKey[domain] = value; - if (!(value || (domain in Config['captchaServiceKey'][0]))) { + if (!(value || $.hasOwn(Config['captchaServiceKey'][0], domain))) { delete captchaServiceKey[domain]; } Conf['captchaServiceKey'] = captchaServiceKey; @@ -13673,8 +13736,8 @@ Settings = (function() { }); $('.warning', section).hidden = Conf['Keybinds']; tbody = $('tbody', section); - items = {}; - inputs = {}; + items = $.dict(); + inputs = $.dict(); ref = Config.hotkeys; for (key in ref) { arr = ref[key]; @@ -14247,7 +14310,7 @@ FappeTyme = (function() { }); $.on(indicator, 'click', function() { var check; - check = FappeTyme.nodes[this.parentNode.id.replace('shortcut-', '')]; + check = $.getOwn(FappeTyme.nodes, this.parentNode.id.replace('shortcut-', '')); check.checked = !check.checked; return $.event('change', null, check); }); @@ -14356,7 +14419,7 @@ Gallery = (function() { } Gallery.images = []; nodes = Gallery.nodes = {}; - Gallery.fileIDs = {}; + Gallery.fileIDs = $.dict(); Gallery.slideshow = false; nodes.el = dialog = $.el('div', { id: 'a-gallery' @@ -14471,11 +14534,11 @@ Gallery = (function() { load: function(thumb, errorCB) { var elType, ext, file; ext = thumb.href.match(/\w*$/); - elType = { + elType = $.getOwn({ 'webm': 'video', 'mp4': 'video', 'pdf': 'iframe' - }[ext] || 'img'; + }, ext) || 'img'; file = $.el(elType); $.extend(file.dataset, thumb.dataset); $.on(file, 'error', errorCB); @@ -14525,7 +14588,7 @@ Gallery = (function() { } else { Gallery.cb.stop(); } - if (Conf['Scroll to Post'] && (post = g.posts[file.dataset.post])) { + if (Conf['Scroll to Post'] && (post = g.posts.get(file.dataset.post))) { Header.scrollTo(post.nodes.root); } if (isNaN(oldID) || newID === (oldID + 1) % Gallery.images.length) { @@ -14540,14 +14603,14 @@ Gallery = (function() { if (ImageCommon.isFromArchive(this)) { return; } - post = g.posts[this.dataset.post]; - file = post.files[this.dataset.file]; + post = g.posts.get(this.dataset.post); + file = post.files[+this.dataset.file]; return ImageCommon.error(this, post, file, null, (function(_this) { return function(url) { if (!url) { return; } - Gallery.images[_this.dataset.id].href = url; + Gallery.images[+_this.dataset.id].href = url; if (Gallery.nodes.current === _this) { return _this.src = url; } @@ -14742,7 +14805,7 @@ Gallery = (function() { var containerHeight, containerWidth, current, dim, frame, height, margin, minHeight, ref, ref1, ref2, ref3, style, width; ref = Gallery.nodes, current = ref.current, frame = ref.frame; style = current.style; - if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts[current.dataset.post]) != null ? ref1.file.dimensions : void 0)) { + if (Conf['Stretch to Fit'] && (dim = (ref1 = g.posts.get(current.dataset.post)) != null ? ref1.file.dimensions : void 0)) { ref2 = dim.split('x'), width = ref2[0], height = ref2[1]; containerWidth = frame.clientWidth; containerHeight = doc.clientHeight - 25; @@ -15812,7 +15875,7 @@ Metadata = (function() { $.rmClass(this.parentNode, 'error'); $.addClass(this.parentNode, 'loading'); index = this.parentNode.dataset.index; - return CrossOrigin.binary(Get.postFromNode(this).files[index].url, (function(_this) { + return CrossOrigin.binary(Get.postFromNode(this).files[+index].url, (function(_this) { return function(data) { var output, title; $.rmClass(_this.parentNode, 'loading'); @@ -15953,7 +16016,7 @@ Sauce = (function() { if (!(link = link.trim())) { return null; } - parts = {}; + parts = $.dict(); ref = link.split(/;(?=(?:text|boards|types|regexp|sandbox):?)/); for (i = j = 0, len = ref.length; j < len; i = ++j) { part = ref[i]; @@ -15986,7 +16049,7 @@ Sauce = (function() { createSauceLink: function(link, post, file) { var a, base, ext, j, key, len, matches, missing, parts, ref; ext = file.url.match(/[^.]*$/)[0]; - parts = {}; + parts = $.dict(); $.extend(parts, link); if (!(!parts['boards'] || parts['boards'][post.siteID + "/" + post.boardID] || parts['boards'][post.siteID + "/*"])) { return null; @@ -16291,7 +16354,7 @@ Embedding = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread' || ref === 'archive') && Conf['Linkify'] && (Conf['Embedding'] || Conf['Link Title'] || Conf['Cover Preview']))) { return; } - this.types = {}; + this.types = $.dict(); ref1 = this.ordered_types; for (j = 0, len = ref1.length; j < len; j++) { type = ref1[j]; @@ -17382,7 +17445,7 @@ DeleteLink = (function() { var DeleteLink; DeleteLink = { - auto: [{}, {}], + auto: [$.dict(), $.dict()], init: function() { var div, fileEl, fileEntry, postEl, postEntry, ref; if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Menu'] && Conf['Delete Link'])) { @@ -17483,7 +17546,7 @@ DeleteLink = (function() { onlyimgdel: fileOnly, pwd: QR.persona.getPassword() }; - form[post.ID] = 'delete'; + form[+post.ID] = 'delete'; return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), { responseType: 'document', withCredentials: true, @@ -17531,7 +17594,7 @@ DeleteLink = (function() { } }, cooldown: { - seconds: {}, + seconds: $.dict(), start: function(post, seconds) { if (DeleteLink.cooldown.seconds[post.fullID] != null) { return; @@ -17887,7 +17950,7 @@ Banner = (function() { } } }, - original: {}, + original: $.dict(), custom: function(child) { var className, data, event, j, len, ref; className = child.className; @@ -18040,7 +18103,7 @@ CatalogLinks = (function() { }, externalParse: function() { var board, boards, excludes, i, len, line, ref, ref1, ref2, url; - CatalogLinks.externalList = {}; + CatalogLinks.externalList = $.dict(); ref = Conf['externalCatalogURLs'].split('\n'); for (i = 0, len = ref.length; i < len; i++) { line = ref[i]; @@ -18049,7 +18112,7 @@ CatalogLinks = (function() { } url = line.split(';')[0]; boards = Filter.parseBoards(((ref1 = line.match(/;boards:([^;]+)/)) != null ? ref1[1] : void 0) || '*'); - excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || {}; + excludes = Filter.parseBoards((ref2 = line.match(/;exclude:([^;]+)/)) != null ? ref2[1] : void 0) || $.dict(); for (board in boards) { if (!(excludes[board] || excludes[board.split('/')[0] + '/*'])) { CatalogLinks.externalList[board] = url; @@ -18250,7 +18313,7 @@ ExpandThread = (function() { slice = [].slice; ExpandThread = { - statuses: {}, + statuses: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Thread Expansion'])) { return; @@ -18398,7 +18461,7 @@ ExpandThread = (function() { if (postData.no === thread.ID) { continue; } - if ((post = thread.posts[postData.no]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(postData.no)) && !post.isFetchedQuote) { if ('file' in post) { filesCount++; } @@ -18479,7 +18542,7 @@ FileInfo = (function() { var a, i, j, len, len1, output, ref, ref1; output = []; formatString.replace(/%(.)|[^%]+/g, function(s, c) { - output.push(c in FileInfo.formatters ? FileInfo.formatters[c].call(post) : { + output.push($.hasOwn(FileInfo.formatters, c) ? FileInfo.formatters[c].call(post) : { innerHTML: E(s) }); return ''; @@ -18644,10 +18707,10 @@ Fourchan = (function() { if (g.BOARD.config.code_tags) { $.on(window, 'prettyprint:cb', function(e) { var post, pre; - if (!(post = g.posts[e.detail.ID])) { + if (!(post = g.posts.get(e.detail.ID))) { return; } - if (!(pre = $$('.prettyprint', post.nodes.comment)[e.detail.i])) { + if (!(pre = $$('.prettyprint', post.nodes.comment)[+e.detail.i])) { return; } if (!$.hasClass(pre, 'prettyprinted')) { @@ -18764,9 +18827,8 @@ IDColor = (function() { if (!(((ref = g.VIEW) === 'index' || ref === 'thread') && Conf['Color User IDs'])) { return; } - this.ids = { - Heaven: [0, 0, 0, '#fff'] - }; + this.ids = $.dict(); + this.ids['Heaven'] = [0, 0, 0, '#fff']; return Callbacks.Post.push({ name: 'Color User IDs', cb: this.node @@ -19452,7 +19514,7 @@ ModContact = (function() { }, node: function() { var links, moveNote, moved; - if (this.isClone || !ModContact.specific[this.info.capcode]) { + if (this.isClone || !$.hasOwn(ModContact.specific, this.info.capcode)) { return; } links = $.el('span', { @@ -19460,7 +19522,7 @@ ModContact = (function() { }); $.extend(links, ModContact.template(this.info.capcode)); $.after(this.nodes.capcode, links); - if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && ModContact.moveNote[moved[1]]) { + if ((moved = this.info.comment.match(/This thread was moved to >>>\/(\w+)\//)) && $.hasOwn(ModContact.moveNote, moved[1])) { moveNote = $.el('div', { className: 'move-note' }); @@ -19561,7 +19623,7 @@ Nav = (function() { getThread: function() { var i, len, ref, thread, threadRoot; if (g.VIEW === 'thread') { - return g.threads[g.BOARD + "." + g.THREADID].nodes.root; + return g.threads.get(g.BOARD + "." + g.THREADID).nodes.root; } if ($.hasClass(doc, 'catalog-mode')) { return; @@ -19953,7 +20015,7 @@ RelativeDates = (function() { if (indexOf.call(RelativeDates.stale, data) >= 0) { return; } - if (data instanceof Post && !g.posts[data.fullID]) { + if (data instanceof Post && !g.posts.get(data.fullID)) { return; } if (data instanceof Element && !doc.contains(data)) { @@ -20218,7 +20280,7 @@ Time = (function() { }, format: function(formatString, date) { return formatString.replace(/%(.)/g, function(s, c) { - if (c in Time.formatters) { + if ($.hasOwn(Time.formatters, c)) { return Time.formatters[c].call(date); } else { return s; @@ -20412,7 +20474,8 @@ Favicon = (function() { '4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAD/AABmZmYA/wBD99DBAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAAAul8NnZ2f/AAD7B+mqAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAD1BMVEUAAAAAAABmzDNmZmb/AAC8/wCMAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAE9JREFUCNdljcsRACEIQ5MOiNKAdGAJ9N/Uiu7nsMzABHgB4B8ygFoZA2hhVWavhhGeURPJU9q45+17hGbfGxa82Ndex3hEM44SJGD2/b4AzDgGlHbl388AAAAASUVORK5CYII='], Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'], 'Metro': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAC/AABrZQDiAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAC/AAD///8dAAApAABsAAAHAAA4AACQAAAsAABMCpCvAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAA1/GhpCidAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAAAA1/H///8AISUALzQAeokACAkAQEcAorYAMTcE9WFNAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAABV/wErM5hwAAAAAXRSTlMAQObYZgAAABJJREFUCB1jZGBgrMNAQEEc4gCSfAX5bRw/NQAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAAAAAAAAABV/wH///8NKAASOAAwkQADCgAZTABAwQATOwC5e3VGAAAAA3RSTlMAPse+s4iwAAAAMklEQVQI12NggAFmY2MDECaNAQZCilAzVJyg5oS4GqAxUtygjIp2KGOKJ5SxepcB3BUAcdYRqxAtgFoAAAAASUVORK5CYII='] - }[Conf['favicon']]; + }; + items = $.getOwn(items, Conf['favicon']); f = Favicon; t = 'data:image/png;base64,'; i = 0; @@ -20470,13 +20533,13 @@ MarkNewIPs = (function() { i = MarkNewIPs.ipCount; for (j = 0, len = newPosts.length; j < len; j++) { fullID = newPosts[j]; - MarkNewIPs.markNew(g.posts[fullID], ++i); + MarkNewIPs.markNew(g.posts.get(fullID), ++i); } break; case -deletedPosts.length: for (k = 0, len1 = newPosts.length; k < len1; k++) { fullID = newPosts[k]; - MarkNewIPs.markOld(g.posts[fullID]); + MarkNewIPs.markOld(g.posts.get(fullID)); } } MarkNewIPs.ipCount = ipCount; @@ -20603,7 +20666,7 @@ ReplyPruning = (function() { for (i = 0, len = ref.length; i < len; i++) { fullID = ref[i]; ReplyPruning.total++; - if (g.posts[fullID].file) { + if (g.posts.get(fullID).file) { ReplyPruning.totalFiles++; } } @@ -20616,7 +20679,7 @@ ReplyPruning = (function() { posts = ReplyPruning.thread.posts; if (ReplyPruning.hidden < hidden2) { while (ReplyPruning.hidden < hidden2 && ReplyPruning.position < posts.keys.length) { - post = posts[posts.keys[ReplyPruning.position++]]; + post = posts.get(posts.keys[ReplyPruning.position++]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.summary.nextSibling) && node !== post.nodes.root) { $.add(ReplyPruning.container, node); @@ -20631,7 +20694,7 @@ ReplyPruning = (function() { } else if (ReplyPruning.hidden > hidden2) { frag = $.frag(); while (ReplyPruning.hidden > hidden2 && ReplyPruning.position > 0) { - post = posts[posts.keys[--ReplyPruning.position]]; + post = posts.get(posts.keys[--ReplyPruning.position]); if (post.isReply && !post.isFetchedQuote) { while ((node = ReplyPruning.container.lastChild) && node !== post.nodes.root) { $.prepend(frag, node); @@ -20726,7 +20789,7 @@ ThreadStats = (function() { posts = ThreadStats.thread.posts; n = posts.keys.length; for (i = j = ref = ThreadStats.postIndex, ref1 = n; j < ref1; i = j += 1) { - post = posts[posts.keys[i]]; + post = posts.get(posts.keys[i]); if (!post.isFetchedQuote) { ThreadStats.postCount++; ThreadStats.fileCount += post.files.length; @@ -20831,7 +20894,7 @@ ThreadStats = (function() { } }, retry: function() { - if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts[ThreadStats.thread.lastPost].info.date > ThreadStats.lastPageUpdate)) { + if (!(ThreadStats.showPage && ThreadStats.pageCountEl.textContent !== '1' && !g.SITE.threadModTimeIgnoresSage && ThreadStats.thread.posts.get(ThreadStats.thread.lastPost).info.date > ThreadStats.lastPageUpdate)) { return; } clearTimeout(ThreadStats.timeout); @@ -21157,7 +21220,7 @@ ThreadUpdater = (function() { thread = ThreadUpdater.thread; board = thread.board; ref = ThreadUpdater.postIDs, lastPost = ref[ref.length - 1]; - if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts[lastPost].info.date < 30 * $.SECOND) { + if (postObjects[postObjects.length - 1].no < lastPost && new Date(req.getResponseHeader('Last-Modified')) - thread.posts.get(lastPost).info.date < 30 * $.SECOND) { return; } g.SITE.Build.spoilerRange[board] = OP.custom_spoiler; @@ -21183,7 +21246,7 @@ ThreadUpdater = (function() { if (ID <= lastPost) { continue; } - if ((post = thread.posts[ID]) && !post.isFetchedQuote) { + if ((post = thread.posts.get(ID)) && !post.isFetchedQuote) { post.resurrect(); continue; } @@ -21201,7 +21264,7 @@ ThreadUpdater = (function() { if (!(indexOf.call(index, ID) < 0)) { continue; } - thread.posts[ID].kill(); + thread.posts.get(ID).kill(); deletedPosts.push(board + "." + ID); } ThreadUpdater.postIDs = index; @@ -21212,7 +21275,7 @@ ThreadUpdater = (function() { if (!(!(indexOf.call(files, ID) >= 0 || (ref3 = board + "." + ID, indexOf.call(deletedPosts, ref3) >= 0)))) { continue; } - thread.posts[ID].kill(true); + thread.posts.get(ID).kill(true); deletedFiles.push(board + "." + ID); } ThreadUpdater.fileIDs = files; @@ -21517,7 +21580,7 @@ ThreadWatcher = (function() { return ThreadWatcher.addRaw(boardID, threadID, {}, cb); } } else if (Conf['Auto Watch Reply']) { - return ThreadWatcher.add(g.threads[boardID + '.' + threadID] || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); + return ThreadWatcher.add(g.threads.get(boardID + '.' + threadID) || new Thread(threadID, g.boards[boardID] || new Board(boardID)), cb); } }, onIndexUpdate: function(e) { @@ -21571,7 +21634,7 @@ ThreadWatcher = (function() { }, onThreadRefresh: function(e) { var thread; - thread = g.threads[e.detail.threadID]; + thread = g.threads.get(e.detail.threadID); if (!(e.detail[404] && ThreadWatcher.isWatched(thread))) { return; } @@ -21634,7 +21697,7 @@ ThreadWatcher = (function() { }, initLastModified: function() { var base, boardID, boards, data, date, lm, ref, ref1, siteID, url; - lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = {})); + lm = ((base = $.lastModified)['ThreadWatcher'] || (base['ThreadWatcher'] = $.dict())); ref = ThreadWatcher.dbLM.data; for (siteID in ref) { boards = ref[siteID]; @@ -21773,7 +21836,7 @@ ThreadWatcher = (function() { boardID: boardID, val: $.item(url, lmDate) }); - threads = {}; + threads = $.dict(); pageLength = 0; nThreads = 0; oldest = null; @@ -22056,7 +22119,7 @@ ThreadWatcher = (function() { }, setPrefixes: function(threads) { var conflicts, conflicts2, j, k, len, len1, len2, prefix, prefixes, siteID, siteID2; - prefixes = {}; + prefixes = $.dict(); for (j = 0, len1 = threads.length; j < len1; j++) { siteID = threads[j].siteID; if (siteID in prefixes) { @@ -22090,7 +22153,7 @@ ThreadWatcher = (function() { ThreadWatcher.setPrefixes(threads); for (j = 0, len1 = threads.length; j < len1; j++) { ref = threads[j], siteID = ref.siteID, boardID = ref.boardID, threadID = ref.threadID, data = ref.data; - if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads[boardID + "." + threadID]) && thread.OP) { + if ((data.excerpt == null) && siteID === g.SITE.ID && (thread = g.threads.get(boardID + "." + threadID)) && thread.OP) { ThreadWatcher.db.extend({ boardID: boardID, threadID: threadID, @@ -22257,7 +22320,7 @@ ThreadWatcher = (function() { oldData = ThreadWatcher.db.get({ boardID: boardID, threadID: threadID, - defaultValue: {} + defaultValue: $.dict() }); delete oldData.last; delete oldData.modified; @@ -22325,7 +22388,7 @@ ThreadWatcher = (function() { } }); return $.on(entryEl, 'click', function() { - return ThreadWatcher.toggle(g.threads[g.BOARD + "." + g.THREADID]); + return ThreadWatcher.toggle(g.threads.get(g.BOARD + "." + g.THREADID)); }); }, addMenuEntries: function() { @@ -22548,7 +22611,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (ID > Unread.lastReadPost) { break; } @@ -22670,7 +22733,7 @@ Unread = (function() { postIDs = Unread.thread.posts.keys; for (i = j = ref = Unread.readCount, ref1 = postIDs.length; j < ref1; i = j += 1) { ID = +postIDs[i]; - if (!Unread.thread.posts[ID].isFetchedQuote) { + if (!Unread.thread.posts.get(ID).isFetchedQuote) { if (Unread.posts.has(ID)) { break; } @@ -22760,9 +22823,9 @@ UnreadIndex = (function() { var UnreadIndex; UnreadIndex = { - lastReadPost: {}, - hr: {}, - markReadLink: {}, + lastReadPost: $.dict(), + hr: $.dict(), + markReadLink: $.dict(), init: function() { if (!(g.VIEW === 'index' && Conf['Remember Last Read Post'] && Conf['Unread Line in Index'])) { return; @@ -22794,7 +22857,7 @@ UnreadIndex = (function() { results = []; for (i = 0, len = ref.length; i < len; i++) { threadID = ref[i]; - thread = g.threads[threadID]; + thread = g.threads.get(threadID); results.push(UnreadIndex.update(thread)); } return results; @@ -22922,14 +22985,10 @@ Captcha = {}; haveCookie: function() { return /\b_ct=/.test(d.cookie) && QR.posts[0].thread !== 'new'; }, - getOne: function(isReply) { - var captcha, i; + getOne: function() { + var captcha; this.clear(); - i = this.captchas.findIndex(function(x) { - return isReply || (x.challenge == null); - }); - if (i >= 0) { - captcha = this.captchas.splice(i, 1)[0]; + if ((captcha = this.captchas.shift())) { this.count(); return captcha; } else { @@ -23186,12 +23245,12 @@ Captcha = {}; } else if (n !== 9 && (i = this.imageKeys16.indexOf(key)) >= 0 && i % 4 < w && (img = this.images[n - (4 - Math.floor(i / 4)) * w + (i % 4)])) { img.click(); verify.focus(); - } else if (dx = { + } else if (dx = $.getOwn({ 'Up': n, 'Down': w, 'Left': last, 'Right': 1 - }[key]) { + }, key)) { x = (x + dx) % (n + w); if ((n < x && x < last)) { x = dx === last ? n : last; @@ -23310,7 +23369,6 @@ Captcha = {}; } }, requestCaptcha: function(e) { - var key, url; if (!this.isEnabled()) { return; } @@ -23327,6 +23385,10 @@ Captcha = {}; this.pending = true; this.aborted = false; e.preventDefault(); + return CrossOrigin.permission(this.requestCaptcha2.bind(this), this.noCaptcha.bind(this, 'Permission denied'), [Conf['captchaServiceDomain'] + "/*"]); + }, + requestCaptcha2: function() { + var key, url; key = Conf['captchaServiceKey'][Conf['captchaServiceDomain']]; if (!(key && /\S/.test(key))) { return this.noCaptcha('API key not set'); @@ -23384,7 +23446,7 @@ Captcha = {}; if (this.aborted) { return; } - error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'; + error || (error = this.req.status === 200 ? this.req.response : this.req.status ? this.req.statusText + " (" + this.req.status + ")" : 'Connection Error'); error = "Failed to retrieve captcha: " + error; return $.event('NoCaptcha', { error: error @@ -23927,7 +23989,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { return QR.abort(); } else { return QR.status(); @@ -24114,7 +24176,7 @@ QR = (function() { return; } thread = QR.posts[0].thread; - if (thread !== 'new' && g.threads[g.BOARD + "." + thread].isDead) { + if (thread !== 'new' && g.threads.get(g.BOARD + "." + thread).isDead) { value = 'Dead'; disabled = true; QR.cooldown.auto = false; @@ -24303,7 +24365,7 @@ QR = (function() { blob = new Blob([file], { type: type }); - blob.name = Conf['pastedname'] + "." + (QR.extensionFromType[type] || 'jpg'); + blob.name = Conf['pastedname'] + "." + ($.getOwn(QR.extensionFromType, type) || 'jpg'); QR.open(); QR.handleFiles([blob]); $.addClass(QR.nodes.el, 'dump'); @@ -24612,7 +24674,7 @@ QR = (function() { post = QR.posts[0]; post.forceSave(); threadID = post.thread; - thread = g.BOARD.threads[threadID]; + thread = g.BOARD.threads.get(threadID); if (g.BOARD.ID === 'f' && threadID === 'new') { filetag = QR.nodes.flashTag.value; } @@ -24623,7 +24685,7 @@ QR = (function() { } else if (!(!!g.BOARD.config.text_only || post.file)) { err = 'No file selected.'; } - } else if (g.BOARD.threads[threadID].isClosed) { + } else if (g.BOARD.threads.get(threadID).isClosed) { err = 'You can\'t reply to this thread anymore.'; } else if (!(post.com || post.file)) { err = 'No comment or file.'; @@ -24889,7 +24951,7 @@ QR = (function() { return; } this.data = Conf['cooldowns']; - this.changes = {}; + this.changes = $.dict(); return $.sync('cooldowns', this.sync); }, setup: function() { @@ -24916,7 +24978,7 @@ QR = (function() { return QR.cooldown.count(); }, sync: function(data) { - QR.cooldown.data = data || {}; + QR.cooldown.data = data || $.dict(); return QR.cooldown.start(); }, add: function(threadID, postID) { @@ -24967,7 +25029,7 @@ QR = (function() { if (!QR.cooldown.data) { return; } - cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = {})); + cooldowns = ((base = QR.cooldown.data)[name = post.board.ID] || (base[name] = $.dict())); for (id in cooldowns) { cooldown = cooldowns[id]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -24981,7 +25043,7 @@ QR = (function() { if (!(QR.cooldown.data && Conf['Cooldown'])) { return 0; } - cooldowns = QR.cooldown.data[post.board.ID] || {}; + cooldowns = QR.cooldown.data[post.board.ID] || $.dict(); for (start in cooldowns) { cooldown = cooldowns[start]; if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) { @@ -25005,7 +25067,7 @@ QR = (function() { }, mergeChange: function(data, scope, id, value) { if (value) { - return (data[scope] || (data[scope] = {}))[id] = value; + return (data[scope] || (data[scope] = $.dict()))[id] = value; } else if (scope in data) { delete data[scope][id]; if (Object.keys(data[scope]).length === 0) { @@ -25016,7 +25078,7 @@ QR = (function() { set: function(scope, id, value) { var base; QR.cooldown.mergeChange(QR.cooldown.data, scope, id, value); - return ((base = QR.cooldown.changes)[scope] || (base[scope] = {}))[id] = value; + return ((base = QR.cooldown.changes)[scope] || (base[scope] = $.dict()))[id] = value; }, save: function() { var changes; @@ -25024,7 +25086,7 @@ QR = (function() { if (!Object.keys(changes).length) { return; } - return $.get('cooldowns', {}, function(arg) { + return $.get('cooldowns', $.dict(), function(arg) { var cooldowns, id, ref, scope, value; cooldowns = arg.cooldowns; for (scope in QR.cooldown.changes) { @@ -25036,7 +25098,7 @@ QR = (function() { QR.cooldown.data = cooldowns; } return $.set('cooldowns', cooldowns, function() { - return QR.cooldown.changes = {}; + return QR.cooldown.changes = $.dict(); }); }); }, @@ -25054,7 +25116,7 @@ QR = (function() { ref1 = [g.BOARD.ID, 'global']; for (i = 0, len = ref1.length; i < len; i++) { scope = ref1[i]; - cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = {})); + cooldowns = ((base = QR.cooldown.data)[scope] || (base[scope] = $.dict())); for (start in cooldowns) { cooldown = cooldowns[start]; start = +start; @@ -25606,6 +25668,9 @@ QR = (function() { return; } name = input.dataset.name; + if (name !== 'thread' && name !== 'name' && name !== 'email' && name !== 'sub' && name !== 'com' && name !== 'filename' && name !== 'flag') { + return; + } prev = this[name]; this[name] = input.value || input.dataset["default"] || null; switch (name) { @@ -25927,7 +25992,7 @@ QR = (function() { _Class.prototype.saveFilename = function() { this.file.newName = (this.filename || '').replace(/[\/\\]/g, '-'); if (!QR.validExtension.test(this.filename)) { - return this.file.newName += "." + (QR.extensionFromType[this.file.type] || 'jpg'); + return this.file.newName += "." + ($.getOwn(QR.extensionFromType, this.file.type) || 'jpg'); } }; @@ -26031,7 +26096,7 @@ QuoteBacklink = (function() { var QuoteBacklink; QuoteBacklink = { - containers: {}, + containers: $.dict(), init: function() { var ref; if (((ref = g.VIEW) !== 'index' && ref !== 'thread') || !Conf['Quote Backlinks']) { @@ -26074,7 +26139,7 @@ QuoteBacklink = (function() { for (i = 0, len = ref.length; i < len; i++) { quote = ref[i]; containers = [QuoteBacklink.getContainer(quote)]; - if ((post = g.posts[quote]) && post.nodes.backlinkContainer) { + if ((post = g.posts.get(quote)) && post.nodes.backlinkContainer) { ref1 = post.clones; for (j = 0, len1 = ref1.length; j < len1; j++) { clone = ref1[j]; @@ -26230,7 +26295,7 @@ QuoteInline = (function() { return; } ref = Get.postDataFromLink(this), boardID = ref.boardID, threadID = ref.threadID, postID = ref.postID; - if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts[boardID + "." + postID]) != null ? ref1.nodes.root.offsetParent : void 0)) { + if (Conf['Inline Cross-thread Quotes Only'] && g.VIEW === 'thread' && ((ref1 = g.posts.get(boardID + "." + postID)) != null ? ref1.nodes.root.offsetParent : void 0)) { return; } if ($.hasClass(doc, 'catalog-mode')) { @@ -26268,7 +26333,7 @@ QuoteInline = (function() { qroot = $.x('ancestor::*[contains(@class,"postContainer")][1]', root); $.addClass(qroot, 'hasInline'); new Fetcher(boardID, threadID, postID, inline, quoter); - if (!((post = g.posts[boardID + "." + postID]) && context.thread === post.thread)) { + if (!((post = g.posts.get(boardID + "." + postID)) && context.thread === post.thread)) { return; } if (isBacklink && Conf['Forward Hiding']) { @@ -26295,9 +26360,9 @@ QuoteInline = (function() { if (!(el = root.firstElementChild)) { return; } - post = g.posts[boardID + "." + postID]; + post = g.posts.get(boardID + "." + postID); post.rmClone(el.dataset.clone); - if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads[boardID + "." + threadID] && !--post.forwarded) { + if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads.get(boardID + "." + threadID) && !--post.forwarded) { delete post.forwarded; $.rmClass(post.nodes.root, 'forwarded'); } @@ -26423,7 +26488,7 @@ QuotePreview = (function() { endEvents: 'mouseout click', cb: QuotePreview.mouseout }); - if (Conf['Quote Highlighting'] && (origin = g.posts[boardID + "." + postID])) { + if (Conf['Quote Highlighting'] && (origin = g.posts.get(boardID + "." + postID))) { posts = [origin].concat(origin.clones); posts.pop(); for (i = 0, len = posts.length; i < len; i++) { @@ -26479,7 +26544,7 @@ QuoteStrikeThrough = (function() { for (i = 0, len = ref.length; i < len; i++) { quotelink = ref[i]; ref1 = Get.postDataFromLink(quotelink), boardID = ref1.boardID, postID = ref1.postID; - if ((ref2 = g.posts[boardID + "." + postID]) != null ? ref2.isHidden : void 0) { + if ((ref2 = g.posts.get(boardID + "." + postID)) != null ? ref2.isHidden : void 0) { $.addClass(quotelink, 'filtered'); } } @@ -26536,9 +26601,9 @@ QuoteThreading = cb: this.node }); }, - parent: {}, - children: {}, - inserted: {}, + parent: $.dict(), + children: $.dict(), + inserted: $.dict(), toggleThreading: function() { return this.setThreadingState(!Conf['Thread Quotes']); }, @@ -26580,7 +26645,7 @@ QuoteThreading = ref = this.quotes; for (j = 0, len = ref.length; j < len; j++) { quote = ref[j]; - if (parent = g.posts[quote]) { + if (parent = g.posts.get(quote)) { if (!parent.isFetchedQuote && parent.isReply && parent.ID < this.ID) { parents.add(parent.ID); if (!lastParent || parent.ID > lastParent.ID) { @@ -26688,7 +26753,7 @@ QuoteThreading = } else { nodes = []; Unread.order = new RandomAccessList(); - QuoteThreading.inserted = {}; + QuoteThreading.inserted = $.dict(); posts.forEach(function(post) { if (post.isFetchedQuote) { return; @@ -26990,7 +27055,7 @@ Quotify = (function() { } boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID; quoteID = boardID + "." + postID; - if (post = g.posts[quoteID]) { + if (post = g.posts.get(quoteID)) { if (!post.isDead) { a = $.el('a', { href: g.SITE.Build.postURL(boardID, post.thread.ID, postID), @@ -27119,7 +27184,7 @@ Main = (function() { flatten = function(parent, obj) { var key, val; if (obj instanceof Array) { - Conf[parent] = obj[0]; + Conf[parent] = $.dict.clone(obj[0]); } else if (typeof obj === 'object') { for (key in obj) { val = obj[key]; @@ -27150,9 +27215,9 @@ Main = (function() { ref2 = DataBoard.keys; for (j = 0, len = ref2.length; j < len; j++) { db = ref2[j]; - Conf[db] = {}; + Conf[db] = $.dict(); } - Conf['customTitles'] = { + Conf['customTitles'] = $.dict.clone({ '4chan.org': { boards: { 'qa': { @@ -27163,18 +27228,18 @@ Main = (function() { } } } - }; + }); Conf['boardConfig'] = { - boards: {} + boards: $.dict() }; Conf['archives'] = Redirect.archives; - Conf['selectedArchives'] = {}; - Conf['cooldowns'] = {}; - Conf['Index Sort'] = {}; + Conf['selectedArchives'] = $.dict(); + Conf['cooldowns'] = $.dict(); + Conf['Index Sort'] = $.dict(); for (i = k = 0; k < 2; i = ++k) { - Conf["Last Long Reply Thresholds " + i] = {}; + Conf["Last Long Reply Thresholds " + i] = $.dict(); } - Conf['siteProperties'] = {}; + Conf['siteProperties'] = $.dict(); Conf['Except Archives from Encryption'] = false; Conf['JSON Navigation'] = true; Conf['Oekaki Links'] = true; @@ -27195,7 +27260,7 @@ Main = (function() { return $.addCSP("script-src " + (jsWhitelist.replace(/^#.*$/mg, '').replace(/[\s;]+/g, ' ').trim())); }); } - items = {}; + items = $.dict(); for (key in Conf) { items[key] = void 0; } @@ -27535,7 +27600,7 @@ Main = (function() { threadRoot = threadRoots[j]; boardObj = (boardID = threadRoot.dataset.board) ? (boardID = encodeURIComponent(boardID), g.boards[boardID] || new Board(boardID)) : g.BOARD; threadID = +threadRoot.id.match(/\d*$/)[0]; - if (!threadID || ((ref = boardObj.threads[threadID]) != null ? ref.nodes.root : void 0)) { + if (!threadID || ((ref = boardObj.threads.get(threadID)) != null ? ref.nodes.root : void 0)) { return; } thread = new Thread(threadID, boardObj); diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip index acf91c1d9..1725a4ca7 100644 Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ diff --git a/builds/updates-beta.json b/builds/updates-beta.json index 5b7c9c9f0..49926a1cc 100644 --- a/builds/updates-beta.json +++ b/builds/updates-beta.json @@ -3,7 +3,7 @@ "4chan-x@4chan-x.net": { "updates": [ { - "version": "1.14.11.0", + "version": "1.14.11.1", "update_link": "https://www.4chan-x.net/builds/4chan-X-beta.crx" } ] diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml index d278bb40a..7c2804231 100644 --- a/builds/updates-beta.xml +++ b/builds/updates-beta.xml @@ -1,7 +1,7 @@ - + diff --git a/builds/updates.json b/builds/updates.json index e3644d62e..5f6b080fc 100644 --- a/builds/updates.json +++ b/builds/updates.json @@ -3,7 +3,7 @@ "4chan-x@4chan-x.net": { "updates": [ { - "version": "1.14.11.0", + "version": "1.14.11.1", "update_link": "https://www.4chan-x.net/builds/4chan-X.crx" } ] diff --git a/builds/updates.xml b/builds/updates.xml index 00cf31358..f274a4127 100644 --- a/builds/updates.xml +++ b/builds/updates.xml @@ -1,7 +1,7 @@ - + diff --git a/version.json b/version.json index 61efeceda..4cc5217a9 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "version": "1.14.11.0", - "date": "2019-07-24T22:12:38.947Z" + "version": "1.14.11.1", + "date": "2019-08-03T18:01:40.027Z" } \ No newline at end of file