Use custom events to add our menu entries.

children -> subEntries
This commit is contained in:
Nicolas Stepien 2013-02-11 14:11:49 +01:00
parent 64cd4a9043
commit 84617ba149
3 changed files with 226 additions and 188 deletions

View File

@ -212,7 +212,7 @@
function Menu(type) { function Menu(type) {
this.type = type; this.type = type;
$.on(d, 'AddMenuEntry', this.addEntryListener.bind(this)); $.on(d, 'AddMenuEntry', this.addEntry.bind(this));
this.close = close.bind(this); this.close = close.bind(this);
this.entries = []; this.entries = [];
} }
@ -276,14 +276,14 @@
}; };
Menu.prototype.insertEntry = function(entry, parent, data) { 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 (typeof entry.open === 'function') {
if (!entry.open(data)) { if (!entry.open(data)) {
return; return;
} }
} }
$.add(parent, entry.el); $.add(parent, entry.el);
if (!entry.children) { if (!entry.subEntries) {
return; return;
} }
if (submenu = $('.submenu', entry.el)) { if (submenu = $('.submenu', entry.el)) {
@ -292,10 +292,10 @@
submenu = $.el('div', { submenu = $.el('div', {
className: 'reply dialog submenu' className: 'reply dialog submenu'
}); });
_ref = entry.children; _ref = entry.subEntries;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
child = _ref[_i]; subEntry = _ref[_i];
this.insertEntry(child, submenu, data); this.insertEntry(subEntry, submenu, data);
} }
$.add(entry.el, submenu); $.add(entry.el, submenu);
}; };
@ -388,36 +388,32 @@
return style.right = right; return style.right = right;
}; };
Menu.prototype.addEntry = function(entry) { Menu.prototype.addEntry = function(e) {
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) {
var entry; var entry;
entry = e.detail; entry = e.detail;
if (entry.type !== this.type) { if (entry.type !== this.type) {
return; 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; return Menu;
@ -1021,9 +1017,12 @@
href: 'javascript:;' href: 'javascript:;'
}); });
$.on(link, 'click', Settings.open); $.on(link, 'click', Settings.open);
Header.menu.addEntry({ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: link detail: {
}); type: 'header',
el: link
}
}));
link = $.el('a', { link = $.el('a', {
className: 'fourchan-settings-link', className: 'fourchan-settings-link',
textContent: '4chan Settings', textContent: '4chan Settings',
@ -1032,12 +1031,15 @@
$.on(link, 'click', function() { $.on(link, 'click', function() {
return $.id('settingsWindowLink').click(); return $.id('settingsWindowLink').click();
}); });
Header.menu.addEntry({ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: link, detail: {
open: function() { type: 'header',
return !Conf['Disable 4chan\'s extension']; el: link,
open: function() {
return !Conf['Disable 4chan\'s extension'];
}
} }
}); }));
if (!Conf['Disable 4chan\'s extension']) { if (!Conf['Disable 4chan\'s extension']) {
return; return;
} }
@ -1260,19 +1262,22 @@
textContent: 'Filter' textContent: 'Filter'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
open: function(post) { open: function(post) {
Filter.menu.post = post; Filter.menu.post = post;
return true; 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']]; _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++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_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) { createSubEntry: function(text, type) {
var el; var el;
@ -1418,25 +1423,28 @@
makeStub = $.el('label', { makeStub = $.el('label', {
innerHTML: "<input type=checkbox checked=" + Conf['Stubs'] + "> Make stub" innerHTML: "<input type=checkbox checked=" + Conf['Stubs'] + "> Make stub"
}); });
return Menu.menu.addEntry({ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: div, detail: {
open: function(post) { type: 'post',
var thread; el: div,
thread = post.thread; open: function(post) {
if (post.isReply || thread.isHidden) { var thread;
return false; thread = post.thread;
} if (post.isReply || thread.isHidden) {
ThreadHiding.menu.thread = thread; return false;
return true; }
}, ThreadHiding.menu.thread = thread;
children: [ return true;
{ },
el: apply subEntries: [
}, { {
el: makeStub el: apply
} }, {
] el: makeStub
}); }
]
}
}));
}, },
hide: function() { hide: function() {
var makeStub, thread; var makeStub, thread;
@ -1626,27 +1634,30 @@
makeStub = $.el('label', { makeStub = $.el('label', {
innerHTML: "<input type=checkbox name=makeStub checked=" + Conf['Stubs'] + "> Make stub" innerHTML: "<input type=checkbox name=makeStub checked=" + Conf['Stubs'] + "> Make stub"
}); });
return Menu.menu.addEntry({ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: div, detail: {
open: function(post) { type: 'post',
if (!post.isReply || post.isClone) { el: div,
return false; open: function(post) {
} if (!post.isReply || post.isClone) {
ReplyHiding.menu.post = post; return false;
return true; }
}, ReplyHiding.menu.post = post;
children: [ return true;
{ },
el: apply subEntries: [
}, { {
el: thisPost el: apply
}, { }, {
el: replies el: thisPost
}, { }, {
el: makeStub el: replies
} }, {
] el: makeStub
}); }
]
}
}));
}, },
hide: function() { hide: function() {
var makeStub, parent, post, replies, thisPost; var makeStub, parent, post, replies, thisPost;
@ -1864,13 +1875,16 @@
textContent: 'Report this post' textContent: 'Report this post'
}); });
$.on(a, 'click', ReportLink.report); $.on(a, 'click', ReportLink.report);
return Menu.menu.addEntry({ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: a, detail: {
open: function(post) { type: 'post',
ReportLink.post = post; el: a,
return !post.isDead; open: function(post) {
ReportLink.post = post;
return !post.isDead;
}
} }
}); }));
}, },
report: function() { report: function() {
var id, post, set, url; var id, post, set, url;
@ -1916,26 +1930,29 @@
return !!post.file; return !!post.file;
} }
}; };
Menu.menu.addEntry({ d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: div, detail: {
open: function(post) { type: 'post',
var node, seconds; el: div,
if (post.isDead) { open: function(post) {
return false; var node, seconds;
} if (post.isDead) {
DeleteLink.post = post; return false;
node = div.firstChild; }
if (seconds = DeleteLink.cooldown[post.fullID]) { DeleteLink.post = post;
node.textContent = "Delete (" + seconds + ")"; node = div.firstChild;
DeleteLink.cooldown.el = node; if (seconds = DeleteLink.cooldown[post.fullID]) {
} else { node.textContent = "Delete (" + seconds + ")";
node.textContent = 'Delete'; DeleteLink.cooldown.el = node;
delete DeleteLink.cooldown.el; } else {
} node.textContent = 'Delete';
return true; delete DeleteLink.cooldown.el;
}, }
children: [postEntry, fileEntry] return true;
}); },
subEntries: [postEntry, fileEntry]
}
}));
return $.on(d, 'QRPostSuccessful', this.cooldown.start); return $.on(d, 'QRPostSuccessful', this.cooldown.start);
}, },
"delete": function() { "delete": function() {
@ -2026,17 +2043,20 @@
className: 'download-link', className: 'download-link',
textContent: 'Download file' textContent: 'Download file'
}); });
return Menu.menu.addEntry({ return d.dispatchEvent(new CustomEvent('AddMenuEntry', {
el: a, detail: {
open: function(post) { type: 'post',
if (!post.file) { el: a,
return false; 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' textContent: 'Archive'
}); });
entry = { entry = {
type: 'post',
el: div, el: div,
open: function(post) { open: function(post) {
var redirect; var redirect;
@ -2060,14 +2081,16 @@
}); });
return redirect !== ("//boards.4chan.org/" + post.board + "/"); 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']]; _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++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
type = _ref[_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) { createSubEntry: function(text, type) {
var el, open; var el, open;

View File

@ -17,7 +17,7 @@ UI = (->
constructor: (@type) -> constructor: (@type) ->
# Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API # Doc here: https://github.com/MayhemYDG/4chan-x/wiki/Menu-API
$.on d, 'AddMenuEntry', @addEntryListener.bind @ $.on d, 'AddMenuEntry', @addEntry.bind @
@close = close.bind @ @close = close.bind @
@entries = [] @entries = []
@ -84,14 +84,14 @@ UI = (->
return unless entry.open data return unless entry.open data
$.add parent, entry.el $.add parent, entry.el
return unless entry.children return unless entry.subEntries
if submenu = $ '.submenu', entry.el if submenu = $ '.submenu', entry.el
# Reset sub menu, remove irrelevant entries. # Reset sub menu, remove irrelevant entries.
$.rm submenu $.rm submenu
submenu = $.el 'div', submenu = $.el 'div',
className: 'reply dialog submenu' className: 'reply dialog submenu'
for child in entry.children for subEntry in entry.subEntries
@insertEntry child, submenu, data @insertEntry subEntry, submenu, data
$.add entry.el, submenu $.add entry.el, submenu
return return
@ -161,28 +161,25 @@ UI = (->
style.left = left style.left = left
style.right = right style.right = right
addEntry: (entry) -> addEntry: (e) ->
entry = e.detail
return if entry.type isnt @type
@parseEntry entry @parseEntry entry
@entries.push entry @entries.push entry
parseEntry: (entry) -> parseEntry: (entry) ->
{el, children} = entry {el, subEntries} = entry
$.addClass el, 'entry' $.addClass el, 'entry'
$.on el, 'focus mouseover', ((e) -> $.on el, 'focus mouseover', ((e) ->
e.stopPropagation() e.stopPropagation()
@focus el @focus el
).bind @ ).bind @
return unless children return unless subEntries
$.addClass el, 'has-submenu' $.addClass el, 'has-submenu'
for child in children for subEntry in subEntries
@parseEntry child @parseEntry subEntry
return return
addEntryListener: (e) ->
entry = e.detail
return if entry.type isnt @type
@addEntry entry
dragstart = (e) -> dragstart = (e) ->
# prevent text selection # prevent text selection

View File

@ -101,8 +101,10 @@ Settings =
textContent: '4chan X Settings' textContent: '4chan X Settings'
href: 'javascript:;' href: 'javascript:;'
$.on link, 'click', Settings.open $.on link, 'click', Settings.open
Header.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: link detail:
type: 'header'
el: link
# 4chan settings link # 4chan settings link
link = $.el 'a', link = $.el 'a',
@ -110,9 +112,11 @@ Settings =
textContent: '4chan Settings' textContent: '4chan Settings'
href: 'javascript:;' href: 'javascript:;'
$.on link, 'click', -> $.id('settingsWindowLink').click() $.on link, 'click', -> $.id('settingsWindowLink').click()
Header.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: link detail:
open: -> !Conf['Disable 4chan\'s extension'] type: 'header'
el: link
open: -> !Conf['Disable 4chan\'s extension']
return unless Conf['Disable 4chan\'s extension'] return unless Conf['Disable 4chan\'s extension']
settings = JSON.parse(localStorage.getItem '4chan-settings') or {} settings = JSON.parse(localStorage.getItem '4chan-settings') or {}
@ -300,11 +304,12 @@ Filter =
textContent: 'Filter' textContent: 'Filter'
entry = entry =
type: 'post'
el: div el: div
open: (post) -> open: (post) ->
Filter.menu.post = post Filter.menu.post = post
true true
children: [] subEntries: []
for type in [ for type in [
['Name', 'name'] ['Name', 'name']
@ -321,9 +326,10 @@ Filter =
['Image MD5', 'MD5'] ['Image MD5', 'MD5']
] ]
# Add a sub entry for each filter type. # 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) -> createSubEntry: (text, type) ->
el = $.el 'a', el = $.el 'a',
@ -475,15 +481,17 @@ ThreadHiding =
makeStub = $.el 'label', makeStub = $.el 'label',
innerHTML: "<input type=checkbox checked=#{Conf['Stubs']}> Make stub" innerHTML: "<input type=checkbox checked=#{Conf['Stubs']}> Make stub"
Menu.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: div detail:
open: (post) -> type: 'post'
{thread} = post el: div
if post.isReply or thread.isHidden open: (post) ->
return false {thread} = post
ThreadHiding.menu.thread = thread if post.isReply or thread.isHidden
true return false
children: [{el: apply}, {el: makeStub}] ThreadHiding.menu.thread = thread
true
subEntries: [{el: apply}, {el: makeStub}]
hide: -> hide: ->
makeStub = $('input', @parentNode).checked makeStub = $('input', @parentNode).checked
{thread} = ThreadHiding.menu {thread} = ThreadHiding.menu
@ -627,14 +635,16 @@ ReplyHiding =
makeStub = $.el 'label', makeStub = $.el 'label',
innerHTML: "<input type=checkbox name=makeStub checked=#{Conf['Stubs']}> Make stub" innerHTML: "<input type=checkbox name=makeStub checked=#{Conf['Stubs']}> Make stub"
Menu.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: div detail:
open: (post) -> type: 'post'
if !post.isReply or post.isClone el: div
return false open: (post) ->
ReplyHiding.menu.post = post if !post.isReply or post.isClone
true return false
children: [{el: apply}, {el: thisPost}, {el: replies}, {el: makeStub}] ReplyHiding.menu.post = post
true
subEntries: [{el: apply}, {el: thisPost}, {el: replies}, {el: makeStub}]
hide: -> hide: ->
parent = @parentNode parent = @parentNode
thisPost = $('input[name=thisPost]', parent).checked thisPost = $('input[name=thisPost]', parent).checked
@ -795,11 +805,13 @@ ReportLink =
href: 'javascript:;' href: 'javascript:;'
textContent: 'Report this post' textContent: 'Report this post'
$.on a, 'click', ReportLink.report $.on a, 'click', ReportLink.report
Menu.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: a detail:
open: (post) -> type: 'post'
ReportLink.post = post el: a
!post.isDead open: (post) ->
ReportLink.post = post
!post.isDead
report: -> report: ->
{post} = ReportLink {post} = ReportLink
url = "//sys.4chan.org/#{post.board}/imgboard.php?mode=report&no=#{post}" url = "//sys.4chan.org/#{post.board}/imgboard.php?mode=report&no=#{post}"
@ -834,20 +846,22 @@ DeleteLink =
$.on fileEl, 'click', DeleteLink.delete $.on fileEl, 'click', DeleteLink.delete
!!post.file !!post.file
Menu.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: div detail:
open: (post) -> type: 'post'
return false if post.isDead el: div
DeleteLink.post = post open: (post) ->
node = div.firstChild return false if post.isDead
if seconds = DeleteLink.cooldown[post.fullID] DeleteLink.post = post
node.textContent = "Delete (#{seconds})" node = div.firstChild
DeleteLink.cooldown.el = node if seconds = DeleteLink.cooldown[post.fullID]
else node.textContent = "Delete (#{seconds})"
node.textContent = 'Delete' DeleteLink.cooldown.el = node
delete DeleteLink.cooldown.el else
true node.textContent = 'Delete'
children: [postEntry, fileEntry] delete DeleteLink.cooldown.el
true
subEntries: [postEntry, fileEntry]
$.on d, 'QRPostSuccessful', @cooldown.start $.on d, 'QRPostSuccessful', @cooldown.start
@ -922,13 +936,15 @@ DownloadLink =
a = $.el 'a', a = $.el 'a',
className: 'download-link' className: 'download-link'
textContent: 'Download file' textContent: 'Download file'
Menu.menu.addEntry d.dispatchEvent new CustomEvent 'AddMenuEntry',
el: a detail:
open: (post) -> type: 'post'
return false unless post.file el: a
a.href = post.file.URL open: (post) ->
a.download = post.file.name return false unless post.file
true a.href = post.file.URL
a.download = post.file.name
true
ArchiveLink = ArchiveLink =
init: -> init: ->
@ -938,6 +954,7 @@ ArchiveLink =
textContent: 'Archive' textContent: 'Archive'
entry = entry =
type: 'post'
el: div el: div
open: (post) -> open: (post) ->
redirect = Redirect.to redirect = Redirect.to
@ -945,7 +962,7 @@ ArchiveLink =
threadID: post.thread threadID: post.thread
postID: post.ID postID: post.ID
redirect isnt "//boards.4chan.org/#{post.board}/" redirect isnt "//boards.4chan.org/#{post.board}/"
children: [] subEntries: []
for type in [ for type in [
['Post', 'post'] ['Post', 'post']
@ -957,9 +974,10 @@ ArchiveLink =
['Image MD5', 'MD5'] ['Image MD5', 'MD5']
] ]
# Add a sub entry for each type. # 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) -> createSubEntry: (text, type) ->
el = $.el 'a', el = $.el 'a',