diff --git a/CHANGELOG.md b/CHANGELOG.md index ef39728ca..16fc7efa2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +<<<<<<< HEAD +======= +- **New feature**: `Color User IDs`, enabled by default + +## 3.10.0 - *2013-08-22* +>>>>>>> 667abe7480b04161ec10cf00fffad17accdf23a0 **MayhemYDG**: - New desktop notification: diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 6a839c30b..7dcbb6ad0 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1340,27 +1340,26 @@ return $.cache("//api.4chan.org/" + boardID + "/threads.json", function(e) { var board, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; - if (e.target.status === 404) { - _this["delete"](boardID); - } else if (e.target.status === 200) { - board = _this.data.boards[boardID]; - threads = {}; - _ref = JSON.parse(e.target.response); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - page = _ref[_i]; - _ref1 = page.threads; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - thread = _ref1[_j]; - if (thread.no in board) { - threads[thread.no] = board[thread.no]; - } + if (e.target.status !== 200) { + return; + } + board = _this.data.boards[boardID]; + threads = {}; + _ref = JSON.parse(e.target.response); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + page = _ref[_i]; + _ref1 = page.threads; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + thread = _ref1[_j]; + if (thread.no in board) { + threads[thread.no] = board[thread.no]; } } - _this.data.boards[boardID] = threads; - _this.deleteIfEmpty({ - boardID: boardID - }); } + _this.data.boards[boardID] = threads; + _this.deleteIfEmpty({ + boardID: boardID + }); return _this.save(); }); }; @@ -1449,7 +1448,7 @@ data = atob(this.toDataURL().slice(22)); l = data.length; ui8a = new Uint8Array(l); - for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) { + for (i = _i = 0; _i < l; i = _i += 1) { ui8a[i] = data.charCodeAt(i); } return cb(new Blob([ui8a], { @@ -5059,7 +5058,7 @@ return; } QR.open(); - if (Conf['Auto Hide QR']) { + if (Conf['Auto-Hide QR'] || g.VIEW === 'catalog') { return QR.hide(); } }, @@ -9953,6 +9952,54 @@ } }; + IDColor = { + init: function() { + if (g.VIEW === 'catalog' || !Conf['Color User IDs']) { + return; + } + this.ids = {}; + return Post.prototype.callbacks.push({ + name: 'Color User IDs', + cb: this.node + }); + }, + node: function() { + var rgb, span, style, uid; + + if (this.isClone || !(uid = this.info.uniqueID)) { + return; + } + rgb = IDColor.compute(uid); + span = this.nodes.uniqueID; + style = span.style; + style.color = rgb[3]; + style.backgroundColor = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; + $.addClass(span, 'painted'); + span.textContent = uid; + return span.title = 'Highlight posts by this ID'; + }, + compute: function(uniqueID) { + var hash, rgb; + + if (uniqueID in IDColor.ids) { + return IDColor.ids[uniqueID]; + } + hash = this.hash(uniqueID); + rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF]; + rgb.push((rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 170 ? 'black' : 'white'); + return this.ids[uniqueID] = rgb; + }, + hash: function(uniqueID) { + var i, msg, _i, _ref; + + msg = 0; + for (i = _i = 0, _ref = uniqueID.length; _i < _ref; i = _i += 1) { + msg = (msg << 5) - msg + uniqueID.charCodeAt(i); + } + return msg; + } + }; + Keybinds = { init: function() { var init; diff --git a/builds/crx/script.js b/builds/crx/script.js index faf01af37..7a433e87e 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1350,27 +1350,26 @@ return $.cache("//api.4chan.org/" + boardID + "/threads.json", function(e) { var board, page, thread, threads, _i, _j, _len, _len1, _ref, _ref1; - if (e.target.status === 404) { - _this["delete"](boardID); - } else if (e.target.status === 200) { - board = _this.data.boards[boardID]; - threads = {}; - _ref = JSON.parse(e.target.response); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - page = _ref[_i]; - _ref1 = page.threads; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - thread = _ref1[_j]; - if (thread.no in board) { - threads[thread.no] = board[thread.no]; - } + if (e.target.status !== 200) { + return; + } + board = _this.data.boards[boardID]; + threads = {}; + _ref = JSON.parse(e.target.response); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + page = _ref[_i]; + _ref1 = page.threads; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + thread = _ref1[_j]; + if (thread.no in board) { + threads[thread.no] = board[thread.no]; } } - _this.data.boards[boardID] = threads; - _this.deleteIfEmpty({ - boardID: boardID - }); } + _this.data.boards[boardID] = threads; + _this.deleteIfEmpty({ + boardID: boardID + }); return _this.save(); }); }; @@ -1463,7 +1462,7 @@ data = atob(this.toDataURL().slice(22)); l = data.length; ui8a = new Uint8Array(l); - for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) { + for (i = _i = 0; _i < l; i = _i += 1) { ui8a[i] = data.charCodeAt(i); } return cb(new Blob([ui8a], { @@ -5067,7 +5066,7 @@ return; } QR.open(); - if (Conf['Auto Hide QR']) { + if (Conf['Auto-Hide QR'] || g.VIEW === 'catalog') { return QR.hide(); } }, @@ -9944,6 +9943,54 @@ } }; + IDColor = { + init: function() { + if (g.VIEW === 'catalog' || !Conf['Color User IDs']) { + return; + } + this.ids = {}; + return Post.prototype.callbacks.push({ + name: 'Color User IDs', + cb: this.node + }); + }, + node: function() { + var rgb, span, style, uid; + + if (this.isClone || !(uid = this.info.uniqueID)) { + return; + } + rgb = IDColor.compute(uid); + span = this.nodes.uniqueID; + style = span.style; + style.color = rgb[3]; + style.backgroundColor = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; + $.addClass(span, 'painted'); + span.textContent = uid; + return span.title = 'Highlight posts by this ID'; + }, + compute: function(uniqueID) { + var hash, rgb; + + if (uniqueID in IDColor.ids) { + return IDColor.ids[uniqueID]; + } + hash = this.hash(uniqueID); + rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF]; + rgb.push((rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 170 ? 'black' : 'white'); + return this.ids[uniqueID] = rgb; + }, + hash: function(uniqueID) { + var i, msg, _i, _ref; + + msg = 0; + for (i = _i = 0, _ref = uniqueID.length; _i < _ref; i = _i += 1) { + msg = (msg << 5) - msg + uniqueID.charCodeAt(i); + } + return msg; + } + }; + Keybinds = { init: function() { var init; diff --git a/css/style.css b/css/style.css new file mode 100644 index 000000000..63ad3c85a --- /dev/null +++ b/css/style.css @@ -0,0 +1,970 @@ +/* General */ +.dialog { + box-shadow: 0 1px 2px rgba(0, 0, 0, .15); + border: 1px solid; + display: block; + padding: 0; +} +.field { + background-color: #FFF; + border: 1px solid #CCC; + -moz-box-sizing: border-box; + box-sizing: border-box; + color: #333; + font-family: inherit; + font-size: 13px; + margin: 0; + padding: 2px 4px 3px; + outline: none; + transition: color .25s, border-color .25s, -webkit-flex .25s; + transition: color .25s, border-color .25s, flex .25s; +} +.field::-moz-placeholder, +.field:hover::-moz-placeholder { + color: #AAA !important; +} +.field:hover { + border-color: #999; +} +.field:hover, .field:focus { + color: #000; +} +.field[disabled] { + background-color: #F2F2F2; + color: #888; +} +.move { + cursor: move; +} +label, .watcher-toggler { + cursor: pointer; +} +a[href="javascript:;"] { + text-decoration: none; +} +.warning { + color: red; +} + +/* 4chan style fixes */ +.opContainer, .op { + display: block !important; +} +.post { + overflow: visible !important; +} +[hidden] { + display: none !important; +} + +/* fixed, z-index */ +#overlay, +#qp, #ihover, +#updater, #thread-stats, +#navlinks, #header, +#qr { + position: fixed; +} +#overlay { + z-index: 999; +} +#notifications { + z-index: 70; +} +#qp, #ihover { + z-index: 60; +} +#menu { + z-index: 50; +} +#navlinks, #updater, #thread-stats { + z-index: 40; +} +#qr { + z-index: 30; +} +#thread-watcher:hover { + z-index: 20; +} +#header { + z-index: 10; +} +#thread-watcher { + z-index: 5; +} + +/* Header */ +:root.top-header body { + margin-top: 2em; +} +:root.bottom-header body { + margin-bottom: 2em; +} +:root.fourchan-x #navtopright, +:root.fourchan-x #navbotright, +:root.fourchan-x:not(.show-original-top-board-list) #boardNavDesktop, +:root.fourchan-x:not(.show-original-bot-board-list) #boardNavDesktopFoot { + display: none !important; +} +#header { + right: 0; + left: 0; +} +#header.top { + top: 0; +} +#header.bottom { + bottom: 0; +} +#header-bar { + border-width: 0; + display: -webkit-flex; + display: flex; + padding: 3px; + position: relative; + transition: all .1s .05s ease-in-out; +} +#header.top #header-bar { + border-bottom-width: 1px; +} +#header.bottom #header-bar { + box-shadow: 0 -1px 2px rgba(0, 0, 0, .15); + border-top-width: 1px; +} +#board-list { + -webkit-flex: 1; + flex: 1; + -webkit-align-self: center; + align-self: center; + text-align: center; +} +#header-bar.autohide:not(:hover) { + box-shadow: none; + transition: all .8s .6s cubic-bezier(.55, .055, .675, .19); +} +#header.top #header-bar.autohide:not(:hover) { + margin-bottom: -1em; + -webkit-transform: translateY(-100%); + transform: translateY(-100%); +} +#header.bottom #header-bar.autohide:not(:hover) { + -webkit-transform: translateY(100%); + transform: translateY(100%); +} +#toggle-header-bar { + left: 0; + right: 0; + height: 10px; + position: absolute; +} +#header.top #toggle-header-bar { + cursor: n-resize; + bottom: -10px; +} +#header.bottom #toggle-header-bar { + cursor: s-resize; + top: -10px; +} +#header.top #header-bar.autohide #toggle-header-bar { + cursor: s-resize; +} +#header.bottom #header-bar.autohide #toggle-header-bar { + cursor: n-resize; +} +#header-bar a:not(.entry) { + text-decoration: none; + padding: 1px; +} +.shortcut:not(:last-child)::after { + content: " / "; +} +.brackets-wrap::before { + content: " [ "; +} +.brackets-wrap::after { + content: " ] "; +} + +/* Notifications */ +#notifications { + height: 0; + text-align: center; +} +#header.bottom #notifications { + position: fixed; + top: 0; + left: 0; + width: 100%; +} +.notification { + color: #FFF; + font-weight: 700; + text-shadow: 0 1px 2px rgba(0, 0, 0, .5); + box-shadow: 0 1px 2px rgba(0, 0, 0, .15); + border-radius: 2px; + margin: 1px auto; + width: 500px; + max-width: 100%; + position: relative; + transition: all .25s ease-in-out; +} +.notification.error { + background-color: hsla(0, 100%, 38%, .9); +} +.notification.warning { + background-color: hsla(36, 100%, 38%, .9); +} +.notification.info { + background-color: hsla(200, 100%, 38%, .9); +} +.notification.success { + background-color: hsla(104, 100%, 38%, .9); +} +.notification a { + color: white; +} +.notification > .close { + padding: 6px; + top: 0; + right: 0; + position: absolute; +} +.message { + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 6px 20px; + max-height: 200px; + width: 100%; + overflow: auto; +} + +/* Settings */ +:root.fourchan-x body { + -moz-box-sizing: border-box; + box-sizing: border-box; +} +#overlay { + background-color: rgba(0, 0, 0, .5); + display: -webkit-flex; + display: flex; + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; +} +#fourchanx-settings { + -moz-box-sizing: border-box; + box-sizing: border-box; + box-shadow: 0 0 15px rgba(0, 0, 0, .15); + height: 600px; + max-height: 100%; + width: 900px; + max-width: 100%; + margin: auto; + padding: 3px; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; +} +#fourchanx-settings > nav { + display: -webkit-flex; + display: flex; + padding: 2px 2px 0; +} +#fourchanx-settings > nav a { + text-decoration: underline; +} +#fourchanx-settings > nav a.close { + text-decoration: none; + padding: 2px; +} +.sections-list { + -webkit-flex: 1; + flex: 1; +} +.tab-selected { + font-weight: 700; +} +.section-container { + -webkit-flex: 1; + flex: 1; + position: relative; +} +.section-container > section { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: auto; +} +.section-sauce ul, +.section-rice ul { + list-style: none; + margin: 0; + padding: 8px; +} +.section-sauce li, +.section-rice li { + padding-left: 4px; +} +.section-main label { + text-decoration: underline; +} +.section-filter ul, +.section-qr ul { + padding: 0; +} +.section-filter li, +.section-qr li { + margin: 10px 40px; +} +.section-filter textarea { + height: 500px; +} +.section-qr textarea { + height: 200px; +} +.section-sauce textarea { + height: 350px; +} +.section-rice .field[name="boardnav"] { + width: 100%; +} +.section-rice textarea { + height: 150px; +} +.section-archives table { + width: 100%; +} +.section-archives th:not(:first-child) { + width: 30%; +} +.section-archives td { + text-align: center; +} +.section-archives select { + width: 90%; +} +.section-keybinds .field { + font-family: monospace; +} +#fourchanx-settings fieldset { + border: 1px solid; + border-radius: 3px; +} +#fourchanx-settings legend { + font-weight: 700; +} +#fourchanx-settings textarea { + font-family: monospace; + min-width: 100%; + max-width: 100%; +} +#fourchanx-settings code { + color: #000; + background-color: #FFF; + padding: 0 2px; +} +.unscroll { + overflow: hidden; +} + +/* Announcement Hiding */ +:root.hide-announcement #globalMessage, +:root.hide-announcement-enabled #toggleMsgBtn { + display: none; +} +a.hide-announcement { + float: left; +} + +/* Unread */ +#unread-line { + margin: 0; +} + +/* Thread Updater */ +#updater:not(:hover) { + background: none; + border: none; + box-shadow: none; +} +#updater > .move { + padding: 0 3px; +} +#updater > div:last-child { + text-align: center; +} +#updater input[type=number] { + width: 4em; +} +#updater:not(:hover) > div:not(.move) { + display: none; +} +#updater input[type="button"] { + width: 100%; +} +.new { + color: limegreen; +} + +/* Thread Watcher */ +#thread-watcher { + max-width: 200px; + min-width: 150px; + padding: 3px; + position: absolute; +} +#thread-watcher > div:first-child { + display: -webkit-flex; + display: flex; + -webkit-align-items: center; + align-items: center; +} +#thread-watcher .move { + -webkit-flex: 1; + flex: 1; +} +#watcher-status:not(:empty)::before { + content: "("; +} +#watcher-status:not(:empty)::after { + content: ")"; +} +#watched-threads:not(:hover) { + max-height: 150px; + overflow: hidden; +} +#watched-threads div { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +#watched-threads .current { + font-weight: 700; +} +#watched-threads a { + text-decoration: none; +} +#watched-threads .dead-thread a[title] { + text-decoration: line-through; +} + +/* Thread Stats */ +#thread-stats { + background: none; + border: none; + box-shadow: none; +} + +/* Quote */ +.deadlink { + text-decoration: none !important; +} +.backlink.deadlink:not(.forwardlink), +.quotelink.deadlink:not(.forwardlink) { + text-decoration: underline !important; +} +.inlined { + opacity: .5; +} +#qp input, .forwarded { + display: none; +} +.quotelink.forwardlink, +.backlink.forwardlink { + text-decoration: none; + border-bottom: 1px dashed; +} +.filtered { + text-decoration: underline line-through; +} +.inline { + border: 1px solid; + display: table; + margin: 2px 0; +} +.inline .post { + border: 0 !important; + background-color: transparent !important; + display: table !important; + margin: 0 !important; + padding: 1px 2px !important; +} +#qp > .opContainer::after { + content: ''; + clear: both; + display: table; +} +#qp .post { + border: none; + margin: 0; + padding: 2px 2px 5px; +} +#qp img { + max-height: 80vh; + max-width: 50vw; +} +.qphl { + outline: 2px solid rgba(216, 94, 49, .7); +} + +/* File */ +.fileText:hover .fntrunc, +.fileText:not(:hover) .fnfull, +.expanded-image > .post > .file > .fileThumb > img[data-md5], +:not(.expanded-image) > .post > .file > .fileThumb > .full-image { + display: none; +} +.expanding { + opacity: .5; +} +.expanded-image { + clear: both; +} +.expanded-image > .op > .file::after { + content: ''; + clear: both; + display: table; +} +:root.fit-height .full-image { + max-height: 100vh; +} +:root.fit-width .full-image { + max-width: 100%; +} +:root.gecko.fit-width .full-image { + width: 100%; +} +#ihover { + -moz-box-sizing: border-box; + box-sizing: border-box; + max-height: 100%; + max-width: 75%; + padding-bottom: 16px; +} + +/* Index/Reply Navigation */ +#navlinks { + font-size: 16px; + top: 25px; + right: 10px; +} + +/* Filter */ +.opContainer.filter-highlight { + box-shadow: inset 5px 0 rgba(255, 0, 0, .5); +} +.filter-highlight > .reply { + box-shadow: -5px 0 rgba(255, 0, 0, .5); +} + +/* Thread & Reply Hiding */ +.hide-thread-button, +.hide-reply-button { + float: left; + margin-right: 2px; +} +.stub ~ * { + display: none !important; +} +.stub input { + display: inline-block; +} + +/* QR */ +:root.hide-original-post-form #postForm, +:root.hide-original-post-form .postingMode, +:root.hide-original-post-form #togglePostForm, +#qr.autohide:not(.has-focus):not(:hover) > form { + display: none; +} +#qr select, #dump-button, .remove, .captcha-img { + cursor: pointer; +} +#qr > div { + min-width: 300px; + display: -webkit-flex; + display: flex; + -webkit-align-items: center; + align-items: center; +} +#qr .move { + -webkit-align-self: stretch; + align-self: stretch; + -webkit-flex: 1; + flex: 1; +} +#qr select { + margin: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border: none; + background: none; + font: inherit; +} +#qr option { + color: #000; + background-color: #F7F7F7; +} +#qr .close { + padding: 0 3px; +} +#qr > form { + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; +} +.persona { + display: -webkit-flex; + display: flex; +} +.persona .field { + -webkit-flex: 1; + flex: 1; +} +.persona .field:hover, +.persona .field:focus { + -webkit-flex: 3; + flex: 3; +} +#dump-button { + background: linear-gradient(#EEE, #CCC); + border: 1px solid #CCC; + margin: 0; + padding: 2px 4px 3px; + outline: none; + width: 30px; +} +#dump-button:hover, +#dump-button:focus { + background: linear-gradient(#FFF, #DDD); +} +#dump-button:active, +.dump #dump-button:not(:hover):not(:focus) { + background: linear-gradient(#CCC, #DDD); +} +:root.gecko #dump-button { + padding: 0; +} +#qr:not(.dump) #dump-list-container { + display: none; +} +#dump-list-container { + height: 100px; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +#dump-list { + counter-reset: qrpreviews; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + position: absolute; + white-space: nowrap; +} +#dump-list:hover { + bottom: -12px; + overflow-x: auto; + z-index: 1; +} +#dump-list::-webkit-scrollbar { + height: 12px; +} +#dump-list::-webkit-scrollbar-thumb { + border: 1px solid; +} +.qr-preview { + background-position: 50% 20%; + background-size: cover; + border: 1px solid #808080; + color: #FFF !important; + font-size: 12px; + -moz-box-sizing: border-box; + box-sizing: border-box; + cursor: move; + display: inline-block; + height: 92px; + width: 92px; + margin: 4px; + padding: 2px; + opacity: .6; + outline: none; + overflow: hidden; + position: relative; + text-shadow: 0 1px 1px #000; + transition: opacity .25s ease-in-out; + vertical-align: top; + white-space: pre; +} +.qr-preview:hover, +.qr-preview:focus { + opacity: .9; + color: #FFF !important; +} +.qr-preview#selected { + opacity: 1; +} +.qr-preview::before { + counter-increment: qrpreviews; + content: counter(qrpreviews); + font-weight: 700; + text-shadow: 0 0 3px #000, 0 0 5px #000; + position: absolute; + top: 3px; + right: 3px; +} +.qr-preview.drag { + border-color: red; + border-style: dashed; + opacity: 1; +} +.qr-preview.over { + border-color: #FFF; + border-style: dashed; + opacity: 1; +} +.remove { + color: #E00 !important; + font-weight: 700; + padding: 3px; +} +.remove:hover::after { + content: ' Remove'; +} +.qr-preview > label { + background: rgba(0, 0, 0, .5); + right: 0; + bottom: 0; + left: 0; + position: absolute; + text-align: center; +} +.qr-preview > label > input { + margin: 1px 0; + vertical-align: bottom; +} +#add-post { + display: inline-block; + font-size: 30px; + height: 30px; + width: 30px; + line-height: 1; + text-align: center; + position: absolute; + right: 0; + bottom: 0; + z-index: 1; +} +#qr textarea { + min-height: 160px; + min-width: 100%; + display: block; +} +#qr.has-captcha textarea { + min-height: 120px; +} +.textarea { + position: relative; +} +#char-count { + color: #000; + background: hsla(0, 0%, 100%, .5); + font-size: 8pt; + position: absolute; + bottom: 1px; + right: 1px; + pointer-events: none; +} +#char-count.warning { + color: red; +} +.captcha-img { + background: #FFF; + outline: 1px solid #CCC; + outline-offset: -1px; +} +.captcha-img > img { + display: block; + height: 57px; + width: 300px; +} +#file-n-submit-container { + position: relative; +} +#file-n-submit { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: -webkit-flex; + display: flex; + -webkit-align-items: center; + align-items: center; +} +#file-n-submit-container input[type='file'] { + /* Keep it to set an appropriate height to the container. */ + visibility: hidden; +} +#file-n-submit-container input { + margin: 0; + padding: 0; +} +#file-n-submit input[type='submit'] { + -webkit-order: 1; + order: 1; +} +#file-n-submit.has-file #qr-no-file, +#file-n-submit:not(.has-file) #qr-filename, +#file-n-submit:not(.has-file) #qr-filesize, +#file-n-submit:not(.has-file) #qr-file-spoiler, +#file-n-submit:not(.has-file) #qr-filerm, +#qr-filename:focus ~ #qr-filesize { + display: none; +} +#qr-no-file, +#qr-filename, +#qr-filesize, +#qr-filerm, +#qr-file-spoiler { + margin: 0 2px !important; +} +#qr-no-file { + cursor: default; + -webkit-flex: 1; + flex: 1; +} +#qr-filename { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: none !important; + color: inherit; + font: inherit; + -webkit-flex: 1; + flex: 1; + text-overflow: ellipsis; +} +#qr-filesize { + font-size: .8em; +} +#qr-filesize::before { + content: " ("; +} +#qr-filesize::after { + content: ")"; +} + +/* Menu */ +.menu-button { + position: relative; +} +.menu-button i:not(.icon-reorder) { + border-top: 6px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + display: inline-block; + margin: 2px; + vertical-align: middle; +} +@media screen and (resolution: 1dppx) { + .icon-reorder { + font-size: 14px; + } + #shortcuts .icon-reorder { + vertical-align: -1px; + } +} +#menu { + border-bottom: 0; + display: -webkit-flex; + display: flex; + margin: 2px 0; + -webkit-flex-direction: column; + flex-direction: column; + position: absolute; + outline: none; +} +#menu.top { + top: 100%; +} +#menu.bottom { + bottom: 100%; +} +#menu.left { + left: 0; +} +#menu.right { + right: 0; +} +.entry { + cursor: pointer; + outline: none; + padding: 3px 7px; + position: relative; + text-decoration: none; + white-space: nowrap; +} +.entry.disabled { + color: graytext !important; +} +.entry.has-submenu { + padding-right: 20px; +} +.has-submenu::after { + content: ''; + border-left: 6px solid; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + display: inline-block; + margin: 4px; + position: absolute; + right: 3px; +} +.has-submenu:not(.focused) > .submenu { + display: none; +} +.submenu { + border-bottom: 0; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; + position: absolute; + margin: -1px 0; +} +.submenu.top { + top: 0; +} +.submenu.bottom { + bottom: 0; +} +.submenu.left { + left: 100%; +} +.submenu.right { + right: 100%; +} +.entry input { + margin: 0; +} + +/* colored uid */ + +.posteruid.painted { + padding: 0 5px; + border-radius: 1em; + font-size: 0.8em; + cursor: pointer; +} diff --git a/src/General/Config.coffee b/src/General/Config.coffee index aa393ab8a..ef62eff3b 100755 --- a/src/General/Config.coffee +++ b/src/General/Config.coffee @@ -317,6 +317,7 @@ Config = true 'When disabled, shows a red border on the CAPTCHA input until a key is pressed instead of a notification.' ] + 'Quote Links': 'Quote Backlinks': [ true diff --git a/src/General/lib/databoard.class b/src/General/lib/databoard.class index 9e1bbc342..80f1262f1 100755 --- a/src/General/lib/databoard.class +++ b/src/General/lib/databoard.class @@ -74,18 +74,15 @@ class DataBoard ajaxClean: (boardID) -> $.cache "//api.4chan.org/#{boardID}/threads.json", (e) => - if e.target.status is 404 - # Deleted board. - @delete boardID - else if e.target.status is 200 - board = @data.boards[boardID] - threads = {} - for page in JSON.parse e.target.response - for thread in page.threads - if thread.no of board - threads[thread.no] = board[thread.no] - @data.boards[boardID] = threads - @deleteIfEmpty {boardID} + return if e.target.status isnt 200 + board = @data.boards[boardID] + threads = {} + for page in JSON.parse e.target.response + for thread in page.threads + if thread.no of board + threads[thread.no] = board[thread.no] + @data.boards[boardID] = threads + @deleteIfEmpty {boardID} @save() onSync: (data) => diff --git a/src/General/lib/polyfill.coffee b/src/General/lib/polyfill.coffee index cba68a122..0ad7c1fe8 100755 --- a/src/General/lib/polyfill.coffee +++ b/src/General/lib/polyfill.coffee @@ -22,7 +22,7 @@ Polyfill = # DataUrl to Binary code from Aeosynth's 4chan X repo l = data.length ui8a = new Uint8Array l - for i in [0...l] + for i in [0...l] by 1 ui8a[i] = data.charCodeAt i cb new Blob [ui8a], type: 'image/png' visibility: -> diff --git a/src/Miscellaneous/IDColor.coffee b/src/Miscellaneous/IDColor.coffee new file mode 100644 index 000000000..def9ee3c7 --- /dev/null +++ b/src/Miscellaneous/IDColor.coffee @@ -0,0 +1,40 @@ +IDColor = + init: -> + return if g.VIEW is 'catalog' or !Conf['Color User IDs'] + @ids = {} + + Post::callbacks.push + name: 'Color User IDs' + cb: @node + + node: -> + return if @isClone or !(uid = @info.uniqueID) + rgb = IDColor.compute uid + span = @nodes.uniqueID + {style} = span + style.color = rgb[3] + style.backgroundColor = "rgb(#{rgb[0]},#{rgb[1]},#{rgb[2]})" + $.addClass span, 'painted' + span.textContent = uid + span.title = 'Highlight posts by this ID' + + compute: (uniqueID) -> + if uniqueID of IDColor.ids + return IDColor.ids[uniqueID] + hash = @hash uniqueID + rgb = [ + (hash >> 24) & 0xFF + (hash >> 16) & 0xFF + (hash >> 8) & 0xFF + ] + rgb.push if (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114) > 170 + 'black' + else + 'white' + @ids[uniqueID] = rgb + + hash: (uniqueID) -> + msg = 0 + for i in [0...uniqueID.length] by 1 + msg = (msg << 5) - msg + uniqueID.charCodeAt i + msg diff --git a/src/Posting/QuickReply.coffee b/src/Posting/QuickReply.coffee index 4a9ad2e92..fbfcafbf0 100755 --- a/src/Posting/QuickReply.coffee +++ b/src/Posting/QuickReply.coffee @@ -77,7 +77,8 @@ QR = persist: -> return unless QR.postingIsEnabled QR.open() - QR.hide() if Conf['Auto Hide QR'] + QR.hide() if Conf['Auto-Hide QR'] or g.VIEW is 'catalog' + open: -> if QR.nodes QR.nodes.el.hidden = false