aboutsummaryrefslogtreecommitdiff
path: root/p/scripts
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2018-09-29 20:47:17 +0200
committerGravatar GitHub <noreply@github.com> 2018-09-29 20:47:17 +0200
commit8ee8a573f1f7e9cc45f9b3c46627d15670f14f3a (patch)
tree14200758ab43e4031f60b46b8c6e9018b43e53af /p/scripts
parent3ae1b57c9d2e23157be54e8fe9865b85872ff9e7 (diff)
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
Diffstat (limited to 'p/scripts')
-rw-r--r--p/scripts/main.js108
1 files changed, 102 insertions, 6 deletions
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('<li class="item"><label><input class="checkboxTag" name="t_0" type="checkbox" /> <input type="text" name="newTag" /></label></li>');
+ if (data && data.length) {
+ for (var i = 0; i < data.length; i++) {
+ var tag = data[i];
+ $ul.append('<li class="item"><label><input class="checkboxTag" name="t_' + tag.id + '" type="checkbox"' +
+ (tag.checked ? ' checked="checked"' : '') + '> ' + tag.name + '</label></li>');
+ }
+ }
+ })
+ .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'));
+ }
+ });
+ });
+}
+
// <actualize>
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();