diff --git a/4chan_x.user.js b/4chan_x.user.js
index 66d2f2f0e..77fda1b8f 100644
--- a/4chan_x.user.js
+++ b/4chan_x.user.js
@@ -212,7 +212,7 @@
function Menu(type) {
this.type = type;
- $.on(d, 'AddMenuEntry', this.addEntryListener.bind(this));
+ $.on(d, 'AddMenuEntry', this.addEntry.bind(this));
this.close = close.bind(this);
this.entries = [];
}
@@ -276,14 +276,14 @@
};
Menu.prototype.insertEntry = function(entry, parent, data) {
- var child, submenu, _i, _len, _ref;
+ var subEntry, submenu, _i, _len, _ref;
if (typeof entry.open === 'function') {
if (!entry.open(data)) {
return;
}
}
$.add(parent, entry.el);
- if (!entry.children) {
+ if (!entry.subEntries) {
return;
}
if (submenu = $('.submenu', entry.el)) {
@@ -292,10 +292,10 @@
submenu = $.el('div', {
className: 'reply dialog submenu'
});
- _ref = entry.children;
+ _ref = entry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- child = _ref[_i];
- this.insertEntry(child, submenu, data);
+ subEntry = _ref[_i];
+ this.insertEntry(subEntry, submenu, data);
}
$.add(entry.el, submenu);
};
@@ -388,36 +388,32 @@
return style.right = right;
};
- Menu.prototype.addEntry = function(entry) {
- this.parseEntry(entry);
- return this.entries.push(entry);
- };
-
- Menu.prototype.parseEntry = function(entry) {
- var child, children, el, _i, _len;
- el = entry.el, children = entry.children;
- $.addClass(el, 'entry');
- $.on(el, 'focus mouseover', (function(e) {
- e.stopPropagation();
- return this.focus(el);
- }).bind(this));
- if (!children) {
- return;
- }
- $.addClass(el, 'has-submenu');
- for (_i = 0, _len = children.length; _i < _len; _i++) {
- child = children[_i];
- this.parseEntry(child);
- }
- };
-
- Menu.prototype.addEntryListener = function(e) {
+ Menu.prototype.addEntry = function(e) {
var entry;
entry = e.detail;
if (entry.type !== this.type) {
return;
}
- return this.addEntry(entry);
+ this.parseEntry(entry);
+ return this.entries.push(entry);
+ };
+
+ Menu.prototype.parseEntry = function(entry) {
+ var el, subEntries, subEntry, _i, _len;
+ el = entry.el, subEntries = entry.subEntries;
+ $.addClass(el, 'entry');
+ $.on(el, 'focus mouseover', (function(e) {
+ e.stopPropagation();
+ return this.focus(el);
+ }).bind(this));
+ if (!subEntries) {
+ return;
+ }
+ $.addClass(el, 'has-submenu');
+ for (_i = 0, _len = subEntries.length; _i < _len; _i++) {
+ subEntry = subEntries[_i];
+ this.parseEntry(subEntry);
+ }
};
return Menu;
@@ -1021,9 +1017,12 @@
href: 'javascript:;'
});
$.on(link, 'click', Settings.open);
- Header.menu.addEntry({
- el: link
- });
+ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'header',
+ el: link
+ }
+ }));
link = $.el('a', {
className: 'fourchan-settings-link',
textContent: '4chan Settings',
@@ -1032,12 +1031,15 @@
$.on(link, 'click', function() {
return $.id('settingsWindowLink').click();
});
- Header.menu.addEntry({
- el: link,
- open: function() {
- return !Conf['Disable 4chan\'s extension'];
+ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'header',
+ el: link,
+ open: function() {
+ return !Conf['Disable 4chan\'s extension'];
+ }
}
- });
+ }));
if (!Conf['Disable 4chan\'s extension']) {
return;
}
@@ -1260,19 +1262,22 @@
textContent: 'Filter'
});
entry = {
+ type: 'post',
el: div,
open: function(post) {
Filter.menu.post = post;
return true;
},
- children: []
+ subEntries: []
};
_ref = [['Name', 'name'], ['Unique ID', 'uniqueID'], ['Tripcode', 'tripcode'], ['Capcode', 'capcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Comment', 'comment'], ['Flag', 'flag'], ['Filename', 'filename'], ['Image dimensions', 'dimensions'], ['Filesize', 'filesize'], ['Image MD5', 'MD5']];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i];
- entry.children.push(Filter.menu.createSubEntry(type[0], type[1]));
+ entry.subEntries.push(Filter.menu.createSubEntry(type[0], type[1]));
}
- return Menu.menu.addEntry(entry);
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: entry
+ }));
},
createSubEntry: function(text, type) {
var el;
@@ -1418,25 +1423,28 @@
makeStub = $.el('label', {
innerHTML: " Make stub"
});
- return Menu.menu.addEntry({
- el: div,
- open: function(post) {
- var thread;
- thread = post.thread;
- if (post.isReply || thread.isHidden) {
- return false;
- }
- ThreadHiding.menu.thread = thread;
- return true;
- },
- children: [
- {
- el: apply
- }, {
- el: makeStub
- }
- ]
- });
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'post',
+ el: div,
+ open: function(post) {
+ var thread;
+ thread = post.thread;
+ if (post.isReply || thread.isHidden) {
+ return false;
+ }
+ ThreadHiding.menu.thread = thread;
+ return true;
+ },
+ subEntries: [
+ {
+ el: apply
+ }, {
+ el: makeStub
+ }
+ ]
+ }
+ }));
},
hide: function() {
var makeStub, thread;
@@ -1626,27 +1634,30 @@
makeStub = $.el('label', {
innerHTML: " Make stub"
});
- return Menu.menu.addEntry({
- el: div,
- open: function(post) {
- if (!post.isReply || post.isClone) {
- return false;
- }
- ReplyHiding.menu.post = post;
- return true;
- },
- children: [
- {
- el: apply
- }, {
- el: thisPost
- }, {
- el: replies
- }, {
- el: makeStub
- }
- ]
- });
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'post',
+ el: div,
+ open: function(post) {
+ if (!post.isReply || post.isClone) {
+ return false;
+ }
+ ReplyHiding.menu.post = post;
+ return true;
+ },
+ subEntries: [
+ {
+ el: apply
+ }, {
+ el: thisPost
+ }, {
+ el: replies
+ }, {
+ el: makeStub
+ }
+ ]
+ }
+ }));
},
hide: function() {
var makeStub, parent, post, replies, thisPost;
@@ -1864,13 +1875,16 @@
textContent: 'Report this post'
});
$.on(a, 'click', ReportLink.report);
- return Menu.menu.addEntry({
- el: a,
- open: function(post) {
- ReportLink.post = post;
- return !post.isDead;
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'post',
+ el: a,
+ open: function(post) {
+ ReportLink.post = post;
+ return !post.isDead;
+ }
}
- });
+ }));
},
report: function() {
var id, post, set, url;
@@ -1916,26 +1930,29 @@
return !!post.file;
}
};
- Menu.menu.addEntry({
- el: div,
- open: function(post) {
- var node, seconds;
- if (post.isDead) {
- return false;
- }
- DeleteLink.post = post;
- node = div.firstChild;
- if (seconds = DeleteLink.cooldown[post.fullID]) {
- node.textContent = "Delete (" + seconds + ")";
- DeleteLink.cooldown.el = node;
- } else {
- node.textContent = 'Delete';
- delete DeleteLink.cooldown.el;
- }
- return true;
- },
- children: [postEntry, fileEntry]
- });
+ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'post',
+ el: div,
+ open: function(post) {
+ var node, seconds;
+ if (post.isDead) {
+ return false;
+ }
+ DeleteLink.post = post;
+ node = div.firstChild;
+ if (seconds = DeleteLink.cooldown[post.fullID]) {
+ node.textContent = "Delete (" + seconds + ")";
+ DeleteLink.cooldown.el = node;
+ } else {
+ node.textContent = 'Delete';
+ delete DeleteLink.cooldown.el;
+ }
+ return true;
+ },
+ subEntries: [postEntry, fileEntry]
+ }
+ }));
return $.on(d, 'QRPostSuccessful', this.cooldown.start);
},
"delete": function() {
@@ -2026,17 +2043,20 @@
className: 'download-link',
textContent: 'Download file'
});
- return Menu.menu.addEntry({
- el: a,
- open: function(post) {
- if (!post.file) {
- return false;
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: {
+ type: 'post',
+ el: a,
+ open: function(post) {
+ if (!post.file) {
+ return false;
+ }
+ a.href = post.file.URL;
+ a.download = post.file.name;
+ return true;
}
- a.href = post.file.URL;
- a.download = post.file.name;
- return true;
}
- });
+ }));
}
};
@@ -2050,6 +2070,7 @@
textContent: 'Archive'
});
entry = {
+ type: 'post',
el: div,
open: function(post) {
var redirect;
@@ -2060,14 +2081,16 @@
});
return redirect !== ("//boards.4chan.org/" + post.board + "/");
},
- children: []
+ subEntries: []
};
_ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_i];
- entry.children.push(this.createSubEntry(type[0], type[1]));
+ entry.subEntries.push(this.createSubEntry(type[0], type[1]));
}
- return Menu.menu.addEntry(entry);
+ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
+ detail: entry
+ }));
},
createSubEntry: function(text, type) {
var el, open;
diff --git a/lib/ui.coffee b/lib/ui.coffee
index 2db8dad3c..593960a7e 100644
--- a/lib/ui.coffee
+++ b/lib/ui.coffee
@@ -17,7 +17,7 @@ UI = (->
constructor: (@type) ->
# Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API
- $.on d, 'AddMenuEntry', @addEntryListener.bind @
+ $.on d, 'AddMenuEntry', @addEntry.bind @
@close = close.bind @
@entries = []
@@ -84,14 +84,14 @@ UI = (->
return unless entry.open data
$.add parent, entry.el
- return unless entry.children
+ return unless entry.subEntries
if submenu = $ '.submenu', entry.el
# Reset sub menu, remove irrelevant entries.
$.rm submenu
submenu = $.el 'div',
className: 'reply dialog submenu'
- for child in entry.children
- @insertEntry child, submenu, data
+ for subEntry in entry.subEntries
+ @insertEntry subEntry, submenu, data
$.add entry.el, submenu
return
@@ -161,28 +161,25 @@ UI = (->
style.left = left
style.right = right
- addEntry: (entry) ->
+ addEntry: (e) ->
+ entry = e.detail
+ return if entry.type isnt @type
@parseEntry entry
@entries.push entry
parseEntry: (entry) ->
- {el, children} = entry
+ {el, subEntries} = entry
$.addClass el, 'entry'
$.on el, 'focus mouseover', ((e) ->
e.stopPropagation()
@focus el
).bind @
- return unless children
+ return unless subEntries
$.addClass el, 'has-submenu'
- for child in children
- @parseEntry child
+ for subEntry in subEntries
+ @parseEntry subEntry
return
- addEntryListener: (e) ->
- entry = e.detail
- return if entry.type isnt @type
- @addEntry entry
-
dragstart = (e) ->
# prevent text selection
diff --git a/src/features.coffee b/src/features.coffee
index e46cb6655..67b7e1e11 100644
--- a/src/features.coffee
+++ b/src/features.coffee
@@ -101,8 +101,10 @@ Settings =
textContent: '4chan X Settings'
href: 'javascript:;'
$.on link, 'click', Settings.open
- Header.menu.addEntry
- el: link
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'header'
+ el: link
# 4chan settings link
link = $.el 'a',
@@ -110,9 +112,11 @@ Settings =
textContent: '4chan Settings'
href: 'javascript:;'
$.on link, 'click', -> $.id('settingsWindowLink').click()
- Header.menu.addEntry
- el: link
- open: -> !Conf['Disable 4chan\'s extension']
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'header'
+ el: link
+ open: -> !Conf['Disable 4chan\'s extension']
return unless Conf['Disable 4chan\'s extension']
settings = JSON.parse(localStorage.getItem '4chan-settings') or {}
@@ -300,11 +304,12 @@ Filter =
textContent: 'Filter'
entry =
+ type: 'post'
el: div
open: (post) ->
Filter.menu.post = post
true
- children: []
+ subEntries: []
for type in [
['Name', 'name']
@@ -321,9 +326,10 @@ Filter =
['Image MD5', 'MD5']
]
# Add a sub entry for each filter type.
- entry.children.push Filter.menu.createSubEntry type[0], type[1]
+ entry.subEntries.push Filter.menu.createSubEntry type[0], type[1]
- Menu.menu.addEntry entry
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail: entry
createSubEntry: (text, type) ->
el = $.el 'a',
@@ -475,15 +481,17 @@ ThreadHiding =
makeStub = $.el 'label',
innerHTML: " Make stub"
- Menu.menu.addEntry
- el: div
- open: (post) ->
- {thread} = post
- if post.isReply or thread.isHidden
- return false
- ThreadHiding.menu.thread = thread
- true
- children: [{el: apply}, {el: makeStub}]
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'post'
+ el: div
+ open: (post) ->
+ {thread} = post
+ if post.isReply or thread.isHidden
+ return false
+ ThreadHiding.menu.thread = thread
+ true
+ subEntries: [{el: apply}, {el: makeStub}]
hide: ->
makeStub = $('input', @parentNode).checked
{thread} = ThreadHiding.menu
@@ -627,14 +635,16 @@ ReplyHiding =
makeStub = $.el 'label',
innerHTML: " Make stub"
- Menu.menu.addEntry
- el: div
- open: (post) ->
- if !post.isReply or post.isClone
- return false
- ReplyHiding.menu.post = post
- true
- children: [{el: apply}, {el: thisPost}, {el: replies}, {el: makeStub}]
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'post'
+ el: div
+ open: (post) ->
+ if !post.isReply or post.isClone
+ return false
+ ReplyHiding.menu.post = post
+ true
+ subEntries: [{el: apply}, {el: thisPost}, {el: replies}, {el: makeStub}]
hide: ->
parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked
@@ -795,11 +805,13 @@ ReportLink =
href: 'javascript:;'
textContent: 'Report this post'
$.on a, 'click', ReportLink.report
- Menu.menu.addEntry
- el: a
- open: (post) ->
- ReportLink.post = post
- !post.isDead
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'post'
+ el: a
+ open: (post) ->
+ ReportLink.post = post
+ !post.isDead
report: ->
{post} = ReportLink
url = "//sys.4chan.org/#{post.board}/imgboard.php?mode=report&no=#{post}"
@@ -834,20 +846,22 @@ DeleteLink =
$.on fileEl, 'click', DeleteLink.delete
!!post.file
- Menu.menu.addEntry
- el: div
- open: (post) ->
- return false if post.isDead
- DeleteLink.post = post
- node = div.firstChild
- if seconds = DeleteLink.cooldown[post.fullID]
- node.textContent = "Delete (#{seconds})"
- DeleteLink.cooldown.el = node
- else
- node.textContent = 'Delete'
- delete DeleteLink.cooldown.el
- true
- children: [postEntry, fileEntry]
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'post'
+ el: div
+ open: (post) ->
+ return false if post.isDead
+ DeleteLink.post = post
+ node = div.firstChild
+ if seconds = DeleteLink.cooldown[post.fullID]
+ node.textContent = "Delete (#{seconds})"
+ DeleteLink.cooldown.el = node
+ else
+ node.textContent = 'Delete'
+ delete DeleteLink.cooldown.el
+ true
+ subEntries: [postEntry, fileEntry]
$.on d, 'QRPostSuccessful', @cooldown.start
@@ -922,13 +936,15 @@ DownloadLink =
a = $.el 'a',
className: 'download-link'
textContent: 'Download file'
- Menu.menu.addEntry
- el: a
- open: (post) ->
- return false unless post.file
- a.href = post.file.URL
- a.download = post.file.name
- true
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail:
+ type: 'post'
+ el: a
+ open: (post) ->
+ return false unless post.file
+ a.href = post.file.URL
+ a.download = post.file.name
+ true
ArchiveLink =
init: ->
@@ -938,6 +954,7 @@ ArchiveLink =
textContent: 'Archive'
entry =
+ type: 'post'
el: div
open: (post) ->
redirect = Redirect.to
@@ -945,7 +962,7 @@ ArchiveLink =
threadID: post.thread
postID: post.ID
redirect isnt "//boards.4chan.org/#{post.board}/"
- children: []
+ subEntries: []
for type in [
['Post', 'post']
@@ -957,9 +974,10 @@ ArchiveLink =
['Image MD5', 'MD5']
]
# Add a sub entry for each type.
- entry.children.push @createSubEntry type[0], type[1]
+ entry.subEntries.push @createSubEntry type[0], type[1]
- Menu.menu.addEntry entry
+ d.dispatchEvent new CustomEvent 'AddMenuEntry',
+ detail: entry
createSubEntry: (text, type) ->
el = $.el 'a',