-
${__("Select...")}
-
-
${__('All')}
-
${__('Unread')}
-
${__('Invert')}
-
${__('None')}
-
-
${__('Toggle unread')}
-
${__('Toggle starred')}
-
${__('Toggle published')}
-
-
${__('Mark as read')}
-
${__('Set score')}
- ${tb.plugin_menu_items}
+
+
+
+
${tb.plugin_buttons}
`);
@@ -675,6 +691,48 @@ const Headlines = {
}
dojo.parser.parse(target.domNode);
+
+ this._headlinesSelectClickHandle = dojo.connect(dijit.byId("headlines-select-articles-dropdown"), 'onItemClick',
+ (item) => {
+ const action = item.option.value;
+
+ switch (action) {
+ case 'headlines_select_all':
+ Headlines.select('all');
+ break;
+ case 'headlines_select_unread':
+ Headlines.select('unread');
+ break;
+ case 'headlines_select_invert':
+ Headlines.select('invert');
+ break;
+ case 'headlines_select_none':
+ Headlines.select('none');
+ break;
+ case 'headlines_selectionToggleUnread':
+ Headlines.selectionToggleUnread();
+ break;
+ case 'headlines_selectionToggleMarked':
+ Headlines.selectionToggleMarked();
+ break;
+ case 'headlines_selectionTogglePublished':
+ Headlines.selectionTogglePublished();
+ break;
+ case 'headlines_catchupSelection':
+ Headlines.catchupSelection();
+ break;
+ case 'article_selectionSetScore':
+ Article.selectionSetScore();
+ break;
+ case 'headlines_deleteSelection':
+ Headlines.deleteSelection();
+ break;
+ default:
+ if (!PluginHost.run_until(PluginHost.HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2, true, action))
+ console.warn('unknown headlines action', action);
+ }
+ }
+ );
},
onLoaded: function (reply, offset, append) {
console.log("Headlines.onLoaded: offset=", offset, "append=", append);
diff --git a/js/PluginHost.js b/js/PluginHost.js
index deb7c0645..513429e4a 100644
--- a/js/PluginHost.js
+++ b/js/PluginHost.js
@@ -21,6 +21,7 @@ const PluginHost = {
HOOK_HEADLINE_MUTATIONS_SYNCED: 16,
HOOK_HEADLINES_RENDERED: 17,
HOOK_HEADLINES_SCROLL_HANDLER: 18,
+ HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2: 19,
hooks: [],
register: function (name, callback) {
if (typeof(this.hooks[name]) == 'undefined')
@@ -36,6 +37,17 @@ const PluginHost = {
this.hooks[name][i](args);
}
},
+ run_until: function (name, check, ...args) {
+ //console.warn('PluginHost.run_until', name, check, args);
+
+ if (typeof(this.hooks[name]) != 'undefined')
+ for (let i = 0; i < this.hooks[name].length; i++) {
+ if (this.hooks[name][i](args) == check)
+ return true;
+ }
+
+ return false;
+ },
unregister: function (name, callback) {
for (let i = 0; i < this.hooks[name].length; i++)
if (this.hooks[name][i] == callback)
diff --git a/js/form/Select.js b/js/form/Select.js
index 530880e2d..0c73cd52c 100755
--- a/js/form/Select.js
+++ b/js/form/Select.js
@@ -1,8 +1,66 @@
-/* global dijit, define */
-define(["dojo/_base/declare", "dijit/form/Select"], function (declare) {
- return declare("fox.form.Select", dijit.form.Select, {
+/* eslint-disable prefer-rest-params */
+/* global define */
+// FIXME: there probably is a better, more dojo-like notation for custom data- properties
+define(["dojo/_base/declare",
+ "dijit/form/Select",
+ "dojo/_base/lang", // lang.hitch
+ "dijit/MenuItem",
+ "dijit/MenuSeparator",
+ "dojo/aspect",
+ ], function (declare, select, lang, MenuItem, MenuSeparator, aspect) {
+ return declare("fox.form.Select", select, {
focus: function() {
return; // Stop dijit.form.Select from keeping focus after closing the menu
},
+ startup: function() {
+ this.inherited(arguments);
+
+ if (this.attr('data-dropdown-skip-first') == 'true') {
+ aspect.before(this, "_loadChildren", () => {
+ this.options = this.options.splice(1);
+ });
+ }
+ },
+ // hook invoked when dropdown MenuItem is clicked
+ onItemClick: function(/*item, menu*/) {
+ //
+ },
+ _setValueAttr: function(/*anything*/ newValue, /*Boolean?*/ priorityChange){
+ if (this.attr('data-prevent-value-change') == 'true' && newValue != '')
+ return;
+
+ this.inherited(arguments);
+ },
+ // the only difference from dijit/form/Select is _onItemClicked() handler
+ _getMenuItemForOption: function(/*_FormSelectWidget.__SelectOption*/ option){
+ // summary:
+ // For the given option, return the menu item that should be
+ // used to display it. This can be overridden as needed
+ if (!option.value && !option.label){
+ // We are a separator (no label set for it)
+ return new MenuSeparator({ownerDocument: this.ownerDocument});
+ } else {
+ // Just a regular menu option
+ const click = lang.hitch(this, "_setValueAttr", option);
+ const item = new MenuItem({
+ option: option,
+ label: (this.labelType === 'text' ? (option.label || '').toString()
+ .replace(/&/g, '&').replace(/ {
+ this.onItemClick(item, this.dropDown);
+
+ click();
+ },
+ ownerDocument: this.ownerDocument,
+ dir: this.dir,
+ textDir: this.textDir,
+ disabled: option.disabled || false
+ });
+ item.focusNode.setAttribute("role", "option");
+
+ return item;
+ }
+ },
});
});
diff --git a/locale/cs_CZ/LC_MESSAGES/messages.mo b/locale/cs_CZ/LC_MESSAGES/messages.mo
index 470547241..31ff2c923 100644
Binary files a/locale/cs_CZ/LC_MESSAGES/messages.mo and b/locale/cs_CZ/LC_MESSAGES/messages.mo differ
diff --git a/locale/cs_CZ/LC_MESSAGES/messages.po b/locale/cs_CZ/LC_MESSAGES/messages.po
index f716401ec..a8dca4355 100644
--- a/locale/cs_CZ/LC_MESSAGES/messages.po
+++ b/locale/cs_CZ/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: TT-RSS CZech\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-18 13:34+0300\n"
-"PO-Revision-Date: 2021-03-12 06:52+0000\n"
+"PO-Revision-Date: 2021-11-24 07:41+0000\n"
"Last-Translator: Marek Pavelka
\n"
"Language-Team: Czech \n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.9.1\n"
#: backend.php:60
msgid "Use default"
@@ -280,20 +280,16 @@ msgid "Open next feed"
msgstr "Otevřít další kanál"
#: classes/rpc.php:567
-#, fuzzy
-#| msgid "Open next feed"
msgid "Open next unread feed"
-msgstr "Otevřít další kanál"
+msgstr "Otevřít další nepřečtený kanál"
#: classes/rpc.php:568
msgid "Open previous feed"
msgstr "Otevřít předchozí kanál"
#: classes/rpc.php:569
-#, fuzzy
-#| msgid "Open previous feed"
msgid "Open previous unread feed"
-msgstr "Otevřít předchozí kanál"
+msgstr "Otevřít předchozí nepřečtený kanál"
#: classes/rpc.php:570
msgid "Open next article (in combined mode, scroll down)"
@@ -461,10 +457,8 @@ msgid "Toggle headline grouping"
msgstr "Přepnout seskupování nadpisů"
#: classes/rpc.php:613
-#, fuzzy
-#| msgid "Toggle sidebar"
msgid "Toggle grid view"
-msgstr "Přepnout postranní panel"
+msgstr "Přepnout zobrazení v mřížce"
#: classes/rpc.php:614
msgid "Debug feed update"
@@ -851,14 +845,12 @@ msgid "May increase server load"
msgstr "Může zvýšit zatížení serveru"
#: classes/pref/prefs.php:121
-#, fuzzy
-#| msgid "Preview"
msgid "Grid view"
-msgstr "Náhled"
+msgstr "Zobrazení v mřížce"
#: classes/pref/prefs.php:121
msgid "On wider screens, if always expanded"
-msgstr ""
+msgstr "Na širších obrazovkách, pokud je vždy rozbaleno"
#: classes/pref/prefs.php:222
msgid "The configuration was saved."
@@ -927,14 +919,12 @@ msgid "Disable OTP"
msgstr "Zakázat jednorázové heslo"
#: classes/pref/prefs.php:472
-#, fuzzy
-#| msgid "OTP Key:"
msgid "OTP secret:"
-msgstr "Klíč jednorázového hesla:"
+msgstr "Tajné jednorázové heslo:"
#: classes/pref/prefs.php:499
msgid "Verification code:"
-msgstr ""
+msgstr "Ověřovací kód:"
#: classes/pref/prefs.php:507
msgid "Enable OTP"
@@ -1609,10 +1599,8 @@ msgid "%d min"
msgstr "%d min"
#: plugins/auth_internal/init.php:112
-#, fuzzy
-#| msgid "Please enter label caption:"
msgid "Please enter verification code (OTP):"
-msgstr "Zadejte titulek štítku:"
+msgstr "Zadejte ověřovací kód (jednorázové heslo):"
#: plugins/auth_internal/init.php:114
msgid "Continue"
@@ -1620,7 +1608,7 @@ msgstr "Pokračovat"
#: plugins/auth_internal/init.php:166
msgid "Too many authentication attempts, throttled."
-msgstr ""
+msgstr "Příliš mnoho pokusů o ověření, omezeno."
#: plugins/auth_internal/init.php:247
msgid "Password has been changed."
@@ -1833,8 +1821,6 @@ msgid "The following comics are currently supported:"
msgstr "Nyní jsou podporovány následující komiksy:"
#: plugins/nsfw/init.php:39
-#, fuzzy
-#| msgid "Not work safe (click to toggle)"
msgid "Not safe for work (click to toggle)"
msgstr "Neotvírat v práci (kliknutím přepnout)"
@@ -2331,13 +2317,11 @@ msgstr "Vymazat protokol událostí?"
#: js/PrefHelpers.js:135
msgid "Name for cloned profile:"
-msgstr ""
+msgstr "Název pro klonovaný profil:"
#: js/PrefHelpers.js:145
-#, fuzzy
-#| msgid "Please select an image file."
msgid "Please select a single profile to clone."
-msgstr "Vyberte soubor obrázku."
+msgstr "Vyberte jeden profil pro klonování."
#: js/PrefHelpers.js:153
msgid ""
@@ -2362,7 +2346,7 @@ msgstr "(aktivní)"
#: js/PrefHelpers.js:219
msgid "(empty)"
-msgstr ""
+msgstr "(prázdný)"
#: js/PrefHelpers.js:242
msgid "Activate selected profile?"
@@ -2749,10 +2733,8 @@ msgid "Looking for articles (%d processed, %f found)..."
msgstr "Hledání článků (%d zpracováno, %f nalezeno)..."
#: js/CommonFilters.js:72
-#, fuzzy
-#| msgid "Found %d articles matching this filter:"
msgid "Articles matching this filter:"
-msgstr "Nalezeno %d článků odpovídajících tomuto filtru:"
+msgstr "Články odpovídající tomuto filtru:"
#: js/CommonFilters.js:74
msgid "Found %d articles matching this filter:"
@@ -2763,10 +2745,8 @@ msgid "Error while trying to get filter test results."
msgstr "Chyba při pokusu o získání výsledků testu filtru."
#: js/CommonFilters.js:95
-#, fuzzy
-#| msgid "Looking for plugins..."
msgid "Looking for articles..."
-msgstr "Vyhledávání modulů..."
+msgstr "Vyhledávání článků..."
#: js/CommonFilters.js:174
msgid "Edit rule"
@@ -2829,10 +2809,8 @@ msgid "Unable to fetch full text for this article"
msgstr "Nelze načíst úplný text pro tento článek"
#: plugins/shorten_expanded/init.js:32
-#, fuzzy
-#| msgid "Email article"
msgid "Expand article"
-msgstr "Odeslat článek e-mailem"
+msgstr "Rozbalit článek"
#: plugins/share/share.js:7
msgid "Share article by URL"
@@ -2896,13 +2874,11 @@ msgstr "URL stránky:"
#: js/PrefHelpers.js:229
msgid "Clone"
-msgstr ""
+msgstr "Klonovat"
#: js/PrefHelpers.js:231
-#, fuzzy
-#| msgid "Activate profile"
msgid "Activate"
-msgstr "Aktivovat profil"
+msgstr "Aktivovat"
#: js/PrefHelpers.js:299
msgid "Apply"
diff --git a/locale/zh_TW/LC_MESSAGES/messages.mo b/locale/zh_TW/LC_MESSAGES/messages.mo
index 6ec886518..74a2f11b3 100644
Binary files a/locale/zh_TW/LC_MESSAGES/messages.mo and b/locale/zh_TW/LC_MESSAGES/messages.mo differ
diff --git a/locale/zh_TW/LC_MESSAGES/messages.po b/locale/zh_TW/LC_MESSAGES/messages.po
index 0ba915e8b..83316edc1 100644
--- a/locale/zh_TW/LC_MESSAGES/messages.po
+++ b/locale/zh_TW/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Tiny Tiny RSS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-18 13:34+0300\n"
-"PO-Revision-Date: 2021-09-22 14:10+0000\n"
+"PO-Revision-Date: 2021-11-21 17:41+0000\n"
"Last-Translator: TonyRL \n"
"Language-Team: Chinese (Traditional) \n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.8.1\n"
+"X-Generator: Weblate 4.9.1\n"
#: backend.php:60
msgid "Use default"
@@ -149,7 +149,7 @@ msgstr "未讀"
#: index.php:192
msgid "With Note"
-msgstr "筆記"
+msgstr "附註記"
#: index.php:195
msgid "Sort articles"
@@ -650,7 +650,7 @@ msgstr "進階"
#: classes/pref/prefs.php:81
msgid "Debugging"
-msgstr "除錯中"
+msgstr "除錯"
#: classes/pref/prefs.php:87
msgid "Never apply these tags automatically (comma-separated list)."
diff --git a/plugins/af_redditimgur/init.php b/plugins/af_redditimgur/init.php
index 8ec947b86..f2a04ce24 100755
--- a/plugins/af_redditimgur/init.php
+++ b/plugins/af_redditimgur/init.php
@@ -158,7 +158,24 @@ class Af_RedditImgur extends Plugin {
private function process_post_media(array $data, DOMDocument $doc, DOMXPath $xpath, DOMElement $anchor) : bool {
$found = 0;
- if (isset($data["media_metadata"])) {
+ // process galleries in the right order
+ if (isset($data["gallery_data"]) && isset($data["media_metadata"])) {
+ foreach ($data["gallery_data"]["items"] as $gal_item) {
+ $media_id = $gal_item["media_id"] ?? null;
+
+ if ($media_id) {
+ $media_url = htmlspecialchars_decode($data["media_metadata"][$media_id]["s"]["u"] ?? "");
+
+ if ($media_url) {
+ Debug::log("found gallery item: $media_id, url: $media_url", Debug::LOG_EXTENDED);
+
+ $this->handle_as_image($doc, $anchor, $media_url);
+ $found = 1;
+ }
+ }
+ }
+ // i'm not sure if this is a thing, but if there's no gallery just process any possible attaches in the random order...
+ } else if (isset($data["media_metadata"])) {
foreach ($data["media_metadata"] as $media) {
if (!empty($media["s"]["u"])) {
$media_url = htmlspecialchars_decode($media["s"]["u"]);
@@ -205,7 +222,7 @@ class Af_RedditImgur extends Plugin {
Debug::log("found hosted video url: $media_url / poster $poster_url, looking up fallback url...", Debug::LOG_VERBOSE);
- $fallback_url = $data["media"]["reddit_video"]["fallback_url"];
+ $fallback_url = $data["media"]["reddit_video"]["fallback_url"] ?? null;
if ($fallback_url) {
Debug::log("found video fallback_url: $fallback_url", Debug::LOG_VERBOSE);
diff --git a/sql/mysql/migrations/146.sql b/sql/mysql/migrations/146.sql
new file mode 100644
index 000000000..6d4824727
--- /dev/null
+++ b/sql/mysql/migrations/146.sql
@@ -0,0 +1,2 @@
+insert into ttrss_filter_actions (id,name,description) values (10, 'ignore-tag',
+ 'Ignore tags');
diff --git a/sql/mysql/schema.sql b/sql/mysql/schema.sql
index ff6ff4797..589d1013a 100644
--- a/sql/mysql/schema.sql
+++ b/sql/mysql/schema.sql
@@ -249,6 +249,9 @@ insert into ttrss_filter_actions (id,name,description) values (8, 'stop',
insert into ttrss_filter_actions (id,name,description) values (9, 'plugin',
'Invoke plugin');
+insert into ttrss_filter_actions (id,name,description) values (10, 'ignore-tag',
+ 'Ignore tags');
+
create table ttrss_filters2(id integer primary key auto_increment,
owner_uid integer not null,
match_any_rule boolean not null default false,
diff --git a/sql/pgsql/migrations/146.sql b/sql/pgsql/migrations/146.sql
new file mode 100644
index 000000000..6d4824727
--- /dev/null
+++ b/sql/pgsql/migrations/146.sql
@@ -0,0 +1,2 @@
+insert into ttrss_filter_actions (id,name,description) values (10, 'ignore-tag',
+ 'Ignore tags');
diff --git a/sql/pgsql/schema.sql b/sql/pgsql/schema.sql
index b539419b6..938ccc905 100644
--- a/sql/pgsql/schema.sql
+++ b/sql/pgsql/schema.sql
@@ -245,6 +245,9 @@ insert into ttrss_filter_actions (id,name,description) values (8, 'stop',
insert into ttrss_filter_actions (id,name,description) values (9, 'plugin',
'Invoke plugin');
+insert into ttrss_filter_actions (id,name,description) values (10, 'ignore-tag',
+ 'Ignore tags');
+
create table ttrss_filters2(id serial not null primary key,
owner_uid integer not null references ttrss_users(id) on delete cascade,
match_any_rule boolean not null default false,
diff --git a/themes/compact.css b/themes/compact.css
index ccd6ef76c..d462892db 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -1475,8 +1475,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #ddd;
border-bottom-width: 1px;
- background: white ! important;
- opacity: 0.9;
+ background: rgba(255, 255, 255, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {
diff --git a/themes/compact_night.css b/themes/compact_night.css
index 6b072e510..8b1cd17bc 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -1475,8 +1475,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #222;
border-bottom-width: 1px;
- background: #333 ! important;
- opacity: 0.9;
+ background: rgba(51, 51, 51, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {
diff --git a/themes/light-high-contrast.css b/themes/light-high-contrast.css
index 18fc67f6a..77f3def7e 100644
--- a/themes/light-high-contrast.css
+++ b/themes/light-high-contrast.css
@@ -1475,8 +1475,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #ddd;
border-bottom-width: 1px;
- background: white ! important;
- opacity: 0.9;
+ background: rgba(255, 255, 255, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {
diff --git a/themes/light.css b/themes/light.css
index 475e4dbbf..8367b07cc 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -1475,8 +1475,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #ddd;
border-bottom-width: 1px;
- background: white ! important;
- opacity: 0.9;
+ background: rgba(255, 255, 255, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {
diff --git a/themes/light/cdm.less b/themes/light/cdm.less
index 4cbfa1d28..6bb3378c1 100644
--- a/themes/light/cdm.less
+++ b/themes/light/cdm.less
@@ -325,8 +325,7 @@
box-shadow : 0 1px 1px -1px rgba(0,0,0,0.1);
border: 0 solid @border-default;
border-bottom-width: 1px;
- background : @default-bg ! important;
- opacity: 0.9;
+ background : fade(@default-bg, 90%) ! important;
backdrop-filter: blur(6px);
}
}
diff --git a/themes/night.css b/themes/night.css
index 24288e149..447ca6f7f 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -1476,8 +1476,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #222;
border-bottom-width: 1px;
- background: #333 ! important;
- opacity: 0.9;
+ background: rgba(51, 51, 51, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {
diff --git a/themes/night_blue.css b/themes/night_blue.css
index 209484935..7a6ce2b69 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -1476,8 +1476,7 @@ body.ttrss_utility hr {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.1);
border: 0 solid #222;
border-bottom-width: 1px;
- background: #333 ! important;
- opacity: 0.9;
+ background: rgba(51, 51, 51, 0.9) ! important;
backdrop-filter: blur(6px);
}
body.ttrss_prefs {