diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/FeedTree.js | 130 | ||||
-rw-r--r-- | js/PluginHost.js | 34 | ||||
-rw-r--r-- | js/PrefFilterTree.js | 28 | ||||
-rw-r--r-- | js/feedlist.js | 89 | ||||
-rw-r--r-- | js/functions.js | 338 | ||||
-rw-r--r-- | js/index.html | 0 | ||||
-rw-r--r-- | js/prefs.js | 122 | ||||
-rw-r--r-- | js/tt-rss.js | 580 | ||||
-rw-r--r-- | js/viewfeed.js | 600 |
9 files changed, 1211 insertions, 710 deletions
diff --git a/js/FeedTree.js b/js/FeedTree.js index 2cb6346e4..d80f46062 100644 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -100,13 +100,13 @@ dojo.declare("fox.FeedTree", dijit.Tree, { _createTreeNode: function(args) { var tnode = new dijit._TreeNode(args); - if (args.item.icon) + if (args.item.icon && args.item.icon[0]) 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) { + if (bare_id < _label_base_index) { var span = dojo.doc.createElement('span'); var fg_color = args.item.fg_color[0]; var bg_color = args.item.bg_color[0]; @@ -162,6 +162,14 @@ dojo.declare("fox.FeedTree", dijit.Tree, { tnode._menu = menu; } + if (id.match("CAT:")) { + loading = dojo.doc.createElement('img'); + loading.className = 'loadingNode'; + loading.src = 'images/blank_icon.gif'; + dojo.place(loading, tnode.labelNode, 'after'); + tnode.loadingNode = loading; + } + if (id.match("CAT:") && bare_id == -1) { var menu = new dijit.Menu(); menu.row_id = bare_id; @@ -176,10 +184,51 @@ dojo.declare("fox.FeedTree", dijit.Tree, { tnode._menu = menu; } + ctr = dojo.doc.createElement('span'); + ctr.className = 'counterNode'; + ctr.innerHTML = args.item.unread; + + //args.item.unread > 0 ? ctr.addClassName("unread") : ctr.removeClassName("unread"); + + args.item.unread > 0 ? Element.show(ctr) : Element.hide(ctr); + + dojo.place(ctr, tnode.rowNode, 'first'); + tnode.counterNode = ctr; //tnode.labelNode.innerHTML = args.label; return tnode; }, + postCreate: function() { + this.connect(this.model, "onChange", "updateCounter"); + + this.inherited(arguments); + }, + updateCounter: function (item) { + var tree = this; + + //console.log("updateCounter: " + item.id[0] + " " + item.unread + " " + tree); + + var node = tree._itemNodesMap[item.id]; + + if (node) { + node = node[0]; + + if (node.counterNode) { + ctr = node.counterNode; + ctr.innerHTML = item.unread; + item.unread > 0 ? Effect.Appear(ctr, {duration : 0.3, + queue: { position: 'end', scope: 'CAPPEAR-' + item.id, limit: 1 }}) : + Element.hide(ctr); + } + } + + }, + getTooltip: function (item) { + if (item.updated) + return item.updated; + else + return ""; + }, getIconClass: function (item, opened) { return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon"; }, @@ -187,8 +236,12 @@ dojo.declare("fox.FeedTree", dijit.Tree, { return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread"; }, getRowClass: function (item, opened) { - return (!item.error || item.error == '') ? "dijitTreeRow" : + var rc = (!item.error || item.error == '') ? "dijitTreeRow" : "dijitTreeRow Error"; + + if (item.unread > 0) rc += " Unread"; + + return rc; }, getLabel: function(item) { var name = String(item.name); @@ -200,17 +253,73 @@ dojo.declare("fox.FeedTree", dijit.Tree, { name = name.replace(/</g, "<"); name = name.replace(/>/g, ">"); - var label; + /* var label; if (item.unread > 0) { label = name + " (" + item.unread + ")"; } else { label = name; + } */ + + return name; + }, + expandParentNodes: function(feed, is_cat, list) { + try { + for (var i = 0; i < list.length; i++) { + var id = String(list[i].id); + var item = this._itemNodesMap[id]; + + if (item) { + item = item[0]; + this._expandNode(item); + } + } + } catch (e) { + exception_error("expandParentNodes", e); } + }, + findNodeParentsAndExpandThem: function(feed, is_cat, root, parents) { + // expands all parents of specified feed to properly mark it as active + // my fav thing about frameworks is doing everything myself + try { + var test_id = is_cat ? 'CAT:' + feed : 'FEED:' + feed; + + if (!root) { + if (!this.model || !this.model.store) return false; + + var items = this.model.store._arrayOfTopLevelItems; - return label; + for (var i = 0; i < items.length; i++) { + if (String(items[i].id) == test_id) { + this.expandParentNodes(feed, is_cat, parents); + } else { + this.findNodeParentsAndExpandThem(feed, is_cat, items[i], []); + } + } + } else { + if (root.items) { + parents.push(root); + + for (var i = 0; i < root.items.length; i++) { + if (String(root.items[i].id) == test_id) { + this.expandParentNodes(feed, is_cat, parents); + } else { + this.findNodeParentsAndExpandThem(feed, is_cat, root.items[i], parents.slice(0)); + } + } + } else { + if (String(root.id) == test_id) { + this.expandParentNodes(feed, is_cat, parents.slice(0)); + } + } + } + } catch (e) { + exception_error("findNodeParentsAndExpandThem", e); + } }, selectFeed: function(feed, is_cat) { + this.findNodeParentsAndExpandThem(feed, is_cat, false, false); + if (is_cat) treeNode = this._itemNodesMap['CAT:' + feed]; else @@ -243,8 +352,13 @@ dojo.declare("fox.FeedTree", dijit.Tree, { if (treeNode) { treeNode = treeNode[0]; - treeNode.expandoNode.src = src; - return true; + if (treeNode.loadingNode) { + treeNode.loadingNode.src = src; + return true; + } else { + treeNode.expandoNode.src = src; + return true; + } } return false; @@ -309,7 +423,7 @@ dojo.declare("fox.FeedTree", dijit.Tree, { var node = tree._itemNodesMap[id]; if (node) { - if (hide && unread == 0 && (bare_id > 0 || !show_special)) { + if (hide && unread == 0 && (bare_id > 0 || bare_id < _label_base_index || !show_special)) { Effect.Fade(node[0].rowNode, {duration : 0.3, queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }}); } else { diff --git a/js/PluginHost.js b/js/PluginHost.js new file mode 100644 index 000000000..668d215f9 --- /dev/null +++ b/js/PluginHost.js @@ -0,0 +1,34 @@ +// based on http://www.velvetcache.org/2010/08/19/a-simple-javascript-hooks-system + +var PluginHost = { + HOOK_ARTICLE_RENDERED: 1, + HOOK_ARTICLE_RENDERED_CDM: 2, + HOOK_ARTICLE_SET_ACTIVE: 3, + HOOK_FEED_SET_ACTIVE: 4, + HOOK_FEED_LOADED: 5, + HOOK_ARTICLE_EXPANDED: 6, + HOOK_ARTICLE_COLLAPSED: 7, + HOOK_PARAMS_LOADED: 8, + HOOK_RUNTIME_INFO_LOADED: 9, + hooks: [], + register: function (name, callback) { + if (typeof(this.hooks[name]) == 'undefined') + this.hooks[name] = []; + + this.hooks[name].push(callback); + }, + run: function (name, args) { + console.warn('PluginHost::run ' + name); + + if (typeof(this.hooks[name]) != 'undefined') + for (i = 0; i < this.hooks[name].length; i++) + if (!this.hooks[name][i](args)) break; + } +}; + +/* PluginHost.register(PluginHost.HOOK_ARTICLE_RENDERED, + function (args) { console.log('ARTICLE_RENDERED: ' + args); return true; }); + +PluginHost.register(PluginHost.HOOK_ARTICLE_RENDERED_CDM, + function (args) { console.log('ARTICLE_RENDERED_CDM: ' + args); return true; }); */ + diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js index afa2f445a..3546e30fb 100644 --- a/js/PrefFilterTree.js +++ b/js/PrefFilterTree.js @@ -1,6 +1,22 @@ dojo.provide("fox.PrefFilterTree"); dojo.require("lib.CheckBoxTree"); +dojo.require("dojo.data.ItemFileWriteStore"); + +dojo.declare("fox.PrefFilterStore", dojo.data.ItemFileWriteStore, { + + _saveEverything: function(saveCompleteCallback, saveFailedCallback, + newFileContentString) { + + dojo.xhrPost({ + url: "backend.php", + content: {op: "pref-filters", method: "savefilterorder", + payload: newFileContentString}, + error: saveFailedCallback, + load: saveCompleteCallback}); + }, + +}); dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, { _createTreeNode: function(args) { @@ -48,5 +64,17 @@ dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, { return (!item.error || item.error == '') ? "dijitTreeRow" : "dijitTreeRow Error"; }, + checkItemAcceptance: function(target, source, position) { + var item = dijit.getEnclosingWidget(target).item; + + // disable copying items + source.copyState = function() { return false; }; + + return position != 'over'; + }, + onDndDrop: function() { + this.inherited(arguments); + this.tree.model.store.save(); + }, }); diff --git a/js/feedlist.js b/js/feedlist.js index e227c9386..51082f827 100644 --- a/js/feedlist.js +++ b/js/feedlist.js @@ -88,8 +88,6 @@ function viewfeed(feed, method, is_cat, offset, background, infscroll_req) { _infscroll_request_sent = timestamp; } - - hideAuxDlg(); } Form.enable("main_toolbar_form"); @@ -125,24 +123,23 @@ function viewfeed(feed, method, is_cat, offset, background, infscroll_req) { 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 { + if (!setFeedExpandoIcon(feed, is_cat, + (is_cat) ? 'images/indicator_tiny.gif' : 'images/indicator_white.gif')) notify_progress("Loading, please wait...", true); - } } query += "&cat=" + is_cat; console.log(query); + setActiveFeedId(feed, is_cat); + 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); + PluginHost.run(PluginHost.HOOK_FEED_LOADED, [feed, is_cat]); } }); } catch (e) { @@ -154,7 +151,8 @@ function feedlist_init() { try { console.log("in feedlist init"); - hideOrShowFeeds(getInitParam("hide_read_feeds") == 1); + loading_set_progress(50); + document.onkeydown = hotkey_handler; setTimeout("hotkey_prefix_timeout()", 5*1000); @@ -211,23 +209,6 @@ function request_counters(force) { } } -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++) { @@ -250,10 +231,6 @@ function parse_counters(elems, scheduled_call) { continue; } - if (id == getActiveFeedId() && ctr > getFeedUnread(id) && scheduled_call) { - displayNewContentPrompt(id); - } - if (getFeedUnread(id, (kind == "cat")) != ctr || (kind == "cat")) { } @@ -408,8 +385,8 @@ function getNextUnreadFeed(feed, is_cat) { } } -function catchupCurrentFeed() { - return catchupFeed(getActiveFeedId(), activeFeedIsCat()); +function catchupCurrentFeed(mode) { + catchupFeed(getActiveFeedId(), activeFeedIsCat(), mode); } function catchupFeedInGroup(id) { @@ -428,11 +405,26 @@ function catchupFeedInGroup(id) { } } -function catchupFeed(feed, is_cat) { +function catchupFeed(feed, is_cat, mode) { try { if (is_cat == undefined) is_cat = false; - var str = __("Mark all articles in %s as read?"); + var str = false; + + switch (mode) { + case "1day": + str = __("Mark all articles in %s older than 1 day as read?"); + break; + case "1week": + str = __("Mark all articles in %s older than 1 week as read?"); + break; + case "2week": + str = __("Mark all articles in %s older than 2 weeks as read?"); + break; + default: + str = __("Mark all articles in %s as read?"); + } + var fn = getFeedName(feed, is_cat); str = str.replace("%s", fn); @@ -441,20 +433,8 @@ function catchupFeed(feed, is_cat) { return; } - var max_id = 0; - - if (feed == getActiveFeedId() && is_cat == activeFeedIsCat()) { - $$("#headlines-frame > div[id*=RROW]").each( - function(child) { - var id = parseInt(child.id.replace("RROW-", "")); - - if (id > max_id) max_id = id; - } - ); - } - var catchup_query = "?op=rpc&method=catchupFeed&feed_id=" + - feed + "&is_cat=" + is_cat + "&max_id=" + max_id; + feed + "&is_cat=" + is_cat + "&mode=" + mode; console.log(catchup_query); @@ -465,15 +445,6 @@ function catchupFeed(feed, is_cat) { onComplete: function(transport) { handle_rpc_json(transport); - if (feed == getActiveFeedId() && is_cat == activeFeedIsCat()) { - - $$("#headlines-frame > div[id*=RROW][class*=Unread]").each( - function(child) { - child.removeClassName("Unread"); - } - ); - } - var show_next_feed = getInitParam("on_catchup_show_next_feed") == "1"; if (show_next_feed) { @@ -482,6 +453,10 @@ function catchupFeed(feed, is_cat) { if (nuf) { viewfeed(nuf, '', is_cat); } + } else { + if (feed == getActiveFeedId() && is_cat == activeFeedIsCat()) { + viewCurrentFeed(); + } } notify(""); @@ -518,3 +493,5 @@ function decrementFeedCounter(feed, is_cat) { exception_error("decrement_feed_counter", e); } } + + diff --git a/js/functions.js b/js/functions.js index 72f72ddaa..8691c1ee5 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1,7 +1,8 @@ -var notify_silent = false; var loading_progress = 0; var sanity_check_done = false; var init_params = {}; +var _label_base_index = -1024; +var notify_hide_timerid = false; Ajax.Base.prototype.initialize = Ajax.Base.prototype.initialize.wrap( function (callOriginal, options) { @@ -49,6 +50,21 @@ function exception_error(location, e, ext_info) { } } + try { + new Ajax.Request("backend.php", { + parameters: {op: "rpc", method: "log", logmsg: msg}, + onComplete: function (transport) { + console.log(transport.responseText); + } }); + + } catch (eii) { + console.log("Exception while trying to log the error."); + console.log(eii); + } + + msg += "<p>"+ __("The error will be reported to the configured log destination.") + + "</p>"; + var content = "<div class=\"fatalError\">" + "<pre>" + msg + "</pre>"; @@ -105,7 +121,28 @@ function exception_error(location, e, ext_info) { dialog.show(); - } catch (e) { + } catch (ei) { + console.log("Exception while trying to report an exception. Oh boy."); + console.log(ei); + console.log("Original exception:"); + console.log(e); + + msg += "\n\nAdditional exception caught while trying to show the error dialog.\n\n" + format_exception_error('exception_error', ei); + + try { + new Ajax.Request("backend.php", { + parameters: {op: "rpc", method: "log", logmsg: msg}, + onComplete: function (transport) { + console.log(transport.responseText); + } }); + + } catch (eii) { + console.log("Third exception while trying to log the error! Seriously?"); + console.log(eii); + } + + msg += "\n\nThe error will be reported to the configured log destination."; + alert(msg); } @@ -146,42 +183,28 @@ function param_unescape(arg) { 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; + Element.hide('notify'); } 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 (!n) return; if (notify_hide_timerid) { window.clearTimeout(notify_hide_timerid); } if (msg == "") { - if (n.style.display == "block") { + if (Element.visible(n)) { notify_hide_timerid = window.setTimeout("hide_notify()", 0); } return; } else { - n.style.display = "block"; + Element.show(n); } /* types: @@ -193,29 +216,31 @@ function notify_real(msg, no_hide, n_type) { */ - if (typeof __ != 'undefined') { - msg = __(msg); - } + msg = "<span class=\"msg\"> " + __(msg) + "</span>"; if (n_type == 1) { n.className = "notify"; } else if (n_type == 2) { - n.className = "notifyProgress"; - msg = "<img src='"+getInitParam("sign_progress")+"'> " + msg; + n.className = "notify progress"; + msg = "<span><img src='images/indicator_white.gif'></span>" + msg; + no_hide = true; } else if (n_type == 3) { - n.className = "notifyError"; - msg = "<img src='"+getInitParam("sign_excl")+"'> " + msg; + n.className = "notify error"; + msg = "<span><img src='images/sign_excl.svg'></span>" + msg; } else if (n_type == 4) { - n.className = "notifyInfo"; - msg = "<img src='"+getInitParam("sign_info")+"'> " + msg; + n.className = "notify info"; + msg = "<span><img src='images/sign_info.svg'></span>" + msg; } + msg += " <span><img src=\"images/close_notify.svg\" class=\"close\" title=\"" + + __("Click to close") + "\" onclick=\"notify('')\"></span>"; + // msg = "<img src='images/live_com_loading.gif'> " + msg; - nb.innerHTML = msg; + n.innerHTML = msg; if (!no_hide) { - notify_hide_timerid = window.setTimeout("hide_notify()", 3000); + notify_hide_timerid = window.setTimeout("hide_notify()", 5*1000); } } @@ -363,6 +388,9 @@ function toggleSelectRow2(sender, row, is_cdm) { row.addClassName('Selected'); else row.removeClassName('Selected'); + + if (typeof updateSelectedPrompt != undefined) + updateSelectedPrompt(); } @@ -374,6 +402,9 @@ function toggleSelectRow(sender, row) { row.addClassName('Selected'); else row.removeClassName('Selected'); + + if (typeof updateSelectedPrompt != undefined) + updateSelectedPrompt(); } function checkboxToggleElement(elem, id) { @@ -410,7 +441,7 @@ function closeInfoBox(cleanup) { } -function displayDlg(id, param, callback) { +function displayDlg(title, id, param, callback) { notify_progress("Loading, please wait...", true); @@ -420,14 +451,14 @@ function displayDlg(id, param, callback) { new Ajax.Request("backend.php", { parameters: query, onComplete: function (transport) { - infobox_callback2(transport); + infobox_callback2(transport, title); if (callback) callback(transport); } }); return false; } -function infobox_callback2(transport) { +function infobox_callback2(transport, title) { try { var dialog = false; @@ -438,13 +469,7 @@ function infobox_callback2(transport) { //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; + var content = transport.responseText; if (!dialog) { dialog = new dijit.Dialog({ @@ -509,7 +534,7 @@ function fatalError(code, msg, ext_info) { if (code == 6) { window.location.href = "index.php"; } else if (code == 5) { - window.location.href = "db-updater.php"; + window.location.href = "public.php?op=dbupdate"; } else { if (msg == "") msg = "Unknown error"; @@ -549,28 +574,6 @@ function fatalError(code, msg, ext_info) { } } -/* 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 { @@ -604,37 +607,9 @@ function filterDlgCheckAction(sender) { } -function filterDlgCheckDate() { - try { - var dialog = dijit.byId("filterEditDlg"); - - var reg_exp = dialog.attr('value').reg_exp; - - var query = "?op=rpc&method=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); + return displayDlg(__("Error explained"), "explainError", code); } function loading_set_progress(p) { @@ -712,15 +687,6 @@ function hotkey_prefix_timeout() { } } -function hideAuxDlg() { - try { - Element.hide('auxDlg'); - } catch (e) { - exception_error("hideAuxDlg", e); - } -} - - function uploadIconHandler(rc) { try { switch (rc) { @@ -840,7 +806,7 @@ function addLabel(select, callback) { function quickAddFeed() { try { - var query = "backend.php?op=dlg&method=quickAddFeed"; + var query = "backend.php?op=feeds&method=quickAddFeed"; // overlapping widgets if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive(); @@ -870,7 +836,7 @@ function quickAddFeed() { notify(''); Element.hide("feed_add_spinner"); - console.log("GOT RC: " + rc); + console.log(rc); switch (parseInt(rc['code'])) { case 1: @@ -886,39 +852,6 @@ function quickAddFeed() { 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&method=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; */ - feeds = rc['feeds']; var select = dijit.byId("feedDlg_feedContainerSelect"); @@ -926,6 +859,8 @@ function quickAddFeed() { while (select.getOptions().length > 0) select.removeOption(0); + select.addOption({value: '', label: __("Expand to select feed")}); + var count = 0; for (var feedUrl in feeds) { select.addOption({value: feedUrl, label: feeds[feedUrl]}); @@ -939,6 +874,11 @@ function quickAddFeed() { alert(__("Couldn't download the specified URL: %s"). replace("%s", rc['message'])); break; + case 6: + alert(__("XML validation failed: %s"). + replace("%s", rc['message'])); + break; + break; case 0: alert(__("You are already subscribed to this feed.")); break; @@ -964,6 +904,8 @@ function createNewRuleElement(parentNode, replaceNode) { try { var form = document.forms["filter_new_rule_form"]; + form.reg_exp.value = form.reg_exp.value.replace(/(<([^>]+)>)/ig,""); + var query = "backend.php?op=pref-filters&method=printrulename&rule="+ param_escape(dojo.formToJson(form)); @@ -1209,20 +1151,31 @@ function quickAddFilter() { var lh = dojo.connect(dialog, "onLoad", function(){ dojo.disconnect(lh); - var title = $("PTITLE-FULL-" + getActiveArticleId()); + var query = "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId(); - if (title || getActiveFeedId() || activeFeedIsCat()) { - if (title) title = title.innerHTML; + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + var reply = JSON.parse(transport.responseText); - console.log(title + " " + getActiveFeedId()); + var title = false; - var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) : - getActiveFeedId(); + if (reply && reply) title = reply.title; - var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 }; + if (title || getActiveFeedId() || activeFeedIsCat()) { + + console.log(title + " " + getActiveFeedId()); + + var feed_id = activeFeedIsCat() ? 'CAT:' + parseInt(getActiveFeedId()) : + getActiveFeedId(); + + var rule = { reg_exp: title, feed_id: feed_id, filter_type: 1 }; + + addFilterRule(null, dojo.toJson(rule)); + } + + } }); - addFilterRule(null, dojo.toJson(rule)); - } }); } @@ -1316,14 +1269,17 @@ function backend_sanity_check_callback(transport) { if (params) { console.log('reading init-params...'); - if (params) { - for (k in params) { - var v = params[k]; - console.log("IP: " + k + " => " + v); - } + for (k in params) { + var v = params[k]; + console.log("IP: " + k + " => " + v); + + if (k == "label_base_index") _label_base_index = parseInt(v); } init_params = params; + + // PluginHost might not be available on non-index pages + window.PluginHost && PluginHost.run(PluginHost.HOOK_PARAMS_LOADED, init_params); } sanity_check_done = true; @@ -1402,7 +1358,7 @@ function genUrlChangeKey(feed, is_cat) { notify_progress("Trying to change address...", true); - var query = "?op=rpc&method=regenFeedKey&id=" + param_escape(feed) + + var query = "?op=pref-feeds&method=regenFeedKey&id=" + param_escape(feed) + "&is_cat=" + param_escape(is_cat); new Ajax.Request("backend.php", { @@ -1630,7 +1586,7 @@ function editFeed(feed, event) { function feedBrowser() { try { - var query = "backend.php?op=dlg&method=feedBrowser"; + var query = "backend.php?op=feeds&method=feedBrowser"; if (dijit.byId("feedAddDlg")) dijit.byId("feedAddDlg").hide(); @@ -1739,7 +1695,7 @@ function feedBrowser() { } }); }, removeFromArchive: function() { - var selected = this.getSelectedFeeds(); + var selected = this.getSelectedFeedIds(); if (selected.length > 0) { @@ -1748,7 +1704,7 @@ function feedBrowser() { if (confirm(pr)) { Element.show('feed_browser_spinner'); - var query = "?op=rpc&method=remarchived&ids=" + + var query = "?op=rpc&method=remarchive&ids=" + param_escape(selected.toString());; new Ajax.Request("backend.php", { @@ -1906,3 +1862,75 @@ function helpDialog(topic) { } } +function htmlspecialchars_decode (string, quote_style) { + // http://kevin.vanzonneveld.net + // + original by: Mirek Slugen + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Mateusz "loonquawl" Zalega + // + input by: ReverseSyntax + // + input by: Slawomir Kaniecki + // + input by: Scott Cariss + // + input by: Francois + // + bugfixed by: Onno Marsman + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Ratheous + // + input by: Mailfaker (http://www.weedem.fr/) + // + reimplemented by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // * example 1: htmlspecialchars_decode("<p>this -> "</p>", 'ENT_NOQUOTES'); + // * returns 1: '<p>this -> "</p>' + // * example 2: htmlspecialchars_decode("&quot;"); + // * returns 2: '"' + var optTemp = 0, + i = 0, + noquotes = false; + if (typeof quote_style === 'undefined') { + quote_style = 2; + } + string = string.toString().replace(/</g, '<').replace(/>/g, '>'); + var OPTS = { + 'ENT_NOQUOTES': 0, + 'ENT_HTML_QUOTE_SINGLE': 1, + 'ENT_HTML_QUOTE_DOUBLE': 2, + 'ENT_COMPAT': 2, + 'ENT_QUOTES': 3, + 'ENT_IGNORE': 4 + }; + if (quote_style === 0) { + noquotes = true; + } + if (typeof quote_style !== 'number') { // Allow for a single string or an array of string flags + quote_style = [].concat(quote_style); + for (i = 0; i < quote_style.length; i++) { + // Resolve string input to bitwise e.g. 'PATHINFO_EXTENSION' becomes 4 + if (OPTS[quote_style[i]] === 0) { + noquotes = true; + } else if (OPTS[quote_style[i]]) { + optTemp = optTemp | OPTS[quote_style[i]]; + } + } + quote_style = optTemp; + } + if (quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) { + string = string.replace(/�*39;/g, "'"); // PHP doesn't currently escape if more than one 0, but it should + // string = string.replace(/'|�*27;/g, "'"); // This would also be useful here, but not a part of PHP + } + if (!noquotes) { + string = string.replace(/"/g, '"'); + } + // Put this in last place to avoid escape being double-decoded + string = string.replace(/&/g, '&'); + + return string; +} + + +function label_to_feed_id(label) { + return _label_base_index - 1 - Math.abs(label); +} + +function feed_to_label_id(feed) { + return _label_base_index - 1 + Math.abs(feed); +} + diff --git a/js/index.html b/js/index.html new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/index.html diff --git a/js/prefs.js b/js/prefs.js index 676fb914a..e226459fc 100644 --- a/js/prefs.js +++ b/js/prefs.js @@ -91,7 +91,7 @@ function editUser(id, event) { new Ajax.Request("backend.php", { parameters: query, onComplete: function(transport) { - infobox_callback2(transport); + infobox_callback2(transport, __("User Editor")); document.forms['user_edit_form'].login.focus(); } }); @@ -547,7 +547,7 @@ function resetSelectedUserPass() { new Ajax.Request("backend.php", { parameters: query, onComplete: function(transport) { - notify_info(transport.responseText); + notify_info(transport.responseText, true); } }); } @@ -582,7 +582,7 @@ function selectedUserDetails() { new Ajax.Request("backend.php", { parameters: query, onComplete: function(transport) { - infobox_callback2(transport); + infobox_callback2(transport, __("User details")); } }); } catch (e) { exception_error("selectedUserDetails", e); @@ -722,6 +722,13 @@ function editSelectedFeeds() { } } catch (e) { } + try { + if (!query.match("&hide_images=") && + this.getChildByName('hide_images').attr('disabled') == false) { + query = query + "&hide_images=false"; + } + } catch (e) { } + if (!query.match("&include_in_digest=") && this.getChildByName('include_in_digest').attr('disabled') == false) { query = query + "&include_in_digest=false"; @@ -760,18 +767,6 @@ function editSelectedFeeds() { } } -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; @@ -857,6 +852,15 @@ function updatePrefsList() { } }); } +function updateSystemList() { + new Ajax.Request("backend.php", { + parameters: "?op=pref-system", + onComplete: function(transport) { + dijit.byId('systemConfigTab').attr('content', transport.responseText); + notify(""); + } }); +} + function selectTab(id, noupdate, method) { try { if (!noupdate) { @@ -872,6 +876,8 @@ function selectTab(id, noupdate, method) { updatePrefsList(); } else if (id == "userConfig") { updateUsersList(); + } else if (id == "systemConfig") { + updateSystemList(); } var tab = dijit.byId(id + "Tab"); @@ -956,8 +962,11 @@ function init() { dojo.addOnLoad(function() { loading_set_progress(50); + var clientTzOffset = new Date().getTimezoneOffset() * 60; + new Ajax.Request("backend.php", { - parameters: {op: "rpc", method: "sanityCheck"}, + parameters: {op: "rpc", method: "sanityCheck", + clientTzOffset: clientTzOffset }, onComplete: function(transport) { backend_sanity_check_callback(transport); } }); @@ -980,13 +989,8 @@ function validatePrefsReset() { 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(); - } + updatePrefsList(); + notify_info(transport.responseText); } }); } @@ -1226,7 +1230,7 @@ function opmlRegenKey() { notify_progress("Trying to change address...", true); - var query = "?op=rpc&method=regenOPMLKey"; + var query = "?op=pref-feeds&method=regenOPMLKey"; new Ajax.Request("backend.php", { parameters: query, @@ -1405,7 +1409,7 @@ function editProfiles() { if (dijit.byId("profileEditDlg")) dijit.byId("profileEditDlg").destroyRecursive(); - var query = "backend.php?op=dlg&method=editPrefProfiles"; + var query = "backend.php?op=pref-prefs&method=editPrefProfiles"; dialog = new dijit.Dialog({ id: "profileEditDlg", @@ -1526,7 +1530,7 @@ function clearFeedAccessKeys() { if (ok) { notify_progress("Clearing URLs..."); - var query = "?op=rpc&method=clearKeys"; + var query = "?op=pref-feeds&method=clearKeys"; new Ajax.Request("backend.php", { parameters: query, @@ -1556,50 +1560,53 @@ function clearArticleAccessKeys() { return false; } -function resetFeedOrder() { + +function resetFilterOrder() { try { notify_progress("Loading, please wait..."); new Ajax.Request("backend.php", { - parameters: "?op=pref-feeds&method=feedsortreset", + parameters: "?op=pref-filters&method=filtersortreset", onComplete: function(transport) { - updateFeedList(); + updateFilterList(); } }); } catch (e) { - exception_error("resetFeedOrder"); + exception_error("resetFilterOrder"); } } -function resetCatOrder() { + +function resetFeedOrder() { try { notify_progress("Loading, please wait..."); new Ajax.Request("backend.php", { - parameters: "?op=pref-feeds&method=catsortreset", + parameters: "?op=pref-feeds&method=feedsortreset", onComplete: function(transport) { updateFeedList(); } }); } catch (e) { - exception_error("resetCatOrder"); + exception_error("resetFeedOrder"); } } -function toggleHiddenFeedCats() { +function resetCatOrder() { try { notify_progress("Loading, please wait..."); new Ajax.Request("backend.php", { - parameters: "?op=pref-feeds&method=togglehiddenfeedcats", + parameters: "?op=pref-feeds&method=catsortreset", onComplete: function(transport) { updateFeedList(); } }); + } catch (e) { - exception_error("toggleHiddenFeedCats"); + exception_error("resetCatOrder"); } } @@ -1699,31 +1706,10 @@ function editLabel(id, event) { } } -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&method=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&method=customizeCSS"; + var query = "backend.php?op=pref-prefs&method=customizeCSS"; if (dijit.byId("cssEditDlg")) dijit.byId("cssEditDlg").destroyRecursive(); @@ -1767,7 +1753,7 @@ function gotoExportOpml(filename, settings) { function batchSubscribe() { try { - var query = "backend.php?op=dlg&method=batchSubscribe"; + var query = "backend.php?op=pref-feeds&method=batchSubscribe"; // overlapping widgets if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive(); @@ -1832,3 +1818,21 @@ function clearPluginData(name) { exception_error("clearPluginData", e); } } + +function clearSqlLog() { + + if (confirm(__("Clear all messages in the error log?"))) { + + notify_progress("Loading, please wait..."); + var query = "?op=pref-system&method=clearLog"; + + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + updateSystemList(); + } }); + + } +} + + diff --git a/js/tt-rss.js b/js/tt-rss.js index badfe8707..e3731c0cb 100644 --- a/js/tt-rss.js +++ b/js/tt-rss.js @@ -1,6 +1,7 @@ var global_unread = -1; var hotkey_prefix = false; var hotkey_prefix_pressed = false; +var hotkey_actions = {}; var _widescreen_mode = false; var _rpc_seq = 0; var _active_feed_id = 0; @@ -35,7 +36,12 @@ function setActiveFeedId(id, is_cat) { _active_feed_id = id; _active_feed_is_cat = is_cat; + $("headlines-frame").setAttribute("feed-id", id); + $("headlines-frame").setAttribute("is-cat", is_cat ? 1 : 0); + selectFeed(id, is_cat); + + PluginHost.run(PluginHost.HOOK_FEED_SET_ACTIVE, _active_article_id); } catch (e) { exception_error("setActiveFeedId", e); } @@ -110,6 +116,7 @@ function updateFeedList() { tree.startup(); + } catch (e) { exception_error("updateFeedList", e); } @@ -130,7 +137,8 @@ function catchupAllFeeds() { new Ajax.Request("backend.php", { parameters: query_str, onComplete: function(transport) { - feedlist_callback2(transport); + request_counters(true); + viewCurrentFeed(); } }); global_unread = 0; @@ -155,7 +163,7 @@ function timeout() { } function search() { - var query = "backend.php?op=dlg&method=search¶m=" + + var query = "backend.php?op=feeds&method=search¶m=" + param_escape(getActiveFeedId() + ":" + activeFeedIsCat()); if (dijit.byId("searchDlg")) @@ -181,7 +189,7 @@ function updateTitle() { var tmp = "Tiny Tiny RSS"; if (global_unread > 0) { - tmp = tmp + " (" + global_unread + ")"; + tmp = "(" + global_unread + ") " + tmp; } if (window.fluid) { @@ -205,6 +213,7 @@ function genericSanityCheck() { return true; } + function init() { try { //dojo.registerModulePath("fox", "../../js/"); @@ -241,16 +250,291 @@ function init() { if (!genericSanityCheck()) return false; - loading_set_progress(20); + loading_set_progress(30); + + var a = document.createElement('audio'); - var hasAudio = !!((myAudioTag = document.createElement('audio')).canPlayType); + var hasAudio = !!a.canPlayType; + var hasSandbox = "sandbox" in document.createElement("iframe"); + var hasMp3 = !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, '')); + var clientTzOffset = new Date().getTimezoneOffset() * 60; new Ajax.Request("backend.php", { - parameters: {op: "rpc", method: "sanityCheck", hasAudio: hasAudio}, + parameters: {op: "rpc", method: "sanityCheck", hasAudio: hasAudio, + hasMp3: hasMp3, + clientTzOffset: clientTzOffset, + hasSandbox: hasSandbox}, onComplete: function(transport) { backend_sanity_check_callback(transport); } }); + hotkey_actions["next_feed"] = function() { + var rv = dijit.byId("feedTree").getNextFeed( + getActiveFeedId(), activeFeedIsCat()); + + if (rv) viewfeed(rv[0], '', rv[1]); + }; + hotkey_actions["prev_feed"] = function() { + var rv = dijit.byId("feedTree").getPreviousFeed( + getActiveFeedId(), activeFeedIsCat()); + + if (rv) viewfeed(rv[0], '', rv[1]); + }; + hotkey_actions["next_article"] = function() { + moveToPost('next'); + }; + hotkey_actions["prev_article"] = function() { + moveToPost('prev'); + }; + hotkey_actions["next_article_noscroll"] = function() { + moveToPost('next', true); + }; + hotkey_actions["prev_article_noscroll"] = function() { + moveToPost('prev', true); + }; + hotkey_actions["next_article_noexpand"] = function() { + moveToPost('next', true, true); + }; + hotkey_actions["prev_article_noexpand"] = function() { + moveToPost('prev', true, true); + }; + hotkey_actions["collapse_article"] = function() { + var id = getActiveArticleId(); + var elem = $("CICD-"+id); + if(elem.visible()) { + cdmCollapseArticle(null, id); + } + else { + cdmExpandArticle(id); + } + }; + hotkey_actions["toggle_expand"] = function() { + var id = getActiveArticleId(); + var elem = $("CICD-"+id); + if(elem.visible()) { + cdmCollapseArticle(null, id, false); + } + else { + cdmExpandArticle(id); + } + }; + hotkey_actions["search_dialog"] = function() { + search(); + }; + hotkey_actions["toggle_mark"] = function() { + selectionToggleMarked(undefined, false, true); + }; + hotkey_actions["toggle_publ"] = function() { + selectionTogglePublished(undefined, false, true); + }; + hotkey_actions["toggle_unread"] = function() { + selectionToggleUnread(undefined, false, true); + }; + hotkey_actions["edit_tags"] = function() { + var id = getActiveArticleId(); + if (id) { + editArticleTags(id); + }; + } + hotkey_actions["dismiss_selected"] = function() { + dismissSelectedArticles(); + }; + hotkey_actions["open_in_new_window"] = function() { + if (getActiveArticleId()) { + openArticleInNewWindow(getActiveArticleId()); + return; + } + }; + hotkey_actions["catchup_below"] = function() { + catchupRelativeToArticle(1); + }; + hotkey_actions["catchup_above"] = function() { + catchupRelativeToArticle(0); + }; + hotkey_actions["article_scroll_down"] = function() { + var ctr = $("content_insert") ? $("content_insert") : $("headlines-frame"); + + scrollArticle(40); + }; + hotkey_actions["article_scroll_up"] = function() { + var ctr = $("content_insert") ? $("content_insert") : $("headlines-frame"); + + scrollArticle(-40); + }; + hotkey_actions["close_article"] = function() { + if (isCdmMode()) { + if (!getInitParam("cdm_expanded")) { + cdmCollapseArticle(false, getActiveArticleId()); + } else { + dismissArticle(getActiveArticleId()); + } + } else { + closeArticlePanel(); + } + }; + hotkey_actions["email_article"] = function() { + if (typeof emailArticle != "undefined") { + emailArticle(); + } else if (typeof mailtoArticle != "undefined") { + mailtoArticle(); + } else { + alert(__("Please enable mail plugin first.")); + } + }; + hotkey_actions["select_all"] = function() { + selectArticles('all'); + }; + hotkey_actions["select_unread"] = function() { + selectArticles('unread'); + }; + hotkey_actions["select_marked"] = function() { + selectArticles('marked'); + }; + hotkey_actions["select_published"] = function() { + selectArticles('published'); + }; + hotkey_actions["select_invert"] = function() { + selectArticles('invert'); + }; + hotkey_actions["select_none"] = function() { + selectArticles('none'); + }; + hotkey_actions["feed_refresh"] = function() { + if (getActiveFeedId() != undefined) { + viewfeed(getActiveFeedId(), '', activeFeedIsCat()); + return; + } + }; + hotkey_actions["feed_unhide_read"] = function() { + toggleDispRead(); + }; + hotkey_actions["feed_subscribe"] = function() { + quickAddFeed(); + }; + hotkey_actions["feed_debug_update"] = function() { + window.open("backend.php?op=feeds&method=view&feed=" + getActiveFeedId() + + "&view_mode=adaptive&order_by=default&update=&m=ForceUpdate&cat=" + + activeFeedIsCat() + "&DevForceUpdate=1&debug=1&xdebug=1&csrf_token=" + + getInitParam("csrf_token")); + }; + hotkey_actions["feed_edit"] = function() { + if (activeFeedIsCat()) + alert(__("You can't edit this kind of feed.")); + else + editFeed(getActiveFeedId()); + }; + hotkey_actions["feed_catchup"] = function() { + if (getActiveFeedId() != undefined) { + catchupCurrentFeed(); + return; + } + }; + hotkey_actions["feed_reverse"] = function() { + reverseHeadlineOrder(); + }; + hotkey_actions["catchup_all"] = function() { + catchupAllFeeds(); + }; + hotkey_actions["cat_toggle_collapse"] = function() { + if (activeFeedIsCat()) { + dijit.byId("feedTree").collapseCat(getActiveFeedId()); + return; + } + }; + hotkey_actions["goto_all"] = function() { + viewfeed(-4); + }; + hotkey_actions["goto_fresh"] = function() { + viewfeed(-3); + }; + hotkey_actions["goto_marked"] = function() { + viewfeed(-1); + }; + hotkey_actions["goto_published"] = function() { + viewfeed(-2); + }; + hotkey_actions["goto_tagcloud"] = function() { + displayDlg(__("Tag cloud"), "printTagCloud"); + }; + hotkey_actions["goto_prefs"] = function() { + gotoPreferences(); + }; + hotkey_actions["select_article_cursor"] = function() { + var id = getArticleUnderPointer(); + if (id) { + var row = $("RROW-" + id); + + if (row) { + var cb = dijit.getEnclosingWidget( + row.getElementsByClassName("rchk")[0]); + + if (cb) { + cb.attr("checked", !cb.attr("checked")); + toggleSelectRowById(cb, "RROW-" + id); + return false; + } + } + } + }; + hotkey_actions["create_label"] = function() { + addLabel(); + }; + hotkey_actions["create_filter"] = function() { + quickAddFilter(); + }; + hotkey_actions["collapse_sidebar"] = function() { + collapse_feedlist(); + }; + hotkey_actions["toggle_embed_original"] = function() { + if (typeof embedOriginalArticle != "undefined") { + if (getActiveArticleId()) + embedOriginalArticle(getActiveArticleId()); + } else { + alert(__("Please enable embed_original plugin first.")); + } + }; + hotkey_actions["toggle_widescreen"] = function() { + if (!isCdmMode()) { + _widescreen_mode = !_widescreen_mode; + + switchPanelMode(_widescreen_mode); + } + }; + hotkey_actions["help_dialog"] = function() { + helpDialog("main"); + }; + hotkey_actions["toggle_combined_mode"] = function() { + notify_progress("Loading, please wait..."); + + var value = isCdmMode() ? "false" : "true"; + var query = "?op=rpc&method=setpref&key=COMBINED_DISPLAY_MODE&value=" + value; + + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + setInitParam("combined_display_mode", + !getInitParam("combined_display_mode")); + + closeArticlePanel(); + viewCurrentFeed(); + + } }); + }; + hotkey_actions["toggle_cdm_expanded"] = function() { + notify_progress("Loading, please wait..."); + + var value = getInitParam("cdm_expanded") ? "false" : "true"; + var query = "?op=rpc&method=setpref&key=CDM_EXPANDED&value=" + value; + + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + setInitParam("cdm_expanded", !getInitParam("cdm_expanded")); + viewCurrentFeed(); + } }); + }; + + } catch (e) { exception_error("init", e); } @@ -264,11 +548,37 @@ function init_second_stage() { closeArticlePanel(); _widescreen_mode = getInitParam("widescreen"); + switchPanelMode(_widescreen_mode); - if (_widescreen_mode) { - switchPanelMode(_widescreen_mode); + if (parseInt(getCookie("ttrss_fh_width")) > 0) { + dijit.byId("feeds-holder").domNode.setStyle( + {width: getCookie("ttrss_fh_width") + "px" }); } + if (parseInt(getCookie("ttrss_ci_width")) > 0) { + if (_widescreen_mode) { + dijit.byId("content-insert").domNode.setStyle( + {width: getCookie("ttrss_ci_width") + "px" }); + + } else { + dijit.byId("content-insert").domNode.setStyle( + {height: getCookie("ttrss_ci_height") + "px" }); + } + } + + dijit.byId("main").resize(); + + var tmph = dojo.connect(dijit.byId('feeds-holder'), 'resize', + function (args) { + setCookie("ttrss_fh_width", args.w, getInitParam("cookie_lifetime")); + }); + + var tmph = dojo.connect(dijit.byId('content-insert'), 'resize', + function (args) { + setCookie("ttrss_ci_width", args.w, getInitParam("cookie_lifetime")); + setCookie("ttrss_ci_height", args.h, getInitParam("cookie_lifetime")); + }); + }); delCookie("ttrss_test"); @@ -290,7 +600,7 @@ function init_second_stage() { setActiveFeedId(hash_feed_id, hash_feed_is_cat); } - loading_set_progress(30); + loading_set_progress(50); // can't use cache_clear() here because viewfeed might not have initialized yet if ('sessionStorage' in window && window['sessionStorage'] !== null) @@ -329,10 +639,10 @@ function quickMenuGo(opid) { gotoLogout(); break; case "qmcTagCloud": - displayDlg("printTagCloud"); + displayDlg(__("Tag cloud"), "printTagCloud"); break; case "qmcTagSelect": - displayDlg("printTagSelect"); + displayDlg(__("Select item(s) by tags"), "printTagSelect"); break; case "qmcSearch": search(); @@ -444,6 +754,12 @@ function parse_runtime_info(data) { return; } + if (k == "dep_ts" && parseInt(getInitParam("dep_ts")) > 0) { + if (parseInt(getInitParam("dep_ts")) < parseInt(v) && getInitParam("reload_on_ts_change")) { + window.location.reload(); + } + } + if (k == "daemon_is_running" && v != 1) { notify_error("<span onclick=\"javascript:explainError(1)\">Update daemon is not running.</span>", true); return; @@ -464,6 +780,8 @@ function parse_runtime_info(data) { init_params[k] = v; notify(''); } + + PluginHost.run(PluginHost.HOOK_RUNTIME_INFO_LOADED, data); } function collapse_feedlist() { @@ -494,10 +812,6 @@ function viewModeChanged() { return viewCurrentFeed(''); } -function viewLimitChanged() { - return viewCurrentFeed(''); -} - function rescoreCurrentFeed() { var actid = getActiveFeedId(); @@ -556,7 +870,7 @@ function hotkey_handler(e) { if (keycode == 16) return; // ignore lone shift if (keycode == 17) return; // ignore lone ctrl - if (!shift_key) keychar = keychar.toLowerCase(); + keychar = keychar.toLowerCase(); var hotkeys = getInitParam("hotkeys"); @@ -577,7 +891,11 @@ function hotkey_handler(e) { Element.hide(cmdline); var hotkey = keychar.search(/[a-zA-Z0-9]/) != -1 ? keychar : "(" + keycode + ")"; + + // ensure ^*char notation + if (shift_key) hotkey = "*" + hotkey; if (ctrl_key) hotkey = "^" + hotkey; + hotkey = hotkey_prefix ? hotkey_prefix + " " + hotkey : hotkey; hotkey_prefix = false; @@ -591,206 +909,11 @@ function hotkey_handler(e) { } } - switch (hotkey_action) { - case "next_feed": - var rv = dijit.byId("feedTree").getNextFeed( - getActiveFeedId(), activeFeedIsCat()); - - if (rv) viewfeed(rv[0], '', rv[1]); - return false; - case "prev_feed": - var rv = dijit.byId("feedTree").getPreviousFeed( - getActiveFeedId(), activeFeedIsCat()); + var action = hotkey_actions[hotkey_action]; - if (rv) viewfeed(rv[0], '', rv[1]); - return false; - case "next_article": - moveToPost('next'); - return false; - case "prev_article": - moveToPost('prev'); - return false; - case "next_article_noscroll": - moveToPost('next', true); - return false; - case "prev_article_noscroll": - moveToPost('prev', true); - return false; - case "search_dialog": - search(); - return ; - case "toggle_mark": - selectionToggleMarked(undefined, false, true); - return false; - case "toggle_publ": - selectionTogglePublished(undefined, false, true); - return false; - case "toggle_unread": - selectionToggleUnread(undefined, false, true); - return false; - case "edit_tags": - var id = getActiveArticleId(); - if (id) { - editArticleTags(id, getActiveFeedId(), isCdmMode()); - return; - } - return false; - case "dismiss_selected": - dismissSelectedArticles(); - return false; - case "dismiss_read": - return false; - case "open_in_new_window": - if (getActiveArticleId()) { - openArticleInNewWindow(getActiveArticleId()); - return; - } - return false; - case "catchup_below": - catchupRelativeToArticle(1); - return false; - case "catchup_above": - catchupRelativeToArticle(0); - return false; - case "article_scroll_down": - scrollArticle(50); - return false; - case "article_scroll_up": - scrollArticle(-50); - return false; - case "close_article": - closeArticlePanel(); - return false; - case "email_article": - if (typeof emailArticle != "undefined") { - emailArticle(); - } else { - alert(__("Please enable mail plugin first.")); - } - return false; - case "select_all": - selectArticles('all'); + if (action != null) { + action(); return false; - case "select_unread": - selectArticles('unread'); - return false; - case "select_marked": - selectArticles('marked'); - return false; - case "select_published": - selectArticles('published'); - return false; - case "select_invert": - selectArticles('invert'); - return false; - case "select_none": - selectArticles('none'); - return false; - case "feed_refresh": - if (getActiveFeedId() != undefined) { - viewfeed(getActiveFeedId(), '', activeFeedIsCat()); - return; - } - return false; - case "feed_unhide_read": - toggleDispRead(); - return false; - case "feed_subscribe": - quickAddFeed(); - return false; - case "feed_debug_update": - window.open("backend.php?op=feeds&method=view&feed=" + getActiveFeedId() + - "&view_mode=adaptive&order_by=default&update=&m=ForceUpdate&cat=" + - activeFeedIsCat() + "&DevForceUpdate=1&debug=1&xdebug=1&csrf_token=" + - getInitParam("csrf_token")); - return false; - case "feed_edit": - if (activeFeedIsCat()) - alert(__("You can't edit this kind of feed.")); - else - editFeed(getActiveFeedId()); - return false; - case "feed_catchup": - if (getActiveFeedId() != undefined) { - catchupCurrentFeed(); - return; - } - return false; - case "feed_reverse": - reverseHeadlineOrder(); - return false; - case "catchup_all": - catchupAllFeeds(); - return false; - case "cat_toggle_collapse": - if (activeFeedIsCat()) { - dijit.byId("feedTree").collapseCat(getActiveFeedId()); - return; - } - return false; - case "goto_all": - viewfeed(-4); - return false; - case "goto_fresh": - viewfeed(-3); - return false; - case "goto_marked": - viewfeed(-1); - return false; - case "goto_published": - viewfeed(-2); - return false; - case "goto_tagcloud": - displayDlg("printTagCloud"); - return false; - case "goto_prefs": - gotoPreferences(); - return false; - case "select_article_cursor": - var id = getArticleUnderPointer(); - if (id) { - var cb = dijit.byId("RCHK-" + id); - if (cb) { - cb.attr("checked", !cb.attr("checked")); - toggleSelectRowById(cb, "RROW-" + id); - return false; - } - } - return false; - case "create_label": - addLabel(); - return false; - case "create_filter": - quickAddFilter(); - return false; - case "collapse_sidebar": - collapse_feedlist(); - return false; - case "toggle_widescreen": - if (!isCdmMode()) { - _widescreen_mode = !_widescreen_mode; - - switchPanelMode(_widescreen_mode); - } - return false; - case "help_dialog": - helpDialog("main"); - return false; - case "toggle_combined_mode": - notify_progress("Loading, please wait..."); - - var value = isCdmMode() ? "false" : "true"; - var query = "?op=rpc&method=setpref&key=COMBINED_DISPLAY_MODE&value=" + value; - - new Ajax.Request("backend.php", { - parameters: query, - onComplete: function(transport) { - window.location.reload(); - } }); - - return false; - default: - console.log("unhandled action: " + hotkey_action + "; hotkey: " + hotkey); } } catch (e) { @@ -805,13 +928,27 @@ function inPreferences() { function reverseHeadlineOrder() { try { - var query_str = "?op=rpc&method=togglepref&key=REVERSE_HEADLINES"; + /* var query_str = "?op=rpc&method=togglepref&key=REVERSE_HEADLINES"; new Ajax.Request("backend.php", { parameters: query_str, onComplete: function(transport) { viewCurrentFeed(); - } }); + } }); */ + + var toolbar = document.forms["main_toolbar_form"]; + var order_by = dijit.getEnclosingWidget(toolbar.order_by); + + var value = order_by.attr('value'); + + if (value == "date_reverse") + value = "default"; + else + value = "date_reverse"; + + order_by.attr('value', value); + + viewCurrentFeed(); } catch (e) { exception_error("reverseHeadlineOrder", e); @@ -884,13 +1021,11 @@ function handle_rpc_json(transport, scheduled_call) { if (counters) parse_counters(counters, scheduled_call); - var runtime_info = reply['runtime-info'];; + var runtime_info = reply['runtime-info']; if (runtime_info) parse_runtime_info(runtime_info); - hideOrShowFeeds(getInitParam("hide_read_feeds") == 1); - Element.hide(dijit.byId("net-alert").domNode); } else { @@ -910,6 +1045,8 @@ function handle_rpc_json(transport, scheduled_call) { function switchPanelMode(wide) { try { + if (isCdmMode()) return; + article_id = getActiveArticleId(); if (wide) { @@ -923,6 +1060,7 @@ function switchPanelMode(wide) { borderTopWidth: '0px' }); $("headlines-toolbar").setStyle({ borderBottomWidth: '0px' }); + $("headlines-frame").setStyle({ borderBottomWidth: '0px' }); } else { @@ -934,6 +1072,8 @@ function switchPanelMode(wide) { borderTopWidth: '1px'}); $("headlines-toolbar").setStyle({ borderBottomWidth: '1px' }); + + $("headlines-frame").setStyle({ borderBottomWidth: '1px' }); } closeArticlePanel(); @@ -973,7 +1113,7 @@ function hash_get(key) { kv = window.location.hash.substring(1).toQueryParams(); return kv[key]; } catch (e) { - exception_error("hash_set", e); + exception_error("hash_get", e); } } function hash_set(key, value) { diff --git a/js/viewfeed.js b/js/viewfeed.js index 622a8109f..dc8d3fe88 100644 --- a/js/viewfeed.js +++ b/js/viewfeed.js @@ -12,6 +12,7 @@ var catchup_timeout_id = false; var cids_requested = []; var loaded_article_ids = []; +var _last_headlines_update = 0; var has_storage = 'sessionStorage' in window && window['sessionStorage'] !== null; @@ -19,8 +20,6 @@ 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; @@ -42,17 +41,16 @@ function headlines_callback2(transport, offset, background, infscroll_req) { if (background) { var content = reply['headlines']['content']; - if (getInitParam("cdm_auto_catchup") == 1) { - content = content + "<div id='headlines-spacer'></div>"; - } + content = content + "<div id='headlines-spacer'></div>"; return; } - setActiveFeedId(feed_id, is_cat); + if (feed_id != getActiveFeedId() || is_cat != activeFeedIsCat()) + return; - dijit.getEnclosingWidget( + /* dijit.getEnclosingWidget( document.forms["main_toolbar_form"].update).attr('disabled', - is_cat || feed_id <= 0); + is_cat || feed_id <= 0); */ try { if (infscroll_req == false) { @@ -60,11 +58,16 @@ function headlines_callback2(transport, offset, background, infscroll_req) { } } catch (e) { }; + $("headlines-frame").removeClassName("cdm"); + $("headlines-frame").removeClassName("normal"); + + $("headlines-frame").addClassName(isCdmMode() ? "cdm" : "normal"); + var headlines_count = reply['headlines-info']['count']; vgroup_last_feed = reply['headlines-info']['vgroup_last_feed']; - if (parseInt(headlines_count) < getInitParam("default_article_limit")) { + if (parseInt(headlines_count) < 30) { _infscroll_disable = 1; } else { _infscroll_disable = 0; @@ -91,11 +94,9 @@ function headlines_callback2(transport, offset, background, infscroll_req) { } }); - 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); - } + var hsp = $("headlines-spacer"); + if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"}); + dijit.byId('headlines-frame').domNode.appendChild(hsp); initHeadlinesMenu(); @@ -138,8 +139,6 @@ function headlines_callback2(transport, offset, background, infscroll_req) { if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"}); - fixHeadlinesOrder(getLoadedArticleIds()); - if (getInitParam("cdm_auto_catchup") == 1) { c.domNode.appendChild(hsp); } @@ -158,16 +157,10 @@ function headlines_callback2(transport, offset, background, infscroll_req) { initHeadlinesMenu(); new_elems.each(function(child) { - var cb = dijit.byId(child.id.replace("RROW-", "RCHK-")); - - if (!cb) { - dojo.parser.parse(child); + dojo.parser.parse(child); - if (!Element.visible(child)) - new Effect.Appear(child, { duration : 0.5 }); - } else { - c.domNode.removeChild(child); - } + if (!Element.visible(child)) + new Effect.Appear(child, { duration : 0.5 }); }); } else { @@ -204,6 +197,19 @@ function headlines_callback2(transport, offset, background, infscroll_req) { } _infscroll_request_sent = 0; + _last_headlines_update = new Date().getTime(); + + unpackVisibleHeadlines(); + + // if we have some more space in the buffer, why not try to fill it + + if (!_infscroll_disable && $("headlines-spacer") && + $("headlines-spacer").offsetTop < $("headlines-frame").offsetHeight) { + + window.setTimeout(function() { + loadMoreHeadlines(); + }, 250); + } notify(""); @@ -223,6 +229,8 @@ function render_article(article) { c.domNode.scrollTop = 0; } catch (e) { }; + PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED, article); + c.attr('content', article); correctHeadlinesOffset(getActiveArticleId()); @@ -236,10 +244,9 @@ function render_article(article) { } } -function showArticleInHeadlines(id) { +function showArticleInHeadlines(id, noexpand) { try { - selectArticles("none"); var crow = $("RROW-" + id); @@ -248,7 +255,9 @@ function showArticleInHeadlines(id) { var article_is_unread = crow.hasClassName("Unread"); - crow.removeClassName("Unread"); + if (!noexpand) + crow.removeClassName("Unread"); + crow.addClassName("active"); selectArticles('none'); @@ -263,7 +272,7 @@ function showArticleInHeadlines(id) { markHeadline(id); - if (article_is_unread) + if (article_is_unread && !noexpand) _force_scheduled_update = true; } catch (e) { @@ -313,7 +322,7 @@ function article_callback2(transport, id) { var unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length request_counters(unread_in_buffer == 0); - headlines_scroll_handler($("headlines-frame")); + //headlines_scroll_handler($("headlines-frame")); /* try { if (!_infscroll_disable && @@ -331,11 +340,19 @@ function article_callback2(transport, id) { } } -function view(id) { +function view(id, activefeed, noexpand) { try { + var oldrow = $("RROW-" + getActiveArticleId()); + if (oldrow) oldrow.removeClassName("active"); + var crow = $("RROW-" + id); if (!crow) return; + if (noexpand) { + setActiveArticleId(id); + showArticleInHeadlines(id, noexpand); + return; + } console.log("loading article: " + id); @@ -343,8 +360,6 @@ function view(id) { console.log("cache check result: " + (cached_article != false)); - hideAuxDlg(); - var query = "?op=article&method=view&id=" + param_escape(id); var neighbor_ids = getRelativePostIds(id); @@ -395,7 +410,7 @@ function view(id) { console.warn(e); } */ - headlines_scroll_handler($("headlines-frame")); + //headlines_scroll_handler($("headlines-frame")); return; } @@ -426,21 +441,27 @@ function toggleMark(id, client_only) { try { var query = "?op=rpc&id=" + id + "&method=mark"; - var img = $("FMPIC-" + id); + var row = $("RROW-" + id); + if (!row) return; - if (!img) return; + var imgs = row.getElementsByClassName("markedPic"); - if (img.src.match("mark_unset")) { - img.src = img.src.replace("mark_unset", "mark_set"); - img.alt = __("Unstar article"); - query = query + "&mark=1"; + for (i = 0; i < imgs.length; i++) { + var img = imgs[i]; - } else { - img.src = img.src.replace("mark_set", "mark_unset"); - img.alt = __("Star article"); - query = query + "&mark=0"; + if (!row.hasClassName("marked")) { + 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"; + } } + row.toggleClassName("marked"); + if (!client_only) { new Ajax.Request("backend.php", { parameters: query, @@ -464,22 +485,30 @@ function togglePub(id, client_only, no_effects, note) { query = query + "¬e=undefined"; } - var img = $("FPPIC-" + id); - - if (!img) return; + var row = $("RROW-" + id); + if (!row) 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"; + var imgs = row.getElementsByClassName("pubPic"); - } else { - img.src = img.src.replace("pub_set", "pub_unset"); - img.alt = __("Publish article"); + for (i = 0; i < imgs.length; i++) { + var img = imgs[i]; - query = query + "&pub=0"; + if (!row.hasClassName("published") || 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"; + } } + if (note != undefined) + row.addClassName("published"); + else + row.toggleClassName("published"); + if (!client_only) { new Ajax.Request("backend.php", { parameters: query, @@ -493,7 +522,7 @@ function togglePub(id, client_only, no_effects, note) { } } -function moveToPost(mode, noscroll) { +function moveToPost(mode, noscroll, noexpand) { try { @@ -537,16 +566,16 @@ function moveToPost(mode, noscroll) { if (!noscroll && article && article.offsetTop + article.offsetHeight > ctr.scrollTop + ctr.offsetHeight) { - scrollArticle(ctr.offsetHeight/2); + scrollArticle(ctr.offsetHeight/4); } else if (next_id) { - cdmExpandArticle(next_id); - cdmScrollToArticleId(next_id, noscroll); + cdmExpandArticle(next_id, noexpand); + cdmScrollToArticleId(next_id, true); } } else if (next_id) { correctHeadlinesOffset(next_id); - view(next_id, getActiveFeedId()); + view(next_id, getActiveFeedId(), noexpand); } } } @@ -559,19 +588,31 @@ function moveToPost(mode, noscroll) { var prev_article = $("RROW-" + prev_id); var ctr = $("headlines-frame"); - if (!noscroll && article && article.offsetTop < ctr.scrollTop) { - scrollArticle(-ctr.offsetHeight/2); - } else if (!noscroll && prev_article && - prev_article.offsetTop < ctr.scrollTop) { - cdmExpandArticle(prev_id); - scrollArticle(-ctr.offsetHeight/2); - } else if (prev_id) { - cdmExpandArticle(prev_id); - cdmScrollToArticleId(prev_id, noscroll); + if (!getInitParam("cdm_expanded")) { + + if (!noscroll && article.offsetTop < ctr.scrollTop) { + scrollArticle(-ctr.offsetHeight/4); + } else { + cdmExpandArticle(prev_id, noexpand); + cdmScrollToArticleId(prev_id, true); + } + } else { + + if (!noscroll && article && article.offsetTop < ctr.scrollTop) { + scrollArticle(-ctr.offsetHeight/3); + } else if (!noscroll && prev_article && + prev_article.offsetTop < ctr.scrollTop) { + cdmExpandArticle(prev_id, noexpand); + scrollArticle(-ctr.offsetHeight/4); + } else if (prev_id) { + cdmExpandArticle(prev_id, noexpand); + cdmScrollToArticleId(prev_id, noscroll); + } } + } else if (prev_id) { correctHeadlinesOffset(prev_id); - view(prev_id, getActiveFeedId()); + view(prev_id, getActiveFeedId(), noexpand); } } } @@ -583,11 +624,12 @@ function moveToPost(mode, noscroll) { function toggleSelected(id, force_on) { try { - - var cb = dijit.byId("RCHK-" + id); var row = $("RROW-" + id); if (row) { + var cb = dijit.getEnclosingWidget( + row.getElementsByClassName("rchk")[0]); + if (row.hasClassName('Selected') && !force_on) { row.removeClassName('Selected'); if (cb) cb.attr("checked", false); @@ -596,11 +638,33 @@ function toggleSelected(id, force_on) { if (cb) cb.attr("checked", true); } } + + updateSelectedPrompt(); } catch (e) { exception_error("toggleSelected", e); } } +function updateSelectedPrompt() { + try { + var count = getSelectedArticleIds2().size(); + var elem = $("selected_prompt"); + + if (elem) { + elem.innerHTML = ngettext("%d article selected", + "%d articles selected", count).replace("%d", count); + + if (count > 0) + Element.show(elem); + else + Element.hide(elem); + } + + } catch (e) { + exception_error("updateSelectedPrompt", e); + } +} + function toggleUnread_afh(effect) { try { @@ -621,12 +685,6 @@ function toggleUnread(id, cmode, effect) { 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"); } @@ -635,12 +693,6 @@ function toggleUnread(id, cmode, effect) { 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"); } @@ -675,7 +727,7 @@ function selectionRemoveLabel(id, ids) { return; } - var query = "?op=rpc&method=removeFromLabel&ids=" + + var query = "?op=article&method=removeFromLabel&ids=" + param_escape(ids.toString()) + "&lid=" + param_escape(id); console.log(query); @@ -703,7 +755,7 @@ function selectionAssignLabel(id, ids) { return; } - var query = "?op=rpc&method=assignToLabel&ids=" + + var query = "?op=article&method=assignToLabel&ids=" + param_escape(ids.toString()) + "&lid=" + param_escape(id); console.log(query); @@ -721,9 +773,9 @@ function selectionAssignLabel(id, ids) { } } -function selectionToggleUnread(set_state, callback, no_error) { +function selectionToggleUnread(set_state, callback, no_error, ids) { try { - var rows = getSelectedArticleIds2(); + var rows = ids ? ids : getSelectedArticleIds2(); if (rows.length == 0 && !no_error) { alert(__("No articles are selected.")); @@ -782,12 +834,13 @@ function selectionToggleUnread(set_state, callback, no_error) { } } -function selectionToggleMarked() { +// sel_state ignored +function selectionToggleMarked(sel_state, callback, no_error, ids) { try { - var rows = getSelectedArticleIds2(); + var rows = ids ? ids : getSelectedArticleIds2(); - if (rows.length == 0) { + if (rows.length == 0 && !no_error) { alert(__("No articles are selected.")); return; } @@ -805,6 +858,7 @@ function selectionToggleMarked() { parameters: query, onComplete: function(transport) { handle_rpc_json(transport); + if (callback) callback(transport); } }); } @@ -814,12 +868,13 @@ function selectionToggleMarked() { } } -function selectionTogglePublished() { +// sel_state ignored +function selectionTogglePublished(sel_state, callback, no_error, ids) { try { - var rows = getSelectedArticleIds2(); + var rows = ids ? ids : getSelectedArticleIds2(); - if (rows.length == 0) { + if (rows.length == 0 && !no_error) { alert(__("No articles are selected.")); return; } @@ -879,7 +934,9 @@ function selectArticles(mode) { children.each(function(child) { var id = child.id.replace("RROW-", ""); - var cb = dijit.byId("RCHK-" + id); + + var cb = dijit.getEnclosingWidget( + child.getElementsByClassName("rchk")[0]); if (mode == "all") { child.addClassName("Selected"); @@ -893,9 +950,7 @@ function selectArticles(mode) { if (cb) cb.attr("checked", false); } } else if (mode == "marked") { - var img = $("FMPIC-" + child.id.replace("RROW-", "")); - - if (img && img.src.match("mark_set")) { + if (child.hasClassName("marked")) { child.addClassName("Selected"); if (cb) cb.attr("checked", true); } else { @@ -903,9 +958,7 @@ function selectArticles(mode) { if (cb) cb.attr("checked", false); } } else if (mode == "published") { - var img = $("FPPIC-" + child.id.replace("RROW-", "")); - - if (img && img.src.match("pub_set")) { + if (child.hasClassName("published")) { child.addClassName("Selected"); if (cb) cb.attr("checked", true); } else { @@ -928,28 +981,13 @@ function selectArticles(mode) { } }); + updateSelectedPrompt(); + } 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 { @@ -965,9 +1003,9 @@ function deleteSelection() { var str; if (getActiveFeedId() != 0) { - str = __("Delete %d selected articles in %s?"); + str = ngettext("Delete %d selected article in %s?", "Delete %d selected articles in %s?" , rows.length); } else { - str = __("Delete %d selected articles?"); + str = ngettext("Delete %d selected article?", "Delete %d selected articles?", rows.length); } str = str.replace("%d", rows.length); @@ -1009,10 +1047,13 @@ function archiveSelection() { var op; if (getActiveFeedId() != 0) { - str = __("Archive %d selected articles in %s?"); + str = ngettext("Archive %d selected article in %s?", "Archive %d selected articles in %s?", rows.length); op = "archive"; } else { - str = __("Move %d archived articles back?"); + str = ngettext("Move %d archived article back?", "Move %d archived articles back?", rows.length); + + str += " " + __("Please note that unstarred articles might get purged on next feed update."); + op = "unarchive"; } @@ -1056,7 +1097,7 @@ function catchupSelection() { var fn = getFeedName(getActiveFeedId(), activeFeedIsCat()); - var str = __("Mark %d selected articles in %s as read?"); + var str = ngettext("Mark %d selected article in %s as read?", "Mark %d selected articles in %s as read?", rows.length); str = str.replace("%d", rows.length); str = str.replace("%s", fn); @@ -1073,7 +1114,7 @@ function catchupSelection() { } function editArticleTags(id) { - var query = "backend.php?op=dlg&method=editArticleTags¶m=" + param_escape(id); + var query = "backend.php?op=article&method=editArticleTags¶m=" + param_escape(id); if (dijit.byId("editTagsDlg")) dijit.byId("editTagsDlg").destroyRecursive(); @@ -1091,22 +1132,25 @@ function editArticleTags(id) { new Ajax.Request("backend.php", { parameters: query, onComplete: function(transport) { - notify(''); - dialog.hide(); + try { + notify(''); + dialog.hide(); - var data = JSON.parse(transport.responseText); + var data = JSON.parse(transport.responseText); - if (data) { - var tags_str = article.tags; - var id = tags_str.id; + if (data) { + var id = data.id; - var tags = $("ATSTR-" + id); - var tooltip = dijit.byId("ATSTRTIP-" + id); + console.log(id); - if (tags) tags.innerHTML = tags_str.content; - if (tooltip) tooltip.attr('label', tags_str.content_full); + var tags = $("ATSTR-" + id); + var tooltip = dijit.byId("ATSTRTIP-" + id); - cache_delete("article:" + id); + if (tags) tags.innerHTML = data.content; + if (tooltip) tooltip.attr('label', data.content_full); + } + } catch (e) { + exception_error("editArticleTags/inner", e); } }}); @@ -1119,7 +1163,7 @@ function editArticleTags(id) { dojo.disconnect(tmph); new Ajax.Autocompleter('tags_str', 'tags_choices', - "backend.php?op=rpc&method=completeTags", + "backend.php?op=article&method=completeTags", { tokens: ',', paramName: "search" }); }); @@ -1136,7 +1180,9 @@ function cdmScrollToArticleId(id, force) { if (force || e.offsetTop+e.offsetHeight > (ctr.scrollTop+ctr.offsetHeight) || e.offsetTop < ctr.scrollTop) { - ctr.scrollTop = e.offsetTop; + + // expanded cdm has a 4px margin now + ctr.scrollTop = parseInt(e.offsetTop) - 4; } } catch (e) { @@ -1146,13 +1192,14 @@ function cdmScrollToArticleId(id, force) { function setActiveArticleId(id) { _active_article_id = id; + PluginHost.run(PluginHost.HOOK_ARTICLE_SET_ACTIVE, _active_article_id); } function getActiveArticleId() { return _active_article_id; } -function postMouseIn(id) { +function postMouseIn(e, id) { post_under_pointer = id; } @@ -1160,10 +1207,39 @@ function postMouseOut(id) { post_under_pointer = false; } +function unpackVisibleHeadlines() { + try { + if (!isCdmMode()) return; + + $$("#headlines-frame > div[id*=RROW]").each( + function(child) { + if (child.offsetTop <= $("headlines-frame").scrollTop + + $("headlines-frame").offsetHeight) { + + var cencw = $("CENCW-" + child.id.replace("RROW-", "")); + + if (cencw) { + PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED_CDM, child); + + cencw.innerHTML = htmlspecialchars_decode(cencw.innerHTML); + cencw.setAttribute('id', ''); + Element.show(cencw); + } + } + } + ); + + } catch (e) { + exception_error("unpackVisibleHeadlines", e); + } +} + function headlines_scroll_handler(e) { try { var hsp = $("headlines-spacer"); + unpackVisibleHeadlines(); + if (!_infscroll_disable) { if ((hsp && e.scrollTop + e.offsetHeight >= hsp.offsetTop - hsp.offsetHeight) || (e.scrollHeight != 0 && @@ -1183,9 +1259,13 @@ function headlines_scroll_handler(e) { if (getInitParam("cdm_auto_catchup") == 1) { + // let's get DOM some time to settle down + var ts = new Date().getTime(); + if (ts - _last_headlines_update < 100) return; + $$("#headlines-frame > div[id*=RROW][class*=Unread]").each( function(child) { - if ($("headlines-frame").scrollTop > + if (child.hasClassName("Unread") && $("headlines-frame").scrollTop > (child.offsetTop + child.offsetHeight/2)) { var id = child.id.replace("RROW-", ""); @@ -1202,7 +1282,7 @@ function headlines_scroll_handler(e) { if (!_infscroll_request_sent) { catchup_timeout_id = window.setTimeout('catchupBatchedArticles()', - 2000); + 500); } } } @@ -1228,7 +1308,11 @@ function catchupBatchedArticles() { onComplete: function(transport) { handle_rpc_json(transport); + reply = JSON.parse(transport.responseText); + var batch = reply.ids; + batch.each(function(id) { + console.log(id); var elem = $("RROW-" + id); if (elem) elem.removeClassName("Unread"); catchup_id_batch.remove(id); @@ -1286,7 +1370,7 @@ function catchupRelativeToArticle(below, id) { 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); + var msg = ngettext("Mark %d article as read?", "Mark %d articles as read?", ids_to_mark.length).replace("%d", ids_to_mark.length); if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) { @@ -1312,10 +1396,50 @@ function catchupRelativeToArticle(below, id) { } } -function cdmExpandArticle(id) { +function cdmCollapseArticle(event, id, unmark) { try { + if (unmark == undefined) unmark = true; - hideAuxDlg(); + var row = $("RROW-" + id); + var elem = $("CICD-" + id); + + if (elem && row) { + var collapse = $$("div#RROW-" + id + + " span[class='collapseBtn']")[0]; + + Element.hide(elem); + Element.show("CEXC-" + id); + Element.hide(collapse); + + if (unmark) { + row.removeClassName("active"); + + markHeadline(id, false); + + if (id == getActiveArticleId()) { + setActiveArticleId(0); + } + + updateSelectedPrompt(); + } + + if (event) Event.stop(event); + + PluginHost.run(PluginHost.HOOK_ARTICLE_COLLAPSED, id); + } + + } catch (e) { + exception_error("cdmCollapseArticle", e); + } +} + +function cdmExpandArticle(id, noexpand) { + try { + console.log("cdmExpandArticle " + id); + + if (!$("RROW-" + id)) return false; + + var oldrow = $("RROW-" + getActiveArticleId()); var elem = $("CICD-" + getActiveArticleId()); @@ -1327,28 +1451,48 @@ function cdmExpandArticle(id) { var old_offset = $("RROW-" + id).offsetTop; if (getActiveArticleId() && elem && !getInitParam("cdm_expanded")) { + var collapse = $$("div#RROW-" + getActiveArticleId() + + " span[class='collapseBtn']")[0]; + Element.hide(elem); Element.show("CEXC-" + getActiveArticleId()); + Element.hide(collapse); } + if (oldrow) oldrow.removeClassName("active"); + setActiveArticleId(id); elem = $("CICD-" + id); - if (!Element.visible(elem)) { + var collapse = $$("div#RROW-" + id + + " span[class='collapseBtn']")[0]; + + var cencw = $("CENCW-" + id); + + if (!Element.visible(elem) && !noexpand) { + if (cencw) { + cencw.innerHTML = htmlspecialchars_decode(cencw.innerHTML); + cencw.setAttribute('id', ''); + Element.show(cencw); + } + Element.show(elem); Element.hide("CEXC-" + id); + Element.show(collapse); } - /* var new_offset = $("RROW-" + id).offsetTop; - - $("headlines-frame").scrollTop += (new_offset-old_offset); + var new_offset = $("RROW-" + id).offsetTop; - if ($("RROW-" + id).offsetTop != old_offset) - $("headlines-frame").scrollTop = new_offset; */ + if (old_offset > new_offset) + $("headlines-frame").scrollTop -= (old_offset-new_offset); - toggleUnread(id, 0, true); + if (!noexpand) + toggleUnread(id, 0, true); toggleSelected(id); + $("RROW-" + id).addClassName("active"); + + PluginHost.run(PluginHost.HOOK_ARTICLE_EXPANDED, id); } catch (e) { exception_error("cdmExpandArticle", e); @@ -1357,26 +1501,6 @@ function cdmExpandArticle(id) { 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; } @@ -1420,6 +1544,8 @@ function dismissArticle(id) { try { var elem = $("RROW-" + id); + if (!elem) return; + toggleUnread(id, 0, true); new Effect.Fade(elem, {duration : 0.5}); @@ -1455,7 +1581,6 @@ function dismissSelectedArticles() { if (sel.length > 0) selectionToggleUnread(false); - fixHeadlinesOrder(tmp); } catch (e) { exception_error("dismissSelectedArticles", e); @@ -1480,8 +1605,6 @@ function dismissReadArticles() { } } - fixHeadlinesOrder(tmp); - } catch (e) { exception_error("dismissSelectedArticles", e); } @@ -1509,22 +1632,24 @@ function cdmClicked(event, id) { try { //var shift_key = event.shiftKey; - hideAuxDlg(); - if (!event.ctrlKey) { if (!getInitParam("cdm_expanded")) { return cdmExpandArticle(id); } else { + var elem = $("RROW-" + getActiveArticleId()); + + if (elem) elem.removeClassName("active"); + selectArticles("none"); toggleSelected(id); var elem = $("RROW-" + id); var article_is_unread = elem.hasClassName("Unread"); - if (elem) - elem.removeClassName("Unread"); + elem.removeClassName("Unread"); + elem.addClassName("active"); setActiveArticleId(id); @@ -1609,16 +1734,22 @@ function isCdmMode() { return getInitParam("combined_display_mode"); } -function markHeadline(id) { +function markHeadline(id, marked) { + if (marked == undefined) marked = true; + var row = $("RROW-" + id); if (row) { - var check = dijit.byId("RCHK-" + id); + var check = dijit.getEnclosingWidget( + row.getElementsByClassName("rchk")[0]); if (check) { - check.attr("checked", true); + check.attr("checked", marked); } - row.addClassName("Selected"); + if (marked) + row.addClassName("Selected"); + else + row.removeClassName("Selected"); } } @@ -1746,6 +1877,47 @@ function initHeadlinesMenu() { openArticleInNewWindow(this.getParent().callerRowId); }})); + menu.addChild(new dijit.MenuItem({ + label: __("Display article URL"), + onClick: function(event) { + displayArticleUrl(this.getParent().callerRowId); + }})); + + menu.addChild(new dijit.MenuSeparator()); + + menu.addChild(new dijit.MenuItem({ + label: __("Toggle unread"), + onClick: function(event) { + var ids = getSelectedArticleIds2(); + // cast to string + var id = this.getParent().callerRowId + ""; + ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id]; + + selectionToggleUnread(undefined, false, true, ids); + }})); + + menu.addChild(new dijit.MenuItem({ + label: __("Toggle marked"), + onClick: function(event) { + var ids = getSelectedArticleIds2(); + // cast to string + var id = this.getParent().callerRowId + ""; + ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id]; + + selectionToggleMarked(undefined, false, true, ids); + }})); + + menu.addChild(new dijit.MenuItem({ + label: __("Toggle published"), + onClick: function(event) { + var ids = getSelectedArticleIds2(); + // cast to string + var id = this.getParent().callerRowId + ""; + ids = ids.size() != 0 && ids.indexOf(id) != -1 ? ids : [id]; + + selectionTogglePublished(undefined, false, true, ids); + }})); + menu.addChild(new dijit.MenuSeparator()); menu.addChild(new dijit.MenuItem({ @@ -1775,7 +1947,7 @@ function initHeadlinesMenu() { var bare_id = id.substr(id.indexOf(":")+1); var name = label.name[0]; - bare_id = -11-bare_id; + bare_id = feed_to_label_id(bare_id); labelAddMenu.addChild(new dijit.MenuItem({ label: name, @@ -1824,34 +1996,6 @@ function initHeadlinesMenu() { } } - -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) @@ -1896,7 +2040,7 @@ function setSelectionScore() { var score = prompt(__("Please enter new score for selected articles:"), score); if (score != undefined) { - var query = "op=rpc&method=setScore&id=" + param_escape(ids.toString()) + + var query = "op=article&method=setScore&id=" + param_escape(ids.toString()) + "&score=" + param_escape(score); new Ajax.Request("backend.php", { @@ -1939,7 +2083,7 @@ function changeScore(id, pic) { if (new_score != undefined) { - var query = "op=rpc&method=setScore&id=" + param_escape(id) + + var query = "op=article&method=setScore&id=" + param_escape(id) + "&score=" + param_escape(new_score); new Ajax.Request("backend.php", { @@ -1957,3 +2101,35 @@ function changeScore(id, pic) { exception_error("changeScore", e); } } + +function displayArticleUrl(id) { + try { + var query = "op=rpc&method=getlinktitlebyid&id=" + param_escape(id); + + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + var reply = JSON.parse(transport.responseText); + + if (reply && reply.link) { + prompt(__("Article URL:"), reply.link); + } + } }); + } catch (e) { + exception_error("changeScore", e); + } +} + +function openSelectedAttachment(elem) { + try { + var url = elem[elem.selectedIndex].value; + + if (url) { + window.open(url); + elem.selectedIndex = 0; + } + + } catch (e) { + exception_error("openSelectedAttachment", e); + } +} |