diff --git a/4chan_x.user.js b/4chan_x.user.js index 4289cfe40..424a3a6ae 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -77,7 +77,7 @@ */ (function() { - var $, $$, Anonymize, AutoGif, Conf, Config, DeleteButton, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, Get, ImageExpand, ImageHover, Keybinds, Main, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Time, TitlePost, UI, Unread, Updater, Watcher, d, g, _base; + var $, $$, Anonymize, AutoGif, Conf, Config, DeleteButton, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, Get, ImageExpand, ImageHover, Keybinds, Main, Menu, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Time, TitlePost, UI, Unread, Updater, Watcher, d, g, _base; Config = { main: { @@ -1071,6 +1071,73 @@ } }; + Menu = { + entries: [], + init: function() { + this.a = $.el('a', { + className: 'menu_button', + href: 'javascript:;', + innerHTML: '[▼]' + }); + this.el = $.el('div', { + className: 'reply dialog', + id: 'menu' + }); + $.on(this.el, 'click', function(e) { + return e.stopPropagation(); + }); + return Main.callbacks.push(this.node); + }, + node: function(post) { + var a; + if (!(a = $('.menu_button', post.el))) { + a = Menu.a.cloneNode(true); + $.add($('.postInfo', post.el), a); + } + return $.on(a, 'click', Menu.toggle); + }, + toggle: function(e) { + var lastOpener, s; + e.preventDefault(); + e.stopPropagation(); + if (Menu.el.parentNode) { + lastOpener = Menu.lastOpener; + Menu.close(); + if (lastOpener === this) { + return; + } + } + s = Menu.el.style; + s.top = this.offsetTop + this.offsetHeight + 2 + 'px'; + s.left = this.offsetLeft + 'px'; + Menu.lastOpener = this; + return Menu.open(Main.preParse($.x('ancestor::div[contains(@class,"postContainer")][1]', this))); + }, + open: function(post) { + var entry, i, _i, _len, _ref; + for (i in post) { + $.add(Menu.el, $.el('code', { + className: 'entry', + textContent: "" + i + ": " + post[i] + })); + } + _ref = Menu.entries; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + entry = _ref[_i]; + $.add(Menu.el, entry.el); + $.addClass(entry.el, 'entry'); + } + $.add(d.body, Menu.el); + return $.on(d, 'click', Menu.close); + }, + close: function() { + $.rm(Menu.el); + Menu.el.innerHTML = null; + delete Menu.lastOpener; + return $.off(d, 'click', Menu.close); + } + }; + Keybinds = { init: function() { var node, _i, _len, _ref; @@ -4429,6 +4496,7 @@ if (Conf['Anonymize']) { Anonymize.init(); } + Menu.init(); if (Conf['Time Formatting']) { Time.init(); } @@ -4715,6 +4783,21 @@ a[href="javascript:;"] {\ display: none !important;\ }\ \ +#menu {\ + position: absolute;\ +}\ +.entry {\ + border-bottom: 1px solid rgba(0, 0, 0, .25);\ + display: block;\ + padding: 3px 4px;\ +}\ +.entry:last-child {\ + border: none;\ +}\ +.entry:hover, .entry:focus {\ + background: rgba(255, 255, 255, .33);\ +}\ +\ h1 {\ text-align: center;\ }\ diff --git a/script.coffee b/script.coffee index ea61bfd78..ceac5dc77 100644 --- a/script.coffee +++ b/script.coffee @@ -814,6 +814,61 @@ ReplyHiding = $('.sideArrows', root).hidden = false $('.post', root).hidden = false +Menu = + entries: [] + init: -> + @a = $.el 'a', + className: 'menu_button' + href: 'javascript:;' + innerHTML: '[▼]' + @el = $.el 'div', + className: 'reply dialog' + id: 'menu' + + $.on @el, 'click', (e) -> e.stopPropagation() + + Main.callbacks.push @node + node: (post) -> + unless a = $ '.menu_button', post.el + a = Menu.a.cloneNode true + $.add $('.postInfo', post.el), a + $.on a, 'click', Menu.toggle + + toggle: (e) -> + e.preventDefault() + e.stopPropagation() + + if Menu.el.parentNode + # Close if it's already opened. + # Reopen if we clicked on another button. + {lastOpener} = Menu + Menu.close() + return if lastOpener is @ + + # Position + s = Menu.el.style + s.top = @offsetTop + @offsetHeight + 2 + 'px' + s.left = @offsetLeft + 'px' + + Menu.lastOpener = @ + Menu.open Main.preParse $.x 'ancestor::div[contains(@class,"postContainer")][1]', @ + open: (post) -> + for i of post + $.add Menu.el, $.el 'code', + className: 'entry' + textContent: "#{i}: #{post[i]}" + for entry in Menu.entries + # if the entry matches this post... + $.add Menu.el, entry.el + $.addClass entry.el, 'entry' # XXX ??? + $.add d.body, Menu.el + $.on d, 'click', Menu.close + close: -> + $.rm Menu.el + Menu.el.innerHTML = null + delete Menu.lastOpener + $.off d, 'click', Menu.close + Keybinds = init: -> for node in $$ '[accesskey]' @@ -3435,6 +3490,8 @@ Main = if Conf['Anonymize'] Anonymize.init() + Menu.init() + if Conf['Time Formatting'] Time.init() @@ -3663,6 +3720,21 @@ a[href="javascript:;"] { display: none !important; } +#menu { + position: absolute; +} +.entry { + border-bottom: 1px solid rgba(0, 0, 0, .25); + display: block; + padding: 3px 4px; +} +.entry:last-child { + border: none; +} +.entry:hover, .entry:focus { + background: rgba(255, 255, 255, .33); +} + h1 { text-align: center; }