summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2011-12-11 23:59:25 +0400
committerAndrew Dolgov <[email protected]>2011-12-11 23:59:25 +0400
commit107d0cf39e3801547a9a86b32762b772b25f6953 (patch)
treec76a639f2b4b77f14c0942aec7cd0117144ff24c /js
parent31303c6bbdaeed42a5cc72bc01f610ed7ca99663 (diff)
overall directory tree cleanup
Diffstat (limited to 'js')
-rw-r--r--js/FeedTree.js434
-rw-r--r--js/PrefFeedTree.js79
-rw-r--r--js/PrefFilterTree.js52
-rw-r--r--js/PrefLabelTree.js43
-rw-r--r--js/deprecated.js29
-rw-r--r--js/digest.js841
-rw-r--r--js/feedlist.js505
-rw-r--r--js/functions.js1657
-rw-r--r--js/prefs.js1967
-rw-r--r--js/tt-rss.js1164
-rw-r--r--js/viewfeed.js2245
11 files changed, 9016 insertions, 0 deletions
diff --git a/js/FeedTree.js b/js/FeedTree.js
new file mode 100644
index 000000000..b5b757164
--- /dev/null
+++ b/js/FeedTree.js
@@ -0,0 +1,434 @@
+dojo.provide("fox.FeedTree");
+dojo.provide("fox.FeedStoreModel");
+
+dojo.require("dijit.Tree");
+dojo.require("dijit.Menu");
+
+dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
+ getItemsInCategory: function (id) {
+ if (!this.store._itemsByIdentity) return undefined;
+
+ cat = this.store._itemsByIdentity['CAT:' + id];
+
+ if (cat && cat.items)
+ return cat.items;
+ else
+ return undefined;
+
+ },
+ getItemById: function(id) {
+ return this.store._itemsByIdentity[id];
+ },
+ getFeedValue: function(feed, is_cat, key) {
+ if (!this.store._itemsByIdentity) return undefined;
+
+ if (is_cat)
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ else
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+ if (treeItem)
+ return this.store.getValue(treeItem, key);
+ },
+ getFeedName: function(feed, is_cat) {
+ return this.getFeedValue(feed, is_cat, 'name');
+ },
+ getFeedUnread: function(feed, is_cat) {
+ var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
+ return (isNaN(unread)) ? 0 : unread;
+ },
+ setFeedUnread: function(feed, is_cat, unread) {
+ return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
+ },
+ setFeedValue: function(feed, is_cat, key, value) {
+ if (!value) value = '';
+ if (!this.store._itemsByIdentity) return undefined;
+
+ if (is_cat)
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ else
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+ if (treeItem)
+ return this.store.setValue(treeItem, key, value);
+ },
+ getNextUnreadFeed: function (feed, is_cat) {
+ if (!this.store._itemsByIdentity)
+ return null;
+
+ if (is_cat) {
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ items = this.store._arrayOfTopLevelItems;
+ } else {
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+ items = this.store._arrayOfAllItems;
+ }
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i+1; j < items.length; j++) {
+ var unread = this.store.getValue(items[j], 'unread');
+ var id = this.store.getValue(items[j], 'id');
+
+ if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
+ }
+
+ for (var j = 0; j < i; j++) {
+ var unread = this.store.getValue(items[j], 'unread');
+ var id = this.store.getValue(items[j], 'id');
+
+ if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
+ }
+ }
+ }
+
+ return null;
+ },
+ hasCats: function() {
+ if (this.store && this.store._itemsByIdentity)
+ return this.store._itemsByIdentity['CAT:-1'] != undefined;
+ else
+ return false;
+ },
+});
+
+dojo.declare("fox.FeedTree", dijit.Tree, {
+ _createTreeNode: function(args) {
+ var tnode = new dijit._TreeNode(args);
+
+ if (args.item.icon)
+ tnode.iconNode.src = args.item.icon[0];
+
+ var id = args.item.id[0];
+ var bare_id = parseInt(id.substr(id.indexOf(':')+1));
+
+ if (bare_id < -10) {
+ var span = dojo.doc.createElement('span');
+ var fg_color = args.item.fg_color[0];
+ var bg_color = args.item.bg_color[0];
+
+ span.innerHTML = "&alpha;";
+ span.className = 'labelColorIndicator';
+ span.setStyle({
+ color: fg_color,
+ backgroundColor: bg_color});
+
+ dojo.place(span, tnode.iconNode, 'replace');
+ }
+
+ if (id.match("FEED:") && bare_id > 0) {
+ var menu = new dijit.Menu();
+ menu.row_id = bare_id;
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark as read"),
+ onClick: function() {
+ catchupFeed(this.getParent().row_id);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Edit feed"),
+ onClick: function() {
+ editFeed(this.getParent().row_id, false);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Update feed"),
+ onClick: function() {
+ scheduleFeedUpdate(this.getParent().row_id, false);
+ }}));
+
+ menu.bindDomNode(tnode.domNode);
+ tnode._menu = menu;
+ }
+
+ if (id.match("CAT:") && bare_id > 0) {
+ var menu = new dijit.Menu();
+ menu.row_id = bare_id;
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark as read"),
+ onClick: function() {
+ catchupFeed(this.getParent().row_id, true);
+ }}));
+
+ menu.bindDomNode(tnode.domNode);
+ tnode._menu = menu;
+ }
+
+ //tnode.labelNode.innerHTML = args.label;
+ return tnode;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+ },
+ getLabelClass: function (item, opened) {
+ return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+ getLabel: function(item) {
+ var name = String(item.name);
+
+ /* Horrible */
+ name = name.replace(/&quot;/g, "\"");
+ name = name.replace(/&amp;/g, "&");
+ name = name.replace(/&mdash;/g, "-");
+ name = name.replace(/&lt;/g, "<");
+ name = name.replace(/&gt;/g, ">");
+
+ if (item.unread > 0) {
+ return name + " (" + item.unread + ")";
+ } else {
+ return name;
+ }
+ },
+ selectFeed: function(feed, is_cat) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ if (!is_cat) this._expandNode(treeNode);
+ this.set("selectedNodes", [treeNode]);
+ }
+ },
+ setFeedIcon: function(feed, is_cat, src) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ treeNode.iconNode.src = src;
+ return true;
+ }
+ return false;
+ },
+ setFeedExpandoIcon: function(feed, is_cat, src) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ treeNode.expandoNode.src = src;
+ return true;
+ }
+
+ return false;
+ },
+ hasCats: function() {
+ return this.model.hasCats();
+ },
+ hideRead: function (hide, show_special) {
+ if (this.hasCats()) {
+
+ var tree = this;
+ var cats = this.model.store._arrayOfTopLevelItems;
+
+ cats.each(function(cat) {
+ var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
+
+ var id = String(cat.id);
+ var node = tree._itemNodesMap[id];
+ var bare_id = parseInt(id.substr(id.indexOf(":")+1));
+
+ if (node) {
+ var check_unread = tree.model.getFeedUnread(bare_id, true);
+
+ if (hide && cat_unread == 0 && check_unread == 0) {
+ Effect.Fade(node[0].rowNode, {duration : 0.3,
+ queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+ } else {
+ Element.show(node[0].rowNode);
+ ++cat_unread;
+ }
+ }
+ });
+
+ } else {
+ this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
+ show_special);
+ }
+ },
+ hideReadFeeds: function (items, hide, show_special) {
+ var tree = this;
+ var cat_unread = 0;
+
+ items.each(function(feed) {
+ var id = String(feed.id);
+ var bare_id = parseInt(feed.bare_id);;
+
+ var unread = feed.unread[0];
+ var node = tree._itemNodesMap[id];
+
+ if (node) {
+ if (hide && unread == 0 && (bare_id > 0 || !show_special)) {
+ Effect.Fade(node[0].rowNode, {duration : 0.3,
+ queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+ } else {
+ Element.show(node[0].rowNode);
+ ++cat_unread;
+ }
+ }
+ });
+
+ return cat_unread;
+ },
+ collapseCat: function(id) {
+ if (!this.model.hasCats()) return;
+
+ var tree = this;
+
+ var node = tree._itemNodesMap['CAT:' + id][0];
+ var item = tree.model.store._itemsByIdentity['CAT:' + id];
+
+ if (node && item) {
+ var hidden = tree.model.store.getValue(item, 'hidden');
+
+ if (hidden)
+ tree._expandNode(node);
+ else
+ tree._collapseNode(node);
+
+ tree.model.store.setValue(item, 'hidden', !hidden);
+ }
+ },
+ collapseHiddenCats: function() {
+ if (!this.model.hasCats()) return;
+
+ var cats = this.model.store._arrayOfTopLevelItems;
+ var tree = this;
+
+ dojo.forEach(cats, function(cat) {
+ var hidden = tree.model.store.getValue(cat, 'hidden');
+ var id = tree.model.store.getValue(cat, 'id');
+ var node = tree._itemNodesMap[id][0];
+
+ if (hidden)
+ tree._collapseNode(node);
+ else
+ tree._expandNode(node);
+
+ });
+ },
+ getVisibleUnreadFeeds: function() {
+ var items = this.model.store._arrayOfAllItems;
+ var rv = [];
+
+ for (var i = 0; i < items.length; i++) {
+ var id = String(items[i].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = false;
+
+ try {
+ cat = box[0].rowNode.parentNode.parentNode;
+ } catch (e) { }
+
+ if (row) {
+ if (Element.visible(row) && (!cat || Element.visible(cat))) {
+ var feed_id = String(items[i].bare_id);
+ var is_cat = !id.match('FEED:');
+ var unread = this.model.getFeedUnread(feed_id, is_cat);
+
+ if (unread > 0)
+ rv.push([feed_id, is_cat]);
+
+ }
+ }
+ }
+ }
+
+ return rv;
+ },
+ getNextFeed: function (feed, is_cat) {
+ if (is_cat) {
+ treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+ } else {
+ treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+ }
+
+ items = this.model.store._arrayOfAllItems;
+ var item = items[0];
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i+1; j < items.length; j++) {
+ var id = String(items[j].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = box[0].rowNode.parentNode.parentNode;
+
+ if (Element.visible(cat) && Element.visible(row)) {
+ item = items[j];
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (item) {
+ return [this.model.store.getValue(item, 'bare_id'),
+ !this.model.store.getValue(item, 'id').match('FEED:')];
+ } else {
+ return false;
+ }
+ },
+ getPreviousFeed: function (feed, is_cat) {
+ if (is_cat) {
+ treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+ } else {
+ treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+ }
+
+ items = this.model.store._arrayOfAllItems;
+ var item = items[0];
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i-1; j > 0; j--) {
+ var id = String(items[j].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = box[0].rowNode.parentNode.parentNode;
+
+ if (Element.visible(cat) && Element.visible(row)) {
+ item = items[j];
+ break;
+ }
+ }
+
+ }
+ break;
+ }
+ }
+
+ if (item) {
+ return [this.model.store.getValue(item, 'bare_id'),
+ !this.model.store.getValue(item, 'id').match('FEED:')];
+ } else {
+ return false;
+ }
+
+ },
+
+});
diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js
new file mode 100644
index 000000000..4ea486609
--- /dev/null
+++ b/js/PrefFeedTree.js
@@ -0,0 +1,79 @@
+dojo.provide("fox.PrefFeedTree");
+dojo.provide("fox.PrefFeedStore");
+
+dojo.require("lib.CheckBoxTree");
+dojo.require("dojo.data.ItemFileWriteStore");
+
+dojo.declare("fox.PrefFeedStore", dojo.data.ItemFileWriteStore, {
+
+ _saveEverything: function(saveCompleteCallback, saveFailedCallback,
+ newFileContentString) {
+
+ dojo.xhrPost({
+ url: "backend.php",
+ content: {op: "pref-feeds", subop: "savefeedorder",
+ payload: newFileContentString},
+ error: saveFailedCallback,
+ load: saveCompleteCallback});
+ },
+
+});
+
+dojo.declare("fox.PrefFeedTree", lib.CheckBoxTree, {
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ if (args.item.icon)
+ tnode.iconNode.src = args.item.icon[0];
+
+ var param = this.model.store.getValue(args.item, 'param');
+
+ if (param) {
+ param = dojo.doc.createElement('span');
+ param.className = 'feedParam';
+ param.innerHTML = args.item.param[0];
+ dojo.place(param, tnode.labelNode, 'after');
+ }
+
+ return tnode;
+ },
+ onDndDrop: function() {
+ this.inherited(arguments);
+ this.tree.model.store.save();
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+ },
+ checkItemAcceptance: function(target, source, position) {
+ var item = dijit.getEnclosingWidget(target).item;
+
+ // disable copying items
+ source.copyState = function() { return false; };
+
+ var source_item = false;
+
+ source.forInSelectedItems(function(node) {
+ source_item = node.data.item;
+ });
+
+ if (!source_item || !item) return false;
+
+ var id = this.tree.model.store.getValue(item, 'id');
+ var source_id = source.tree.model.store.getValue(source_item, 'id');
+
+ //console.log(id + " " + position + " " + source_id);
+
+ if (source_id.match("FEED:")) {
+ return ((id.match("CAT:") && position == "over") ||
+ (id.match("FEED:") && position != "over"));
+ } else if (source_id.match("CAT:")) {
+ return ((id.match("CAT:") && position != "over") ||
+ (id.match("root") && position == "over"));
+ }
+ },
+});
+
diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js
new file mode 100644
index 000000000..a4cf3dac8
--- /dev/null
+++ b/js/PrefFilterTree.js
@@ -0,0 +1,52 @@
+dojo.provide("fox.PrefFilterTree");
+
+dojo.require("lib.CheckBoxTree");
+
+dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ var enabled = this.model.store.getValue(args.item, 'enabled');
+ var param = this.model.store.getValue(args.item, 'param');
+
+ if (param) {
+ param = dojo.doc.createElement('span');
+ param.className = (enabled != false) ? 'labelParam' : 'labelParam Disabled';
+ param.innerHTML = args.item.param[0];
+ dojo.place(param, tnode.labelNode, 'after');
+ }
+
+ return tnode;
+ },
+
+ getLabel: function(item) {
+ var label = item.name;
+
+ var feed = this.model.store.getValue(item, 'feed');
+ var inverse = this.model.store.getValue(item, 'inverse');
+
+ if (feed)
+ label += " (" + __("Feed:") + " " + feed + ")";
+
+ if (inverse)
+ label += " (" + __("Inverse") + ")";
+
+/* if (item.param)
+ label = "<span class=\"labelFixedLength\">" + label +
+ "</span>" + item.param[0]; */
+
+ return label;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+ },
+ getLabelClass: function (item, opened) {
+ var enabled = this.model.store.getValue(item, 'enabled');
+ return (enabled != false) ? "dijitTreeLabel labelFixedLength" : "dijitTreeLabel labelFixedLength Disabled";
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+});
+
diff --git a/js/PrefLabelTree.js b/js/PrefLabelTree.js
new file mode 100644
index 000000000..05a0c15b6
--- /dev/null
+++ b/js/PrefLabelTree.js
@@ -0,0 +1,43 @@
+dojo.provide("fox.PrefLabelTree");
+
+dojo.require("lib.CheckBoxTree");
+dojo.require("dijit.form.DropDownButton");
+
+dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
+ setNameById: function (id, name) {
+ var item = this.model.store._itemsByIdentity['LABEL:' + id];
+
+ if (item)
+ this.model.store.setValue(item, 'name', name);
+
+ },
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ var fg_color = this.model.store.getValue(args.item, 'fg_color');
+ var bg_color = this.model.store.getValue(args.item, 'bg_color');
+ var type = this.model.store.getValue(args.item, 'type');
+ var bare_id = this.model.store.getValue(args.item, 'bare_id');
+
+ if (type == 'label') {
+ var span = dojo.doc.createElement('span');
+ span.innerHTML = '&alpha;';
+ span.className = 'labelColorIndicator2';
+ span.id = 'LICID-' + bare_id;
+
+ span.setStyle({
+ color: fg_color,
+ backgroundColor: bg_color});
+
+ tnode._labelIconNode = span;
+
+ dojo.place(tnode._labelIconNode, tnode.labelNode, 'before');
+ }
+
+ return tnode;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+ },
+});
+
diff --git a/js/deprecated.js b/js/deprecated.js
new file mode 100644
index 000000000..1d04a1adc
--- /dev/null
+++ b/js/deprecated.js
@@ -0,0 +1,29 @@
+function selectTableRow(r, do_select) {
+
+ if (do_select) {
+ r.addClassName("Selected");
+ } else {
+ r.removeClassName("Selected");
+ }
+}
+
+function selectTableRowById(elem_id, check_id, do_select) {
+
+ try {
+
+ var row = $(elem_id);
+
+ if (row) {
+ selectTableRow(row, do_select);
+ }
+
+ var check = $(check_id);
+
+ if (check) {
+ check.checked = do_select;
+ }
+ } catch (e) {
+ exception_error("selectTableRowById", e);
+ }
+}
+
diff --git a/js/digest.js b/js/digest.js
new file mode 100644
index 000000000..7dba6d36e
--- /dev/null
+++ b/js/digest.js
@@ -0,0 +1,841 @@
+var last_feeds = [];
+var init_params = {};
+
+var _active_feed_id = false;
+var _update_timeout = false;
+var _view_update_timeout = false;
+var _feedlist_expanded = false;
+var _update_seq = 1;
+
+function article_appear(article_id) {
+ try {
+ new Effect.Appear('A-' + article_id);
+ } catch (e) {
+ exception_error("article_appear", e);
+ }
+}
+
+function catchup_feed(feed_id, callback) {
+ try {
+
+ var fn = find_feed(last_feeds, feed_id).title;
+
+ if (confirm(__("Mark all articles in %s as read?").replace("%s", fn))) {
+
+ var is_cat = "";
+
+ if (feed_id < 0) is_cat = "true"; // KLUDGE
+
+ var query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed_id + "&is_cat=" + is_cat;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+
+ update();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("catchup_article", e);
+ }
+}
+
+function get_visible_article_ids() {
+ try {
+ var elems = $("headlines-content").getElementsByTagName("LI");
+ var ids = [];
+
+ for (var i = 0; i < elems.length; i++) {
+ if (elems[i].id && elems[i].id.match("A-")) {
+ ids.push(elems[i].id.replace("A-", ""));
+ }
+ }
+
+ return ids;
+
+ } catch (e) {
+ exception_error("get_visible_article_ids", e);
+ }
+}
+
+function catchup_visible_articles(callback) {
+ try {
+
+ var ids = get_visible_article_ids();
+
+ if (confirm(__("Mark %d displayed articles as read?").replace("%d", ids.length))) {
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(ids);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+
+ viewfeed(_active_feed_id, 0);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("catchup_visible_articles", e);
+ }
+}
+
+function catchup_article(article_id, callback) {
+ try {
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + article_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("catchup_article", e);
+ }
+}
+
+function set_selected_article(article_id) {
+ try {
+ $$("#headlines-content > li[id*=A-]").each(function(article) {
+ var id = article.id.replace("A-", "");
+
+ var cb = article.getElementsByTagName("INPUT")[0];
+
+ if (id == article_id) {
+ article.addClassName("selected");
+ cb.checked = true;
+ } else {
+ article.removeClassName("selected");
+ cb.checked = false;
+ }
+
+ });
+
+ } catch (e) {
+ exception_error("mark_selected_feed", e);
+ }
+}
+
+
+function set_selected_feed(feed_id) {
+ try {
+ var feeds = $("feeds-content").getElementsByTagName("LI");
+
+ for (var i = 0; i < feeds.length; i++) {
+ if (feeds[i].id == "F-" + feed_id)
+ feeds[i].className = "selected";
+ else
+ feeds[i].className = "";
+ }
+
+ _active_feed_id = feed_id;
+
+ } catch (e) {
+ exception_error("mark_selected_feed", e);
+ }
+}
+
+function load_more() {
+ try {
+ var pr = $("H-LOADING-IMG");
+
+ if (pr) Element.show(pr);
+
+ var offset = $$("#headlines-content > li[id*=A-][class*=fresh],li[id*=A-][class*=unread]").length;
+
+ viewfeed(false, offset, false, false, true,
+ function() {
+ var pr = $("H-LOADING-IMG");
+
+ if (pr) Element.hide(pr);
+ });
+ } catch (e) {
+ exception_error("load_more", e);
+ }
+}
+
+function update(callback) {
+ try {
+ console.log('updating feeds...');
+
+ window.clearTimeout(_update_timeout);
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=digest-init",
+ onComplete: function(transport) {
+ fatal_error_check(transport);
+ parse_feeds(transport);
+ set_selected_feed(_active_feed_id);
+
+ if (callback) callback(transport);
+ } });
+
+ _update_timeout = window.setTimeout('update()', 5*1000);
+ } catch (e) {
+ exception_error("update", e);
+ }
+}
+
+function remove_headline_entry(article_id) {
+ try {
+ var elem = $('A-' + article_id);
+
+ if (elem) {
+ elem.parentNode.removeChild(elem);
+ }
+
+ } catch (e) {
+ exception_error("remove_headline_entry", e);
+ }
+}
+
+function view_update() {
+ try {
+ viewfeed(_active_feed_id, _active_feed_offset, false, true, true);
+ update();
+ } catch (e) {
+ exception_error("view_update", e);
+ }
+}
+
+function view(article_id) {
+ try {
+ $("content").addClassName("move");
+
+ var a = $("A-" + article_id);
+ var h = $("headlines");
+
+ setTimeout(function() {
+ // below or above viewport, reposition headline
+ if (a.offsetTop > h.scrollTop + h.offsetHeight || a.offsetTop+a.offsetHeight < h.scrollTop+a.offsetHeight)
+ h.scrollTop = a.offsetTop - (h.offsetHeight/2 - a.offsetHeight/2);
+ }, 500);
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=digest-get-contents&article_id=" +
+ article_id,
+ onComplete: function(transport) {
+ fatal_error_check(transport);
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ var article = reply['article'];
+
+ var mark_part = "";
+ var publ_part = "";
+
+ var tags_part = "";
+
+ if (article.tags.length > 0) {
+ tags_part = " " + __("in") + " ";
+
+ for (var i = 0; i < Math.min(5, article.tags.length); i++) {
+ //tags_part += "<a href=\"#\" onclick=\"viewfeed('" +
+ // article.tags[i] + "')\">" +
+ // article.tags[i] + "</a>, ";
+
+ tags_part += article.tags[i] + ", ";
+ }
+
+ tags_part = tags_part.replace(/, $/, "");
+ tags_part = "<span class=\"tags\">" + tags_part + "</span>";
+
+ }
+
+ if (article.marked)
+ mark_part = "<img title='"+ __("Unstar article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_set.png'>";
+ else
+ mark_part = "<img title='"+__("Star article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_unset.png'>";
+
+ if (article.published)
+ publ_part = "<img title='"+__("Unpublish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_set.png'>";
+ else
+ publ_part = "<img title='"+__("Publish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_unset.png'>";
+
+ var tmp = "<div id=\"toolbar\">" +
+ "<a target=\"_blank\" href=\""+article.url+"\">" + __("Original article") + "</a>" +
+ "<div style=\"float : right\"><a href=\"#\" onclick=\"close_article()\">" +
+ __("Close this panel") + "</a></div></div>" +
+ "<div id=\"inner\">" +
+ "<div id=\"ops\">" +
+ mark_part +
+ publ_part +
+ "</div>" +
+ "<h1>" + article.title + "</h1>" +
+ "<div id=\"tags\">" +
+ tags_part +
+ "</div>" +
+ article.content + "</div>";
+
+ $("article-content").innerHTML = tmp;
+ $("article").addClassName("visible");
+
+ set_selected_article(article.id);
+
+ catchup_article(article_id,
+ function() {
+ $("A-" + article_id).addClassName("read");
+ });
+
+ } else {
+ elem.innerHTML = __("Error: unable to load article.");
+ }
+ }
+ });
+
+
+ return false;
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function close_article() {
+ $("content").removeClassName("move");
+ $("article").removeClassName("visible");
+}
+
+function viewfeed(feed_id, offset, replace, no_effects, no_indicator, callback) {
+ try {
+
+ if (!feed_id) feed_id = _active_feed_id;
+ if (offset == undefined) offset = 0;
+ if (replace == undefined) replace = (offset == 0);
+
+ _update_seq = _update_seq + 1;
+
+ if (!offset) $("headlines").scrollTop = 0;
+
+ var query = "backend.php?op=rpc&subop=digest-update&feed_id=" +
+ param_escape(feed_id) + "&offset=" + offset +
+ "&seq=" + _update_seq;
+
+ console.log(query);
+
+ var img = false;
+
+ if ($("F-" + feed_id)) {
+ img = $("F-" + feed_id).getElementsByTagName("IMG")[0];
+
+ if (img && !no_indicator) {
+ img.setAttribute("orig_src", img.src);
+ img.src = 'images/indicator_tiny.gif';
+ }
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ Element.hide("overlay");
+
+ fatal_error_check(transport);
+ parse_headlines(transport, replace, no_effects);
+ set_selected_feed(feed_id);
+ _active_feed_offset = offset;
+
+ if (img && !no_indicator)
+ img.src = img.getAttribute("orig_src");
+
+ if (callback) callback(transport);
+
+ } });
+
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function find_article(articles, article_id) {
+ try {
+ for (var i = 0; i < articles.length; i++) {
+ if (articles[i].id == article_id)
+ return articles[i];
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("find_article", e);
+ }
+}
+
+function find_feed(feeds, feed_id) {
+ try {
+ for (var i = 0; i < feeds.length; i++) {
+ if (feeds[i].id == feed_id)
+ return feeds[i];
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("find_feed", e);
+ }
+}
+
+function get_feed_icon(feed) {
+ try {
+ if (feed.has_icon)
+ return getInitParam('icons_url') + "/" + feed.id + '.ico';
+
+ if (feed.id == -1)
+ return 'images/mark_set.png';
+
+ if (feed.id == -2)
+ return 'images/pub_set.png';
+
+ if (feed.id == -3)
+ return 'images/fresh.png';
+
+ if (feed.id == -4)
+ return 'images/tag.png';
+
+ if (feed.id < -10)
+ return 'images/label.png';
+
+ return 'images/blank_icon.gif';
+
+ } catch (e) {
+ exception_error("get_feed_icon", e);
+ }
+}
+
+function add_feed_entry(feed) {
+ try {
+ var icon_part = "";
+
+ icon_part = "<img src='" + get_feed_icon(feed) + "'/>";
+
+ var tmp_html = "<li id=\"F-"+feed.id+"\" onclick=\"viewfeed("+feed.id+")\">" +
+ icon_part + feed.title +
+ "<div class='unread-ctr'>" + "<span class=\"unread\">" + feed.unread + "</span>" +
+ "</div>" + "</li>";
+
+ $("feeds-content").innerHTML += tmp_html;
+
+
+ } catch (e) {
+ exception_error("add_feed_entry", e);
+ }
+}
+
+function add_headline_entry(article, feed, no_effects) {
+ try {
+
+ var icon_part = "";
+
+ icon_part = "<img class='icon' src='" + get_feed_icon(feed) + "'/>";
+
+
+ var style = "";
+
+ //if (!no_effects) style = "style=\"display : none\"";
+
+ if (article.excerpt.trim() == "")
+ article.excerpt = __("Click to expand article.");
+
+ var li_class = "unread";
+
+ var fresh_max = getInitParam("fresh_article_max_age") * 60 * 60;
+ var d = new Date();
+
+ if (d.getTime() / 1000 - article.updated < fresh_max)
+ li_class = "fresh";
+
+ //"<img title='" + __("Share on Twitter") + "' onclick=\"tweet_article("+article.id+", true)\" src='images/art-tweet.png'>" +
+
+ //"<img title='" + __("Mark as read") + "' onclick=\"view("+article.id+", true)\" src='images/digest_checkbox.png'>" +
+
+ var checkbox_part = "<input type=\"checkbox\" class=\"cb\" onclick=\"toggle_select_article(this)\"/>";
+
+ var date = new Date(article.updated * 1000);
+
+ var date_part = date.toString().substring(0,21);
+
+ var tmp_html = "<li id=\"A-"+article.id+"\" "+style+" class=\""+li_class+"\">" +
+ checkbox_part +
+ icon_part +
+ "<a target=\"_blank\" href=\""+article.link+"\""+
+ "onclick=\"return view("+article.id+")\" class='title'>" +
+ article.title + "</a>" +
+ "<div class='body'>" +
+ "<div onclick=\"view("+article.id+")\" class='excerpt'>" +
+ article.excerpt + "</div>" +
+ "<div class='info'>";
+
+/* tmp_html += "<a href=\#\" onclick=\"viewfeed("+feed.id+")\">" +
+ feed.title + "</a> " + " @ "; */
+
+ tmp_html += date_part + "</div>" +
+ "</div></li>";
+
+ $("headlines-content").innerHTML += tmp_html;
+
+ if (!no_effects)
+ window.setTimeout('article_appear(' + article.id + ')', 100);
+
+ } catch (e) {
+ exception_error("add_headline_entry", e);
+ }
+}
+
+function expand_feeds() {
+ try {
+ _feedlist_expanded = true;
+
+ redraw_feedlist(last_feeds);
+
+ } catch (e) {
+ exception_error("expand_feeds", e);
+ }
+}
+
+function redraw_feedlist(feeds) {
+ try {
+
+ $('feeds-content').innerHTML = "";
+
+ var limit = 10;
+
+ if (_feedlist_expanded) limit = feeds.length;
+
+ for (var i = 0; i < Math.min(limit, feeds.length); i++) {
+ add_feed_entry(feeds[i]);
+ }
+
+ if (feeds.length > limit) {
+ $('feeds-content').innerHTML += "<li id='F-MORE-PROMPT'>" +
+ "<img src='images/blank_icon.gif'>" +
+ "<a href=\"#\" onclick=\"expand_feeds()\">" +
+ __("%d more...").replace("%d", feeds.length-10) +
+ "</a>" + "</li>";
+ }
+
+ if (feeds.length == 0) {
+ $('feeds-content').innerHTML =
+ "<div class='insensitive' style='text-align : center'>" +
+ __("No unread feeds.") + "</div>";
+ }
+
+ if (_active_feed_id)
+ set_selected_feed(_active_feed_id);
+
+ } catch (e) {
+ exception_error("redraw_feedlist", e);
+ }
+}
+
+function parse_feeds(transport) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+
+ if (!reply) return;
+
+ var feeds = reply['feeds'];
+
+ if (feeds) {
+
+ feeds.sort( function (a,b)
+ {
+ if (b.unread != a.unread)
+ return (b.unread - a.unread);
+ else
+ if (a.title > b.title)
+ return 1;
+ else if (a.title < b.title)
+ return -1;
+ else
+ return 0;
+ });
+
+ var all_articles = find_feed(feeds, -4);
+
+ update_title(all_articles.unread);
+
+ last_feeds = feeds;
+
+ redraw_feedlist(feeds);
+ }
+
+ } catch (e) {
+ exception_error("parse_feeds", e);
+ }
+}
+
+function parse_headlines(transport, replace, no_effects) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+ if (!reply) return;
+
+ var seq = reply['seq'];
+
+ if (seq) {
+ if (seq != _update_seq) {
+ console.log("parse_headlines: wrong sequence received.");
+ return;
+ }
+ } else {
+ return;
+ }
+
+ var headlines = reply['headlines']['content'];
+ var headlines_title = reply['headlines']['title'];
+
+ if (headlines && headlines_title) {
+
+ if (replace) {
+ $('headlines-content').innerHTML = '';
+ }
+
+ var pr = $('H-MORE-PROMPT');
+
+ if (pr) pr.parentNode.removeChild(pr);
+
+ var inserted = false;
+
+ for (var i = 0; i < headlines.length; i++) {
+
+ if (!$('A-' + headlines[i].id)) {
+ add_headline_entry(headlines[i],
+ find_feed(last_feeds, headlines[i].feed_id), !no_effects);
+
+ }
+ }
+
+ console.log(inserted.id);
+
+ var ids = get_visible_article_ids();
+
+ if (ids.length > 0) {
+ if (pr) {
+ $('headlines-content').appendChild(pr);
+
+ } else {
+ $('headlines-content').innerHTML += "<li id='H-MORE-PROMPT'>" +
+ "<div class='body'>" +
+ "<a href=\"#\" onclick=\"catchup_visible_articles()\">" +
+ __("Mark as read") + "</a> | " +
+ "<a href=\"javascript:load_more()\">" +
+ __("Load more...") + "</a>" +
+ "<img style=\"display : none\" "+
+ "id=\"H-LOADING-IMG\" src='images/indicator_tiny.gif'>" +
+ "</div></li>";
+ }
+ } else {
+ // FIXME : display some kind of "nothing to see here" prompt here
+ }
+
+// if (replace && !no_effects)
+// new Effect.Appear('headlines-content', {duration : 0.3});
+
+ //new Effect.Appear('headlines-content');
+ }
+
+ } catch (e) {
+ exception_error("parse_headlines", e);
+ }
+}
+
+function init_second_stage() {
+ try {
+ new Ajax.Request("backend.php", {
+ parameters: "backend.php?op=rpc&subop=digest-init",
+ onComplete: function(transport) {
+ parse_feeds(transport);
+ Element.hide("overlay");
+
+ window.setTimeout('viewfeed(-4)', 100);
+ _update_timeout = window.setTimeout('update()', 5*1000);
+ } });
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function init() {
+ try {
+ dojo.require("dijit.Dialog");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=sanityCheck",
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("digest_init", e);
+ }
+}
+
+function toggle_mark(img, id) {
+
+ try {
+
+ var query = "?op=rpc&id=" + id + "&subop=mark";
+
+ if (!img) return;
+
+ if (img.src.match("mark_unset")) {
+ img.src = img.src.replace("mark_unset", "mark_set");
+ img.alt = __("Unstar article");
+ query = query + "&mark=1";
+ } else {
+ img.src = img.src.replace("mark_set", "mark_unset");
+ img.alt = __("Star article");
+ query = query + "&mark=0";
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ update();
+ } });
+
+ } catch (e) {
+ exception_error("toggle_mark", e);
+ }
+}
+
+function toggle_pub(img, id, note) {
+
+ try {
+
+ var query = "?op=rpc&id=" + id + "&subop=publ";
+
+ if (note != undefined) {
+ query = query + "&note=" + param_escape(note);
+ } else {
+ query = query + "&note=undefined";
+ }
+
+ if (!img) return;
+
+ if (img.src.match("pub_unset") || note != undefined) {
+ img.src = img.src.replace("pub_unset", "pub_set");
+ img.alt = __("Unpublish article");
+ query = query + "&pub=1";
+
+ } else {
+ img.src = img.src.replace("pub_set", "pub_unset");
+ img.alt = __("Publish article");
+ query = query + "&pub=0";
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ update();
+ } });
+
+ } catch (e) {
+ exception_error("toggle_pub", e);
+ }
+}
+
+function fatal_error(code, msg) {
+ try {
+
+ if (code == 6) {
+ window.location.href = "digest.php";
+ } else if (code == 5) {
+ window.location.href = "db-updater.php";
+ } else {
+
+ if (msg == "") msg = "Unknown error";
+
+ console.error("Fatal error: " + code + "\n" +
+ msg);
+
+ }
+
+ } catch (e) {
+ exception_error("fatalError", e);
+ }
+}
+
+function fatal_error_check(transport) {
+ try {
+ if (transport.responseXML) {
+ var error = transport.responseXML.getElementsByTagName("error")[0];
+
+ if (error) {
+ var code = error.getAttribute("error-code");
+ var msg = error.getAttribute("error-msg");
+ if (code != 0) {
+ fatal_error(code, msg);
+ return false;
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("fatal_error_check", e);
+ }
+ return true;
+}
+
+function update_title(unread) {
+ try {
+ document.title = "Tiny Tiny RSS";
+
+ if (unread > 0)
+ document.title += " (" + unread + ")";
+
+ } catch (e) {
+ exception_error("update_title", e);
+ }
+}
+
+function tweet_article(id) {
+ try {
+
+ var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
+
+ console.log(query);
+
+ var d = new Date();
+ var ts = d.getTime();
+
+ var w = window.open('backend.php?op=loading', 'ttrss_tweet',
+ "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var ti = JSON.parse(transport.responseText);
+
+ var share_url = "http://twitter.com/share?_=" + ts +
+ "&text=" + param_escape(ti.title) +
+ "&url=" + param_escape(ti.link);
+
+ w.location.href = share_url;
+
+ } });
+
+ } catch (e) {
+ exception_error("tweet_article", e);
+ }
+}
+
+function toggle_select_article(elem) {
+ try {
+ var article = elem.parentNode;
+
+ if (article.hasClassName("selected"))
+ article.removeClassName("selected");
+ else
+ article.addClassName("selected");
+
+ } catch (e) {
+ exception_error("toggle_select_article", e);
+ }
+}
diff --git a/js/feedlist.js b/js/feedlist.js
new file mode 100644
index 000000000..62c44b494
--- /dev/null
+++ b/js/feedlist.js
@@ -0,0 +1,505 @@
+var _infscroll_disable = 0;
+var _infscroll_request_sent = 0;
+var _search_query = false;
+
+var counter_timeout_id = false;
+
+var counters_last_request = 0;
+
+function viewCategory(cat) {
+ viewfeed(cat, '', true);
+ return false;
+}
+
+function loadMoreHeadlines() {
+ try {
+ console.log("loadMoreHeadlines");
+
+ var offset = 0;
+
+ var view_mode = document.forms["main_toolbar_form"].view_mode.value;
+ var num_unread = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
+ var num_all = $$("#headlines-frame > div[id*=RROW]").length;
+
+ // TODO implement marked & published
+
+ if (view_mode == "marked") {
+ console.warn("loadMoreHeadlines: marked is not implemented, falling back.");
+ offset = num_all;
+ } else if (view_mode == "published") {
+ console.warn("loadMoreHeadlines: published is not implemented, falling back.");
+ offset = num_all;
+ } else if (view_mode == "unread") {
+ offset = num_unread;
+ } else if (view_mode == "adaptive") {
+ if (num_unread > 0)
+ offset = num_unread;
+ else
+ offset = num_all;
+ } else {
+ offset = num_all;
+ }
+
+ viewfeed(getActiveFeedId(), '', activeFeedIsCat(), offset, false, true);
+
+ } catch (e) {
+ exception_error("viewNextFeedPage", e);
+ }
+}
+
+
+function viewfeed(feed, subop, is_cat, offset, background, infscroll_req) {
+ try {
+ if (is_cat == undefined)
+ is_cat = false;
+ else
+ is_cat = !!is_cat;
+
+ if (subop == undefined) subop = '';
+ if (offset == undefined) offset = 0;
+ if (background == undefined) background = false;
+ if (infscroll_req == undefined) infscroll_req = false;
+
+ last_requested_article = 0;
+
+ var cached_headlines = false;
+
+ if (feed == getActiveFeedId()) {
+ cache_delete("feed:" + feed + ":" + is_cat);
+ } else {
+ cached_headlines = cache_get("feed:" + feed + ":" + is_cat);
+
+ // switching to a different feed, we might as well catchup stuff visible
+ // in headlines buffer (if any)
+ if (!background && getInitParam("cdm_auto_catchup") == 1 && parseInt(getActiveFeedId()) > 0) {
+
+ $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
+ function(child) {
+ var hf = $("headlines-frame");
+
+ if (hf.scrollTop + hf.offsetHeight >=
+ child.offsetTop + child.offsetHeight) {
+
+ var id = child.id.replace("RROW-", "");
+
+ if (catchup_id_batch.indexOf(id) == -1)
+ catchup_id_batch.push(id);
+
+ }
+
+ if (catchup_id_batch.length > 0) {
+ window.clearTimeout(catchup_timeout_id);
+
+ if (!_infscroll_request_sent) {
+ catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
+ 2000);
+ }
+ }
+
+ });
+ }
+ }
+
+ if (offset == 0 && !background)
+ dijit.byId("content-tabs").selectChild(
+ dijit.byId("content-tabs").getChildren()[0]);
+
+ if (!background) {
+ if (getActiveFeedId() != feed || offset == 0) {
+ active_post_id = 0;
+ _infscroll_disable = 0;
+ }
+
+ if (!offset && !subop && cached_headlines && !background) {
+ try {
+ render_local_headlines(feed, is_cat, JSON.parse(cached_headlines));
+ return;
+ } catch (e) {
+ console.warn("render_local_headlines failed: " + e);
+ }
+ }
+
+ if (offset != 0 && !subop) {
+ var date = new Date();
+ var timestamp = Math.round(date.getTime() / 1000);
+
+ if (_infscroll_request_sent && _infscroll_request_sent + 30 > timestamp) {
+ //console.log("infscroll request in progress, aborting");
+ return;
+ }
+
+ _infscroll_request_sent = timestamp;
+ }
+
+ hideAuxDlg();
+ }
+
+ Form.enable("main_toolbar_form");
+
+ var toolbar_query = Form.serialize("main_toolbar_form");
+
+ var query = "?op=viewfeed&feed=" + feed + "&" +
+ toolbar_query + "&subop=" + param_escape(subop);
+
+ if (!background) {
+ if (_search_query) {
+ force_nocache = true;
+ query = query + "&" + _search_query;
+ _search_query = false;
+ }
+
+ if (subop == "MarkAllRead") {
+
+ var show_next_feed = getInitParam("on_catchup_show_next_feed") == "1";
+
+ if (show_next_feed) {
+ var nuf = getNextUnreadFeed(feed, is_cat);
+
+ if (nuf) {
+ var cached_nuf = cache_get("feed:" + nuf + ":false");
+
+ if (cached_nuf) {
+
+ render_local_headlines(nuf, false, JSON.parse(cached_nuf));
+
+ var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed + "&is_cat=" + is_cat;
+
+ console.log(catchup_query);
+
+ new Ajax.Request("backend.php", {
+ parameters: catchup_query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ return;
+ } else {
+ query += "&nuf=" + param_escape(nuf);
+ }
+ }
+ }
+ }
+
+ if (offset != 0) {
+ query = query + "&skip=" + offset;
+
+ // to prevent duplicate feed titles when showing grouped vfeeds
+ if (vgroup_last_feed) {
+ query = query + "&vgrlf=" + param_escape(vgroup_last_feed);
+ }
+ }
+
+ Form.enable("main_toolbar_form");
+
+ if (!offset)
+ if (!is_cat) {
+ if (!setFeedExpandoIcon(feed, is_cat, 'images/indicator_white.gif'))
+ notify_progress("Loading, please wait...", true);
+ } else {
+ notify_progress("Loading, please wait...", true);
+ }
+ }
+
+ query += "&cat=" + is_cat;
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
+ headlines_callback2(transport, offset, background, infscroll_req);
+ } });
+
+ } catch (e) {
+ exception_error("viewfeed", e);
+ }
+}
+
+function feedlist_init() {
+ try {
+ console.log("in feedlist init");
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+ document.onkeydown = hotkey_handler;
+ setTimeout("hotkey_prefix_timeout()", 5*1000);
+
+ if (!getActiveFeedId()) {
+ setTimeout("viewfeed(-3)", 100);
+ }
+
+ console.log("T:" +
+ getInitParam("cdm_auto_catchup") + " " + getFeedUnread(-3));
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ setTimeout("timeout()", 5000);
+ setTimeout("precache_headlines_idle()", 3000);
+
+ } catch (e) {
+ exception_error("feedlist/init", e);
+ }
+}
+
+function request_counters_real() {
+ try {
+ console.log("requesting counters...");
+
+ var query = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
+
+ query = query + "&omode=flc";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ try {
+ handle_rpc_json(transport);
+ } catch (e) {
+ exception_error("viewfeed/getcounters", e);
+ }
+ } });
+
+ } catch (e) {
+ exception_error("request_counters_real", e);
+ }
+}
+
+
+function request_counters() {
+
+ try {
+
+ if (getInitParam("bw_limit") == "1") return;
+
+ var date = new Date();
+ var timestamp = Math.round(date.getTime() / 1000);
+
+ if (timestamp - counters_last_request > 5) {
+ console.log("scheduling request of counters...");
+
+ window.clearTimeout(counter_timeout_id);
+ counter_timeout_id = window.setTimeout("request_counters_real()", 1000);
+
+ counters_last_request = timestamp;
+ } else {
+ console.log("request_counters: rate limit reached: " + (timestamp - counters_last_request));
+ }
+
+ } catch (e) {
+ exception_error("request_counters", e);
+ }
+}
+
+function displayNewContentPrompt(id) {
+ try {
+
+ var msg = "<a href='#' onclick='viewCurrentFeed()'>" +
+ __("New articles available in this feed (click to show)") + "</a>";
+
+ msg = msg.replace("%s", getFeedName(id));
+
+ $('auxDlg').innerHTML = msg;
+
+ new Effect.Appear('auxDlg', {duration : 0.5});
+
+ } catch (e) {
+ exception_error("displayNewContentPrompt", e);
+ }
+}
+
+function parse_counters(elems, scheduled_call) {
+ try {
+ for (var l = 0; l < elems.length; l++) {
+
+ var id = elems[l].id;
+ var kind = elems[l].kind;
+ var ctr = parseInt(elems[l].counter);
+ var error = elems[l].error;
+ var has_img = elems[l].has_img;
+ var updated = elems[l].updated;
+
+ if (id == "global-unread") {
+ global_unread = ctr;
+ updateTitle();
+ continue;
+ }
+
+ if (id == "subscribed-feeds") {
+ feeds_found = ctr;
+ continue;
+ }
+
+ // TODO: enable new content notification for categories
+
+ if (!activeFeedIsCat() && id == getActiveFeedId()
+ && ctr > getFeedUnread(id) && scheduled_call) {
+ displayNewContentPrompt(id);
+ }
+
+ if (getFeedUnread(id, (kind == "cat")) != ctr)
+ cache_delete("feed:" + id + ":" + (kind == "cat"));
+
+ setFeedUnread(id, (kind == "cat"), ctr);
+
+ if (kind != "cat") {
+ setFeedValue(id, false, 'error', error);
+ setFeedValue(id, false, 'updated', updated);
+
+ if (id > 0) {
+ if (has_img) {
+ setFeedIcon(id, false,
+ getInitParam("icons_url") + "/" + id + ".ico");
+ } else {
+ setFeedIcon(id, false, 'images/blank_icon.gif');
+ }
+ }
+ }
+ }
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ } catch (e) {
+ exception_error("parse_counters", e);
+ }
+}
+
+function getFeedUnread(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedUnread(feed, is_cat);
+
+ } catch (e) {
+ //
+ }
+
+ return -1;
+}
+
+function hideOrShowFeeds(hide) {
+ var tree = dijit.byId("feedTree");
+
+ if (tree)
+ return tree.hideRead(hide, getInitParam("hide_read_shows_special"));
+}
+
+function getFeedName(feed, is_cat) {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedValue(feed, is_cat, 'name');
+}
+
+function getFeedValue(feed, is_cat, key) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedValue(feed, is_cat, key);
+
+ } catch (e) {
+ //
+ }
+ return '';
+}
+
+function setFeedUnread(feed, is_cat, unread) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.setFeedUnread(feed, is_cat, unread);
+
+ } catch (e) {
+ exception_error("setFeedUnread", e);
+ }
+}
+
+function setFeedValue(feed, is_cat, key, value) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.setFeedValue(feed, is_cat, key, value);
+
+ } catch (e) {
+ //
+ }
+}
+
+function selectFeed(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.selectFeed(feed, is_cat);
+
+ } catch (e) {
+ exception_error("selectFeed", e);
+ }
+}
+
+function setFeedIcon(feed, is_cat, src) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.setFeedIcon(feed, is_cat, src);
+
+ } catch (e) {
+ exception_error("setFeedIcon", e);
+ }
+}
+
+function setFeedExpandoIcon(feed, is_cat, src) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);
+
+ } catch (e) {
+ exception_error("setFeedIcon", e);
+ }
+ return false;
+}
+
+function getNextUnreadFeed(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+ var nuf = tree.model.getNextUnreadFeed(feed, is_cat);
+
+ if (nuf)
+ return tree.model.store.getValue(nuf, 'bare_id');
+
+ } catch (e) {
+ exception_error("getNextUnreadFeed", e);
+ }
+}
+
+function catchupFeed(feed, is_cat) {
+ try {
+ var str = __("Mark all articles in %s as read?");
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed + "&is_cat=" + is_cat;
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: catchup_query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ notify("");
+ } });
+
+ } catch (e) {
+ exception_error("catchupFeed", e);
+ }
+}
diff --git a/js/functions.js b/js/functions.js
new file mode 100644
index 000000000..02fbadf53
--- /dev/null
+++ b/js/functions.js
@@ -0,0 +1,1657 @@
+var notify_silent = false;
+var loading_progress = 0;
+var sanity_check_done = false;
+
+/* add method to remove element from array */
+
+Array.prototype.remove = function(s) {
+ for (var i=0; i < this.length; i++) {
+ if (s == this[i]) this.splice(i, 1);
+ }
+};
+
+/* create console.log if it doesn't exist */
+
+if (!window.console) console = {};
+console.log = console.log || function(msg) { };
+console.warn = console.warn || function(msg) { };
+console.error = console.error || function(msg) { };
+
+function exception_error(location, e, ext_info) {
+ var msg = format_exception_error(location, e);
+
+ if (!ext_info) ext_info = false;
+
+ try {
+
+ if (ext_info) {
+ if (ext_info.responseText) {
+ ext_info = ext_info.responseText;
+ }
+ }
+
+ var content = "<div class=\"fatalError\">" +
+ "<pre>" + msg + "</pre>";
+
+ content += "<form name=\"exceptionForm\" id=\"exceptionForm\" target=\"_blank\" "+
+ "action=\"http://tt-rss.org/report.php\" method=\"POST\">";
+
+ content += "<textarea style=\"display : none\" name=\"message\">" + msg + "</textarea>";
+ content += "<textarea style=\"display : none\" name=\"params\">N/A</textarea>";
+
+ if (ext_info) {
+ content += "<div><b>Additional information:</b></div>" +
+ "<textarea name=\"xinfo\" readonly=\"1\">" + ext_info + "</textarea>";
+ }
+
+ content += "<div><b>Stack trace:</b></div>" +
+ "<textarea name=\"stack\" readonly=\"1\">" + e.stack + "</textarea>";
+
+ content += "</form>";
+
+ content += "</div>";
+
+ content += "<div class='dlgButtons'>";
+
+ content += "<button dojoType=\"dijit.form.Button\""+
+ "onclick=\"dijit.byId('exceptionDlg').report()\">" +
+ __('Report to tt-rss.org') + "</button> ";
+ content += "<button dojoType=\"dijit.form.Button\" "+
+ "onclick=\"dijit.byId('exceptionDlg').hide()\">" +
+ __('Close') + "</button>";
+ content += "</div>";
+
+ if (dijit.byId("exceptionDlg"))
+ dijit.byId("exceptionDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "exceptionDlg",
+ title: "Unhandled exception",
+ style: "width: 600px",
+ report: function() {
+ if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database."))) {
+
+ document.forms['exceptionForm'].params.value = $H({
+ browserName: navigator.appName,
+ browserVersion: navigator.appVersion,
+ browserPlatform: navigator.platform,
+ browserCookies: navigator.cookieEnabled,
+ }).toQueryString();
+
+ document.forms['exceptionForm'].submit();
+
+ }
+ },
+ content: content});
+
+ dialog.show();
+
+ } catch (e) {
+ alert(msg);
+ }
+
+}
+
+function format_exception_error(location, e) {
+ var msg;
+
+ if (e.fileName) {
+ var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
+
+ msg = "Exception: " + e.name + ", " + e.message +
+ "\nFunction: " + location + "()" +
+ "\nLocation: " + base_fname + ":" + e.lineNumber;
+
+ } else if (e.description) {
+ msg = "Exception: " + e.description + "\nFunction: " + location + "()";
+ } else {
+ msg = "Exception: " + e + "\nFunction: " + location + "()";
+ }
+
+ console.error("EXCEPTION: " + msg);
+
+ return msg;
+}
+
+function param_escape(arg) {
+ if (typeof encodeURIComponent != 'undefined')
+ return encodeURIComponent(arg);
+ else
+ return escape(arg);
+}
+
+function param_unescape(arg) {
+ if (typeof decodeURIComponent != 'undefined')
+ return decodeURIComponent(arg);
+ else
+ return unescape(arg);
+}
+
+var notify_hide_timerid = false;
+
+function hide_notify() {
+ var n = $("notify");
+ if (n) {
+ n.style.display = "none";
+ }
+}
+
+function notify_silent_next() {
+ notify_silent = true;
+}
+
+function notify_real(msg, no_hide, n_type) {
+
+ if (notify_silent) {
+ notify_silent = false;
+ return;
+ }
+
+ var n = $("notify");
+ var nb = $("notify_body");
+
+ if (!n || !nb) return;
+
+ if (notify_hide_timerid) {
+ window.clearTimeout(notify_hide_timerid);
+ }
+
+ if (msg == "") {
+ if (n.style.display == "block") {
+ notify_hide_timerid = window.setTimeout("hide_notify()", 0);
+ }
+ return;
+ } else {
+ n.style.display = "block";
+ }
+
+ /* types:
+
+ 1 - generic
+ 2 - progress
+ 3 - error
+ 4 - info
+
+ */
+
+ if (typeof __ != 'undefined') {
+ msg = __(msg);
+ }
+
+ if (n_type == 1) {
+ n.className = "notify";
+ } else if (n_type == 2) {
+ n.className = "notifyProgress";
+ msg = "<img src='"+getInitParam("sign_progress")+"'> " + msg;
+ } else if (n_type == 3) {
+ n.className = "notifyError";
+ msg = "<img src='"+getInitParam("sign_excl")+"'> " + msg;
+ } else if (n_type == 4) {
+ n.className = "notifyInfo";
+ msg = "<img src='"+getInitParam("sign_info")+"'> " + msg;
+ }
+
+// msg = "<img src='images/live_com_loading.gif'> " + msg;
+
+ nb.innerHTML = msg;
+
+ if (!no_hide) {
+ notify_hide_timerid = window.setTimeout("hide_notify()", 3000);
+ }
+}
+
+function notify(msg, no_hide) {
+ notify_real(msg, no_hide, 1);
+}
+
+function notify_progress(msg, no_hide) {
+ notify_real(msg, no_hide, 2);
+}
+
+function notify_error(msg, no_hide) {
+ notify_real(msg, no_hide, 3);
+
+}
+
+function notify_info(msg, no_hide) {
+ notify_real(msg, no_hide, 4);
+}
+
+function setCookie(name, value, lifetime, path, domain, secure) {
+
+ var d = false;
+
+ if (lifetime) {
+ d = new Date();
+ d.setTime(d.getTime() + (lifetime * 1000));
+ }
+
+ console.log("setCookie: " + name + " => " + value + ": " + d);
+
+ int_setCookie(name, value, d, path, domain, secure);
+
+}
+
+function int_setCookie(name, value, expires, path, domain, secure) {
+ document.cookie= name + "=" + escape(value) +
+ ((expires) ? "; expires=" + expires.toGMTString() : "") +
+ ((path) ? "; path=" + path : "") +
+ ((domain) ? "; domain=" + domain : "") +
+ ((secure) ? "; secure" : "");
+}
+
+function delCookie(name, path, domain) {
+ if (getCookie(name)) {
+ document.cookie = name + "=" +
+ ((path) ? ";path=" + path : "") +
+ ((domain) ? ";domain=" + domain : "" ) +
+ ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
+ }
+}
+
+
+function getCookie(name) {
+
+ var dc = document.cookie;
+ var prefix = name + "=";
+ var begin = dc.indexOf("; " + prefix);
+ if (begin == -1) {
+ begin = dc.indexOf(prefix);
+ if (begin != 0) return null;
+ }
+ else {
+ begin += 2;
+ }
+ var end = document.cookie.indexOf(";", begin);
+ if (end == -1) {
+ end = dc.length;
+ }
+ return unescape(dc.substring(begin + prefix.length, end));
+}
+
+function gotoPreferences() {
+ document.location.href = "prefs.php";
+}
+
+function gotoMain() {
+ document.location.href = "index.php";
+}
+
+function gotoExportOpml(filename, settings) {
+ tmp = settings ? 1 : 0;
+ document.location.href = "opml.php?op=Export&filename=" + filename + "&settings=" + tmp;
+}
+
+
+/** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
+ * * @author Sundar Dorai-Raj
+ * * Email: [email protected]
+ * * This program is free software; you can redistribute it and/or
+ * * modify it under the terms of the GNU General Public License
+ * * as published by the Free Software Foundation; either version 2
+ * * of the License, or (at your option) any later version,
+ * * provided that any use properly credits the author.
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details at http://www.gnu.org * * */
+
+ var numbers=".0123456789";
+ function isNumeric(x) {
+ // is x a String or a character?
+ if(x.length>1) {
+ // remove negative sign
+ x=Math.abs(x)+"";
+ for(var j=0;j<x.length;j++) {
+ // call isNumeric recursively for each character
+ number=isNumeric(x.substring(j,j+1));
+ if(!number) return number;
+ }
+ return number;
+ }
+ else {
+ // if x is number return true
+ if(numbers.indexOf(x)>=0) return true;
+ return false;
+ }
+ }
+
+
+function toggleSelectRowById(sender, id) {
+ var row = $(id);
+ return toggleSelectRow(sender, row);
+}
+
+function toggleSelectListRow(sender) {
+ var row = sender.parentNode;
+ return toggleSelectRow(sender, row);
+}
+
+/* this is for dijit Checkbox */
+function toggleSelectListRow2(sender) {
+ var row = sender.domNode.parentNode;
+ return toggleSelectRow(sender, row);
+}
+
+function tSR(sender, row) {
+ return toggleSelectRow(sender, row);
+}
+
+/* this is for dijit Checkbox */
+function toggleSelectRow2(sender, row) {
+
+ if (!row) row = sender.domNode.parentNode.parentNode;
+
+ if (sender.checked && !row.hasClassName('Selected'))
+ row.addClassName('Selected');
+ else
+ row.removeClassName('Selected');
+}
+
+
+function toggleSelectRow(sender, row) {
+
+ if (!row) row = sender.parentNode.parentNode;
+
+ if (sender.checked && !row.hasClassName('Selected'))
+ row.addClassName('Selected');
+ else
+ row.removeClassName('Selected');
+}
+
+function checkboxToggleElement(elem, id) {
+ if (elem.checked) {
+ Effect.Appear(id, {duration : 0.5});
+ } else {
+ Effect.Fade(id, {duration : 0.5});
+ }
+}
+
+function dropboxSelect(e, v) {
+ for (var i = 0; i < e.length; i++) {
+ if (e[i].value == v) {
+ e.selectedIndex = i;
+ break;
+ }
+ }
+}
+
+function getURLParam(param){
+ return String(window.location.href).parseQuery()[param];
+}
+
+function leading_zero(p) {
+ var s = String(p);
+ if (s.length == 1) s = "0" + s;
+ return s;
+}
+
+function make_timestamp() {
+ var d = new Date();
+
+ return leading_zero(d.getHours()) + ":" + leading_zero(d.getMinutes()) +
+ ":" + leading_zero(d.getSeconds());
+}
+
+
+function closeInfoBox(cleanup) {
+ try {
+ dialog = dijit.byId("infoBox");
+
+ if (dialog) dialog.hide();
+
+ } catch (e) {
+ //exception_error("closeInfoBox", e);
+ }
+ return false;
+}
+
+
+function displayDlg(id, param, callback) {
+
+ notify_progress("Loading, please wait...", true);
+
+ var query = "?op=dlg&id=" +
+ param_escape(id) + "&param=" + param_escape(param);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function (transport) {
+ infobox_callback2(transport);
+ if (callback) callback(transport);
+ } });
+
+ return false;
+}
+
+function infobox_callback2(transport) {
+ try {
+ var dialog = false;
+
+ if (dijit.byId("infoBox")) {
+ dialog = dijit.byId("infoBox");
+ }
+
+ //console.log("infobox_callback2");
+ notify('');
+
+ var title = transport.responseXML.getElementsByTagName("title")[0];
+ if (title)
+ title = title.firstChild.nodeValue;
+
+ var content = transport.responseXML.getElementsByTagName("content")[0];
+
+ content = content.firstChild.nodeValue;
+
+ if (!dialog) {
+ dialog = new dijit.Dialog({
+ title: title,
+ id: 'infoBox',
+ style: "width: 600px",
+ onCancel: function() {
+ return true;
+ },
+ onExecute: function() {
+ return true;
+ },
+ onClose: function() {
+ return true;
+ },
+ content: content});
+ } else {
+ dialog.attr('title', title);
+ dialog.attr('content', content);
+ }
+
+ dialog.show();
+
+ notify("");
+ } catch (e) {
+ exception_error("infobox_callback2", e);
+ }
+}
+
+function filterCR(e, f)
+{
+ var key;
+
+ if(window.event)
+ key = window.event.keyCode; //IE
+ else
+ key = e.which; //firefox
+
+ if (key == 13) {
+ if (typeof f != 'undefined') {
+ f();
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+}
+
+function getInitParam(key) {
+ return init_params[key];
+}
+
+function setInitParam(key, value) {
+ init_params[key] = value;
+}
+
+function fatalError(code, msg, ext_info) {
+ try {
+
+ if (code == 6) {
+ window.location.href = "index.php";
+ } else if (code == 5) {
+ window.location.href = "db-updater.php";
+ } else {
+
+ if (msg == "") msg = "Unknown error";
+
+ if (ext_info) {
+ if (ext_info.responseText) {
+ ext_info = ext_info.responseText;
+ }
+ }
+
+ if (ERRORS && ERRORS[code] && !msg) {
+ msg = ERRORS[code];
+ }
+
+ var content = "<div><b>Error code:</b> " + code + "</div>" +
+ "<p>" + msg + "</p>";
+
+ if (ext_info) {
+ content = content + "<div><b>Additional information:</b></div>" +
+ "<textarea style='width: 100%' readonly=\"1\">" +
+ ext_info + "</textarea>";
+ }
+
+ var dialog = new dijit.Dialog({
+ title: "Fatal error",
+ style: "width: 600px",
+ content: content});
+
+ dialog.show();
+
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("fatalError", e);
+ }
+}
+
+function filterDlgCheckType(sender) {
+
+ try {
+
+ var ftype = sender.value;
+
+ // if selected filter type is 5 (Date) enable the modifier dropbox
+ if (ftype == 5) {
+ Element.show("filterDlg_dateModBox");
+ Element.show("filterDlg_dateChkBox");
+ } else {
+ Element.hide("filterDlg_dateModBox");
+ Element.hide("filterDlg_dateChkBox");
+
+ }
+
+ } catch (e) {
+ exception_error("filterDlgCheckType", e);
+ }
+
+}
+
+function filterDlgCheckAction(sender) {
+
+ try {
+
+ var action = sender.value;
+
+ var action_param = $("filterDlg_paramBox");
+
+ if (!action_param) {
+ console.log("filterDlgCheckAction: can't find action param box!");
+ return;
+ }
+
+ // if selected action supports parameters, enable params field
+ if (action == 4 || action == 6 || action == 7) {
+ new Effect.Appear(action_param, {duration : 0.5});
+ if (action != 7) {
+ Element.show(dijit.byId("filterDlg_actionParam").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
+ } else {
+ Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParam").domNode);
+ }
+ } else {
+ Element.hide(action_param);
+ }
+
+ } catch (e) {
+ exception_error("filterDlgCheckAction", e);
+ }
+
+}
+
+function filterDlgCheckDate() {
+ try {
+ var dialog = dijit.byId("filterEditDlg");
+
+ var reg_exp = dialog.attr('value').reg_exp;
+
+ var query = "?op=rpc&subop=checkDate&date=" + reg_exp;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply['result'] == true) {
+ alert(__("Date syntax appears to be correct:") + " " + reply['date']);
+ return;
+ } else {
+ alert(__("Date syntax is incorrect."));
+ }
+
+ } });
+
+
+ } catch (e) {
+ exception_error("filterDlgCheckDate", e);
+ }
+}
+
+function explainError(code) {
+ return displayDlg("explainError", code);
+}
+
+function displayHelpInfobox(topic_id) {
+
+ var url = "backend.php?op=help&tid=" + param_escape(topic_id);
+
+ window.open(url, "ttrss_help",
+ "status=0,toolbar=0,location=0,width=450,height=500,scrollbars=1,menubar=0");
+
+}
+
+function loading_set_progress(p) {
+ try {
+ loading_progress += p;
+
+ if (dijit.byId("loading_bar"))
+ dijit.byId("loading_bar").update({progress: loading_progress});
+
+ if (loading_progress >= 90)
+ remove_splash();
+
+ } catch (e) {
+ exception_error("loading_set_progress", e);
+ }
+}
+
+function remove_splash() {
+
+ if (Element.visible("overlay")) {
+ console.log("about to remove splash, OMG!");
+ Element.hide("overlay");
+ console.log("removed splash!");
+ }
+}
+
+function transport_error_check(transport) {
+ try {
+ if (transport.responseXML) {
+ var error = transport.responseXML.getElementsByTagName("error")[0];
+
+ if (error) {
+ var code = error.getAttribute("error-code");
+ var msg = error.getAttribute("error-msg");
+ if (code != 0) {
+ fatalError(code, msg);
+ return false;
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("check_for_error_xml", e);
+ }
+ return true;
+}
+
+function strip_tags(s) {
+ return s.replace(/<\/?[^>]+(>|$)/g, "");
+}
+
+function truncate_string(s, length) {
+ if (!length) length = 30;
+ var tmp = s.substring(0, length);
+ if (s.length > length) tmp += "&hellip;";
+ return tmp;
+}
+
+function hotkey_prefix_timeout() {
+ try {
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ if (hotkey_prefix_pressed && ts - hotkey_prefix_pressed >= 5) {
+ console.log("hotkey_prefix seems to be stuck, aborting");
+ hotkey_prefix_pressed = false;
+ hotkey_prefix = false;
+ Element.hide('cmdline');
+ }
+
+ setTimeout("hotkey_prefix_timeout()", 1000);
+
+ } catch (e) {
+ exception_error("hotkey_prefix_timeout", e);
+ }
+}
+
+function hideAuxDlg() {
+ try {
+ Element.hide('auxDlg');
+ } catch (e) {
+ exception_error("hideAuxDlg", e);
+ }
+}
+
+
+function uploadIconHandler(rc) {
+ try {
+ switch (rc) {
+ case 0:
+ notify_info("Upload complete.");
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ setTimeout('updateFeedList(false, false)', 50);
+ }
+ break;
+ case 1:
+ notify_error("Upload failed: icon is too big.");
+ break;
+ case 2:
+ notify_error("Upload failed.");
+ break;
+ }
+
+ } catch (e) {
+ exception_error("uploadIconHandler", e);
+ }
+}
+
+function removeFeedIcon(id) {
+
+ try {
+
+ if (confirm(__("Remove stored feed icon?"))) {
+ var query = "backend.php?op=pref-feeds&subop=removeicon&feed_id=" + param_escape(id);
+
+ console.log(query);
+
+ notify_progress("Removing feed icon...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Feed icon removed.");
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ setTimeout('updateFeedList(false, false)', 50);
+ }
+ } });
+ }
+
+ return false;
+ } catch (e) {
+ exception_error("uploadFeedIcon", e);
+ }
+}
+
+function uploadFeedIcon() {
+
+ try {
+
+ var file = $("icon_file");
+
+ if (file.value.length == 0) {
+ alert(__("Please select an image file to upload."));
+ } else {
+ if (confirm(__("Upload new icon for this feed?"))) {
+ notify_progress("Uploading, please wait...", true);
+ return true;
+ }
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("uploadFeedIcon", e);
+ }
+}
+
+function addLabel(select, callback) {
+
+ try {
+
+ var caption = prompt(__("Please enter label caption:"), "");
+
+ if (caption != undefined) {
+
+ if (caption == "") {
+ alert(__("Can't create label: missing caption."));
+ return false;
+ }
+
+ var query = "?op=pref-labels&subop=add&caption=" +
+ param_escape(caption);
+
+ if (select)
+ query += "&output=select";
+
+ notify_progress("Loading, please wait...", true);
+
+ if (inPreferences() && !select) active_tab = "labelConfig";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) {
+ callback(transport);
+ } else if (inPreferences()) {
+ updateLabelList();
+ } else {
+ updateFeedList();
+ }
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("addLabel", e);
+ }
+}
+
+function quickAddFeed() {
+ try {
+ var query = "backend.php?op=dlg&id=quickAddFeed";
+
+ if (dijit.byId("feedAddDlg"))
+ dijit.byId("feedAddDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "feedAddDlg",
+ title: __("Subscribe to Feed"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ console.log(dojo.objectToQuery(this.attr('value')));
+
+ var feed_url = this.attr('value').feed;
+
+ notify_progress(__("Subscribing to feed..."), true);
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ try {
+
+ var reply = JSON.parse(transport.responseText);
+
+ var rc = parseInt(reply['result']);
+
+ notify('');
+
+ console.log("GOT RC: " + rc);
+
+ switch (rc) {
+ case 1:
+ dialog.hide();
+ notify_info(__("Subscribed to %s").replace("%s", feed_url));
+
+ updateFeedList();
+ break;
+ case 2:
+ alert(__("Specified URL seems to be invalid."));
+ break;
+ case 3:
+ alert(__("Specified URL doesn't seem to contain any feeds."));
+ break;
+ case 4:
+ notify_progress("Searching for feed urls...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: 'op=rpc&subop=extractfeedurls&url=' + param_escape(feed_url),
+ onComplete: function(transport, dialog, feed_url) {
+
+ notify('');
+
+ var reply = JSON.parse(transport.responseText);
+
+ var feeds = reply['urls'];
+
+ console.log(transport.responseText);
+
+ var select = dijit.byId("feedDlg_feedContainerSelect");
+
+ while (select.getOptions().length > 0)
+ select.removeOption(0);
+
+ var count = 0;
+ for (var feedUrl in feeds) {
+ select.addOption({value: feedUrl, label: feeds[feedUrl]});
+ count++;
+ }
+
+// if (count > 5) count = 5;
+// select.size = count;
+
+ Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
+ }
+ });
+ break;
+ case 5:
+ alert(__("Couldn't download the specified URL."));
+ break;
+ case 0:
+ alert(__("You are already subscribed to this feed."));
+ break;
+ }
+
+ } catch (e) {
+ exception_error("subscribeToFeed", e, transport);
+ }
+
+ } });
+
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("quickAddFeed", e);
+ }
+}
+
+function quickAddFilter() {
+ try {
+ var query = "backend.php?op=dlg&id=quickAddFilter";
+
+ if (dijit.byId("filterEditDlg"))
+ dijit.byId("filterEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "filterEditDlg",
+ title: __("Create Filter"),
+ style: "width: 600px",
+ test: function() {
+ if (this.validate()) {
+
+ if (dijit.byId("filterTestDlg"))
+ dijit.byId("filterTestDlg").destroyRecursive();
+
+ tdialog = new dijit.Dialog({
+ id: "filterTestDlg",
+ title: __("Filter Test Results"),
+ style: "width: 600px",
+ href: "backend.php?savemode=test&" +
+ dojo.objectToQuery(dialog.attr('value')),
+ });
+
+ tdialog.show();
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+
+ var query = "?op=rpc&subop=verifyRegexp&reg_exp=" +
+ param_escape(dialog.attr('value').reg_exp);
+
+ notify_progress("Verifying regular expression...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ notify('');
+
+ if (!reply['status']) {
+ alert("Match regular expression seems to be invalid.");
+ return;
+ } else {
+ notify_progress("Saving data...", true);
+
+ console.log(dojo.objectToQuery(dialog.attr('value')));
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify_info(transport.responseText);
+ if (inPreferences()) {
+ updateFilterList();
+ }
+ }});
+ }
+ }
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("quickAddFilter", e);
+ }
+}
+
+function resetPubSub(feed_id, title) {
+
+ var msg = __("Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update.").replace("%s", title);
+
+ if (title == undefined || confirm(msg)) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=resetPubSub&ids=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dijit.byId("pubsubReset_Btn").attr('disabled', true);
+ notify_info("Subscription reset.");
+ } });
+ }
+
+ return false;
+}
+
+
+function unsubscribeFeed(feed_id, title) {
+
+ var msg = __("Unsubscribe from %s?").replace("%s", title);
+
+ if (title == undefined || confirm(msg)) {
+ notify_progress("Removing feed...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=remove&ids=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ if (dijit.byId("feedEditDlg")) dijit.byId("feedEditDlg").hide();
+
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ if (feed_id == getActiveFeedId())
+ setTimeout("viewfeed(-5)", 100);
+ }
+
+ } });
+ }
+
+ return false;
+}
+
+
+function backend_sanity_check_callback(transport) {
+
+ try {
+
+ if (sanity_check_done) {
+ fatalError(11, "Sanity check request received twice. This can indicate "+
+ "presence of Firebug or some other disrupting extension. "+
+ "Please disable it and try again.");
+ return;
+ }
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (!reply) {
+ fatalError(3, "Sanity check: invalid RPC reply", transport.responseText);
+ return;
+ }
+
+ var error_code = reply['error']['code'];
+
+ if (error_code && error_code != 0) {
+ return fatalError(error_code, reply['error']['message']);
+ }
+
+ console.log("sanity check ok");
+
+ var params = reply['init-params'];
+
+ if (params) {
+ console.log('reading init-params...');
+
+ if (params) {
+ for (k in params) {
+ var v = params[k];
+ console.log("IP: " + k + " => " + v);
+ }
+ }
+
+ init_params = params;
+ }
+
+ sanity_check_done = true;
+
+ init_second_stage();
+
+ } catch (e) {
+ exception_error("backend_sanity_check_callback", e, transport);
+ }
+}
+
+/*function has_local_storage() {
+ try {
+ return 'sessionStorage' in window && window['sessionStorage'] != null;
+ } catch (e) {
+ return false;
+ }
+} */
+
+function catSelectOnChange(elem) {
+ try {
+/* var value = elem[elem.selectedIndex].value;
+ var def = elem.getAttribute('default');
+
+ if (value == "ADD_CAT") {
+
+ if (def)
+ dropboxSelect(elem, def);
+ else
+ elem.selectedIndex = 0;
+
+ quickAddCat(elem);
+ } */
+
+ } catch (e) {
+ exception_error("catSelectOnChange", e);
+ }
+}
+
+function quickAddCat(elem) {
+ try {
+ var cat = prompt(__("Please enter category title:"));
+
+ if (cat) {
+
+ var query = "?op=rpc&subop=quickAddCat&cat=" + param_escape(cat);
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function (transport) {
+ var response = transport.responseXML;
+ var select = response.getElementsByTagName("select")[0];
+ var options = select.getElementsByTagName("option");
+
+ dropbox_replace_options(elem, options);
+
+ notify('');
+
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("quickAddCat", e);
+ }
+}
+
+function genUrlChangeKey(feed, is_cat) {
+
+ try {
+ var ok = confirm(__("Generate new syndication address for this feed?"));
+
+ if (ok) {
+
+ notify_progress("Trying to change address...", true);
+
+ var query = "?op=rpc&subop=regenFeedKey&id=" + param_escape(feed) +
+ "&is_cat=" + param_escape(is_cat);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ var new_link = reply.link;
+
+ var e = $('gen_feed_url');
+
+ if (new_link) {
+
+ e.innerHTML = e.innerHTML.replace(/\&amp;key=.*$/,
+ "&amp;key=" + new_link);
+
+ e.href = e.href.replace(/\&key=.*$/,
+ "&key=" + new_link);
+
+ new Effect.Highlight(e);
+
+ notify('');
+
+ } else {
+ notify_error("Could not change feed URL.");
+ }
+ } });
+ }
+ } catch (e) {
+ exception_error("genUrlChangeKey", e);
+ }
+ return false;
+}
+
+function labelSelectOnChange(elem) {
+ try {
+/* var value = elem[elem.selectedIndex].value;
+ var def = elem.getAttribute('default');
+
+ if (value == "ADD_LABEL") {
+
+ if (def)
+ dropboxSelect(elem, def);
+ else
+ elem.selectedIndex = 0;
+
+ addLabel(elem, function(transport) {
+
+ try {
+
+ var response = transport.responseXML;
+ var select = response.getElementsByTagName("select")[0];
+ var options = select.getElementsByTagName("option");
+
+ dropbox_replace_options(elem, options);
+
+ notify('');
+ } catch (e) {
+ exception_error("addLabel", e);
+ }
+ });
+ } */
+
+ } catch (e) {
+ exception_error("labelSelectOnChange", e);
+ }
+}
+
+function dropbox_replace_options(elem, options) {
+
+ try {
+ while (elem.hasChildNodes())
+ elem.removeChild(elem.firstChild);
+
+ var sel_idx = -1;
+
+ for (var i = 0; i < options.length; i++) {
+ var text = options[i].firstChild.nodeValue;
+ var value = options[i].getAttribute("value");
+
+ if (value == undefined) value = text;
+
+ var issel = options[i].getAttribute("selected") == "1";
+
+ var option = new Option(text, value, issel);
+
+ if (options[i].getAttribute("disabled"))
+ option.setAttribute("disabled", true);
+
+ elem.insert(option);
+
+ if (issel) sel_idx = i;
+ }
+
+ // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
+ if (sel_idx >= 0) elem.selectedIndex = sel_idx;
+
+ } catch (e) {
+ exception_error("dropbox_replace_options", e);
+ }
+}
+
+// mode = all, none, invert
+function selectTableRows(id, mode) {
+ try {
+ var rows = $(id).rows;
+
+ for (var i = 0; i < rows.length; i++) {
+ var row = rows[i];
+ var cb = false;
+
+ if (row.id && row.className) {
+ var bare_id = row.id.replace(/^[A-Z]*?-/, "");
+ var inputs = rows[i].getElementsByTagName("input");
+
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+
+ if (input.getAttribute("type") == "checkbox" &&
+ input.id.match(bare_id)) {
+
+ cb = input;
+ break;
+ }
+ }
+
+ if (cb) {
+ var issel = row.hasClassName("Selected");
+
+ if (mode == "all" && !issel) {
+ row.addClassName("Selected");
+ cb.checked = true;
+ } else if (mode == "none" && issel) {
+ row.removeClassName("Selected");
+ cb.checked = false;
+ } else if (mode == "invert") {
+
+ if (issel) {
+ row.removeClassName("Selected");
+ cb.checked = false;
+ } else {
+ row.addClassName("Selected");
+ cb.checked = true;
+ }
+ }
+ }
+ }
+ }
+
+ } catch (e) {
+ exception_error("selectTableRows", e);
+
+ }
+}
+
+function getSelectedTableRowIds(id) {
+ var rows = [];
+
+ try {
+ var elem_rows = $(id).rows;
+
+ for (var i = 0; i < elem_rows.length; i++) {
+ if (elem_rows[i].hasClassName("Selected")) {
+ var bare_id = elem_rows[i].id.replace(/^[A-Z]*?-/, "");
+ rows.push(bare_id);
+ }
+ }
+
+ } catch (e) {
+ exception_error("getSelectedTableRowIds", e);
+ }
+
+ return rows;
+}
+
+function editFeed(feed, event) {
+ try {
+ if (feed <= 0)
+ return alert(__("You can't edit this kind of feed."));
+
+ var query = "backend.php?op=pref-feeds&subop=editfeed&id=" +
+ param_escape(feed);
+
+ console.log(query);
+
+ if (dijit.byId("feedEditDlg"))
+ dijit.byId("feedEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "feedEditDlg",
+ title: __("Edit Feed"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+// console.log(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress("Saving data...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateFeedList();
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeed", e);
+ }
+}
+
+function feedBrowser() {
+ try {
+ var query = "backend.php?op=dlg&id=feedBrowser";
+
+ if (dijit.byId("feedAddDlg"))
+ dijit.byId("feedAddDlg").hide();
+
+ if (dijit.byId("feedBrowserDlg"))
+ dijit.byId("feedBrowserDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "feedBrowserDlg",
+ title: __("More Feeds"),
+ style: "width: 600px",
+ getSelectedFeedIds: function() {
+ var list = $$("#browseFeedList li[id*=FBROW]");
+ var selected = new Array();
+
+ list.each(function(child) {
+ var id = child.id.replace("FBROW-", "");
+
+ if (child.hasClassName('Selected')) {
+ selected.push(id);
+ }
+ });
+
+ return selected;
+ },
+ getSelectedFeeds: function() {
+ var list = $$("#browseFeedList li.Selected");
+ var selected = new Array();
+
+ list.each(function(child) {
+ var title = child.getElementsBySelector("span.fb_feedTitle")[0].innerHTML;
+ var url = child.getElementsBySelector("a.fb_feedUrl")[0].href;
+
+ selected.push([title,url]);
+
+ });
+
+ return selected;
+ },
+
+ subscribe: function() {
+ var mode = this.attr('value').mode;
+ var selected = [];
+
+ if (mode == "1")
+ selected = this.getSelectedFeeds();
+ else
+ selected = this.getSelectedFeedIds();
+
+ if (selected.length > 0) {
+ dijit.byId("feedBrowserDlg").hide();
+
+ notify_progress("Loading, please wait...", true);
+
+ // we use dojo.toJson instead of JSON.stringify because
+ // it somehow escapes everything TWICE, at least in Chrome 9
+
+ var query = "?op=rpc&subop=massSubscribe&payload="+
+ param_escape(dojo.toJson(selected)) + "&mode=" + param_escape(mode);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ updateFeedList();
+ } });
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ },
+ update: function() {
+ var query = dojo.objectToQuery(dialog.attr('value'));
+
+ Element.show('feed_browser_spinner');
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+
+ Element.hide('feed_browser_spinner');
+
+ var c = $("browseFeedList");
+
+ var reply = JSON.parse(transport.responseText);
+
+ var r = reply['content'];
+ var mode = reply['mode'];
+
+ if (c && r) {
+ c.innerHTML = r;
+ }
+
+ dojo.parser.parse("browseFeedList");
+
+ if (mode == 2) {
+ Element.show(dijit.byId('feed_archive_remove').domNode);
+ } else {
+ Element.hide(dijit.byId('feed_archive_remove').domNode);
+ }
+
+ } });
+ },
+ removeFromArchive: function() {
+ var selected = this.getSelectedFeeds();
+
+ if (selected.length > 0) {
+
+ var pr = __("Remove selected feeds from the archive? Feeds with stored articles will not be removed.");
+
+ if (confirm(pr)) {
+ Element.show('feed_browser_spinner');
+
+ var query = "?op=rpc&subop=remarchived&ids=" +
+ param_escape(selected.toString());;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dialog.update();
+ } });
+ }
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ this.subscribe();
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeed", e);
+ }
+}
+
+function showFeedsWithErrors() {
+ try {
+ var query = "backend.php?op=dlg&id=feedsWithErrors";
+
+ if (dijit.byId("errorFeedsDlg"))
+ dijit.byId("errorFeedsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "errorFeedsDlg",
+ title: __("Feeds with update errors"),
+ style: "width: 600px",
+ getSelectedFeeds: function() {
+ return getSelectedTableRowIds("prefErrorFeedList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedFeeds();
+
+ console.log(sel_rows);
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected feeds?"));
+
+ if (ok) {
+ notify_progress("Removing selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("showFeedsWithErrors", e);
+ }
+
+}
+
+/* new support functions for SelectByTag */
+
+function get_all_tags(selObj){
+ try {
+ if( !selObj ) return "";
+
+ var result = "";
+ var len = selObj.options.length;
+
+ for (var i=0; i < len; i++){
+ if (selObj.options[i].selected) {
+ result += selObj[i].value + "%2C"; // is really a comma
+ }
+ }
+
+ if (result.length > 0){
+ result = result.substr(0, result.length-3); // remove trailing %2C
+ }
+
+ return(result);
+
+ } catch (e) {
+ exception_error("get_all_tags", e);
+ }
+}
+
+function get_radio_checked(radioObj) {
+ try {
+ if (!radioObj) return "";
+
+ var len = radioObj.length;
+
+ if (len == undefined){
+ if(radioObj.checked){
+ return(radioObj.value);
+ } else {
+ return("");
+ }
+ }
+
+ for( var i=0; i < len; i++ ){
+ if( radioObj[i].checked ){
+ return( radioObj[i].value);
+ }
+ }
+
+ } catch (e) {
+ exception_error("get_radio_checked", e);
+ }
+ return("");
+}
diff --git a/js/prefs.js b/js/prefs.js
new file mode 100644
index 000000000..e40d6d723
--- /dev/null
+++ b/js/prefs.js
@@ -0,0 +1,1967 @@
+var init_params = new Array();
+
+var hotkey_prefix = false;
+var hotkey_prefix_pressed = false;
+
+var seq = "";
+
+function instancelist_callback2(transport) {
+ try {
+ dijit.byId('instanceConfigTab').attr('content', transport.responseText);
+ selectTab("instanceConfig", true);
+ notify("");
+ } catch (e) {
+ exception_error("instancelist_callback2", e);
+ }
+}
+
+function feedlist_callback2(transport) {
+ try {
+ dijit.byId('feedConfigTab').attr('content', transport.responseText);
+ selectTab("feedConfig", true);
+ notify("");
+ } catch (e) {
+ exception_error("feedlist_callback2", e);
+ }
+}
+
+function filterlist_callback2(transport) {
+ dijit.byId('filterConfigTab').attr('content', transport.responseText);
+ notify("");
+}
+
+function labellist_callback2(transport) {
+ try {
+ dijit.byId('labelConfigTab').attr('content', transport.responseText);
+ notify("");
+ } catch (e) {
+ exception_error("labellist_callback2", e);
+ }
+}
+
+function userlist_callback2(transport) {
+ try {
+ dijit.byId('userConfigTab').attr('content', transport.responseText);
+
+ notify("");
+ } catch (e) {
+ exception_error("userlist_callback2", e);
+ }
+}
+
+function prefslist_callback2(transport) {
+ try {
+ dijit.byId('genConfigTab').attr('content', transport.responseText);
+
+ notify("");
+ } catch (e) {
+ exception_error("prefslist_callback2", e);
+ }
+}
+
+function notify_callback2(transport) {
+ notify_info(transport.responseText);
+}
+
+function updateFeedList(sort_key) {
+
+ var user_search = $("feed_search");
+ var search = "";
+ if (user_search) { search = user_search.value; }
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&search=" + param_escape(search),
+ onComplete: function(transport) {
+ feedlist_callback2(transport);
+ } });
+}
+
+function updateInstanceList(sort_key) {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-instances&sort=" + param_escape(sort_key),
+ onComplete: function(transport) {
+ instancelist_callback2(transport);
+ } });
+}
+
+function updateUsersList(sort_key) {
+
+ try {
+
+ var user_search = $("user_search");
+ var search = "";
+ if (user_search) { search = user_search.value; }
+
+ var query = "?op=pref-users&sort="
+ + param_escape(sort_key) +
+ "&search=" + param_escape(search);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("updateUsersList", e);
+ }
+}
+
+function addUser() {
+
+ try {
+
+ var login = prompt(__("Please enter login:"), "");
+
+ if (login == null) {
+ return false;
+ }
+
+ if (login == "") {
+ alert(__("Can't create user: no login specified."));
+ return false;
+ }
+
+ notify_progress("Adding user...");
+
+ var query = "?op=pref-users&subop=add&login=" +
+ param_escape(login);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("addUser", e);
+ }
+}
+
+function editUser(id, event) {
+
+ try {
+ if (!event || !event.ctrlKey) {
+
+ notify_progress("Loading, please wait...");
+
+ selectTableRows('prefUserList', 'none');
+ selectTableRowById('UMRR-'+id, 'UMCHK-'+id, true);
+
+ var query = "?op=pref-users&subop=edit&id=" +
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ infobox_callback2(transport);
+ document.forms['user_edit_form'].login.focus();
+ } });
+
+ } else if (event.ctrlKey) {
+ var cb = $('UMCHK-' + id);
+ cb.checked = !cb.checked;
+ toggleSelectRow(cb);
+ }
+
+ } catch (e) {
+ exception_error("editUser", e);
+ }
+
+}
+
+function editFilter(id) {
+ try {
+
+ var query = "backend.php?op=pref-filters&subop=edit&id=" + param_escape(id);
+
+ if (dijit.byId("filterEditDlg"))
+ dijit.byId("filterEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "filterEditDlg",
+ title: __("Edit Filter"),
+ style: "width: 600px",
+ removeFilter: function() {
+ var title = this.attr('value').reg_exp;
+ var msg = __("Remove filter %s?").replace("%s", title);
+
+ if (confirm(msg)) {
+ this.hide();
+
+ notify_progress("Removing filter...");
+
+ var id = this.attr('value').id;
+
+ var query = "?op=pref-filters&subop=remove&ids="+
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ },
+ test: function() {
+ if (this.validate()) {
+
+ if (dijit.byId("filterTestDlg"))
+ dijit.byId("filterTestDlg").destroyRecursive();
+
+ tdialog = new dijit.Dialog({
+ id: "filterTestDlg",
+ title: __("Filter Test Results"),
+ style: "width: 600px",
+ href: "backend.php?savemode=test&" +
+ dojo.objectToQuery(dialog.attr('value')),
+ });
+
+ tdialog.show();
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+
+ var query = "?op=rpc&subop=verifyRegexp&reg_exp=" +
+ param_escape(dialog.attr('value').reg_exp);
+
+ notify_progress("Verifying regular expression...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ notify('');
+
+ if (!reply['status']) {
+ alert("Match regular expression seems to be invalid.");
+ return;
+ } else {
+ notify_progress("Saving data...", true);
+
+ console.log(dojo.objectToQuery(dialog.attr('value')));
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ updateFilterList();
+ }});
+ }
+ }
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+
+ } catch (e) {
+ exception_error("editFilter", e);
+ }
+}
+
+function getSelectedLabels() {
+ var tree = dijit.byId("labelTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+}
+
+function getSelectedUsers() {
+ return getSelectedTableRowIds("prefUserList");
+}
+
+function getSelectedFeeds() {
+ var tree = dijit.byId("feedTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ if (item.id[0].match("FEED:"))
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+}
+
+function getSelectedFilters() {
+ var tree = dijit.byId("filterTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+
+}
+
+/* function getSelectedFeedCats() {
+ return getSelectedTableRowIds("prefFeedCatList");
+} */
+
+function removeSelectedLabels() {
+
+ var sel_rows = getSelectedLabels();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected labels?"));
+
+ if (ok) {
+ notify_progress("Removing selected labels...");
+
+ var query = "?op=pref-labels&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+
+ }
+ } else {
+ alert(__("No labels are selected."));
+ }
+
+ return false;
+}
+
+function removeSelectedUsers() {
+
+ try {
+
+ var sel_rows = getSelectedUsers();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
+
+ if (ok) {
+ notify_progress("Removing selected users...");
+
+ var query = "?op=pref-users&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ }
+
+ } else {
+ alert(__("No users are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedUsers", e);
+ }
+
+ return false;
+}
+
+function removeSelectedFilters() {
+
+ try {
+
+ var sel_rows = getSelectedFilters();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected filters?"));
+
+ if (ok) {
+ notify_progress("Removing selected filters...");
+
+ var query = "?op=pref-filters&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ } else {
+ alert(__("No filters are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedFilters", e);
+ }
+
+ return false;
+}
+
+
+function removeSelectedFeeds() {
+
+ try {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Unsubscribe from selected feeds?"));
+
+ if (ok) {
+
+ notify_progress("Unsubscribing from selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedFeeds", e);
+ }
+
+ return false;
+}
+
+function clearSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 1) {
+ alert(__("Please select only one feed."));
+ return;
+ }
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Erase all non-starred articles in selected feed?"));
+
+ if (ok) {
+ notify_progress("Clearing selected feed...");
+ clearFeedArticles(sel_rows[0]);
+ }
+
+ } else {
+
+ alert(__("No feeds are selected."));
+
+ }
+
+ return false;
+}
+
+function purgeSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ var pr = prompt(__("How many days of articles to keep (0 - use default)?"), "0");
+
+ if (pr != undefined) {
+ notify_progress("Purging selected feed...");
+
+ var query = "?op=rpc&subop=purge&ids="+
+ param_escape(sel_rows.toString()) + "&days=" + pr;
+
+ console.log(query);
+
+ new Ajax.Request("prefs.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ } });
+ }
+
+ } else {
+
+ alert(__("No feeds are selected."));
+
+ }
+
+ return false;
+}
+
+function userEditCancel() {
+ closeInfoBox();
+ return false;
+}
+
+function userEditSave() {
+
+ try {
+
+ var login = document.forms["user_edit_form"].login.value;
+
+ if (login.length == 0) {
+ alert(__("Login field cannot be blank."));
+ return;
+ }
+
+ notify_progress("Saving user...");
+
+ closeInfoBox();
+
+ var query = Form.serialize("user_edit_form");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("userEditSave", e);
+ }
+
+ return false;
+
+}
+
+
+function editSelectedUser() {
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ notify("");
+
+ editUser(rows[0]);
+}
+
+function resetSelectedUserPass() {
+
+ try {
+
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ var ok = confirm(__("Reset password of selected user?"));
+
+ if (ok) {
+ notify_progress("Resetting password for selected user...");
+
+ var id = rows[0];
+
+ var query = "?op=pref-users&subop=resetPass&id=" +
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("resetSelectedUserPass", e);
+ }
+}
+
+function selectedUserDetails() {
+
+ try {
+
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ notify_progress("Loading, please wait...");
+
+ var id = rows[0];
+
+ var query = "?op=pref-users&subop=user-details&id=" + id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ infobox_callback2(transport);
+ } });
+ } catch (e) {
+ exception_error("selectedUserDetails", e);
+ }
+}
+
+
+function editSelectedFilter() {
+ var rows = getSelectedFilters();
+
+ if (rows.length == 0) {
+ alert(__("No filters are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one filter."));
+ return;
+ }
+
+ notify("");
+
+ editFilter(rows[0]);
+
+}
+
+
+function editSelectedFeed() {
+ var rows = getSelectedFeeds();
+
+ if (rows.length == 0) {
+ alert(__("No feeds are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ return editSelectedFeeds();
+ }
+
+ notify("");
+
+ editFeed(rows[0], {});
+
+}
+
+function editSelectedFeeds() {
+
+ try {
+ var rows = getSelectedFeeds();
+
+ if (rows.length == 0) {
+ alert(__("No feeds are selected."));
+ return;
+ }
+
+ notify_progress("Loading, please wait...");
+
+ var query = "backend.php?op=pref-feeds&subop=editfeeds&ids=" +
+ param_escape(rows.toString());
+
+ console.log(query);
+
+ if (dijit.byId("feedEditDlg"))
+ dijit.byId("feedEditDlg").destroyRecursive();
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ notify("");
+
+ var dialog = new dijit.Dialog({
+ id: "feedEditDlg",
+ title: __("Edit Multiple Feeds"),
+ style: "width: 600px",
+ getChildByName: function (name) {
+ var rv = null;
+ this.getChildren().each(
+ function(child) {
+ if (child.name == name) {
+ rv = child;
+ return;
+ }
+ });
+ return rv;
+ },
+ toggleField: function (checkbox, elem, label) {
+ this.getChildByName(elem).attr('disabled', !checkbox.checked);
+
+ if ($(label))
+ if (checkbox.checked)
+ $(label).removeClassName('insensitive');
+ else
+ $(label).addClassName('insensitive');
+
+ },
+ execute: function() {
+ if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ /* Form.serialize ignores unchecked checkboxes */
+
+ if (!query.match("&rtl_content=") &&
+ this.getChildByName('rtl_content').attr('disabled') == false) {
+ query = query + "&rtl_content=false";
+ }
+
+ if (!query.match("&private=") &&
+ this.getChildByName('private').attr('disabled') == false) {
+ query = query + "&private=false";
+ }
+
+ try {
+ if (!query.match("&cache_images=") &&
+ this.getChildByName('cache_images').attr('disabled') == false) {
+ query = query + "&cache_images=false";
+ }
+ } catch (e) { }
+
+ if (!query.match("&include_in_digest=") &&
+ this.getChildByName('include_in_digest').attr('disabled') == false) {
+ query = query + "&include_in_digest=false";
+ }
+
+ if (!query.match("&always_display_enclosures=") &&
+ this.getChildByName('always_display_enclosures').attr('disabled') == false) {
+ query = query + "&always_display_enclosures=false";
+ }
+
+ if (!query.match("&mark_unread_on_update=") &&
+ this.getChildByName('mark_unread_on_update').attr('disabled') == false) {
+ query = query + "&mark_unread_on_update=false";
+ }
+
+ if (!query.match("&update_on_checksum_change=") &&
+ this.getChildByName('update_on_checksum_change').attr('disabled') == false) {
+ query = query + "&update_on_checksum_change=false";
+ }
+
+ console.log(query);
+
+ notify_progress("Saving data...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dialog.hide();
+ updateFeedList();
+ }});
+ }
+ },
+ content: transport.responseText});
+
+ dialog.show();
+
+ } });
+
+ } catch (e) {
+ exception_error("editSelectedFeeds", e);
+ }
+}
+
+function piggie(enable) {
+ if (enable) {
+ console.log("I LOVEDED IT!");
+ var piggie = $("piggie");
+
+ Element.show(piggie);
+ Position.Center(piggie);
+ Effect.Puff(piggie);
+
+ }
+}
+
+function opmlImportComplete(iframe) {
+ try {
+ if (!iframe.contentDocument.body.innerHTML) return false;
+
+ notify('');
+
+ if (dijit.byId('opmlImportDlg'))
+ dijit.byId('opmlImportDlg').destroyRecursive();
+
+ var content = iframe.contentDocument.body.innerHTML;
+
+ dialog = new dijit.Dialog({
+ id: "opmlImportDlg",
+ title: __("OPML Import"),
+ style: "width: 600px",
+ onCancel: function() {
+ updateFeedList();
+ },
+ content: content});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("opmlImportComplete", e);
+ }
+}
+
+function opmlImport() {
+
+ var opml_file = $("opml_file");
+
+ if (opml_file.value.length == 0) {
+ alert(__("Please choose an OPML file first."));
+ return false;
+ } else {
+ notify_progress("Importing, please wait...", true);
+ return true;
+ }
+}
+
+function updateFilterList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-filters",
+ onComplete: function(transport) {
+ filterlist_callback2(transport);
+ } });
+}
+
+function updateLabelList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-labels",
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+}
+
+function updatePrefsList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-prefs",
+ onComplete: function(transport) {
+ prefslist_callback2(transport);
+ } });
+}
+
+function selectTab(id, noupdate, subop) {
+ try {
+ if (!noupdate) {
+ notify_progress("Loading, please wait...");
+
+ if (id == "feedConfig") {
+ updateFeedList();
+ } else if (id == "filterConfig") {
+ updateFilterList();
+ } else if (id == "labelConfig") {
+ updateLabelList();
+ } else if (id == "genConfig") {
+ updatePrefsList();
+ } else if (id == "userConfig") {
+ updateUsersList();
+ }
+
+ var tab = dijit.byId(id + "Tab");
+ dijit.byId("pref-tabs").selectChild(tab);
+
+ }
+
+ } catch (e) {
+ exception_error("selectTab", e);
+ }
+}
+
+function init_second_stage() {
+ try {
+
+ document.onkeydown = pref_hotkey_handler;
+ loading_set_progress(50);
+ notify("");
+
+ dojo.addOnLoad(function() {
+ var tab = getURLParam('tab');
+
+ if (tab) {
+ tab = dijit.byId(tab + "Tab");
+ if (tab) dijit.byId("pref-tabs").selectChild(tab);
+ }
+
+ var subop = getURLParam('subop');
+
+ if (subop == 'editFeed') {
+ var param = getURLParam('subopparam');
+
+ window.setTimeout('editFeed(' + param + ')', 100);
+ }
+ });
+
+ setTimeout("hotkey_prefix_timeout()", 5*1000);
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function init() {
+
+ try {
+ dojo.registerModulePath("lib", "..");
+ dojo.registerModulePath("fox", "../../js/");
+
+ dojo.require("lib.CheckBoxTree");
+ dojo.require("fox.PrefFeedTree");
+ dojo.require("fox.PrefFilterTree");
+ dojo.require("fox.PrefLabelTree");
+
+ dojo.parser.parse();
+
+ dojo.addOnLoad(function() {
+ loading_set_progress(50);
+
+ new Ajax.Request("backend.php", {
+ parameters: {op: "rpc", subop: "sanityCheck"},
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+ });
+
+ } catch (e) {
+ exception_error("init", e);
+ }
+}
+
+function validatePrefsReset() {
+ try {
+ var ok = confirm(__("Reset to defaults?"));
+
+ if (ok) {
+
+ query = "?op=pref-prefs&subop=reset-config";
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var msg = transport.responseText;
+ if (msg.match("PREFS_THEME_CHANGED")) {
+ window.location.reload();
+ } else {
+ notify_info(msg);
+ selectTab();
+ }
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("validatePrefsReset", e);
+ }
+
+ return false;
+
+}
+
+
+function pref_hotkey_handler(e) {
+ try {
+ if (e.target.nodeName == "INPUT") return;
+
+ var keycode = false;
+ var shift_key = false;
+
+ var cmdline = $('cmdline');
+
+ try {
+ shift_key = e.shiftKey;
+ } catch (e) {
+
+ }
+
+ if (window.event) {
+ keycode = window.event.keyCode;
+ } else if (e) {
+ keycode = e.which;
+ }
+
+ var keychar = String.fromCharCode(keycode);
+
+ if (keycode == 27) { // escape
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+ hotkey_prefix = false;
+ closeInfoBox();
+ }
+
+ if (keycode == 16) return; // ignore lone shift
+ if (keycode == 17) return; // ignore lone ctrl
+
+ if ((keycode == 67 || keycode == 71) && !hotkey_prefix) {
+ hotkey_prefix = keycode;
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ hotkey_prefix_pressed = ts;
+
+ cmdline.innerHTML = keychar;
+ Element.show(cmdline);
+
+ console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar);
+ return;
+ }
+
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+
+ if (keycode == 13 || keycode == 27) {
+ seq = "";
+ } else {
+ seq = seq + "" + keycode;
+ }
+
+ /* Global hotkeys */
+
+ Element.hide(cmdline);
+
+ if (!hotkey_prefix) {
+
+ if ((keycode == 191 || keychar == '?') && shift_key) { // ?
+ if (!Element.visible("hotkey_help_overlay")) {
+ //Element.show("hotkey_help_overlay");
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3, to: 0.9});
+ } else {
+ Element.hide("hotkey_help_overlay");
+ }
+ return false;
+ }
+
+ if (keycode == 191 || keychar == '/') { // /
+ var search_boxes = new Array("label_search",
+ "feed_search", "filter_search", "user_search", "feed_browser_search");
+
+ for (var i = 0; i < search_boxes.length; i++) {
+ var elem = $(search_boxes[i]);
+ if (elem) {
+ $(search_boxes[i]).focus();
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Prefix c */
+
+ if (hotkey_prefix == 67) { // c
+ hotkey_prefix = false;
+
+ if (keycode == 70) { // f
+ quickAddFilter();
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ quickAddFeed();
+ return false;
+ }
+
+ if (keycode == 85) { // u
+ // no-op
+ }
+
+ if (keycode == 67) { // c
+ editFeedCats();
+ return false;
+ }
+
+ if (keycode == 84 && shift_key) { // T
+ feedBrowser();
+ return false;
+ }
+
+ }
+
+ /* Prefix g */
+
+ if (hotkey_prefix == 71) { // g
+
+ hotkey_prefix = false;
+
+ if (keycode == 49 && $("genConfigTab")) { // 1
+ selectTab("genConfig");
+ return false;
+ }
+
+ if (keycode == 50 && $("feedConfigTab")) { // 2
+ selectTab("feedConfig");
+ return false;
+ }
+
+ if (keycode == 51 && $("filterConfigTab")) { // 4
+ selectTab("filterConfig");
+ return false;
+ }
+
+ if (keycode == 52 && $("labelConfigTab")) { // 5
+ selectTab("labelConfig");
+ return false;
+ }
+
+ if (keycode == 53 && $("userConfigTab")) { // 6
+ selectTab("userConfig");
+ return false;
+ }
+
+ if (keycode == 88) { // x
+ return gotoMain();
+ }
+
+ }
+
+ if ($("piggie")) {
+ if (seq.match("8073717369")) {
+ seq = "";
+ piggie(true);
+ } else {
+ piggie(false);
+ }
+ }
+
+ if (hotkey_prefix) {
+ console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
+ } else {
+ console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
+ }
+
+ } catch (e) {
+ exception_error("pref_hotkey_handler", e);
+ }
+}
+
+function editFeedCats() {
+ try {
+ var query = "backend.php?op=pref-feeds&subop=editCats";
+
+ if (dijit.byId("feedCatEditDlg"))
+ dijit.byId("feedCatEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "feedCatEditDlg",
+ title: __("Feed Categories"),
+ style: "width: 600px",
+ getSelectedCategories: function() {
+ return getSelectedTableRowIds("prefFeedCatList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedCategories();
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected categories?"));
+
+ if (ok) {
+ notify_progress("Removing selected categories...", true);
+
+ var query = "?op=pref-feeds&subop=editCats&action=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.attr('content', transport.responseText);
+ updateFeedList();
+ } });
+
+ }
+
+ } else {
+ alert(__("No categories are selected."));
+ }
+ },
+ addCategory: function() {
+ if (this.validate()) {
+ notify_progress("Creating category...");
+
+ var query = "?op=pref-feeds&subop=editCats&action=add&cat=" +
+ param_escape(this.attr('value').newcat);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.attr('content', transport.responseText);
+ updateFeedList();
+ } });
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeedCats", e);
+ }
+}
+
+function showInactiveFeeds() {
+ try {
+ var query = "backend.php?op=dlg&id=inactiveFeeds";
+
+ if (dijit.byId("inactiveFeedsDlg"))
+ dijit.byId("inactiveFeedsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "inactiveFeedsDlg",
+ title: __("Feeds without recent updates"),
+ style: "width: 600px",
+ getSelectedFeeds: function() {
+ return getSelectedTableRowIds("prefInactiveFeedList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedFeeds();
+
+ console.log(sel_rows);
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected feeds?"));
+
+ if (ok) {
+ notify_progress("Removing selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("showInactiveFeeds", e);
+ }
+
+}
+
+function opmlRegenKey() {
+
+ try {
+ var ok = confirm(__("Replace current OPML publishing address with a new one?"));
+
+ if (ok) {
+
+ notify_progress("Trying to change address...", true);
+
+ var query = "?op=rpc&subop=regenOPMLKey";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ var new_link = reply.link;
+
+ var e = $('pub_opml_url');
+
+ if (new_link) {
+ e.href = new_link;
+ e.innerHTML = new_link;
+
+ new Effect.Highlight(e);
+
+ notify('');
+
+ } else {
+ notify_error("Could not change feed URL.");
+ }
+ } });
+ }
+ } catch (e) {
+ exception_error("opmlRegenKey", e);
+ }
+ return false;
+}
+
+function feedActionChange() {
+ try {
+ var chooser = $("feedActionChooser");
+ var opid = chooser[chooser.selectedIndex].value;
+
+ chooser.selectedIndex = 0;
+ feedActionGo(opid);
+ } catch (e) {
+ exception_error("feedActionChange", e);
+ }
+}
+
+function feedActionGo(op) {
+ try {
+ if (op == "facEdit") {
+
+ var rows = getSelectedFeeds();
+
+ if (rows.length > 1) {
+ editSelectedFeeds();
+ } else {
+ editSelectedFeed();
+ }
+ }
+
+ if (op == "facClear") {
+ clearSelectedFeeds();
+ }
+
+ if (op == "facPurge") {
+ purgeSelectedFeeds();
+ }
+
+ if (op == "facEditCats") {
+ editFeedCats();
+ }
+
+ if (op == "facRescore") {
+ rescoreSelectedFeeds();
+ }
+
+ if (op == "facUnsubscribe") {
+ removeSelectedFeeds();
+ }
+
+ } catch (e) {
+ exception_error("feedActionGo", e);
+
+ }
+}
+
+function clearFeedArticles(feed_id) {
+
+ notify_progress("Clearing feed...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=clear&id=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ } });
+
+ return false;
+}
+
+function rescoreSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
+ var ok = confirm(__("Rescore articles in selected feeds?"));
+
+ if (ok) {
+ notify_progress("Rescoring selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=rescore&quiet=1&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_callback2(transport);
+ } });
+
+ }
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ return false;
+}
+
+function rescore_all_feeds() {
+ var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
+
+ if (ok) {
+ notify_progress("Rescoring feeds...", true);
+
+ var query = "?op=pref-feeds&subop=rescoreAll&quiet=1";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_callback2(transport);
+ } });
+ }
+}
+
+function labelColorReset() {
+ try {
+ var labels = getSelectedLabels();
+
+ if (labels.length > 0) {
+ var ok = confirm(__("Reset selected labels to default colors?"));
+
+ if (ok) {
+ var query = "?op=pref-labels&subop=color-reset&ids="+
+ param_escape(labels.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+ }
+
+ } else {
+ alert(__("No labels are selected."));
+ }
+
+ } catch (e) {
+ exception_error("labelColorReset", e);
+ }
+}
+
+
+function inPreferences() {
+ return true;
+}
+
+function editProfiles() {
+ try {
+
+ if (dijit.byId("profileEditDlg"))
+ dijit.byId("profileEditDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=editPrefProfiles";
+
+ dialog = new dijit.Dialog({
+ id: "profileEditDlg",
+ title: __("Settings Profiles"),
+ style: "width: 600px",
+ getSelectedProfiles: function() {
+ return getSelectedTableRowIds("prefFeedProfileList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedProfiles();
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
+
+ if (ok) {
+ notify_progress("Removing selected profiles...", true);
+
+ var query = "?op=rpc&subop=remprofiles&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ editProfiles();
+ } });
+
+ }
+
+ } else {
+ alert(__("No profiles are selected."));
+ }
+ },
+ activateProfile: function() {
+ var sel_rows = this.getSelectedProfiles();
+
+ if (sel_rows.length == 1) {
+
+ var ok = confirm(__("Activate selected profile?"));
+
+ if (ok) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=rpc&subop=setprofile&id="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ window.location.reload();
+ } });
+ }
+
+ } else {
+ alert(__("Please choose a profile to activate."));
+ }
+ },
+ addProfile: function() {
+ if (this.validate()) {
+ notify_progress("Creating profile...", true);
+
+ var query = "?op=rpc&subop=addprofile&title=" +
+ param_escape(dialog.attr('value').newprofile);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ editProfiles();
+ } });
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("editProfiles", e);
+ }
+}
+
+function activatePrefProfile() {
+
+ var sel_rows = getSelectedFeedCats();
+
+ if (sel_rows.length == 1) {
+
+ var ok = confirm(__("Activate selected profile?"));
+
+ if (ok) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=rpc&subop=setprofile&id="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ window.location.reload();
+ } });
+ }
+
+ } else {
+ alert(__("Please choose a profile to activate."));
+ }
+
+ return false;
+}
+
+function clearFeedAccessKeys() {
+
+ var ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing URLs...");
+
+ var query = "?op=rpc&subop=clearKeys";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Generated URLs cleared.");
+ } });
+ }
+
+ return false;
+}
+
+function clearArticleAccessKeys() {
+
+ var ok = confirm(__("This will invalidate all previously shared article URLs. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing URLs...");
+
+ var query = "?op=rpc&subop=clearArticleKeys";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Shared URLs cleared.");
+ } });
+ }
+
+ return false;
+}
+function resetFeedOrder() {
+ try {
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&subop=feedsortreset",
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+
+
+ } catch (e) {
+ exception_error("resetFeedOrder");
+ }
+}
+
+function resetCatOrder() {
+ try {
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&subop=catsortreset",
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+
+
+ } catch (e) {
+ exception_error("resetCatOrder");
+ }
+}
+
+function editCat(id, item, event) {
+ try {
+ var new_name = prompt(__('Rename category to:'), item.name);
+
+ if (new_name && new_name != item.name) {
+
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: {
+ op: 'pref-feeds',
+ subop: 'renamecat',
+ id: id,
+ title: new_name,
+ },
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("editCat", e);
+ }
+}
+
+function editLabel(id, event) {
+ try {
+ var query = "backend.php?op=pref-labels&subop=edit&id=" +
+ param_escape(id);
+
+ if (dijit.byId("labelEditDlg"))
+ dijit.byId("labelEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "labelEditDlg",
+ title: __("Label Editor"),
+ style: "width: 600px",
+ setLabelColor: function(id, fg, bg) {
+
+ var kind = '';
+ var color = '';
+
+ if (fg && bg) {
+ kind = 'both';
+ } else if (fg) {
+ kind = 'fg';
+ color = fg;
+ } else if (bg) {
+ kind = 'bg';
+ color = bg;
+ }
+
+ var query = "?op=pref-labels&subop=color-set&kind="+kind+
+ "&ids=" + param_escape(id) + "&fg=" + param_escape(fg) +
+ "&bg=" + param_escape(bg) + "&color=" + param_escape(color);
+
+ // console.log(query);
+
+ var e = $("LICID-" + id);
+
+ if (e) {
+ if (fg) e.style.color = fg;
+ if (bg) e.style.backgroundColor = bg;
+ }
+
+ new Ajax.Request("backend.php", { parameters: query });
+
+ updateFilterList();
+ },
+ execute: function() {
+ if (this.validate()) {
+ var caption = this.attr('value').caption;
+ var fg_color = this.attr('value').fg_color;
+ var bg_color = this.attr('value').bg_color;
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ dijit.byId('labelTree').setNameById(id, caption);
+ this.setLabelColor(id, fg_color, bg_color);
+ this.hide();
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editLabel", e);
+ }
+}
+
+function clearTwitterCredentials() {
+ try {
+ var ok = confirm(__("This will clear your stored authentication information for Twitter. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing credentials...");
+
+ var query = "?op=pref-feeds&subop=remtwitterinfo";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Twitter credentials have been cleared.");
+ updateFeedList();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("clearTwitterCredentials", e);
+ }
+}
+
+function customizeCSS() {
+ try {
+ var query = "backend.php?op=dlg&id=customizeCSS";
+
+ if (dijit.byId("cssEditDlg"))
+ dijit.byId("cssEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "cssEditDlg",
+ title: __("Customize stylesheet"),
+ style: "width: 600px",
+ execute: function() {
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ notify('');
+ window.location.reload();
+ } });
+
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("customizeCSS", e);
+ }
+}
+
+function insertSSLserial(value) {
+ try {
+ dijit.byId("SSL_CERT_SERIAL").attr('value', value);
+ } catch (e) {
+ exception_error("insertSSLcerial", e);
+ }
+}
+
+function getSelectedInstances() {
+ return getSelectedTableRowIds("prefInstanceList");
+}
+
+function addInstance() {
+ try {
+ var query = "backend.php?op=dlg&id=addInstance";
+
+ if (dijit.byId("instanceAddDlg"))
+ dijit.byId("instanceAddDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "instanceAddDlg",
+ title: __("Link Instance"),
+ style: "width: 600px",
+ regenKey: function() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=genHash",
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ if (reply)
+ dijit.byId('instance_add_key').attr('value', reply.hash);
+
+ } });
+ },
+ execute: function() {
+ if (this.validate()) {
+ console.warn(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateInstanceList();
+ } });
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("addInstance", e);
+ }
+}
+
+function editInstance(id, event) {
+ try {
+ if (!event || !event.ctrlKey) {
+
+ selectTableRows('prefInstanceList', 'none');
+ selectTableRowById('LIRR-'+id, 'LICHK-'+id, true);
+
+ var query = "backend.php?op=pref-instances&subop=edit&id=" +
+ param_escape(id);
+
+ if (dijit.byId("instanceEditDlg"))
+ dijit.byId("instanceEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "instanceEditDlg",
+ title: __("Edit Instance"),
+ style: "width: 600px",
+ regenKey: function() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=genHash",
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ if (reply)
+ dijit.byId('instance_edit_key').attr('value', reply.hash);
+
+ } });
+ },
+ execute: function() {
+ if (this.validate()) {
+// console.warn(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateInstanceList();
+ } });
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } else if (event.ctrlKey) {
+ var cb = $('LICHK-' + id);
+ cb.checked = !cb.checked;
+ toggleSelectRow(cb);
+ }
+
+
+ } catch (e) {
+ exception_error("editInstance", e);
+ }
+}
+
+function removeSelectedInstances() {
+ try {
+ var sel_rows = getSelectedInstances();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected instances?"));
+
+ if (ok) {
+ notify_progress("Removing selected instances...");
+
+ var query = "?op=pref-instances&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ updateInstanceList();
+ } });
+ }
+
+ } else {
+ alert(__("No instances are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeInstance", e);
+ }
+}
+
+function editSelectedInstance() {
+ var rows = getSelectedInstances();
+
+ if (rows.length == 0) {
+ alert(__("No instances are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one instance."));
+ return;
+ }
+
+ notify("");
+
+ editInstance(rows[0]);
+}
+
diff --git a/js/tt-rss.js b/js/tt-rss.js
new file mode 100644
index 000000000..589091959
--- /dev/null
+++ b/js/tt-rss.js
@@ -0,0 +1,1164 @@
+var total_unread = 0;
+var global_unread = -1;
+var firsttime_update = true;
+var _active_feed_id = 0;
+var _active_feed_is_cat = false;
+var hotkey_prefix = false;
+var hotkey_prefix_pressed = false;
+var init_params = {};
+var _force_scheduled_update = false;
+var last_scheduled_update = false;
+
+var _rpc_seq = 0;
+
+function next_seq() {
+ _rpc_seq += 1;
+ return _rpc_seq;
+}
+
+function get_seq() {
+ return _rpc_seq;
+}
+
+function activeFeedIsCat() {
+ return _active_feed_is_cat;
+}
+
+function getActiveFeedId() {
+ try {
+ //console.log("gAFID: " + _active_feed_id);
+ return _active_feed_id;
+ } catch (e) {
+ exception_error("getActiveFeedId", e);
+ }
+}
+
+function setActiveFeedId(id, is_cat) {
+ try {
+ _active_feed_id = id;
+
+ if (is_cat != undefined) {
+ _active_feed_is_cat = is_cat;
+ }
+
+ selectFeed(id, is_cat);
+
+ } catch (e) {
+ exception_error("setActiveFeedId", e);
+ }
+}
+
+
+function updateFeedList() {
+ try {
+
+// $("feeds-holder").innerHTML = "<div id=\"feedlistLoading\">" +
+// __("Loading, please wait...") + "</div>";
+
+ Element.show("feedlistLoading");
+
+ if (dijit.byId("feedTree")) {
+ dijit.byId("feedTree").destroyRecursive();
+ }
+
+ var store = new dojo.data.ItemFileWriteStore({
+ url: "backend.php?op=feeds"});
+
+ var treeModel = new fox.FeedStoreModel({
+ store: store,
+ query: {
+ "type": "feed"
+ },
+ rootId: "root",
+ rootLabel: "Feeds",
+ childrenAttrs: ["items"]
+ });
+
+ var tree = new fox.FeedTree({
+ persist: false,
+ model: treeModel,
+ onOpen: function (item, node) {
+ var id = String(item.id);
+ var cat_id = id.substr(id.indexOf(":")+1);
+
+ new Ajax.Request("backend.php",
+ { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
+ param_escape(cat_id) + "&mode=0" } );
+ },
+ onClose: function (item, node) {
+ var id = String(item.id);
+ var cat_id = id.substr(id.indexOf(":")+1);
+
+ new Ajax.Request("backend.php",
+ { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
+ param_escape(cat_id) + "&mode=1" } );
+
+ },
+ onClick: function (item, node) {
+ var id = String(item.id);
+ var is_cat = id.match("^CAT:");
+ var feed = id.substr(id.indexOf(":")+1);
+ viewfeed(feed, '', is_cat);
+ return false;
+ },
+ openOnClick: false,
+ showRoot: false,
+ id: "feedTree",
+ }, "feedTree");
+
+/* var menu = new dijit.Menu({id: 'feedMenu'});
+
+ menu.addChild(new dijit.MenuItem({
+ label: "Simple menu item"
+ }));
+
+// menu.bindDomNode(tree.domNode); */
+
+ var tmph = dojo.connect(dijit.byId('feedMenu'), '_openMyself', function (event) {
+ console.log(dijit.getEnclosingWidget(event.target));
+ dojo.disconnect(tmph);
+ });
+
+ $("feeds-holder").appendChild(tree.domNode);
+
+ var tmph = dojo.connect(tree, 'onLoad', function() {
+ dojo.disconnect(tmph);
+ Element.hide("feedlistLoading");
+
+ tree.collapseHiddenCats();
+
+ feedlist_init();
+
+// var node = dijit.byId("feedTree")._itemNodesMap['FEED:-2'][0].domNode
+// menu.bindDomNode(node);
+
+ loading_set_progress(25);
+ });
+
+ tree.startup();
+
+ } catch (e) {
+ exception_error("updateFeedList", e);
+ }
+}
+
+function catchupAllFeeds() {
+
+ var str = __("Mark all articles as read?");
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+
+ var query_str = "backend.php?op=feeds&subop=catchupAll";
+
+ notify_progress("Marking all feeds as read...");
+
+ //console.log("catchupAllFeeds Q=" + query_str);
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ feedlist_callback2(transport);
+ } });
+
+ global_unread = 0;
+ updateTitle("");
+ }
+}
+
+function viewCurrentFeed(subop) {
+
+ if (getActiveFeedId() != undefined) {
+ viewfeed(getActiveFeedId(), subop, activeFeedIsCat());
+ }
+ return false; // block unneeded form submits
+}
+
+function timeout() {
+ if (getInitParam("bw_limit") == "1") return;
+
+ try {
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ if (ts - last_scheduled_update > 10 || _force_scheduled_update) {
+
+ //console.log("timeout()");
+
+ window.clearTimeout(counter_timeout_id);
+
+ var query_str = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
+
+ var omode;
+
+ if (firsttime_update && !navigator.userAgent.match("Opera")) {
+ firsttime_update = false;
+ omode = "T";
+ } else {
+ omode = "flc";
+ }
+
+ query_str = query_str + "&omode=" + omode;
+
+ if (!_force_scheduled_update)
+ query_str = query_str + "&last_article_id=" + getInitParam("last_article_id");
+
+ //console.log("[timeout]" + query_str);
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ handle_rpc_json(transport, !_force_scheduled_update);
+ _force_scheduled_update = false;
+ } });
+
+ last_scheduled_update = ts;
+ }
+
+ } catch (e) {
+ exception_error("timeout", e);
+ }
+
+ setTimeout("timeout()", 3000);
+}
+
+function search() {
+ var query = "backend.php?op=dlg&id=search&param=" +
+ param_escape(getActiveFeedId() + ":" + activeFeedIsCat());
+
+ if (dijit.byId("searchDlg"))
+ dijit.byId("searchDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "searchDlg",
+ title: __("Search"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ _search_query = dojo.objectToQuery(this.attr('value'));
+ this.hide();
+ viewCurrentFeed();
+ }
+ },
+ href: query});
+
+ dialog.show();
+}
+
+function updateTitle() {
+ var tmp = "Tiny Tiny RSS";
+
+ if (global_unread > 0) {
+ tmp = tmp + " (" + global_unread + ")";
+ }
+
+ if (window.fluid) {
+ if (global_unread > 0) {
+ window.fluid.dockBadge = global_unread;
+ } else {
+ window.fluid.dockBadge = "";
+ }
+ }
+
+ document.title = tmp;
+}
+
+function genericSanityCheck() {
+ setCookie("ttrss_test", "TEST");
+
+ if (getCookie("ttrss_test") != "TEST") {
+ return fatalError(2);
+ }
+
+ return true;
+}
+
+function init() {
+ try {
+ dojo.registerModulePath("fox", "../../js/");
+
+ dojo.require("fox.FeedTree");
+
+ if (typeof themeBeforeLayout == 'function') {
+ themeBeforeLayout();
+ }
+
+ dojo.parser.parse();
+
+ dojo.addOnLoad(function() {
+ updateFeedList();
+ closeArticlePanel();
+
+ if (typeof themeAfterLayout == 'function') {
+ themeAfterLayout();
+ }
+
+ });
+
+ if (!genericSanityCheck())
+ return false;
+
+ loading_set_progress(20);
+
+ var hasAudio = !!((myAudioTag = document.createElement('audio')).canPlayType);
+
+ new Ajax.Request("backend.php", {
+ parameters: {op: "rpc", subop: "sanityCheck", hasAudio: hasAudio},
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("init", e);
+ }
+}
+
+function init_second_stage() {
+
+ try {
+
+ delCookie("ttrss_test");
+
+ var toolbar = document.forms["main_toolbar_form"];
+
+ dijit.getEnclosingWidget(toolbar.view_mode).attr('value',
+ getInitParam("default_view_mode"));
+
+ dijit.getEnclosingWidget(toolbar.order_by).attr('value',
+ getInitParam("default_view_order_by"));
+
+ feeds_sort_by_unread = getInitParam("feeds_sort_by_unread") == 1;
+
+ loading_set_progress(30);
+
+ // can't use cache_clear() here because viewfeed might not have initialized yet
+ if ('sessionStorage' in window && window['sessionStorage'] !== null)
+ sessionStorage.clear();
+
+ console.log("second stage ok");
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function quickMenuGo(opid) {
+ try {
+ if (opid == "qmcPrefs") {
+ gotoPreferences();
+ }
+
+ if (opid == "qmcTagCloud") {
+ displayDlg("printTagCloud");
+ }
+
+ if (opid == "qmcTagSelect") {
+ displayDlg("printTagSelect");
+ }
+
+ if (opid == "qmcSearch") {
+ search();
+ return;
+ }
+
+ if (opid == "qmcAddFeed") {
+ quickAddFeed();
+ return;
+ }
+
+ if (opid == "qmcDigest") {
+ window.location.href = "digest.php";
+ return;
+ }
+
+ if (opid == "qmcEditFeed") {
+ if (activeFeedIsCat())
+ alert(__("You can't edit this kind of feed."));
+ else
+ editFeed(getActiveFeedId());
+ return;
+ }
+
+ if (opid == "qmcRemoveFeed") {
+ var actid = getActiveFeedId();
+
+ if (activeFeedIsCat()) {
+ alert(__("You can't unsubscribe from the category."));
+ return;
+ }
+
+ if (!actid) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var fn = getFeedName(actid);
+
+ var pr = __("Unsubscribe from %s?").replace("%s", fn);
+
+ if (confirm(pr)) {
+ unsubscribeFeed(actid);
+ }
+
+ return;
+ }
+
+ if (opid == "qmcCatchupAll") {
+ catchupAllFeeds();
+ return;
+ }
+
+ if (opid == "qmcShowOnlyUnread") {
+ toggleDispRead();
+ return;
+ }
+
+ if (opid == "qmcAddFilter") {
+ quickAddFilter();
+ return;
+ }
+
+ if (opid == "qmcAddLabel") {
+ addLabel();
+ return;
+ }
+
+ if (opid == "qmcRescoreFeed") {
+ rescoreCurrentFeed();
+ return;
+ }
+
+ if (opid == "qmcHKhelp") {
+ //Element.show("hotkey_help_overlay");
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3});
+ }
+
+ if (opid == "qmcAbout") {
+ dialog = new dijit.Dialog({
+ title: __("About..."),
+ style: "width: 400px",
+ href: "backend.php?op=dlg&id=about",
+ });
+
+ dialog.show();
+ }
+
+ } catch (e) {
+ exception_error("quickMenuGo", e);
+ }
+}
+
+function toggleDispRead() {
+ try {
+
+ var hide = !(getInitParam("hide_read_feeds") == "1");
+
+ hideOrShowFeeds(hide);
+
+ var query = "?op=rpc&subop=setpref&key=HIDE_READ_FEEDS&value=" +
+ param_escape(hide);
+
+ setInitParam("hide_read_feeds", hide);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ } });
+
+ } catch (e) {
+ exception_error("toggleDispRead", e);
+ }
+}
+
+function parse_runtime_info(data) {
+
+ //console.log("parsing runtime info...");
+
+ for (k in data) {
+ var v = data[k];
+
+// console.log("RI: " + k + " => " + v);
+
+ if (k == "new_version_available") {
+ var icon = $("newVersionIcon");
+ if (icon) {
+ if (v == "1") {
+ icon.style.display = "inline";
+ } else {
+ icon.style.display = "none";
+ }
+ }
+ return;
+ }
+
+ if (k == "daemon_is_running" && v != 1) {
+ notify_error("<span onclick=\"javascript:explainError(1)\">Update daemon is not running.</span>", true);
+ return;
+ }
+
+ if (k == "daemon_stamp_ok" && v != 1) {
+ notify_error("<span onclick=\"javascript: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.");
+ updateFeedList();
+ }
+ }
+
+ init_params[k] = v;
+ notify('');
+ }
+}
+
+function catchupCurrentFeed() {
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark all articles in %s as read?").replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+ return viewCurrentFeed('MarkAllRead');
+ }
+}
+
+function catchupFeedInGroup(id) {
+
+ try {
+
+ var title = getFeedName(id);
+
+ var str = __("Mark all articles in %s as read?").replace("%s", title);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+ return viewCurrentFeed('MarkAllReadGR:' + id);
+ }
+
+ } catch (e) {
+ exception_error("catchupFeedInGroup", e);
+ }
+}
+
+function collapse_feedlist() {
+ try {
+
+ if (!Element.visible('feeds-holder')) {
+ Element.show('feeds-holder');
+ Element.show('feeds-holder_splitter');
+ $("collapse_feeds_btn").innerHTML = "&lt;&lt;";
+ } else {
+ Element.hide('feeds-holder');
+ Element.hide('feeds-holder_splitter');
+ $("collapse_feeds_btn").innerHTML = "&gt;&gt;";
+ }
+
+ dijit.byId("main").resize();
+
+ query = "?op=rpc&subop=setpref&key=_COLLAPSED_FEEDLIST&value=true";
+ new Ajax.Request("backend.php", { parameters: query });
+
+ } catch (e) {
+ exception_error("collapse_feedlist", e);
+ }
+}
+
+function viewModeChanged() {
+ return viewCurrentFeed('');
+}
+
+function viewLimitChanged() {
+ return viewCurrentFeed('');
+}
+
+/* function adjustArticleScore(id, score) {
+ try {
+
+ var pr = prompt(__("Assign score to article:"), score);
+
+ if (pr != undefined) {
+ var query = "?op=rpc&subop=setScore&id=" + id + "&score=" + pr;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+
+ }
+ } catch (e) {
+ exception_error("adjustArticleScore", e);
+ }
+} */
+
+function rescoreCurrentFeed() {
+
+ var actid = getActiveFeedId();
+
+ if (activeFeedIsCat() || actid < 0) {
+ alert(__("You can't rescore this kind of feed."));
+ return;
+ }
+
+ if (!actid) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var fn = getFeedName(actid);
+ var pr = __("Rescore articles in %s?").replace("%s", fn);
+
+ if (confirm(pr)) {
+ notify_progress("Rescoring articles...");
+
+ var query = "?op=pref-feeds&subop=rescore&quiet=1&ids=" + actid;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+ }
+}
+
+function hotkey_handler(e) {
+ try {
+
+ if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") return;
+
+ var keycode = false;
+ var shift_key = false;
+
+ var cmdline = $('cmdline');
+
+ try {
+ shift_key = e.shiftKey;
+ } catch (e) {
+
+ }
+
+ if (window.event) {
+ keycode = window.event.keyCode;
+ } else if (e) {
+ keycode = e.which;
+ }
+
+ var keychar = String.fromCharCode(keycode);
+
+ if (keycode == 27) { // escape
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+ hotkey_prefix = false;
+ }
+
+ if (keycode == 16) return; // ignore lone shift
+ if (keycode == 17) return; // ignore lone ctrl
+
+ if ((keycode == 70 || keycode == 67 || keycode == 71 || keycode == 65)
+ && !hotkey_prefix) {
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ hotkey_prefix = keycode;
+ hotkey_prefix_pressed = ts;
+
+ cmdline.innerHTML = keychar;
+ Element.show(cmdline);
+
+ console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar + " TS=" + ts);
+ return true;
+ }
+
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+
+ /* Global hotkeys */
+
+ Element.hide(cmdline);
+
+ if (!hotkey_prefix) {
+
+ if (keycode == 27) { // escape
+ closeArticlePanel();
+ return;
+ }
+
+ if (keycode == 69) { // e
+ var id = getActiveArticleId();
+ emailArticle(id);
+ }
+
+ if ((keycode == 191 || keychar == '?') && shift_key) { // ?
+ if (!Element.visible("hotkey_help_overlay")) {
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3, to : 0.9});
+ } else {
+ Element.hide("hotkey_help_overlay");
+ }
+ return false;
+ }
+
+ if (keycode == 191 || keychar == '/') { // /
+ search();
+ return false;
+ }
+
+ if (keycode == 74 && !shift_key) { // j
+ var rv = dijit.byId("feedTree").getPreviousFeed(
+ getActiveFeedId(), activeFeedIsCat());
+
+ if (rv) viewfeed(rv[0], '', rv[1]);
+
+ return;
+ }
+
+ if (keycode == 75) { // k
+ var rv = dijit.byId("feedTree").getNextFeed(
+ getActiveFeedId(), activeFeedIsCat());
+
+ if (rv) viewfeed(rv[0], '', rv[1]);
+
+ return;
+ }
+
+ if (shift_key && keycode == 40) { // shift-down
+ catchupRelativeToArticle(1);
+ return;
+ }
+
+ if (shift_key && keycode == 38) { // shift-up
+ catchupRelativeToArticle(0);
+ return;
+ }
+
+ if (shift_key && keycode == 78) { // N
+ scrollArticle(50);
+ return;
+ }
+
+ if (shift_key && keycode == 80) { // P
+ scrollArticle(-50);
+ return;
+ }
+
+ if (keycode == 68 && shift_key) { // shift-D
+ dismissSelectedArticles();
+ return;
+ }
+
+ if (keycode == 88 && shift_key) { // shift-X
+ dismissReadArticles();
+ return;
+ }
+
+ if (keycode == 78 || keycode == 40) { // n, down
+ if (typeof moveToPost != 'undefined') {
+ moveToPost('next');
+ return false;
+ }
+ }
+
+ if (keycode == 80 || keycode == 38) { // p, up
+ if (typeof moveToPost != 'undefined') {
+ moveToPost('prev');
+ return false;
+ }
+ }
+
+ if (keycode == 83 && shift_key) { // S
+ selectionTogglePublished(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 83) { // s
+ selectionToggleMarked(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 85) { // u
+ selectionToggleUnread(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 84 && shift_key) { // T
+ var id = getActiveArticleId();
+ if (id) {
+ editArticleTags(id, getActiveFeedId(), isCdmMode());
+ return;
+ }
+ }
+
+ if (keycode == 9) { // tab
+ var id = getArticleUnderPointer();
+ if (id) {
+ var cb = $("RCHK-" + id);
+
+ if (cb) {
+ cb.checked = !cb.checked;
+ toggleSelectRowById(cb, "RROW-" + id);
+ return false;
+ }
+ }
+ }
+
+ if (keycode == 79) { // o
+ if (getActiveArticleId()) {
+ openArticleInNewWindow(getActiveArticleId());
+ return;
+ }
+ }
+
+ if (keycode == 81 && shift_key) { // Q
+ if (typeof catchupAllFeeds != 'undefined') {
+ catchupAllFeeds();
+ return;
+ }
+ }
+
+ if (keycode == 88 && !shift_key) { // x
+ if (activeFeedIsCat()) {
+ dijit.byId("feedTree").collapseCat(getActiveFeedId());
+ return;
+ }
+ }
+ }
+
+ /* Prefix a */
+
+ if (hotkey_prefix == 65) { // a
+ hotkey_prefix = false;
+
+ if (keycode == 65) { // a
+ selectArticles('all');
+ return;
+ }
+
+ if (keycode == 85) { // u
+ selectArticles('unread');
+ return;
+ }
+
+ if (keycode == 73) { // i
+ selectArticles('invert');
+ return;
+ }
+
+ if (keycode == 78) { // n
+ selectArticles('none');
+ return;
+ }
+
+ }
+
+ /* Prefix f */
+
+ if (hotkey_prefix == 70) { // f
+
+ hotkey_prefix = false;
+
+ if (keycode == 81) { // q
+ if (getActiveFeedId()) {
+ catchupCurrentFeed();
+ return;
+ }
+ }
+
+ if (keycode == 82) { // r
+ if (getActiveFeedId()) {
+ viewfeed(getActiveFeedId(), '', activeFeedIsCat());
+ return;
+ }
+ }
+
+ if (keycode == 65) { // a
+ toggleDispRead();
+ return false;
+ }
+
+ if (keycode == 85) { // u
+ if (getActiveFeedId()) {
+ viewfeed(getActiveFeedId(), '');
+ return false;
+ }
+ }
+
+ if (keycode == 69) { // e
+
+ if (activeFeedIsCat())
+ alert(__("You can't edit this kind of feed."));
+ else
+ editFeed(getActiveFeedId());
+ return;
+
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ quickAddFeed();
+ return false;
+ }
+
+ if (keycode == 67 && shift_key) { // C
+ if (typeof catchupAllFeeds != 'undefined') {
+ catchupAllFeeds();
+ return false;
+ }
+ }
+
+ if (keycode == 67) { // c
+ if (getActiveFeedId()) {
+ catchupCurrentFeed();
+ return false;
+ }
+ }
+
+ if (keycode == 88) { // x
+ reverseHeadlineOrder();
+ return;
+ }
+ }
+
+ /* Prefix c */
+
+ if (hotkey_prefix == 67) { // c
+ hotkey_prefix = false;
+
+ if (keycode == 70) { // f
+ quickAddFilter();
+ return false;
+ }
+
+ if (keycode == 76) { // l
+ addLabel();
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ if (typeof collapse_feedlist != 'undefined') {
+ collapse_feedlist();
+ return false;
+ }
+ }
+
+ if (keycode == 77) { // m
+ // TODO: sortable feedlist
+ return;
+ }
+
+ if (keycode == 78) { // n
+ catchupRelativeToArticle(1);
+ return;
+ }
+
+ if (keycode == 80) { // p
+ catchupRelativeToArticle(0);
+ return;
+ }
+
+
+ }
+
+ /* Prefix g */
+
+ if (hotkey_prefix == 71) { // g
+
+ hotkey_prefix = false;
+
+
+ if (keycode == 65) { // a
+ viewfeed(-4);
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ viewfeed(-1);
+ return false;
+ }
+
+ if (keycode == 80 && shift_key) { // P
+ gotoPreferences();
+ return false;
+ }
+
+ if (keycode == 80) { // p
+ viewfeed(-2);
+ return false;
+ }
+
+ if (keycode == 70) { // f
+ viewfeed(-3);
+ return false;
+ }
+
+ if (keycode == 84) { // t
+ displayDlg("printTagCloud");
+ return false;
+ }
+ }
+
+ /* Cmd */
+
+ if (hotkey_prefix == 224 || hotkey_prefix == 91) { // f
+ hotkey_prefix = false;
+ return;
+ }
+
+ if (hotkey_prefix) {
+ console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
+ } else {
+ console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
+ }
+
+
+ } catch (e) {
+ exception_error("hotkey_handler", e);
+ }
+}
+
+function inPreferences() {
+ return false;
+}
+
+function reverseHeadlineOrder() {
+ try {
+
+ var query_str = "?op=rpc&subop=togglepref&key=REVERSE_HEADLINES";
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("reverseHeadlineOrder", e);
+ }
+}
+
+function scheduleFeedUpdate(id, is_cat) {
+ try {
+ if (!id) {
+ id = getActiveFeedId();
+ is_cat = activeFeedIsCat();
+ }
+
+ if (!id) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=scheduleFeedUpdate&id=" +
+ param_escape(id) +
+ "&is_cat=" + param_escape(is_cat);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+
+ var reply = JSON.parse(transport.responseText);
+ var message = reply['message'];
+
+ if (message) {
+ notify_info(message);
+ return;
+ }
+
+ } });
+
+
+ } catch (e) {
+ exception_error("scheduleFeedUpdate", e);
+ }
+}
+
+function newVersionDlg() {
+ try {
+ var query = "backend.php?op=dlg&id=newVersion";
+
+ if (dijit.byId("newVersionDlg"))
+ dijit.byId("newVersionDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "newVersionDlg",
+ title: __("New version available!"),
+ style: "width: 600px",
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("newVersionDlg", e);
+ }
+}
+
+function handle_rpc_json(transport, scheduled_call) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+
+ var error = reply['error'];
+
+ if (error) {
+ var code = error['code'];
+ var msg = error['msg'];
+
+ console.warn("[handle_rpc_json] received fatal error " + code + "/" + msg);
+
+ if (code != 0) {
+ fatalError(code, msg);
+ return false;
+ }
+ }
+
+ var seq = reply['seq'];
+
+ if (seq) {
+ if (get_seq() != seq) {
+ console.log("[handle_rpc_json] sequence mismatch: " + seq +
+ " (want: " + get_seq() + ")");
+ return true;
+ }
+ }
+
+ var message = reply['message'];
+
+ if (message) {
+ if (message == "UPDATE_COUNTERS") {
+ console.log("need to refresh counters...");
+ setInitParam("last_article_id", -1);
+ _force_scheduled_update = true;
+ }
+ }
+
+ var counters = reply['counters'];
+
+ if (counters)
+ parse_counters(counters, scheduled_call);
+
+ var runtime_info = reply['runtime-info'];;
+
+ if (runtime_info)
+ parse_runtime_info(runtime_info);
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ } else {
+ notify_error("Error communicating with server.");
+ }
+
+ } catch (e) {
+ notify_error("Error communicating with server.");
+ console.log(e);
+ //exception_error("handle_rpc_json", e, transport);
+ }
+
+ return true;
+}
+
diff --git a/js/viewfeed.js b/js/viewfeed.js
new file mode 100644
index 000000000..9cb902315
--- /dev/null
+++ b/js/viewfeed.js
@@ -0,0 +1,2245 @@
+var active_post_id = false;
+
+var article_cache = new Array();
+
+var vgroup_last_feed = false;
+var post_under_pointer = false;
+
+var last_requested_article = false;
+
+var catchup_id_batch = [];
+var catchup_timeout_id = false;
+var feed_precache_timeout_id = false;
+var precache_idle_timeout_id = false;
+
+var cids_requested = [];
+
+var has_storage = 'sessionStorage' in window && window['sessionStorage'] !== null;
+
+function headlines_callback2(transport, offset, background, infscroll_req) {
+ try {
+ handle_rpc_json(transport);
+
+ loading_set_progress(25);
+
+ console.log("headlines_callback2 [offset=" + offset + "] B:" + background + " I:" + infscroll_req);
+
+ var is_cat = false;
+ var feed_id = false;
+
+ var reply = false;
+
+ try {
+ reply = JSON.parse(transport.responseText);
+ } catch (e) {
+ console.error(e);
+ }
+
+ if (reply) {
+
+ is_cat = reply['headlines']['is_cat'];
+ feed_id = reply['headlines']['id'];
+
+ if (background) {
+ var content = reply['headlines']['content'];
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ content = content + "<div id='headlines-spacer'></div>";
+ }
+
+ cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], content);
+ return;
+ }
+
+ setActiveFeedId(feed_id, is_cat);
+
+ try {
+ if (offset == 0 && infscroll_req == false) {
+ $("headlines-frame").scrollTop = 0;
+ }
+ } catch (e) { };
+
+ var headlines_count = reply['headlines-info']['count'];
+
+ vgroup_last_feed = reply['headlines-info']['vgroup_last_feed'];
+
+ if (parseInt(headlines_count) < getInitParam("default_article_limit")) {
+ _infscroll_disable = 1;
+ } else {
+ _infscroll_disable = 0;
+ }
+
+ var counters = reply['counters'];
+ var articles = reply['articles'];
+ //var runtime_info = reply['runtime-info'];
+
+ if (offset == 0 && infscroll_req == false) {
+ dijit.byId("headlines-frame").attr('content',
+ reply['headlines']['content']);
+
+ dijit.byId("headlines-toolbar").attr('content',
+ reply['headlines']['toolbar']);
+
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ var hsp = $("headlines-spacer");
+ if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
+ dijit.byId('headlines-frame').domNode.appendChild(hsp);
+ }
+
+ initHeadlinesMenu();
+
+ } else {
+
+ if (headlines_count > 0 && feed_id == getActiveFeedId() && is_cat == activeFeedIsCat()) {
+ console.log("adding some more headlines...");
+
+ var c = dijit.byId("headlines-frame");
+ var ids = getSelectedArticleIds2();
+
+ $("headlines-tmp").innerHTML = reply['headlines']['content'];
+
+ var hsp = $("headlines-spacer");
+
+ if (hsp)
+ c.domNode.removeChild(hsp);
+
+ $$("#headlines-tmp > div").each(function(row) {
+ if ($$("#headlines-frame DIV[id="+row.id+"]").length == 0) {
+ row.style.display = 'none';
+ c.domNode.appendChild(row);
+ } else {
+ row.parentNode.removeChild(row);
+ }
+ });
+
+ if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
+
+ fixHeadlinesOrder(getLoadedArticleIds());
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ c.domNode.appendChild(hsp);
+ }
+
+ console.log("restore selected ids: " + ids);
+
+ for (var i = 0; i < ids.length; i++) {
+ markHeadline(ids[i]);
+ }
+
+ initHeadlinesMenu();
+
+ $$("#headlines-frame > div[id*=RROW]").each(
+ function(child) {
+ if (!Element.visible(child))
+ new Effect.Appear(child, { duration : 0.5 });
+ });
+
+ } else {
+ console.log("no new headlines received");
+
+ var hsp = $("headlines-spacer");
+
+ if (hsp) hsp.innerHTML = "";
+ }
+ }
+
+ if (headlines_count > 0)
+ cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], $("headlines-frame").innerHTML);
+
+ if (articles) {
+ for (var i = 0; i < articles.length; i++) {
+ var a_id = articles[i]['id'];
+ cache_set("article:" + a_id, articles[i]['content']);
+ }
+ } else {
+ console.log("no cached articles received");
+ }
+
+ // do not precache stuff after fresh feed
+ if (feed_id != -3)
+ precache_headlines();
+
+ if (counters)
+ parse_counters(counters);
+ else
+ request_counters();
+
+ } else {
+ console.error("Invalid object received: " + transport.responseText);
+ dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
+ __('Could not update headlines (invalid object received - see error console for details)') +
+ "</div>");
+ }
+
+ _infscroll_request_sent = 0;
+
+ notify("");
+
+ } catch (e) {
+ exception_error("headlines_callback2", e, transport);
+ }
+}
+
+function render_article(article) {
+ try {
+ dijit.byId("headlines-wrap-inner").addChild(
+ dijit.byId("content-insert"));
+
+ var c = dijit.byId("content-insert");
+
+ try {
+ c.domNode.scrollTop = 0;
+ } catch (e) { };
+
+ c.attr('content', article);
+
+ correctHeadlinesOffset(getActiveArticleId());
+
+ try {
+ c.focus();
+ } catch (e) { };
+
+ } catch (e) {
+ exception_error("render_article", e);
+ }
+}
+
+function showArticleInHeadlines(id) {
+
+ try {
+
+ selectArticles("none");
+
+ var crow = $("RROW-" + id);
+
+ if (!crow) return;
+
+ var article_is_unread = crow.hasClassName("Unread");
+
+ crow.removeClassName("Unread");
+
+ selectArticles('none');
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ var view_mode = false;
+
+ try {
+ view_mode = document.forms['main_toolbar_form'].view_mode;
+ view_mode = view_mode[view_mode.selectedIndex].value;
+ } catch (e) {
+ //
+ }
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ } else if (article_is_unread && view_mode == "all_articles") {
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+ }
+
+ markHeadline(id);
+
+ if (article_is_unread)
+ _force_scheduled_update = true;
+
+ } catch (e) {
+ exception_error("showArticleInHeadlines", e);
+ }
+}
+
+function article_callback2(transport, id) {
+ try {
+ console.log("article_callback2 " + id);
+
+ handle_rpc_json(transport);
+
+ var reply = false;
+
+ try {
+ reply = JSON.parse(transport.responseText);
+ } catch (e) {
+ console.error(e);
+ }
+
+ if (reply) {
+
+ var upic = $('FUPDPIC-' + id);
+
+ if (upic) upic.src = 'images/blank_icon.gif';
+
+ reply.each(function(article) {
+ if (active_post_id == article['id']) {
+ render_article(article['content']);
+ }
+ cids_requested.remove(article['id']);
+
+ cache_set("article:" + article['id'], article['content']);
+ });
+
+// if (id != last_requested_article) {
+// console.log("requested article id is out of sequence, aborting");
+// return;
+// }
+
+ } else {
+ console.error("Invalid object received: " + transport.responseText);
+
+ render_article("<div class='whiteBox'>" +
+ __('Could not display article (invalid object received - see error console for details)') + "</div>");
+ }
+
+ request_counters();
+
+ try {
+ if (!_infscroll_disable &&
+ $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
+
+ loadMoreHeadlines();
+ }
+ } catch (e) {
+ console.warn(e);
+ }
+
+ notify("");
+ } catch (e) {
+ exception_error("article_callback2", e, transport);
+ }
+}
+
+function view(id) {
+ try {
+ console.log("loading article: " + id);
+
+ var cached_article = cache_get("article:" + id);
+
+ console.log("cache check result: " + (cached_article != false));
+
+ hideAuxDlg();
+
+ var query = "?op=view&id=" + param_escape(id);
+
+ var neighbor_ids = getRelativePostIds(id);
+
+ /* only request uncached articles */
+
+ var cids_to_request = [];
+
+ for (var i = 0; i < neighbor_ids.length; i++) {
+ if (cids_requested.indexOf(neighbor_ids[i]) == -1)
+ if (!cache_get("article:" + neighbor_ids[i])) {
+ cids_to_request.push(neighbor_ids[i]);
+ cids_requested.push(neighbor_ids[i]);
+ }
+ }
+
+ console.log("additional ids: " + cids_to_request.toString());
+
+ query = query + "&cids=" + cids_to_request.toString();
+
+ var crow = $("RROW-" + id);
+ var article_is_unread = crow.hasClassName("Unread");
+
+ active_post_id = id;
+ showArticleInHeadlines(id);
+
+ precache_headlines();
+
+ if (!cached_article) {
+
+ var upic = $('FUPDPIC-' + id);
+
+ if (upic) {
+ upic.src = getInitParam("sign_progress");
+ }
+
+ } else if (cached_article && article_is_unread) {
+
+ query = query + "&mode=prefetch";
+
+ render_article(cached_article);
+
+ } else if (cached_article) {
+
+ query = query + "&mode=prefetch_old";
+ render_article(cached_article);
+
+ // if we don't need to request any relative ids, we might as well skip
+ // the server roundtrip altogether
+ if (cids_to_request.length == 0) {
+
+ try {
+ if (!_infscroll_disable &&
+ $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
+
+ loadMoreHeadlines();
+ }
+ } catch (e) {
+ console.warn(e);
+ }
+
+ return;
+ }
+ }
+
+ last_requested_article = id;
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ article_callback2(transport, id);
+ } });
+
+ return false;
+
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function toggleMark(id, client_only) {
+ try {
+ var query = "?op=rpc&id=" + id + "&subop=mark";
+
+ var img = $("FMPIC-" + id);
+
+ if (!img) return;
+
+ if (img.src.match("mark_unset")) {
+ img.src = img.src.replace("mark_unset", "mark_set");
+ img.alt = __("Unstar article");
+ query = query + "&mark=1";
+
+ } else {
+ img.src = img.src.replace("mark_set", "mark_unset");
+ img.alt = __("Star article");
+ query = query + "&mark=0";
+ }
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ if (!client_only) {
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+ }
+
+ } catch (e) {
+ exception_error("toggleMark", e);
+ }
+}
+
+function togglePub(id, client_only, no_effects, note) {
+ try {
+ var query = "?op=rpc&id=" + id + "&subop=publ";
+
+ if (note != undefined) {
+ query = query + "&note=" + param_escape(note);
+ } else {
+ query = query + "&note=undefined";
+ }
+
+ var img = $("FPPIC-" + id);
+
+ if (!img) return;
+
+ if (img.src.match("pub_unset") || note != undefined) {
+ img.src = img.src.replace("pub_unset", "pub_set");
+ img.alt = __("Unpublish article");
+ query = query + "&pub=1";
+
+ } else {
+ img.src = img.src.replace("pub_set", "pub_unset");
+ img.alt = __("Publish article");
+
+ query = query + "&pub=0";
+ }
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ if (!client_only) {
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+ }
+
+ } catch (e) {
+ exception_error("togglePub", e);
+ }
+}
+
+function moveToPost(mode) {
+
+ try {
+
+ var rows = getVisibleArticleIds();
+
+ var prev_id = false;
+ var next_id = false;
+
+ if (!$('RROW-' + active_post_id)) {
+ active_post_id = false;
+ }
+
+ if (active_post_id == false) {
+ next_id = getFirstVisibleHeadlineId();
+ prev_id = getLastVisibleHeadlineId();
+ } else {
+ for (var i = 0; i < rows.length; i++) {
+ if (rows[i] == active_post_id) {
+ prev_id = rows[i-1];
+ next_id = rows[i+1];
+ }
+ }
+ }
+
+ if (mode == "next") {
+ if (next_id) {
+ if (isCdmMode()) {
+
+ cdmExpandArticle(next_id);
+ cdmScrollToArticleId(next_id);
+
+ } else {
+ correctHeadlinesOffset(next_id);
+ view(next_id, getActiveFeedId());
+ }
+ }
+ }
+
+ if (mode == "prev") {
+ if (prev_id) {
+ if (isCdmMode()) {
+ cdmExpandArticle(prev_id);
+ cdmScrollToArticleId(prev_id);
+ } else {
+ correctHeadlinesOffset(prev_id);
+ view(prev_id, getActiveFeedId());
+ }
+ }
+ }
+
+ } catch (e) {
+ exception_error("moveToPost", e);
+ }
+}
+
+function toggleSelected(id, force_on) {
+ try {
+
+ var cb = $("RCHK-" + id);
+ var row = $("RROW-" + id);
+
+ if (row) {
+ if (row.hasClassName('Selected') && !force_on) {
+ row.removeClassName('Selected');
+ if (cb) cb.checked = false;
+ } else {
+ row.addClassName('Selected');
+ if (cb) cb.checked = true;
+ }
+ }
+ } catch (e) {
+ exception_error("toggleSelected", e);
+ }
+}
+
+function toggleUnread_afh(effect) {
+ try {
+
+ var elem = effect.element;
+ elem.style.backgroundColor = "";
+
+ } catch (e) {
+ exception_error("toggleUnread_afh", e);
+ }
+}
+
+function toggleUnread(id, cmode, effect) {
+ try {
+
+ var row = $("RROW-" + id);
+ if (row) {
+ if (cmode == undefined || cmode == 2) {
+ if (row.hasClassName("Unread")) {
+ row.removeClassName("Unread");
+
+ if (effect) {
+ new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
+ afterFinish: toggleUnread_afh,
+ queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
+ }
+
+ } else {
+ row.addClassName("Unread");
+ }
+
+ } else if (cmode == 0) {
+
+ row.removeClassName("Unread");
+
+ if (effect) {
+ new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
+ afterFinish: toggleUnread_afh,
+ queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
+ }
+
+ } else if (cmode == 1) {
+ row.addClassName("Unread");
+ }
+
+ if (cmode == undefined) cmode = 2;
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=" + param_escape(cmode) + "&ids=" + param_escape(id);
+
+// notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("toggleUnread", e);
+ }
+}
+
+function selectionRemoveLabel(id, ids) {
+ try {
+
+ if (!ids) ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=removeFromLabel&ids=" +
+ param_escape(ids.toString()) + "&lid=" + param_escape(id);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ show_labels_in_headlines(transport);
+ } });
+
+ } catch (e) {
+ exception_error("selectionAssignLabel", e);
+
+ }
+}
+
+function selectionAssignLabel(id, ids) {
+ try {
+
+ if (!ids) ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=assignToLabel&ids=" +
+ param_escape(ids.toString()) + "&lid=" + param_escape(id);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ show_labels_in_headlines(transport);
+ } });
+
+ } catch (e) {
+ exception_error("selectionAssignLabel", e);
+
+ }
+}
+
+function selectionToggleUnread(set_state, callback, no_error) {
+ try {
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0 && !no_error) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ var row = $("RROW-" + rows[i]);
+ if (row) {
+ if (set_state == undefined) {
+ if (row.hasClassName("Unread")) {
+ row.removeClassName("Unread");
+ } else {
+ row.addClassName("Unread");
+ }
+ }
+
+ if (set_state == false) {
+ row.removeClassName("Unread");
+ }
+
+ if (set_state == true) {
+ row.addClassName("Unread");
+ }
+ }
+ }
+
+ if (rows.length > 0) {
+
+ var cmode = "";
+
+ if (set_state == undefined) {
+ cmode = "2";
+ } else if (set_state == true) {
+ cmode = "1";
+ } else if (set_state == false) {
+ cmode = "0";
+ }
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=" + cmode + "&ids=" + param_escape(rows.toString());
+
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ if (callback) callback(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleUnread", e);
+ }
+}
+
+function selectionToggleMarked() {
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ toggleMark(rows[i], true, true);
+ }
+
+ if (rows.length > 0) {
+
+ var query = "?op=rpc&subop=markSelected&ids=" +
+ param_escape(rows.toString()) + "&cmode=2";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleMarked", e);
+ }
+}
+
+function selectionTogglePublished() {
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ togglePub(rows[i], true, true);
+ }
+
+ if (rows.length > 0) {
+
+ var query = "?op=rpc&subop=publishSelected&ids=" +
+ param_escape(rows.toString()) + "&cmode=2";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleMarked", e);
+ }
+}
+
+function getSelectedArticleIds2() {
+
+ var rv = [];
+
+ $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
+ function(child) {
+ rv.push(child.id.replace("RROW-", ""));
+ });
+
+ return rv;
+}
+
+function getLoadedArticleIds() {
+ var rv = [];
+
+ var children = $$("#headlines-frame > div[id*=RROW-]");
+
+ children.each(function(child) {
+ rv.push(child.id.replace("RROW-", ""));
+ });
+
+ return rv;
+
+}
+
+// mode = all,none,unread,invert
+function selectArticles(mode) {
+ try {
+
+ var children = $$("#headlines-frame > div[id*=RROW]");
+
+ children.each(function(child) {
+ var id = child.id.replace("RROW-", "");
+ var cb = $("RCHK-" + id);
+
+ if (mode == "all") {
+ child.addClassName("Selected");
+ cb.checked = true;
+ } else if (mode == "unread") {
+ if (child.hasClassName("Unread")) {
+ child.addClassName("Selected");
+ cb.checked = true;
+ } else {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ }
+ } else if (mode == "invert") {
+ if (child.hasClassName("Selected")) {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ } else {
+ child.addClassName("Selected");
+ cb.checked = true;
+ }
+
+ } else {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ }
+ });
+
+ } catch (e) {
+ exception_error("selectArticles", e);
+ }
+}
+
+function catchupPage() {
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark all visible articles in %s as read?");
+
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ selectArticles('all');
+ selectionToggleUnread(false, 'viewCurrentFeed()', true);
+ selectArticles('none');
+}
+
+function deleteSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+ var str;
+
+ if (getActiveFeedId() != 0) {
+ str = __("Delete %d selected articles in %s?");
+ } else {
+ str = __("Delete %d selected articles?");
+ }
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ query = "?op=rpc&subop=delete&ids=" + param_escape(rows);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("deleteSelection", e);
+ }
+}
+
+function archiveSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+ var str;
+ var op;
+
+ if (getActiveFeedId() != 0) {
+ str = __("Archive %d selected articles in %s?");
+ op = "archive";
+ } else {
+ str = __("Move %d archived articles back?");
+ op = "unarchive";
+ }
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ query = "?op=rpc&subop="+op+"&ids=" + param_escape(rows);
+
+ console.log(query);
+
+ for (var i = 0; i < rows.length; i++) {
+ cache_delete("article:" + rows[i]);
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("archiveSelection", e);
+ }
+}
+
+function catchupSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark %d selected articles in %s as read?");
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ selectionToggleUnread(false, 'viewCurrentFeed()', true);
+
+ } catch (e) {
+ exception_error("catchupSelection", e);
+ }
+}
+
+function editArticleTags(id) {
+ var query = "backend.php?op=dlg&id=editArticleTags&param=" + param_escape(id);
+
+ if (dijit.byId("editTagsDlg"))
+ dijit.byId("editTagsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "editTagsDlg",
+ title: __("Edit article Tags"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ notify_progress("Saving article tags...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+
+ var data = JSON.parse(transport.responseText);
+
+ if (data) {
+ var tags_str = article.tags;
+ var id = tags_str.id;
+
+ var tags = $("ATSTR-" + id);
+ var tooltip = dijit.byId("ATSTRTIP-" + id);
+
+ if (tags) tags.innerHTML = tags_str.content;
+ if (tooltip) tooltip.attr('label', tags_str.content_full);
+
+ cache_delete("article:" + id);
+ }
+
+ }});
+ }
+ },
+ href: query,
+ });
+
+ var tmph = dojo.connect(dialog, 'onLoad', function() {
+ dojo.disconnect(tmph);
+
+ new Ajax.Autocompleter('tags_str', 'tags_choices',
+ "backend.php?op=rpc&subop=completeTags",
+ { tokens: ',', paramName: "search" });
+ });
+
+ dialog.show();
+
+}
+
+function cdmScrollToArticleId(id) {
+ try {
+ var ctr = $("headlines-frame");
+ var e = $("RROW-" + id);
+
+ if (!e || !ctr) return;
+
+ ctr.scrollTop = e.offsetTop;
+
+ } catch (e) {
+ exception_error("cdmScrollToArticleId", e);
+ }
+}
+
+function getActiveArticleId() {
+ return active_post_id;
+}
+
+function postMouseIn(id) {
+ post_under_pointer = id;
+}
+
+function postMouseOut(id) {
+ post_under_pointer = false;
+}
+
+function headlines_scroll_handler(e) {
+ try {
+ var hsp = $("headlines-spacer");
+
+ if (!_infscroll_disable) {
+ if (hsp && (e.scrollTop + e.offsetHeight > hsp.offsetTop) ||
+ e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
+
+ if (hsp)
+ hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
+ __("Loading, please wait...");
+
+ loadMoreHeadlines();
+ return;
+
+ }
+ } else {
+ if (hsp) hsp.innerHTML = "";
+ }
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+
+ $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
+ function(child) {
+ if ($("headlines-frame").scrollTop >
+ (child.offsetTop + child.offsetHeight/2)) {
+
+ var id = child.id.replace("RROW-", "");
+
+ if (catchup_id_batch.indexOf(id) == -1)
+ catchup_id_batch.push(id);
+
+ //console.log("auto_catchup_batch: " + catchup_id_batch.toString());
+ }
+ });
+
+ if (catchup_id_batch.length > 0) {
+ window.clearTimeout(catchup_timeout_id);
+
+ if (!_infscroll_request_sent) {
+ catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
+ 2000);
+ }
+ }
+ }
+
+ } catch (e) {
+ console.warn("headlines_scroll_handler: " + e);
+ }
+}
+
+function catchupBatchedArticles() {
+ try {
+ if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(catchup_id_batch.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+
+ catchup_id_batch.each(function(id) {
+ var elem = $("RROW-" + id);
+ if (elem) elem.removeClassName("Unread");
+ });
+
+ catchup_id_batch = [];
+ } });
+ }
+
+ } catch (e) {
+ exception_error("catchupBatchedArticles", e);
+ }
+}
+
+function catchupRelativeToArticle(below, id) {
+
+ try {
+
+ if (!id) id = getActiveArticleId();
+
+ if (!id) {
+ alert(__("No article is selected."));
+ return;
+ }
+
+ var visible_ids = getVisibleArticleIds();
+
+ var ids_to_mark = new Array();
+
+ if (!below) {
+ for (var i = 0; i < visible_ids.length; i++) {
+ if (visible_ids[i] != id) {
+ var e = $("RROW-" + visible_ids[i]);
+
+ if (e && e.hasClassName("Unread")) {
+ ids_to_mark.push(visible_ids[i]);
+ }
+ } else {
+ break;
+ }
+ }
+ } else {
+ for (var i = visible_ids.length-1; i >= 0; i--) {
+ if (visible_ids[i] != id) {
+ var e = $("RROW-" + visible_ids[i]);
+
+ if (e && e.hasClassName("Unread")) {
+ ids_to_mark.push(visible_ids[i]);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (ids_to_mark.length == 0) {
+ alert(__("No articles found to mark"));
+ } else {
+ var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) {
+
+ for (var i = 0; i < ids_to_mark.length; i++) {
+ var e = $("RROW-" + ids_to_mark[i]);
+ e.removeClassName("Unread");
+ }
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0" + "&ids=" + param_escape(ids_to_mark.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+ }
+
+ } catch (e) {
+ exception_error("catchupRelativeToArticle", e);
+ }
+}
+
+function cdmExpandArticle(id) {
+ try {
+
+ hideAuxDlg();
+
+ var elem = $("CICD-" + active_post_id);
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+ }
+
+ if (id == active_post_id && Element.visible(elem))
+ return true;
+
+ selectArticles("none");
+
+ var old_offset = $("RROW-" + id).offsetTop;
+
+ if (active_post_id && elem && !getInitParam("cdm_expanded")) {
+ Element.hide(elem);
+ Element.show("CEXC-" + active_post_id);
+ }
+
+ active_post_id = id;
+
+ elem = $("CICD-" + id);
+
+ if (!Element.visible(elem)) {
+ Element.show(elem);
+ Element.hide("CEXC-" + id);
+
+ if ($("CWRAP-" + id).innerHTML == "") {
+
+ $("FUPDPIC-" + id).src = "images/indicator_tiny.gif";
+
+ $("CWRAP-" + id).innerHTML = "<div class=\"insensitive\">" +
+ __("Loading, please wait...") + "</div>";
+
+ var query = "?op=rpc&subop=cdmGetArticle&id=" + param_escape(id);
+
+ var neighbor_ids = getRelativePostIds(id);
+
+ /* only request uncached articles */
+ var cids_to_request = [];
+
+ for (var i = 0; i < neighbor_ids.length; i++) {
+ if (cids_requested.indexOf(neighbor_ids[i]) == -1)
+ if ($("CWRAP-" + neighbor_ids[i]).innerHTML == "") {
+ cids_to_request.push(neighbor_ids[i]);
+ cids_requested.push(neighbor_ids[i]);
+ }
+ }
+
+ console.log("additional ids: " + cids_to_request.toString());
+
+ query = query + "&cids=" + cids_to_request.toString();
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ $("FUPDPIC-" + id).src = 'images/blank_icon.gif';
+
+ handle_rpc_json(transport);
+
+ var reply = JSON.parse(transport.responseText);
+
+ reply.each(function(article) {
+ $("CWRAP-" + article['id']).innerHTML = article['content'];
+ cids_requested.remove(article['id']);
+ });
+ }});
+
+ }
+ }
+
+ var new_offset = $("RROW-" + id).offsetTop;
+
+ $("headlines-frame").scrollTop += (new_offset-old_offset);
+
+ if ($("RROW-" + id).offsetTop != old_offset)
+ $("headlines-frame").scrollTop = new_offset;
+
+ toggleUnread(id, 0, true);
+ toggleSelected(id);
+
+ } catch (e) {
+ exception_error("cdmExpandArticle", e);
+ }
+
+ return false;
+}
+
+function fixHeadlinesOrder(ids) {
+ try {
+ for (var i = 0; i < ids.length; i++) {
+ var e = $("RROW-" + ids[i]);
+
+ if (e) {
+ if (i % 2 == 0) {
+ e.removeClassName("even");
+ e.addClassName("odd");
+ } else {
+ e.removeClassName("odd");
+ e.addClassName("even");
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("fixHeadlinesOrder", e);
+ }
+}
+
+function getArticleUnderPointer() {
+ return post_under_pointer;
+}
+
+function zoomToArticle(event, id) {
+ try {
+ var cached_article = cache_get("article: " + id);
+
+ if (dijit.byId("ATAB-" + id))
+ if (!event || !event.shiftKey)
+ return dijit.byId("content-tabs").selectChild(dijit.byId("ATAB-" + id));
+
+ if (dijit.byId("ATSTRTIP-" + id))
+ dijit.byId("ATSTRTIP-" + id).destroyRecursive();
+
+ if (cached_article) {
+ //closeArticlePanel();
+
+ var article_pane = new dijit.layout.ContentPane({
+ title: __("Loading...") , content: cached_article,
+ style: 'padding : 0px;',
+ id: 'ATAB-' + id,
+ closable: true });
+
+ dijit.byId("content-tabs").addChild(article_pane);
+
+ if (!event || !event.shiftKey)
+ dijit.byId("content-tabs").selectChild(article_pane);
+
+ if ($("PTITLE-" + id))
+ article_pane.attr('title', $("PTITLE-" + id).innerHTML);
+
+ } else {
+
+ var query = "?op=rpc&subop=getArticles&ids=" + param_escape(id);
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ //closeArticlePanel();
+
+ var content = reply[0]['content'];
+
+ var article_pane = new dijit.layout.ContentPane({
+ title: "article-" + id , content: content,
+ style: 'padding : 0px;',
+ id: 'ATAB-' + id,
+ closable: true });
+
+ dijit.byId("content-tabs").addChild(article_pane);
+
+ if (!event || !event.shiftKey)
+ dijit.byId("content-tabs").selectChild(article_pane);
+
+ if ($("PTITLE-" + id))
+ article_pane.attr('title', $("PTITLE-" + id).innerHTML);
+ }
+
+ } });
+ }
+
+ } catch (e) {
+ exception_error("zoomToArticle", e);
+ }
+}
+
+function scrollArticle(offset) {
+ try {
+ if (!isCdmMode()) {
+ var ci = $("content-insert");
+ if (ci) {
+ ci.scrollTop += offset;
+ }
+ } else {
+ var hi = $("headlines-frame");
+ if (hi) {
+ hi.scrollTop += offset;
+ }
+
+ }
+ } catch (e) {
+ exception_error("scrollArticle", e);
+ }
+}
+
+function show_labels_in_headlines(transport) {
+ try {
+ var data = JSON.parse(transport.responseText);
+
+ if (data) {
+ data['info-for-headlines'].each(function(elem) {
+ var ctr = $("HLLCTR-" + elem.id);
+
+ if (ctr) ctr.innerHTML = elem.labels;
+ });
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ }
+ } catch (e) {
+ exception_error("show_labels_in_headlines", e);
+ }
+}
+
+/* function toggleHeadlineActions() {
+ try {
+ var e = $("headlineActionsBody");
+ var p = $("headlineActionsDrop");
+
+ if (!Element.visible(e)) {
+ Element.show(e);
+ } else {
+ Element.hide(e);
+ }
+
+ e.scrollTop = 0;
+ e.style.left = (p.offsetLeft + 1) + "px";
+ e.style.top = (p.offsetTop + p.offsetHeight + 2) + "px";
+
+ } catch (e) {
+ exception_error("toggleHeadlineActions", e);
+ }
+} */
+
+/* function publishWithNote(id, def_note) {
+ try {
+ if (!def_note) def_note = '';
+
+ var note = prompt(__("Please enter a note for this article:"), def_note);
+
+ if (note != undefined) {
+ togglePub(id, false, false, note);
+ }
+
+ } catch (e) {
+ exception_error("publishWithNote", e);
+ }
+} */
+
+function emailArticle(id) {
+ try {
+ if (!id) {
+ var ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ id = ids.toString();
+ }
+
+ if (dijit.byId("emailArticleDlg"))
+ dijit.byId("emailArticleDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=emailArticle&param=" + param_escape(id);
+
+ dialog = new dijit.Dialog({
+ id: "emailArticleDlg",
+ title: __("Forward article by email"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+
+ var reply = JSON.parse(transport.responseText);
+
+ var error = reply['error'];
+
+ if (error) {
+ alert(__('Error sending email:') + ' ' + error);
+ } else {
+ notify_info('Your message has been sent.');
+ dialog.hide();
+ }
+
+ } });
+ }
+ },
+ href: query});
+
+ var tmph = dojo.connect(dialog, 'onLoad', function() {
+ dojo.disconnect(tmph);
+
+ new Ajax.Autocompleter('emailArticleDlg_destination', 'emailArticleDlg_dst_choices',
+ "backend.php?op=rpc&subop=completeEmails",
+ { tokens: '', paramName: "search" });
+ });
+
+ dialog.show();
+
+ /* displayDlg('emailArticle', id,
+ function () {
+ document.forms['article_email_form'].destination.focus();
+
+ new Ajax.Autocompleter('destination', 'destination_choices',
+ "backend.php?op=rpc&subop=completeEmails",
+ { tokens: '', paramName: "search" });
+
+ }); */
+
+ } catch (e) {
+ exception_error("emailArticle", e);
+ }
+}
+
+function dismissArticle(id) {
+ try {
+ var elem = $("RROW-" + id);
+
+ toggleUnread(id, 0, true);
+
+ new Effect.Fade(elem, {duration : 0.5});
+
+ active_post_id = false;
+
+ } catch (e) {
+ exception_error("dismissArticle", e);
+ }
+}
+
+function dismissSelectedArticles() {
+ try {
+
+ var ids = getVisibleArticleIds();
+ var tmp = [];
+ var sel = [];
+
+ for (var i = 0; i < ids.length; i++) {
+ var elem = $("RROW-" + ids[i]);
+
+ if (elem.className && elem.hasClassName("Selected") &&
+ ids[i] != active_post_id) {
+ new Effect.Fade(elem, {duration : 0.5});
+ sel.push(ids[i]);
+ } else {
+ tmp.push(ids[i]);
+ }
+ }
+
+ if (sel.length > 0)
+ selectionToggleUnread(false);
+
+ fixHeadlinesOrder(tmp);
+
+ } catch (e) {
+ exception_error("dismissSelectedArticles", e);
+ }
+}
+
+function dismissReadArticles() {
+ try {
+
+ var ids = getVisibleArticleIds();
+ var tmp = [];
+
+ for (var i = 0; i < ids.length; i++) {
+ var elem = $("RROW-" + ids[i]);
+
+ if (elem.className && !elem.hasClassName("Unread") &&
+ !elem.hasClassName("Selected")) {
+
+ new Effect.Fade(elem, {duration : 0.5});
+ } else {
+ tmp.push(ids[i]);
+ }
+ }
+
+ fixHeadlinesOrder(tmp);
+
+ } catch (e) {
+ exception_error("dismissSelectedArticles", e);
+ }
+}
+
+function getVisibleArticleIds() {
+ var ids = [];
+
+ try {
+
+ getLoadedArticleIds().each(function(id) {
+ var elem = $("RROW-" + id);
+ if (elem && Element.visible(elem))
+ ids.push(id);
+ });
+
+ } catch (e) {
+ exception_error("getVisibleArticleIds", e);
+ }
+
+ return ids;
+}
+
+function cdmClicked(event, id) {
+ try {
+ //var shift_key = event.shiftKey;
+
+ hideAuxDlg();
+
+ if (!event.ctrlKey) {
+
+ if (!getInitParam("cdm_expanded")) {
+ return cdmExpandArticle(id);
+ } else {
+
+ selectArticles("none");
+ toggleSelected(id);
+
+ var elem = $("RROW-" + id);
+
+ if (elem)
+ elem.removeClassName("Unread");
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+ }
+
+ active_post_id = id;
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ return true;
+ }
+
+ } else {
+ toggleSelected(id, true);
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+ }
+
+ } catch (e) {
+ exception_error("cdmClicked");
+ }
+
+ return false;
+}
+
+function postClicked(event, id) {
+ try {
+
+ if (!event.ctrlKey) {
+ return true;
+ } else {
+ postOpenInNewTab(event, id);
+ return false;
+ }
+
+ } catch (e) {
+ exception_error("postClicked");
+ }
+}
+
+function hlOpenInNewTab(event, id) {
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+}
+
+function postOpenInNewTab(event, id) {
+ closeArticlePanel(id);
+ zoomToArticle(event, id);
+}
+
+function hlClicked(event, id) {
+ try {
+ if (event.which == 2) {
+ view(id);
+ return true;
+ } else if (event.altKey) {
+ openArticleInNewWindow(id);
+ } else if (!event.ctrlKey) {
+ view(id);
+ return false;
+ } else {
+ toggleSelected(id);
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+ return false;
+ }
+
+ } catch (e) {
+ exception_error("hlClicked");
+ }
+}
+
+function getFirstVisibleHeadlineId() {
+ var rows = getVisibleArticleIds();
+ return rows[0];
+
+}
+
+function getLastVisibleHeadlineId() {
+ var rows = getVisibleArticleIds();
+ return rows[rows.length-1];
+}
+
+function openArticleInNewWindow(id) {
+ toggleUnread(id, 0, false);
+ window.open("backend.php?op=la&id=" + id);
+}
+
+function isCdmMode() {
+ return getInitParam("combined_display_mode");
+}
+
+function markHeadline(id) {
+ var row = $("RROW-" + id);
+ if (row) {
+ var check = $("RCHK-" + id);
+
+ if (check) {
+ check.checked = true;
+ }
+
+ row.addClassName("Selected");
+ }
+}
+
+function getRelativePostIds(id, limit) {
+
+ var tmp = [];
+
+ try {
+
+ if (!limit) limit = 6; //3
+
+ var ids = getVisibleArticleIds();
+
+ for (var i = 0; i < ids.length; i++) {
+ if (ids[i] == id) {
+ for (var k = 1; k <= limit; k++) {
+ //if (i > k-1) tmp.push(ids[i-k]);
+ if (i < ids.length-k) tmp.push(ids[i+k]);
+ }
+ break;
+ }
+ }
+
+ } catch (e) {
+ exception_error("getRelativePostIds", e);
+ }
+
+ return tmp;
+}
+
+function correctHeadlinesOffset(id) {
+
+ try {
+
+ var container = $("headlines-frame");
+ var row = $("RROW-" + id);
+
+ var viewport = container.offsetHeight;
+
+ var rel_offset_top = row.offsetTop - container.scrollTop;
+ var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
+
+ //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
+ //console.log("Vport: " + viewport);
+
+ if (rel_offset_top <= 0 || rel_offset_top > viewport) {
+ container.scrollTop = row.offsetTop;
+ } else if (rel_offset_bottom > viewport) {
+
+ /* doesn't properly work with Opera in some cases because
+ Opera fucks up element scrolling */
+
+ container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
+ }
+
+ } catch (e) {
+ exception_error("correctHeadlinesOffset", e);
+ }
+
+}
+
+function headlineActionsChange(elem) {
+ try {
+ eval(elem.value);
+ elem.attr('value', 'false');
+ } catch (e) {
+ exception_error("headlineActionsChange", e);
+ }
+}
+
+function closeArticlePanel() {
+
+ var tabs = dijit.byId("content-tabs");
+ var child = tabs.selectedChildWidget;
+
+ if (child && tabs.getIndexOfChild(child) > 0) {
+ tabs.removeChild(child);
+ child.destroy();
+ } else {
+ if (dijit.byId("content-insert"))
+ dijit.byId("headlines-wrap-inner").removeChild(
+ dijit.byId("content-insert"));
+ }
+}
+
+function initHeadlinesMenu() {
+ try {
+ if (dijit.byId("headlinesMenu"))
+ dijit.byId("headlinesMenu").destroyRecursive();
+
+ var ids = [];
+
+ if (!isCdmMode()) {
+ nodes = $$("#headlines-frame > div[id*=RROW]");
+ } else {
+ nodes = $$("#headlines-frame span[id*=RTITLE]");
+ }
+
+ nodes.each(function(node) {
+ ids.push(node.id);
+ });
+
+ var menu = new dijit.Menu({
+ id: "headlinesMenu",
+ targetNodeIds: ids,
+ });
+
+ var tmph = dojo.connect(menu, '_openMyself', function (event) {
+ var callerNode = event.target, match = null, tries = 0;
+
+ while (match == null && callerNode && tries <= 3) {
+ match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
+ callerNode = callerNode.parentNode;
+ ++tries;
+ }
+
+ if (match) this.callerRowId = parseInt(match[1]);
+
+ });
+
+/* if (!isCdmMode())
+ menu.addChild(new dijit.MenuItem({
+ label: __("View article"),
+ onClick: function(event) {
+ view(this.getParent().callerRowId);
+ }})); */
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Open original article"),
+ onClick: function(event) {
+ openArticleInNewWindow(this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("View in a tt-rss tab"),
+ onClick: function(event) {
+ hlOpenInNewTab(event, this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuSeparator());
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark above as read"),
+ onClick: function(event) {
+ catchupRelativeToArticle(0, this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark below as read"),
+ onClick: function(event) {
+ catchupRelativeToArticle(1, this.getParent().callerRowId);
+ }}));
+
+
+ var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
+
+ if (labels) {
+
+ menu.addChild(new dijit.MenuSeparator());
+
+ var labelAddMenu = new dijit.Menu({ownerMenu: menu});
+ var labelDelMenu = new dijit.Menu({ownerMenu: menu});
+
+ labels.each(function(label) {
+ var id = label.id[0];
+ var bare_id = id.substr(id.indexOf(":")+1);
+ var name = label.name[0];
+
+ bare_id = -11-bare_id;
+
+ labelAddMenu.addChild(new dijit.MenuItem({
+ label: name,
+ labelId: bare_id,
+ onClick: function(event) {
+ selectionAssignLabel(this.labelId,
+ [this.getParent().ownerMenu.callerRowId]);
+ }}));
+
+ labelDelMenu.addChild(new dijit.MenuItem({
+ label: name,
+ labelId: bare_id,
+ onClick: function(event) {
+ selectionRemoveLabel(this.labelId,
+ [this.getParent().ownerMenu.callerRowId]);
+ }}));
+
+ });
+
+ menu.addChild(new dijit.PopupMenuItem({
+ label: __("Assign label"),
+ popup: labelAddMenu,
+ }));
+
+ menu.addChild(new dijit.PopupMenuItem({
+ label: __("Remove label"),
+ popup: labelDelMenu,
+ }));
+
+ }
+
+ menu.startup();
+
+ } catch (e) {
+ exception_error("initHeadlinesMenu", e);
+ }
+}
+
+function tweetArticle(id) {
+ try {
+ var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
+
+ console.log(query);
+
+ var d = new Date();
+ var ts = d.getTime();
+
+ var w = window.open('backend.php?op=loading', 'ttrss_tweet',
+ "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var ti = JSON.parse(transport.responseText);
+
+ var share_url = "http://twitter.com/share?_=" + ts +
+ "&text=" + param_escape(ti.title) +
+ "&url=" + param_escape(ti.link);
+
+ w.location.href = share_url;
+
+ } });
+
+
+ } catch (e) {
+ exception_error("tweetArticle", e);
+ }
+}
+
+function editArticleNote(id) {
+ try {
+
+ var query = "backend.php?op=dlg&id=editArticleNote&param=" + param_escape(id);
+
+ if (dijit.byId("editNoteDlg"))
+ dijit.byId("editNoteDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "editNoteDlg",
+ title: __("Edit article note"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ notify_progress("Saving article note...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+
+ var reply = JSON.parse(transport.responseText);
+
+ cache_delete("article:" + id);
+
+ var elem = $("POSTNOTE-" + id);
+
+ if (elem) {
+ Element.hide(elem);
+ elem.innerHTML = reply.note;
+
+ if (reply.raw_length != 0)
+ new Effect.Appear(elem);
+ }
+
+ }});
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editArticleNote", e);
+ }
+}
+
+function player(elem) {
+ var aid = elem.getAttribute("audio-id");
+ var status = elem.getAttribute("status");
+
+ var audio = $(aid);
+
+ if (audio) {
+ if (status == 0) {
+ audio.play();
+ status = 1;
+ elem.innerHTML = __("Playing...");
+ elem.title = __("Click to pause");
+ elem.addClassName("playing");
+ } else {
+ audio.pause();
+ status = 0;
+ elem.innerHTML = __("Play");
+ elem.title = __("Click to play");
+ elem.removeClassName("playing");
+ }
+
+ elem.setAttribute("status", status);
+ } else {
+ alert("Your browser doesn't seem to support HTML5 audio.");
+ }
+}
+
+function cache_set(id, obj) {
+ //console.log("cache_set: " + id);
+ if (has_storage)
+ try {
+ sessionStorage[id] = obj;
+ } catch (e) {
+ sessionStorage.clear();
+ }
+}
+
+function cache_get(id) {
+ if (has_storage)
+ return sessionStorage[id];
+}
+
+function cache_clear() {
+ if (has_storage)
+ sessionStorage.clear();
+}
+
+function cache_delete(id) {
+ if (has_storage)
+ sessionStorage.removeItem(id);
+}
+
+function cache_headlines(feed, is_cat, toolbar_obj, content_obj) {
+ if (toolbar_obj && content_obj) {
+ cache_set("feed:" + feed + ":" + is_cat,
+ JSON.stringify({toolbar: toolbar_obj, content: content_obj}));
+ } else {
+ try {
+ obj = cache_get("feed:" + feed + ":" + is_cat);
+
+ if (obj) {
+ obj = JSON.parse(obj);
+
+ if (toolbar_obj) obj.toolbar = toolbar_obj;
+ if (content_obj) obj.content = content_obj;
+
+ cache_set("feed:" + feed + ":" + is_cat, JSON.stringify(obj));
+ }
+
+ } catch (e) {
+ console.warn("cache_headlines failed: " + e);
+ }
+ }
+}
+
+function render_local_headlines(feed, is_cat, obj) {
+ try {
+
+ dijit.byId("headlines-toolbar").attr('content',
+ obj.toolbar);
+
+ dijit.byId("headlines-frame").attr('content',
+ obj.content);
+
+ dojo.parser.parse('headlines-toolbar');
+
+ $("headlines-frame").scrollTop = 0;
+ selectArticles('none');
+ setActiveFeedId(feed, is_cat);
+ initHeadlinesMenu();
+
+ precache_headlines();
+
+ } catch (e) {
+ exception_error("render_local_headlines", e);
+ }
+}
+
+function precache_headlines_idle() {
+ try {
+ if (!feed_precache_timeout_id) {
+ var feeds = dijit.byId("feedTree").getVisibleUnreadFeeds();
+ var uncached = [];
+
+ feeds.each(function(item) {
+ if (parseInt(item[0]) > 0 && !cache_get("feed:" + item[0] + ":" + item[1]))
+ uncached.push(item);
+ });
+
+ if (uncached.length > 0) {
+ var rf = uncached[Math.floor(Math.random()*uncached.length)];
+ viewfeed(rf[0], '', rf[1], 0, true);
+ }
+ }
+ precache_idle_timeout_id = setTimeout("precache_headlines_idle()", 1000*30);
+
+ } catch (e) {
+ exception_error("precache_headlines_idle", e);
+ }
+}
+
+function precache_headlines() {
+ try {
+
+ if (!feed_precache_timeout_id) {
+ feed_precache_timeout_id = window.setTimeout(function() {
+ var nuf = getNextUnreadFeed(getActiveFeedId(), activeFeedIsCat());
+ var nf = dijit.byId("feedTree").getNextFeed(getActiveFeedId(), activeFeedIsCat());
+
+ if (nuf && !cache_get("feed:" + nuf + ":" + activeFeedIsCat()))
+ viewfeed(nuf, '', activeFeedIsCat(), 0, true);
+
+ if (nf != nuf && nf && !cache_get("feed:" + nf[0] + ":" + nf[1]))
+ viewfeed(nf[0], '', nf[1], 0, true);
+
+ window.setTimeout(function() {
+ feed_precache_timeout_id = false;
+ }, 3000);
+ }, 1000);
+ }
+
+ } catch (e) {
+ exception_error("precache_headlines", e);
+ }
+}
+
+function shareArticle(id) {
+ try {
+ if (dijit.byId("shareArticleDlg"))
+ dijit.byId("shareArticleDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=shareArticle&param=" + param_escape(id);
+
+ dialog = new dijit.Dialog({
+ id: "shareArticleDlg",
+ title: __("Share article by URL"),
+ style: "width: 600px",
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("emailArticle", e);
+ }
+}
+
+