From 8ee8a573f1f7e9cc45f9b3c46627d15670f14f3a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 29 Sep 2018 20:47:17 +0200 Subject: Custom labels (#2027) * First draft of custom tags https://github.com/FreshRSS/FreshRSS/issues/928 https://github.com/FreshRSS/FreshRSS/issues/1367 * SMALLINT to BIGINT for id_entry And uppercase SQL types * Fix layout for unreads * Start UI menu * Change menu order * Clean database helpers https://github.com/FreshRSS/FreshRSS/pull/2027#discussion_r217971535 * Travis rules do not understand PostgreSQL constants Grrr * Tag controller + UI * Add column attributes to tags * Use only favicon for now, for label * Fix styling for different themes * Constant for maximum InnoDB index length in Unicode https://github.com/FreshRSS/FreshRSS/pull/2027#discussion_r219052200 (I would have personnally prefered keeping the readability of a real value instead of a constant, in this case of many SQL fields) * Use FreshRSS_Factory::createCategoryDao * Add view of all articles containing any tag * Fix search in tags * Mark as read tags * Partial auto-update unread tags * More auto update tag unreads * Add tag deletion * Do not purge tagged articles * Minor comment * Fix SQLite and UI bug * Google Reader API support for user tags Add SQL check that tag names must be distinct from category names * whitespace * Add missing API for EasyRSS * Compatibility SQLite Problematic parentheses * Add SQL DISTINCT for cases with multiple tags * Fix for PostgreSQL PostgreSQL needs some additional type hint to avoid "could not determine data type of parameter $1" http://www.postgresql-archive.org/Could-not-determine-data-type-of-parameter-1-tp2171092p2171094.html --- p/scripts/main.js | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-) (limited to 'p/scripts') diff --git a/p/scripts/main.js b/p/scripts/main.js index 6ab256065..cac2e8706 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -114,6 +114,17 @@ function incUnreadsFeed(article, feed_id, nb) { return isCurrentView; } +function incUnreadsTag(tag_id, nb) { + var $t = $('#t_' + tag_id); + var unreads = str2int($t.attr('data-unread')); + $t.attr('data-unread', unreads + nb) + .children('.item-title').attr('data-unread', numberFormat(unreads + nb)); + + $t = $('.category.tags').find('.title'); + unreads = str2int($t.attr('data-unread')); + $t.attr('data-unread', numberFormat(unreads + nb)); +} + var pending_entries = {}; function mark_read(active, only_not_read) { if ((active.length === 0) || (!active.attr('id')) || @@ -157,6 +168,12 @@ function mark_read(active, only_not_read) { } faviconNbUnread(); + if (data.tags) { + for (var i = data.tags.length - 1; i >= 0; i--) { + incUnreadsTag(data.tags[i], inc); + } + } + delete pending_entries[active.attr('id')]; }).fail(function (data) { openNotification(i18n.notif_request_failed, 'bad'); @@ -529,12 +546,16 @@ function init_column_categories() { $(this).parent().next(".tree-folder-items").slideToggle(300 , function() { $(document.body).trigger("sticky_kit:recalc"); }); return false; }); - $('#aside_feed').on('click', '.tree-folder-items .item .dropdown-toggle', function () { + $('#aside_feed').on('click', '.tree-folder-items .feed .dropdown-toggle', function () { if ($(this).nextAll('.dropdown-menu').length === 0) { - var feed_id = $(this).closest('.item').attr('id').substr(2), + var itemId = $(this).closest('.item').attr('id'), + templateId = itemId.substring(0, 2) === 't_' ? 'tag_config_template' : 'feed_config_template', + id = itemId.substr(2), feed_web = $(this).data('fweb'), - template = $('#feed_config_template').html().replace(/------/g, feed_id).replace('http://example.net/', feed_web); - $(this).attr('href', '#dropdown-' + feed_id).prev('.dropdown-target').attr('id', 'dropdown-' + feed_id).parent().append(template); + template = $('#' + templateId) + .html().replace(/------/g, id).replace('http://example.net/', feed_web); + $(this).attr('href', '#dropdown-' + id).prev('.dropdown-target').attr('id', 'dropdown-' + id).parent() + .append(template).find('button.confirm').removeAttr('disabled'); $('.tree-folder-items .dropdown-close a').click(function(){ $('.tree').removeClass('treepadding'); $(document.body).trigger("sticky_kit:recalc"); @@ -606,7 +627,7 @@ function init_shortcuts() { auto_share(String.fromCharCode(evt.keyCode)); } } - for(var i = 1; i < 10; i++) { + for (var i = 1; i < 10; i++) { shortcut.add(i.toString(), addShortcut, { 'disable_in_input': true }); @@ -830,6 +851,69 @@ function init_nav_entries() { }); } +function loadDynamicTags($div) { + $div.removeClass('dynamictags'); + $div.find('li.item').remove(); + var entryId = $div.closest('div.flux').attr('id').replace(/^flux_/, ''); + $.getJSON('./?c=tag&a=getTagsForEntry&id_entry=' + entryId) + .done(function (data) { + var $ul = $div.find('.dropdown-menu'); + $ul.append('
  • '); + if (data && data.length) { + for (var i = 0; i < data.length; i++) { + var tag = data[i]; + $ul.append('
  • '); + } + } + }) + .fail(function () { + $div.find('li.item').remove(); + $div.addClass('dynamictags'); + }); +} + +function init_dynamic_tags() { + $stream.on('click', '.dynamictags', function () { + loadDynamicTags($(this)); + }); + + $stream.on('change', '.checkboxTag', function (ev) { + var $checkbox = $(this); + $checkbox.prop('disabled', true); + var isChecked = $checkbox.prop('checked'); + var tagId = $checkbox.attr('name').replace(/^t_/, ''); + var tagName = $checkbox.siblings('input[name]').val(); + var $entry = $checkbox.closest('div.flux'); + var entryId = $entry.attr('id').replace(/^flux_/, ''); + $.ajax({ + type: 'POST', + url: './?c=tag&a=tagEntry', + data: { + _csrf: context.csrf, + id_tag: tagId, + name_tag: tagId == 0 ? tagName : '', + id_entry: entryId, + checked: isChecked, + }, + }) + .done(function () { + if ($entry.hasClass('not_read')) { + incUnreadsTag(tagId, isChecked ? 1 : -1); + } + }) + .fail(function () { + $checkbox.prop('checked', !isChecked); + }) + .always(function () { + $checkbox.prop('disabled', false); + if (tagId == 0) { + loadDynamicTags($checkbox.closest('div.dropdown')); + } + }); + }); +} + // var feed_processed = 0; @@ -1004,7 +1088,7 @@ function refreshUnreads() { var isAll = $('.category.all.active').length > 0, new_articles = false; - $.each(data, function(feed_id, nbUnreads) { + $.each(data.feeds, function(feed_id, nbUnreads) { feed_id = 'f_' + feed_id; var elem = $('#' + feed_id).get(0), feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0; @@ -1016,6 +1100,17 @@ function refreshUnreads() { } }); + var nbUnreadTags = 0; + + $.each(data.tags, function(tag_id, nbUnreads) { + nbUnreadTags += nbUnreads; + $('#t_' + tag_id).attr('data-unread', nbUnreads) + .children('.item-title').attr('data-unread', numberFormat(nbUnreads)); + }); + + $('.category.tags').attr('data-unread', nbUnreadTags) + .find('.title').attr('data-unread', numberFormat(nbUnreadTags)); + var nb_unreads = str2int($('.category.all .title').attr('data-unread')); if (nb_unreads > 0 && new_articles) { @@ -1432,6 +1527,7 @@ function init_afterDOM() { init_load_more($stream); init_posts(); init_nav_entries(); + init_dynamic_tags(); init_print_action(); init_post_action(); init_notifs_html5(); -- cgit v1.2.3