diff --git a/js/post-filter.js b/js/post-filter.js
index c2c5a764..83684176 100644
--- a/js/post-filter.js
+++ b/js/post-filter.js
@@ -204,192 +204,150 @@ if (active_page === 'thread' || active_page === 'index') {
/*
* create filter menu when the button is clicked
*/
- function addMenu(e, ele, threadId, pageData) {
+ function initPostMenu(pageData) {
- var $ele = $(ele);
- var $buffer;
+ var submenu;
+ Menu.add_item('filter-menu-hide', 'Hide post');
+ Menu.add_item('filter-menu-unhide', 'Unhide post');
- var postId = $ele.find('.post_no').not('[id]').text();
- if (pageData.hasUID) {
- var postUid = $ele.find('.poster_id').text();
- }
- var postName;
- var postTrip = '';
- if (!pageData.forcedAnon) {
- postName = (typeof $ele.find('.name').contents()[0] == 'undefined') ? '' : $ele.find('.name').contents()[0].nodeValue.trim();
- postTrip = $ele.find('.trip').text();
- }
+ submenu = Menu.add_submenu('filter-menu-add', 'Add filter');
+ submenu.add_item('filter-add-post-plus', 'Post +', 'Hide post and all replies');
+ submenu.add_item('filter-add-id', 'ID');
+ submenu.add_item('filter-add-id-plus', 'ID +', 'Hide ID and all replies');
+ submenu.add_item('filter-add-name', 'Name');
+ submenu.add_item('filter-add-trip', 'Tripcode');
- // get the button's position
- var pos = $(e.target).offset();
+ submenu = Menu.add_submenu('filter-menu-remove', 'Remove filter');
+ submenu.add_item('filter-remove-id', 'ID');
+ submenu.add_item('filter-remove-name', 'Name');
+ submenu.add_item('filter-remove-trip', 'Tripcode');
- $buffer = $('
').append(
- $('').append(
- $('- ', {id: 'filter-menu-unhide'}).text('Unhide post'),
- $('
- ', {id: 'filter-menu-add'}).append(
- $('
').append(
- $('- ', {class: 'filter-post'}).text('Post'),
- $('
- ', {class: 'filter-post-plus', title: 'Hide post and all replies'}).text('Post +'),
- $('
- ', {class: 'filter-id'}).text('ID'),
- $('
- ', {class: 'filter-id-plus', title: 'Hide ID and all replies'}).text('ID +'),
- $('
- ', {class: 'filter-name'}).text('Name'),
- $('
- ', {class: 'filter-trip'}).text('Tripcode')
- ),
- 'Add filter',
- $('', {class: 'filter-menu-arrow'}).append('»')
- ),
- $('
- ', {id: 'filter-menu-remove'}).append(
- $('
').append(
- $('- ', {class: 'filter-id'}).text('ID'),
- $('
- ', {class: 'filter-name'}).text('Name'),
- $('
- ', {class: 'filter-trip'}).text('Tripcode')
- ),
- 'Remove filter',
- $('', {class: 'filter-menu-arrow'}).append('»')
- )
- )
- );
+ Menu.onclick(function (e, $buffer) {
+ var ele = e.target.parentElement.parentElement;
+ var $ele = $(ele);
- /* display logic and bind click handlers
- */
+ var threadId = $ele.parent().attr('id').replace('thread_', '');
+ var postId = $ele.find('.post_no').not('[id]').text();
+ if (pageData.hasUID) {
+ var postUid = $ele.find('.poster_id').text();
+ }
- // unhide button
- if ($(ele).data('hidden') == '1' && $(ele).data('hiddenByUid') == '0' &&
- $(ele).data('hiddenByName') == '0' && $(ele).data('hiddenByTrip') == '0') {
- $buffer.find('#filter-menu-unhide').click(function () {
- // if hidden due to post id, remove it from blacklist
- // otherwise just show this post
- blacklist.remove.post(pageData.boardId, threadId, postId);
- show(ele);
- });
- } else {
- $buffer.find('#filter-menu-unhide').addClass('hidden');
- }
+ var postName;
+ var postTrip = '';
+ if (!pageData.forcedAnon) {
+ postName = (typeof $ele.find('.name').contents()[0] == 'undefined') ? '' : $ele.find('.name').contents()[0].nodeValue.trim();
+ postTrip = $ele.find('.trip').text();
+ }
- // post id
- if ($(ele).data('hiddenByPost') == '0') {
- $buffer.find('#filter-menu-add .filter-post').click(function () {
- blacklist.add.post(pageData.boardId, threadId, postId, false);
- });
- $buffer.find('#filter-menu-add .filter-post-plus').click(function () {
- blacklist.add.post(pageData.boardId, threadId, postId, true);
- });
- } else {
- $buffer.find('#filter-menu-add .filter-post').addClass('hidden');
- $buffer.find('#filter-menu-add .filter-post-plus').addClass('hidden');
- }
+ /* display logic and bind click handlers
+ */
- // UID
- if (pageData.hasUID && $(ele).data('hiddenByUid') == '0') {
- $buffer.find('#filter-menu-add .filter-id').click(function () {
- blacklist.add.uid(pageData.boardId, threadId, postUid, false);
- });
- $buffer.find('#filter-menu-add .filter-id-plus').click(function () {
- blacklist.add.uid(pageData.boardId, threadId, postUid, true);
- });
+ // unhide button
+ if ($ele.data('hidden') == '1' && $ele.data('hiddenByUid') == '0' &&
+ $ele.data('hiddenByName') == '0' && $ele.data('hiddenByTrip') == '0') {
+ $buffer.find('#filter-menu-unhide').click(function () {
+ // if hidden due to post id, remove it from blacklist
+ // otherwise just show this post
+ blacklist.remove.post(pageData.boardId, threadId, postId);
+ show(ele);
+ });
+ } else {
+ $buffer.find('#filter-menu-unhide').addClass('hidden');
+ }
- $buffer.find('#filter-menu-remove .filter-id').addClass('hidden');
- } else if (pageData.hasUID) {
- $buffer.find('#filter-menu-remove .filter-id').click(function () {
- blacklist.remove.uid(pageData.boardId, threadId, postUid);
- });
+ // post id
+ if ($ele.data('hiddenByPost') == '0') {
+ $buffer.find('#filter-menu-hide').click(function () {
+ blacklist.add.post(pageData.boardId, threadId, postId, false);
+ });
+ $buffer.find('#filter-add-post-plus').click(function () {
+ blacklist.add.post(pageData.boardId, threadId, postId, true);
+ });
+ } else {
+ $buffer.find('#filter-menu-hide').addClass('hidden');
+ $buffer.find('#filter-add-post-plus').addClass('hidden');
+ }
- $buffer.find('#filter-menu-add .filter-id').addClass('hidden');
- $buffer.find('#filter-menu-add .filter-id-plus').addClass('hidden');
- } else {
- // board doesn't use UID
- $buffer.find('#filter-menu-add .filter-id').addClass('hidden');
- $buffer.find('#filter-menu-add .filter-id-plus').addClass('hidden');
- $buffer.find('#filter-menu-remove .filter-id').addClass('hidden');
- }
+ // UID
+ if (pageData.hasUID && $ele.data('hiddenByUid') == '0') {
+ $buffer.find('#filter-add-id').click(function () {
+ blacklist.add.uid(pageData.boardId, threadId, postUid, false);
+ });
+ $buffer.find('#filter-add-id-plus').click(function () {
+ blacklist.add.uid(pageData.boardId, threadId, postUid, true);
+ });
- // name
- if (!pageData.forcedAnon && $(ele).data('hiddenByName') == '0') {
- $buffer.find('#filter-menu-add .filter-name').click(function () {
- blacklist.add.name(postName);
- });
+ $buffer.find('#filter-remove-id').addClass('hidden');
+ } else if (pageData.hasUID) {
+ $buffer.find('#filter-remove-id').click(function () {
+ blacklist.remove.uid(pageData.boardId, threadId, postUid);
+ });
- $buffer.find('#filter-menu-remove .filter-name').addClass('hidden');
- } else if (!pageData.forcedAnon) {
- $buffer.find('#filter-menu-remove .filter-name').click(function () {
- blacklist.remove.name(postName);
- });
+ $buffer.find('#filter-add-id').addClass('hidden');
+ $buffer.find('#filter-add-id-plus').addClass('hidden');
+ } else {
+ // board doesn't use UID
+ $buffer.find('#filter-add-id').addClass('hidden');
+ $buffer.find('#filter-add-id-plus').addClass('hidden');
+ $buffer.find('#filter-remove-id').addClass('hidden');
+ }
- $buffer.find('#filter-menu-add .filter-name').addClass('hidden');
- } else {
- // board has forced anon
- $buffer.find('#filter-menu-remove .filter-name').addClass('hidden');
- $buffer.find('#filter-menu-add .filter-name').addClass('hidden');
- }
+ // name
+ if (!pageData.forcedAnon && $ele.data('hiddenByName') == '0') {
+ $buffer.find('#filter-add-name').click(function () {
+ blacklist.add.name(postName);
+ });
- // tripcode
- if (!pageData.forcedAnon && $(ele).data('hiddenByTrip') == '0' && postTrip !== '') {
- $buffer.find('#filter-menu-add .filter-trip').click(function () {
- blacklist.add.trip(postTrip);
- });
+ $buffer.find('#filter-remove-name').addClass('hidden');
+ } else if (!pageData.forcedAnon) {
+ $buffer.find('#filter-remove-name').click(function () {
+ blacklist.remove.name(postName);
+ });
- $buffer.find('#filter-menu-remove .filter-trip').addClass('hidden');
- } else if (!pageData.forcedAnon && postTrip !== '') {
- $buffer.find('#filter-menu-remove .filter-trip').click(function () {
- blacklist.remove.trip(postTrip);
- });
+ $buffer.find('#filter-add-name').addClass('hidden');
+ } else {
+ // board has forced anon
+ $buffer.find('#filter-remove-name').addClass('hidden');
+ $buffer.find('#filter-add-name').addClass('hidden');
+ }
- $buffer.find('#filter-menu-add .filter-trip').addClass('hidden');
- } else {
- // board has forced anon
- $buffer.find('#filter-menu-remove .filter-trip').addClass('hidden');
- $buffer.find('#filter-menu-add .filter-trip').addClass('hidden');
- }
+ // tripcode
+ if (!pageData.forcedAnon && $ele.data('hiddenByTrip') == '0' && postTrip !== '') {
+ $buffer.find('#filter-add-trip').click(function () {
+ blacklist.add.trip(postTrip);
+ });
- /* hide sub menus if all items are hidden
- */
- if (!$buffer.find('#filter-menu-remove > ul').children().not('.hidden').length) {
- $buffer.find('#filter-menu-remove').addClass('hidden');
- }
- if (!$buffer.find('#filter-menu-add > ul').children().not('.hidden').length) {
- $buffer.find('#filter-menu-add').addClass('hidden');
- }
+ $buffer.find('#filter-remove-trip').addClass('hidden');
+ } else if (!pageData.forcedAnon && postTrip !== '') {
+ $buffer.find('#filter-remove-trip').click(function () {
+ blacklist.remove.trip(postTrip);
+ });
- /* set menu position
- */
- $buffer.css({top: pos.top + 20, left: pos.left});
+ $buffer.find('#filter-add-trip').addClass('hidden');
+ } else {
+ // board has forced anon
+ $buffer.find('#filter-remove-trip').addClass('hidden');
+ $buffer.find('#filter-add-trip').addClass('hidden');
+ }
- /* finally append to page
- */
- $('body').append($buffer);
+ /* hide sub menus if all items are hidden
+ */
+ if (!$buffer.find('#filter-menu-remove > ul').children().not('.hidden').length) {
+ $buffer.find('#filter-menu-remove').addClass('hidden');
+ }
+ if (!$buffer.find('#filter-menu-add > ul').children().not('.hidden').length) {
+ $buffer.find('#filter-menu-add').addClass('hidden');
+ }
+ });
}
/*
* add menu button to the thread/post
*/
- function addMenuButton(ele, threadId, pageData) {
- if ($(ele).find('.filter-btn').length)
- $('.filter-btn').remove();
+ function quickToggle(ele, threadId, pageData) {
/*if ($(ele).find('.hide-thread-link').length)
$('.hide-thread-link').remove();*/
- $(ele).find('.intro')
- .append(
- $('', {href: '#', class: 'filter-btn', title: 'Filter menu'})
- .text('▶')
- .click(function (e) {
- // button toggle
- e.preventDefault();
- // remove existing menu
- $('.filter-menu').remove();
-
- if ($(e.target).hasClass('filter-btn-open')) {
- $('.filter-btn-open').removeClass('filter-btn-open');
- } else {
- // close previous button
- $('.filter-btn-open').removeClass('filter-btn-open');
- // mark the menu button as open
- $(ele).find('.filter-btn').addClass('filter-btn-open');
- addMenu(e, ele, threadId, pageData);
- }
- })
- );
-
if ($(ele).hasClass('op') && !$(ele).find('.hide-thread-link').length) {
$('[' + ($(ele).data('hidden') == '1' ? '+' : '–') + ']')
.insertBefore($(ele).find(':not(h2,h2 *):first'))
@@ -528,22 +486,18 @@ if (active_page === 'thread' || active_page === 'index') {
}
// run filter on OP
filter(op, threadId, pageData);
- addMenuButton(op, threadId, pageData);
+ quickToggle(op, threadId, pageData);
// iterate filter over each post
if ($(op).data('hidden') != '1' || active_page == 'thread') {
$thread.find('.reply').not('.hidden').each(function () {
filter(this, threadId, pageData);
- addMenuButton(this, threadId, pageData);
});
}
});
}
- /*
- *
- */
function initStyle() {
var $ele, cssStyle, cssString;
@@ -552,23 +506,7 @@ if (active_page === 'thread' || active_page === 'index') {
cssStyle.hoverBg = $('body').css('background-color');
$ele.remove();
- cssString =
- '\n/*** Generated by post-filter ***/\n' +
- '.filter-menu {position: absolute; font-size: 12px; line-height: 1.3em;}\n' +
- '.filter-menu ul {\n' +
- ' background-color: '+ cssStyle['background-color'] +'; border: 1px solid '+ cssStyle['border-color'] +'; border-right-width: 2px;\n' +
- ' list-style: none; padding: 0; margin: 0; white-space: nowrap;\n}\n' +
- '.filter-menu li {cursor: pointer; position: relative; padding: 4px 4px; vertical-align: middle; border-bottom: 1px solid '+ cssStyle['border-color'] +'; white-space: normal; width: 90px;}\n' +
- '.filter-menu li:hover {background-color: '+ cssStyle.hoverBg +';}\n' +
- '.filter-menu ul ul {display: none; position: absolute;}\n' +
- '.filter-menu li:hover ul {display: block; left: 100%; margin-top: -3px;}\n' +
- '.filter-menu li ul li {white-space: nowrap; width: auto;}\n' +
- '.filter-menu-arrow {float: right; margin-left: 10px;}\n' +
- '.filter-menu.hidden, .filter-menu .hidden {display: none;}\n' +
- '.filter-btn {transition: transform 0.1s; width: 15px; text-align: center; font-size: 12pt; opacity: 0.8; text-decoration: none; margin: -6px 0px; display: inline-block;}\n' +
- '.filter-btn:hover {opacity: 1;}\n' +
- '.filter-btn-open {transform: rotate(90deg);}\n';
- cssString +=
+ cssString = '\n/*** Generated by post-filter ***/\n' +
'#filter-control #clear {float: right;}\n' +
'#filter-container {margin-top: 20px; border: 1px solid; height: 270px; overflow: auto;}\n' +
'#filter-list {width: 100%; border-collapse: collapse;}\n' +
@@ -764,27 +702,21 @@ if (active_page === 'thread' || active_page === 'index') {
initStyle();
initOptionsPanel();
+ initPostMenu(pageData);
filterPage(pageData);
- // menu close click handler
- $(document).on('click', function (e){
- if ($(e.target).hasClass('filter-btn'))
- return;
-
- $('.filter-menu').remove();
- $('.filter-btn-open').removeClass('filter-btn-open');
- });
-
// on new posts
$(document).on('new_post', function (e, post) {
+ var threadId;
+
if ($(post).hasClass('reply')) {
- var threadId = $(post).parent().attr('id').replace('thread_', '');
+ threadId = $(post).parent().attr('id').replace('thread_', '');
} else {
- var threadId = $(post).attr('id').replace('thread_', '');
+ threadId = $(post).attr('id').replace('thread_', '');
}
filter(post, threadId, pageData);
- addMenuButton(post, threadId, pageData);
+ quickToggle(post, threadId, pageData);
});
$(document).on('filter_page', function () {
diff --git a/js/post-menu.js b/js/post-menu.js
new file mode 100644
index 00000000..edf66ebb
--- /dev/null
+++ b/js/post-menu.js
@@ -0,0 +1,209 @@
+/*
+ * post-menu.js - adds dropdown menu to posts
+ *
+ * Creates a global Menu object with four public methods:
+ *
+ * Menu.onclick(fnc)
+ * registers a function to be executed after button click, before the menu is displayed
+ * Menu.add_item(id, text[, title])
+ * adds an item to the top level of menu
+ * Menu.add_submenu(id, text)
+ * creates and returns a List object through which to manipulate the content of the submenu
+ * Menu.get_submenu(id)
+ * returns the submenu with the specified id from the top level menu
+ *
+ * The List object contains all the methods from Menu except onclick()
+ *
+ * Example usage:
+ * Menu.add_item('filter-menu-hide', 'Hide post');
+ * Menu.add_item('filter-menu-unhide', 'Unhide post');
+ *
+ * submenu = Menu.add_submenu('filter-menu-add', 'Add filter');
+ * submenu.add_item('filter-add-post-plus', 'Post +', 'Hide post and all replies');
+ * submenu.add_item('filter-add-id', 'ID');
+ *
+ * Usage:
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/post-menu.js';
+ */
+(function () {
+
+var List = function (menuId, text) {
+ this.id = menuId;
+ this.text = text;
+ this.items = [];
+
+ this.add_item = function (itemId, text, title) {
+ this.items.push(new Item(itemId, text, title));
+ };
+ this.list_items = function () {
+ var array = [];
+ var i, length, obj, $ele;
+
+ if ($.isEmptyObject(this.items))
+ return;
+
+ length = this.items.length;
+ for (i = 0; i < length; i++) {
+ obj = this.items[i];
+
+ $ele = $('
- ', {id: obj.id}).text(obj.text);
+ if ('title' in obj) $ele.attr('title', obj.title);
+
+ if (obj instanceof Item) {
+ $ele.addClass('post-item');
+ } else {
+ $ele.addClass('post-submenu');
+
+ $ele.prepend(obj.list_items());
+ $ele.append($('', {class: 'post-menu-arrow'}).text('»'));
+ }
+
+ array.push($ele);
+ }
+
+ return $('
').append(array);
+ };
+ this.add_submenu = function (menuId, text) {
+ var ele = new List(menuId, text);
+ this.items.push(ele);
+ return ele;
+ };
+ this.get_submenu = function (menuId) {
+ for (var i = 0; i < this.items.length; i++) {
+ if ((this.items[i] instanceof Item) || this.items[i].id != menuId) continue;
+ return this.items[i];
+ }
+ };
+};
+
+var Item = function (itemId, text, title) {
+ this.id = itemId;
+ this.text = text;
+
+ // optional
+ if (typeof title != 'undefined') this.title = title;
+};
+
+function buildMenu(e) {
+ var pos = $(e.target).offset();
+ var i, length;
+
+ var $menu = $('').append(mainMenu.list_items());
+
+ // execute registered click handlers
+ length = onclick_callbacks.length;
+ for (i = 0; i < length; i++) {
+ onclick_callbacks[i](e, $menu);
+ }
+
+ // set menu position and append to page
+ $menu.css({top: pos.top, left: pos.left + 20});
+ $('body').append($menu);
+}
+
+function addButton(post) {
+ var $ele = $(post);
+ $ele.find('input.delete').after(
+ $('', {href: '#', class: 'post-btn', title: 'Post menu'}).text('▶')
+ );
+}
+
+
+/* * * * * * * * * *
+ Public methods
+ * * * * * * * * * */
+var Menu = {};
+var mainMenu = new List();
+var onclick_callbacks = [];
+
+Menu.onclick = function (fnc) {
+ onclick_callbacks.push(fnc);
+};
+
+Menu.add_item = function (itemId, text, title) {
+ mainMenu.add_item(itemId, text, title);
+};
+
+Menu.add_submenu = function (menuId, text) {
+ return mainMenu.add_submenu(menuId, text);
+};
+
+Menu.get_submenu = function (id) {
+ return mainMenu.get_submenu(id);
+};
+
+
+/* * * * * * * *
+ Initialize
+ * * * * * * * */
+
+/* Styling
+ */
+var $ele, cssStyle, cssString;
+
+$ele = $('').addClass('post reply').hide().appendTo('body');
+cssStyle = $ele.css(['border-top-color']);
+cssStyle.hoverBg = $('body').css('background-color');
+$ele.remove();
+
+cssString =
+ '\n/*** Generated by post-menu ***/\n' +
+ '.post-menu {position: absolute; font-size: 12px; line-height: 1.3em;}\n' +
+ '.post-menu ul {\n' +
+ ' background-color: '+ cssStyle['border-top-color'] +'; border: 1px solid #666;\n' +
+ ' list-style: none; padding: 0; margin: 0; white-space: nowrap;\n}\n' +
+ '.post-menu .post-submenu{white-space: normal; width: 90px;}' +
+ '.post-menu .post-submenu>ul{white-space: nowrap; width: auto;}' +
+ '.post-menu li {cursor: pointer; position: relative; padding: 4px 4px; vertical-align: middle;}\n' +
+ '.post-menu li:hover {background-color: '+ cssStyle.hoverBg +';}\n' +
+ '.post-menu ul ul {display: none; position: absolute;}\n' +
+ '.post-menu li:hover>ul {display: block; left: 100%; margin-top: -3px;}\n' +
+ '.post-menu-arrow {float: right; margin-left: 10px;}\n' +
+ '.post-menu.hidden, .post-menu .hidden {display: none;}\n' +
+ '.post-btn {transition: transform 0.1s; width: 15px; text-align: center; font-size: 10pt; opacity: 0.8; text-decoration: none; margin: -6px 0px 0px -5px !important; display: inline-block;}\n' +
+ '.post-btn:hover {opacity: 1;}\n' +
+ '.post-btn-open {transform: rotate(90deg);}\n';
+
+if (!$('style.generated-css').length) $('