further objectification of JS code
This commit is contained in:
parent
049a37aa0e
commit
d86ddbc635
|
@ -388,7 +388,7 @@ class Feeds extends Handler_Protected {
|
||||||
|
|
||||||
$vgroup_last_feed = $feed_id;
|
$vgroup_last_feed = $feed_id;
|
||||||
|
|
||||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
$vf_catchup_link = "<a class='catchup' onclick='Feeds.catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||||
|
|
||||||
$reply['content'] .= "<div data-feed-id='$feed_id' class='feed-titl'>".
|
$reply['content'] .= "<div data-feed-id='$feed_id' class='feed-titl'>".
|
||||||
"<div style='float : right'>$feed_icon_img</div>".
|
"<div style='float : right'>$feed_icon_img</div>".
|
||||||
|
@ -481,7 +481,7 @@ class Feeds extends Handler_Protected {
|
||||||
|
|
||||||
$vgroup_last_feed = $feed_id;
|
$vgroup_last_feed = $feed_id;
|
||||||
|
|
||||||
$vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
$vf_catchup_link = "<a class='catchup' onclick='Feeds.catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
|
||||||
|
|
||||||
$feed_icon_src = Feeds::getFeedIcon($feed_id);
|
$feed_icon_src = Feeds::getFeedIcon($feed_id);
|
||||||
$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"$feed_icon_src\">";
|
$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"$feed_icon_src\">";
|
||||||
|
|
|
@ -207,16 +207,16 @@
|
||||||
<option value="title"><?php echo __('Title') ?></option>
|
<option value="title"><?php echo __('Title') ?></option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div dojoType="dijit.form.ComboButton" onclick="catchupCurrentFeed()">
|
<div dojoType="dijit.form.ComboButton" onclick="Feeds.catchupCurrentFeed()">
|
||||||
<span><?php echo __('Mark as read') ?></span>
|
<span><?php echo __('Mark as read') ?></span>
|
||||||
<div dojoType="dijit.DropDownMenu">
|
<div dojoType="dijit.DropDownMenu">
|
||||||
<div dojoType="dijit.MenuItem" onclick="catchupCurrentFeed('1day')">
|
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrentFeed('1day')">
|
||||||
<?php echo __('Older than one day') ?>
|
<?php echo __('Older than one day') ?>
|
||||||
</div>
|
</div>
|
||||||
<div dojoType="dijit.MenuItem" onclick="catchupCurrentFeed('1week')">
|
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrentFeed('1week')">
|
||||||
<?php echo __('Older than one week') ?>
|
<?php echo __('Older than one week') ?>
|
||||||
</div>
|
</div>
|
||||||
<div dojoType="dijit.MenuItem" onclick="catchupCurrentFeed('2week')">
|
<div dojoType="dijit.MenuItem" onclick="Feeds.catchupCurrentFeed('2week')">
|
||||||
<?php echo __('Older than two weeks') ?>
|
<?php echo __('Older than two weeks') ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,7 +41,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"],
|
||||||
menu.addChild(new dijit.MenuItem({
|
menu.addChild(new dijit.MenuItem({
|
||||||
label: __("Mark as read"),
|
label: __("Mark as read"),
|
||||||
onClick: function() {
|
onClick: function() {
|
||||||
catchupFeed(this.getParent().row_id);
|
Feeds.catchupFeed(this.getParent().row_id);
|
||||||
}}));
|
}}));
|
||||||
|
|
||||||
if (bare_id > 0) {
|
if (bare_id > 0) {
|
||||||
|
@ -69,7 +69,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"],
|
||||||
menu.addChild(new dijit.MenuItem({
|
menu.addChild(new dijit.MenuItem({
|
||||||
label: __("Mark as read"),
|
label: __("Mark as read"),
|
||||||
onClick: function() {
|
onClick: function() {
|
||||||
catchupFeed(this.getParent().row_id, true);
|
Feeds.catchupFeed(this.getParent().row_id, true);
|
||||||
}}));
|
}}));
|
||||||
|
|
||||||
menu.addChild(new dijit.MenuItem({
|
menu.addChild(new dijit.MenuItem({
|
||||||
|
|
274
js/feedlist.js
274
js/feedlist.js
|
@ -69,23 +69,23 @@ const Feeds = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (getFeedUnread(id, (kind == "cat")) != ctr ||
|
/*if (Feeds.getFeedUnread(id, (kind == "cat")) != ctr ||
|
||||||
(kind == "cat")) {
|
(kind == "cat")) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
setFeedUnread(id, (kind == "cat"), ctr);
|
Feeds.setFeedUnread(id, (kind == "cat"), ctr);
|
||||||
setFeedValue(id, (kind == "cat"), 'auxcounter', auxctr);
|
Feeds.setFeedValue(id, (kind == "cat"), 'auxcounter', auxctr);
|
||||||
|
|
||||||
if (kind != "cat") {
|
if (kind != "cat") {
|
||||||
setFeedValue(id, false, 'error', error);
|
Feeds.setFeedValue(id, false, 'error', error);
|
||||||
setFeedValue(id, false, 'updated', updated);
|
Feeds.setFeedValue(id, false, 'updated', updated);
|
||||||
|
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
if (has_img) {
|
if (has_img) {
|
||||||
setFeedIcon(id, false,
|
Feeds.setFeedIcon(id, false,
|
||||||
getInitParam("icons_url") + "/" + id + ".ico?" + has_img);
|
getInitParam("icons_url") + "/" + id + ".ico?" + has_img);
|
||||||
} else {
|
} else {
|
||||||
setFeedIcon(id, false, 'images/blank_icon.gif');
|
Feeds.setFeedIcon(id, false, 'images/blank_icon.gif');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ const Feeds = {
|
||||||
},
|
},
|
||||||
openNextUnreadFeed: function() {
|
openNextUnreadFeed: function() {
|
||||||
const is_cat = Feeds.activeFeedIsCat();
|
const is_cat = Feeds.activeFeedIsCat();
|
||||||
const nuf = getNextUnreadFeed(Feeds.getActiveFeedId(), is_cat);
|
const nuf = Feeds.getNextUnreadFeed(Feeds.getActiveFeedId(), is_cat);
|
||||||
if (nuf) this.viewfeed({feed: nuf, is_cat: is_cat});
|
if (nuf) this.viewfeed({feed: nuf, is_cat: is_cat});
|
||||||
},
|
},
|
||||||
collapseFeedlist: function() {
|
collapseFeedlist: function() {
|
||||||
|
@ -129,13 +129,13 @@ const Feeds = {
|
||||||
|
|
||||||
counters_last_request = timestamp;
|
counters_last_request = timestamp;
|
||||||
|
|
||||||
let query = {op: "rpc", method: "getAllCounters", seq: App.next_seq()};
|
let query = {op: "rpc", method: "getAllCounters", seq: Utils.next_seq()};
|
||||||
|
|
||||||
if (!force)
|
if (!force)
|
||||||
query.last_article_id = getInitParam("last_article_id");
|
query.last_article_id = getInitParam("last_article_id");
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -357,7 +357,7 @@ const Feeds = {
|
||||||
Form.enable("main_toolbar_form");
|
Form.enable("main_toolbar_form");
|
||||||
|
|
||||||
if (!delayed)
|
if (!delayed)
|
||||||
if (!setFeedExpandoIcon(feed, is_cat,
|
if (!Feeds.setFeedExpandoIcon(feed, is_cat,
|
||||||
(is_cat) ? 'images/indicator_tiny.gif' : 'images/indicator_white.gif'))
|
(is_cat) ? 'images/indicator_tiny.gif' : 'images/indicator_white.gif'))
|
||||||
notify_progress("Loading, please wait...", true);
|
notify_progress("Loading, please wait...", true);
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ const Feeds = {
|
||||||
catchupBatchedArticles(() => {
|
catchupBatchedArticles(() => {
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
try {
|
try {
|
||||||
setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
|
Feeds.setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
|
||||||
Headlines.onLoaded(transport, offset);
|
Headlines.onLoaded(transport, offset);
|
||||||
PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
|
PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -404,132 +404,92 @@ const Feeds = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
decrementFeedCounter: function(feed, is_cat) {
|
decrementFeedCounter: function(feed, is_cat) {
|
||||||
let ctr = getFeedUnread(feed, is_cat);
|
let ctr = Feeds.getFeedUnread(feed, is_cat);
|
||||||
|
|
||||||
if (ctr > 0) {
|
if (ctr > 0) {
|
||||||
setFeedUnread(feed, is_cat, ctr - 1);
|
Feeds.setFeedUnread(feed, is_cat, ctr - 1);
|
||||||
App.global_unread -= 1;
|
App.global_unread -= 1;
|
||||||
App.updateTitle();
|
App.updateTitle();
|
||||||
|
|
||||||
if (!is_cat) {
|
if (!is_cat) {
|
||||||
const cat = parseInt(getFeedCategory(feed));
|
const cat = parseInt(Feeds.getFeedCategory(feed));
|
||||||
|
|
||||||
if (!isNaN(cat)) {
|
if (!isNaN(cat)) {
|
||||||
ctr = getFeedUnread(cat, true);
|
ctr = Feeds.getFeedUnread(cat, true);
|
||||||
|
|
||||||
if (ctr > 0) {
|
if (ctr > 0) {
|
||||||
setFeedUnread(cat, true, ctr - 1);
|
Feeds.setFeedUnread(cat, true, ctr - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
catchupFeed: function(feed, is_cat, mode) {
|
||||||
|
if (is_cat == undefined) is_cat = false;
|
||||||
|
|
||||||
function getFeedUnread(feed, is_cat) {
|
let str = false;
|
||||||
try {
|
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
|
|
||||||
if (tree && tree.model)
|
switch (mode) {
|
||||||
return tree.model.getFeedUnread(feed, is_cat);
|
case "1day":
|
||||||
|
str = __("Mark %w in %s older than 1 day as read?");
|
||||||
} catch (e) {
|
break;
|
||||||
//
|
case "1week":
|
||||||
|
str = __("Mark %w in %s older than 1 week as read?");
|
||||||
|
break;
|
||||||
|
case "2week":
|
||||||
|
str = __("Mark %w in %s older than 2 weeks as read?");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = __("Mark %w in %s as read?");
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
const mark_what = last_search_query && last_search_query[0] ? __("search results") : __("all articles");
|
||||||
}
|
const fn = Feeds.getFeedName(feed, is_cat);
|
||||||
|
|
||||||
function getFeedCategory(feed) {
|
str = str.replace("%s", fn)
|
||||||
try {
|
.replace("%w", mark_what);
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
|
|
||||||
if (tree && tree.model)
|
if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
|
||||||
return tree.getFeedCategory(feed);
|
return;
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
const catchup_query = {
|
||||||
}
|
op: 'rpc', method: 'catchupFeed', feed_id: feed,
|
||||||
|
is_cat: is_cat, mode: mode, search_query: last_search_query[0],
|
||||||
|
search_lang: last_search_query[1]
|
||||||
|
};
|
||||||
|
|
||||||
function getFeedName(feed, is_cat) {
|
notify_progress("Loading, please wait...", true);
|
||||||
|
|
||||||
if (isNaN(feed)) return feed; // it's a tag
|
xhrPost("backend.php", catchup_query, (transport) => {
|
||||||
|
Utils.handleRpcJson(transport);
|
||||||
|
|
||||||
const tree = dijit.byId("feedTree");
|
const show_next_feed = getInitParam("on_catchup_show_next_feed") == "1";
|
||||||
|
|
||||||
if (tree && tree.model)
|
if (show_next_feed) {
|
||||||
return tree.model.getFeedValue(feed, is_cat, 'name');
|
const nuf = Feeds.getNextUnreadFeed(feed, is_cat);
|
||||||
}
|
|
||||||
|
|
||||||
/* function getFeedValue(feed, is_cat, key) {
|
if (nuf) {
|
||||||
try {
|
this.viewfeed({feed: nuf, is_cat: is_cat});
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
|
|
||||||
if (tree && tree.model)
|
|
||||||
return tree.model.getFeedValue(feed, is_cat, key);
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
return '';
|
} else if (feed == Feeds.getActiveFeedId() && is_cat == Feeds.activeFeedIsCat()) {
|
||||||
} */
|
this.viewCurrentFeed();
|
||||||
|
|
||||||
function setFeedUnread(feed, is_cat, unread) {
|
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
|
|
||||||
if (tree && tree.model)
|
|
||||||
return tree.model.setFeedUnread(feed, is_cat, unread);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setFeedValue(feed, is_cat, key, value) {
|
|
||||||
try {
|
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
|
|
||||||
if (tree && tree.model)
|
|
||||||
return tree.model.setFeedValue(feed, is_cat, key, value);
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function setFeedIcon(feed, is_cat, src) {
|
notify("");
|
||||||
const tree = dijit.byId("feedTree");
|
});
|
||||||
|
},
|
||||||
if (tree) return tree.setFeedIcon(feed, is_cat, src);
|
catchupCurrentFeed: function(mode) {
|
||||||
}
|
Feeds.catchupFeed(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat(), mode);
|
||||||
|
},
|
||||||
function setFeedExpandoIcon(feed, is_cat, src) {
|
catchupFeedInGroup: function(id) {
|
||||||
const tree = dijit.byId("feedTree");
|
const title = Feeds.getFeedName(id);
|
||||||
|
|
||||||
if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNextUnreadFeed(feed, is_cat) {
|
|
||||||
const tree = dijit.byId("feedTree");
|
|
||||||
const nuf = tree.model.getNextUnreadFeed(feed, is_cat);
|
|
||||||
|
|
||||||
if (nuf)
|
|
||||||
return tree.model.store.getValue(nuf, 'bare_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
function catchupCurrentFeed(mode) {
|
|
||||||
catchupFeed(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat(), mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function catchupFeedInGroup(id) {
|
|
||||||
const title = getFeedName(id);
|
|
||||||
|
|
||||||
const str = __("Mark all articles in %s as read?").replace("%s", title);
|
const str = __("Mark all articles in %s as read?").replace("%s", title);
|
||||||
|
|
||||||
if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
|
if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
|
||||||
|
|
||||||
const rows = $$("#headlines-frame > div[id*=RROW][data-orig-feed-id='"+id+"']");
|
const rows = $$("#headlines-frame > div[id*=RROW][data-orig-feed-id='" + id + "']");
|
||||||
|
|
||||||
if (rows.length > 0) {
|
if (rows.length > 0) {
|
||||||
|
|
||||||
|
@ -560,65 +520,91 @@ function catchupFeedInGroup(id) {
|
||||||
|
|
||||||
notify_progress("Loading, please wait...", true);
|
notify_progress("Loading, please wait...", true);
|
||||||
|
|
||||||
xhrPost("backend.php", { op: "rpc", method: "catchupFeed", feed_id: id, is_cat: false}, (transport) => {
|
xhrPost("backend.php", {op: "rpc", method: "catchupFeed", feed_id: id, is_cat: false}, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
getFeedUnread: function(feed, is_cat) {
|
||||||
|
try {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
function catchupFeed(feed, is_cat, mode) {
|
if (tree && tree.model)
|
||||||
if (is_cat == undefined) is_cat = false;
|
return tree.model.getFeedUnread(feed, is_cat);
|
||||||
|
|
||||||
let str = false;
|
} catch (e) {
|
||||||
|
//
|
||||||
switch (mode) {
|
|
||||||
case "1day":
|
|
||||||
str = __("Mark %w in %s older than 1 day as read?");
|
|
||||||
break;
|
|
||||||
case "1week":
|
|
||||||
str = __("Mark %w in %s older than 1 week as read?");
|
|
||||||
break;
|
|
||||||
case "2week":
|
|
||||||
str = __("Mark %w in %s older than 2 weeks as read?");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
str = __("Mark %w in %s as read?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mark_what = last_search_query && last_search_query[0] ? __("search results") : __("all articles");
|
return -1;
|
||||||
const fn = getFeedName(feed, is_cat);
|
},
|
||||||
|
getFeedCategory: function(feed) {
|
||||||
|
try {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
str = str.replace("%s", fn)
|
if (tree && tree.model)
|
||||||
.replace("%w", mark_what);
|
return tree.getFeedCategory(feed);
|
||||||
|
|
||||||
if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
|
} catch (e) {
|
||||||
return;
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
const catchup_query = {op: 'rpc', method: 'catchupFeed', feed_id: feed,
|
return false;
|
||||||
is_cat: is_cat, mode: mode, search_query: last_search_query[0],
|
},
|
||||||
search_lang: last_search_query[1]};
|
getFeedName: function(feed, is_cat) {
|
||||||
|
if (isNaN(feed)) return feed; // it's a tag
|
||||||
|
|
||||||
notify_progress("Loading, please wait...", true);
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
xhrPost("backend.php", catchup_query, (transport) => {
|
if (tree && tree.model)
|
||||||
App.handleRpcJson(transport);
|
return tree.model.getFeedValue(feed, is_cat, 'name');
|
||||||
|
},
|
||||||
|
setFeedUnread: function(feed, is_cat, unread) {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
const show_next_feed = getInitParam("on_catchup_show_next_feed") == "1";
|
if (tree && tree.model)
|
||||||
|
return tree.model.setFeedUnread(feed, is_cat, unread);
|
||||||
|
},
|
||||||
|
setFeedValue: function(feed, is_cat, key, value) {
|
||||||
|
try {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
if (show_next_feed) {
|
if (tree && tree.model)
|
||||||
const nuf = getNextUnreadFeed(feed, is_cat);
|
return tree.model.setFeedValue(feed, is_cat, key, value);
|
||||||
|
|
||||||
if (nuf) {
|
} catch (e) {
|
||||||
Feeds.viewfeed({feed: nuf, is_cat: is_cat});
|
//
|
||||||
}
|
}
|
||||||
} else if (feed == Feeds.getActiveFeedId() && is_cat == Feeds.activeFeedIsCat()) {
|
},
|
||||||
Feeds.viewCurrentFeed();
|
getFeedValue: function(feed, is_cat, key) {
|
||||||
|
try {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
|
if (tree && tree.model)
|
||||||
|
return tree.model.getFeedValue(feed, is_cat, key);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
setFeedIcon: function(feed, is_cat, src) {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
notify("");
|
if (tree) return tree.setFeedIcon(feed, is_cat, src);
|
||||||
});
|
},
|
||||||
}
|
setFeedExpandoIcon: function(feed, is_cat, src) {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
|
||||||
|
if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
getNextUnreadFeed: function(feed, is_cat) {
|
||||||
|
const tree = dijit.byId("feedTree");
|
||||||
|
const nuf = tree.model.getNextUnreadFeed(feed, is_cat);
|
||||||
|
|
||||||
|
if (nuf)
|
||||||
|
return tree.model.store.getValue(nuf, 'bare_id');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
128
js/functions.js
128
js/functions.js
|
@ -57,6 +57,14 @@ Array.prototype.remove = function(s) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Utils = {
|
const Utils = {
|
||||||
|
_rpc_seq: 0,
|
||||||
|
next_seq: function() {
|
||||||
|
this._rpc_seq += 1;
|
||||||
|
return this._rpc_seq;
|
||||||
|
},
|
||||||
|
get_seq: function() {
|
||||||
|
return this._rpc_seq;
|
||||||
|
},
|
||||||
cleanupMemory: function(root) {
|
cleanupMemory: function(root) {
|
||||||
const dijits = dojo.query("[widgetid]", dijit.byId(root).domNode).map(dijit.byNode);
|
const dijits = dojo.query("[widgetid]", dijit.byId(root).domNode).map(dijit.byNode);
|
||||||
|
|
||||||
|
@ -127,6 +135,126 @@ const Utils = {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
handleRpcJson: function(transport) {
|
||||||
|
|
||||||
|
const netalert_dijit = dijit.byId("net-alert");
|
||||||
|
let netalert = false;
|
||||||
|
|
||||||
|
if (netalert_dijit) netalert = netalert_dijit.domNode;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const reply = JSON.parse(transport.responseText);
|
||||||
|
|
||||||
|
if (reply) {
|
||||||
|
|
||||||
|
const error = reply['error'];
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
const code = error['code'];
|
||||||
|
const msg = error['msg'];
|
||||||
|
|
||||||
|
console.warn("[handleRpcJson] received fatal error " + code + "/" + msg);
|
||||||
|
|
||||||
|
if (code != 0) {
|
||||||
|
fatalError(code, msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const seq = reply['seq'];
|
||||||
|
|
||||||
|
if (seq && this.get_seq() != seq) {
|
||||||
|
console.log("[handleRpcJson] sequence mismatch: " + seq +
|
||||||
|
" (want: " + this.get_seq() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = reply['message'];
|
||||||
|
|
||||||
|
if (message == "UPDATE_COUNTERS") {
|
||||||
|
console.log("need to refresh counters...");
|
||||||
|
setInitParam("last_article_id", -1);
|
||||||
|
Feeds.requestCounters(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const counters = reply['counters'];
|
||||||
|
|
||||||
|
if (counters)
|
||||||
|
Feeds.parseCounters(counters);
|
||||||
|
|
||||||
|
const runtime_info = reply['runtime-info'];
|
||||||
|
|
||||||
|
if (runtime_info)
|
||||||
|
Utils.parseRuntimeInfo(runtime_info);
|
||||||
|
|
||||||
|
if (netalert) netalert.hide();
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (netalert)
|
||||||
|
netalert.show();
|
||||||
|
else
|
||||||
|
notify_error("Communication problem with server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
if (netalert)
|
||||||
|
netalert.show();
|
||||||
|
else
|
||||||
|
notify_error("Communication problem with server.");
|
||||||
|
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
parseRuntimeInfo: function(data) {
|
||||||
|
|
||||||
|
//console.log("parsing runtime info...");
|
||||||
|
|
||||||
|
for (const k in data) {
|
||||||
|
const v = data[k];
|
||||||
|
|
||||||
|
if (k == "dep_ts" && parseInt(getInitParam("dep_ts")) > 0) {
|
||||||
|
if (parseInt(getInitParam("dep_ts")) < parseInt(v) && getInitParam("reload_on_ts_change")) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == "daemon_is_running" && v != 1) {
|
||||||
|
notify_error("<span onclick=\"explainError(1)\">Update daemon is not running.</span>", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == "update_result") {
|
||||||
|
const updatesIcon = dijit.byId("updatesIcon").domNode;
|
||||||
|
|
||||||
|
if (v) {
|
||||||
|
Element.show(updatesIcon);
|
||||||
|
} else {
|
||||||
|
Element.hide(updatesIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == "daemon_stamp_ok" && v != 1) {
|
||||||
|
notify_error("<span onclick=\"explainError(3)\">Update daemon is not updating feeds.</span>", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == "max_feed_id" || k == "num_feeds") {
|
||||||
|
if (init_params[k] != v) {
|
||||||
|
console.log("feed count changed, need to reload feedlist.");
|
||||||
|
Feeds.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init_params[k] = v;
|
||||||
|
notify('');
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginHost.run(PluginHost.HOOK_RUNTIME_INFO_LOADED, data);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function report_error(message, filename, lineno, colno, error) {
|
function report_error(message, filename, lineno, colno, error) {
|
||||||
|
|
134
js/tt-rss.js
134
js/tt-rss.js
|
@ -4,15 +4,7 @@ let _widescreen_mode = false;
|
||||||
let hotkey_actions = {};
|
let hotkey_actions = {};
|
||||||
|
|
||||||
const App = {
|
const App = {
|
||||||
_rpc_seq: 0,
|
|
||||||
global_unread: -1,
|
global_unread: -1,
|
||||||
next_seq: function() {
|
|
||||||
this._rpc_seq += 1;
|
|
||||||
return this._rpc_seq;
|
|
||||||
},
|
|
||||||
get_seq: function() {
|
|
||||||
return this._rpc_seq;
|
|
||||||
},
|
|
||||||
updateTitle: function() {
|
updateTitle: function() {
|
||||||
let tmp = "Tiny Tiny RSS";
|
let tmp = "Tiny Tiny RSS";
|
||||||
|
|
||||||
|
@ -85,126 +77,6 @@ const App = {
|
||||||
|
|
||||||
xhrPost("backend.php", {op: "rpc", method: "setpanelmode", wide: wide ? 1 : 0});
|
xhrPost("backend.php", {op: "rpc", method: "setpanelmode", wide: wide ? 1 : 0});
|
||||||
},
|
},
|
||||||
parseRuntimeInfo: function(data) {
|
|
||||||
|
|
||||||
//console.log("parsing runtime info...");
|
|
||||||
|
|
||||||
for (const k in data) {
|
|
||||||
const v = data[k];
|
|
||||||
|
|
||||||
if (k == "dep_ts" && parseInt(getInitParam("dep_ts")) > 0) {
|
|
||||||
if (parseInt(getInitParam("dep_ts")) < parseInt(v) && getInitParam("reload_on_ts_change")) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k == "daemon_is_running" && v != 1) {
|
|
||||||
notify_error("<span onclick=\"explainError(1)\">Update daemon is not running.</span>", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k == "update_result") {
|
|
||||||
const updatesIcon = dijit.byId("updatesIcon").domNode;
|
|
||||||
|
|
||||||
if (v) {
|
|
||||||
Element.show(updatesIcon);
|
|
||||||
} else {
|
|
||||||
Element.hide(updatesIcon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k == "daemon_stamp_ok" && v != 1) {
|
|
||||||
notify_error("<span onclick=\"explainError(3)\">Update daemon is not updating feeds.</span>", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k == "max_feed_id" || k == "num_feeds") {
|
|
||||||
if (init_params[k] != v) {
|
|
||||||
console.log("feed count changed, need to reload feedlist.");
|
|
||||||
Feeds.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init_params[k] = v;
|
|
||||||
notify('');
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginHost.run(PluginHost.HOOK_RUNTIME_INFO_LOADED, data);
|
|
||||||
},
|
|
||||||
handleRpcJson: function(transport) {
|
|
||||||
|
|
||||||
const netalert_dijit = dijit.byId("net-alert");
|
|
||||||
let netalert = false;
|
|
||||||
|
|
||||||
if (netalert_dijit) netalert = netalert_dijit.domNode;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const reply = JSON.parse(transport.responseText);
|
|
||||||
|
|
||||||
if (reply) {
|
|
||||||
|
|
||||||
const error = reply['error'];
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
const code = error['code'];
|
|
||||||
const msg = error['msg'];
|
|
||||||
|
|
||||||
console.warn("[handleRpcJson] received fatal error " + code + "/" + msg);
|
|
||||||
|
|
||||||
if (code != 0) {
|
|
||||||
fatalError(code, msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const seq = reply['seq'];
|
|
||||||
|
|
||||||
if (seq && this.get_seq() != seq) {
|
|
||||||
console.log("[handleRpcJson] sequence mismatch: " + seq +
|
|
||||||
" (want: " + this.get_seq() + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = reply['message'];
|
|
||||||
|
|
||||||
if (message == "UPDATE_COUNTERS") {
|
|
||||||
console.log("need to refresh counters...");
|
|
||||||
setInitParam("last_article_id", -1);
|
|
||||||
Feeds.requestCounters(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const counters = reply['counters'];
|
|
||||||
|
|
||||||
if (counters)
|
|
||||||
Feeds.parseCounters(counters);
|
|
||||||
|
|
||||||
const runtime_info = reply['runtime-info'];
|
|
||||||
|
|
||||||
if (runtime_info)
|
|
||||||
this.parseRuntimeInfo(runtime_info);
|
|
||||||
|
|
||||||
if (netalert) netalert.hide();
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (netalert)
|
|
||||||
netalert.show();
|
|
||||||
else
|
|
||||||
notify_error("Communication problem with server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
if (netalert)
|
|
||||||
netalert.show();
|
|
||||||
else
|
|
||||||
notify_error("Communication problem with server.");
|
|
||||||
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
|
@ -459,7 +331,7 @@ function init_hotkey_actions() {
|
||||||
};
|
};
|
||||||
hotkey_actions["feed_catchup"] = function() {
|
hotkey_actions["feed_catchup"] = function() {
|
||||||
if (Feeds.getActiveFeedId() != undefined) {
|
if (Feeds.getActiveFeedId() != undefined) {
|
||||||
catchupCurrentFeed();
|
Feeds.catchupCurrentFeed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -677,7 +549,7 @@ function quickMenuGo(opid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fn = getFeedName(actid);
|
var fn = Feeds.getFeedName(actid);
|
||||||
|
|
||||||
var pr = __("Unsubscribe from %s?").replace("%s", fn);
|
var pr = __("Unsubscribe from %s?").replace("%s", fn);
|
||||||
|
|
||||||
|
@ -743,7 +615,7 @@ function update_random_feed() {
|
||||||
console.log("in update_random_feed");
|
console.log("in update_random_feed");
|
||||||
|
|
||||||
xhrPost("backend.php", { op: "rpc", method: "updateRandomFeed" }, (transport) => {
|
xhrPost("backend.php", { op: "rpc", method: "updateRandomFeed" }, (transport) => {
|
||||||
App.handleRpcJson(transport, true);
|
Utils.handleRpcJson(transport, true);
|
||||||
window.setTimeout(update_random_feed, 30*1000);
|
window.setTimeout(update_random_feed, 30*1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ const Headlines = {
|
||||||
const view_mode = document.forms["main_toolbar_form"].view_mode.value;
|
const view_mode = document.forms["main_toolbar_form"].view_mode.value;
|
||||||
const unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
|
const unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
|
||||||
const num_all = $$("#headlines-frame > div[id*=RROW]").length;
|
const num_all = $$("#headlines-frame > div[id*=RROW]").length;
|
||||||
const num_unread = getFeedUnread(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
const num_unread = Feeds.getFeedUnread(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
||||||
|
|
||||||
// TODO implement marked & published
|
// TODO implement marked & published
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ const Headlines = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoaded: function(transport, offset) {
|
onLoaded: function(transport, offset) {
|
||||||
const reply = App.handleRpcJson(transport);
|
const reply = Utils.handleRpcJson(transport);
|
||||||
|
|
||||||
console.log("Headlines.onLoaded: offset=", offset);
|
console.log("Headlines.onLoaded: offset=", offset);
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ function view(id, noexpand) {
|
||||||
|
|
||||||
xhrPost("backend.php", {op: "article", method: "view", id: id, cids: cids.toString()}, (transport) => {
|
xhrPost("backend.php", {op: "article", method: "view", id: id, cids: cids.toString()}, (transport) => {
|
||||||
try {
|
try {
|
||||||
const reply = App.handleRpcJson(transport);
|
const reply = Utils.handleRpcJson(transport);
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ function toggleMark(id, client_only) {
|
||||||
|
|
||||||
if (!client_only)
|
if (!client_only)
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,7 +518,7 @@ function togglePub(id, client_only) {
|
||||||
|
|
||||||
if (!client_only)
|
if (!client_only)
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -642,7 +642,7 @@ function toggleUnread(id, cmode) {
|
||||||
if (row.className != origClassName)
|
if (row.className != origClassName)
|
||||||
xhrPost("backend.php",
|
xhrPost("backend.php",
|
||||||
{op: "rpc", method: "catchupSelected", cmode: cmode, ids: id},(transport) => {
|
{op: "rpc", method: "catchupSelected", cmode: cmode, ids: id},(transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,7 +659,7 @@ function selectionRemoveLabel(id, ids) {
|
||||||
ids: ids.toString(), lid: id };
|
ids: ids.toString(), lid: id };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
updateHeadlineLabels(transport);
|
updateHeadlineLabels(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -676,7 +676,7 @@ function selectionAssignLabel(id, ids) {
|
||||||
ids: ids.toString(), lid: id };
|
ids: ids.toString(), lid: id };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
updateHeadlineLabels(transport);
|
updateHeadlineLabels(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -719,7 +719,7 @@ function selectionToggleUnread(params) {
|
||||||
notify_progress("Loading, please wait...");
|
notify_progress("Loading, please wait...");
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
if (callback) callback(transport);
|
if (callback) callback(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ function selectionToggleMarked(ids) {
|
||||||
ids: rows.toString(), cmode: 2 };
|
ids: rows.toString(), cmode: 2 };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,7 +762,7 @@ function selectionTogglePublished(ids) {
|
||||||
ids: rows.toString(), cmode: 2 };
|
ids: rows.toString(), cmode: 2 };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -862,7 +862,7 @@ function deleteSelection() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn = getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
const fn = Feeds.getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
||||||
let str;
|
let str;
|
||||||
|
|
||||||
if (Feeds.getActiveFeedId() != 0) {
|
if (Feeds.getActiveFeedId() != 0) {
|
||||||
|
@ -881,7 +881,7 @@ function deleteSelection() {
|
||||||
const query = { op: "rpc", method: "delete", ids: rows.toString() };
|
const query = { op: "rpc", method: "delete", ids: rows.toString() };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
Feeds.viewCurrentFeed();
|
Feeds.viewCurrentFeed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -896,7 +896,7 @@ function archiveSelection() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn = getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
const fn = Feeds.getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
||||||
let str;
|
let str;
|
||||||
let op;
|
let op;
|
||||||
|
|
||||||
|
@ -924,7 +924,7 @@ function archiveSelection() {
|
||||||
const query = {op: "rpc", method: op, ids: rows.toString()};
|
const query = {op: "rpc", method: op, ids: rows.toString()};
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
Feeds.viewCurrentFeed();
|
Feeds.viewCurrentFeed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -938,7 +938,7 @@ function catchupSelection() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn = getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
const fn = Feeds.getFeedName(Feeds.getActiveFeedId(), Feeds.activeFeedIsCat());
|
||||||
|
|
||||||
let str = ngettext("Mark %d selected article in %s as read?", "Mark %d selected articles in %s as read?", rows.length);
|
let str = ngettext("Mark %d selected article in %s as read?", "Mark %d selected articles in %s as read?", rows.length);
|
||||||
|
|
||||||
|
@ -1091,7 +1091,7 @@ function catchupBatchedArticles(callback) {
|
||||||
cmode: 0, ids: batch.toString() };
|
cmode: 0, ids: batch.toString() };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
const reply = App.handleRpcJson(transport);
|
const reply = Utils.handleRpcJson(transport);
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
const batch = reply.ids;
|
const batch = reply.ids;
|
||||||
|
@ -1167,7 +1167,7 @@ function catchupRelativeToArticle(below, id) {
|
||||||
cmode: 0, ids: ids_to_mark.toString() };
|
cmode: 0, ids: ids_to_mark.toString() };
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
App.handleRpcJson(transport);
|
Utils.handleRpcJson(transport);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1489,7 +1489,7 @@ function initHeadlinesMenu() {
|
||||||
menu.addChild(new dijit.MenuItem({
|
menu.addChild(new dijit.MenuItem({
|
||||||
label: __("Mark feed as read"),
|
label: __("Mark feed as read"),
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
catchupFeedInGroup(this.getParent().currentTarget.getAttribute("data-feed-id"));
|
Feeds.catchupFeedInGroup(this.getParent().currentTarget.getAttribute("data-feed-id"));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue