diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/AppBase.js | 22 | ||||
-rw-r--r-- | js/CommonDialogs.js | 56 | ||||
-rw-r--r-- | js/FeedStoreModel.js | 2 | ||||
-rwxr-xr-x | js/FeedTree.js | 22 | ||||
-rw-r--r-- | js/Feeds.js | 42 | ||||
-rwxr-xr-x | js/Headlines.js | 93 | ||||
-rw-r--r-- | js/PluginHost.js | 7 | ||||
-rw-r--r-- | js/PrefFeedTree.js | 4 | ||||
-rw-r--r-- | js/PrefUsers.js | 2 | ||||
-rwxr-xr-x | js/Toolbar.js | 14 | ||||
-rwxr-xr-x | js/form/ComboButton.js | 12 | ||||
-rwxr-xr-x | js/form/DropDownButton.js | 12 | ||||
-rwxr-xr-x | js/form/Select.js | 8 | ||||
-rwxr-xr-x | js/prefs.js | 11 | ||||
-rw-r--r-- | js/tt-rss.js | 22 |
15 files changed, 252 insertions, 77 deletions
diff --git a/js/AppBase.js b/js/AppBase.js index 121b7aa85..a5e20b8f9 100644 --- a/js/AppBase.js +++ b/js/AppBase.js @@ -60,14 +60,12 @@ define(["dojo/_base/declare"], function (declare) { const hotkeys_map = App.getInitParam("hotkeys"); const keycode = event.which; - const keychar = String.fromCharCode(keycode).toLowerCase(); + const keychar = String.fromCharCode(keycode); if (keycode == 27) { // escape and drop prefix this.hotkey_prefix = false; } - if (keycode == 16 || keycode == 17) return; // ignore lone shift / ctrl - if (!this.hotkey_prefix && hotkeys_map[0].indexOf(keychar) != -1) { this.hotkey_prefix = keychar; @@ -87,13 +85,19 @@ define(["dojo/_base/declare"], function (declare) { Element.hide("cmdline"); - let hotkey_name = keychar.search(/[a-zA-Z0-9]/) != -1 ? keychar : "(" + keycode + ")"; + let hotkey_name = ""; + + if (event.type == "keydown") { + hotkey_name = "(" + keycode + ")"; - // ensure ^*char notation - if (event.shiftKey) hotkey_name = "*" + hotkey_name; - if (event.ctrlKey) hotkey_name = "^" + hotkey_name; - if (event.altKey) hotkey_name = "+" + hotkey_name; - if (event.metaKey) hotkey_name = "%" + hotkey_name; + // ensure ^*char notation + if (event.shiftKey) hotkey_name = "*" + hotkey_name; + if (event.ctrlKey) hotkey_name = "^" + hotkey_name; + if (event.altKey) hotkey_name = "+" + hotkey_name; + if (event.metaKey) hotkey_name = "%" + hotkey_name; + } else { + hotkey_name = keychar ? keychar : "(" + keycode + ")"; + } const hotkey_full = this.hotkey_prefix ? this.hotkey_prefix + " " + hotkey_name : hotkey_name; this.hotkey_prefix = false; diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js index 2b7ee8a7f..e0338a97c 100644 --- a/js/CommonDialogs.js +++ b/js/CommonDialogs.js @@ -7,25 +7,6 @@ define(["dojo/_base/declare"], function (declare) { const dialog = dijit.byId("infoBox"); if (dialog) dialog.hide(); }, - uploadIconHandler: function(rc) { - switch (rc) { - case 0: - Notify.info("Upload complete."); - - if (App.isPrefs()) - dijit.byId("feedTree").reload(); - else - Feeds.reload(); - - break; - case 1: - Notify.error("Upload failed: icon is too big."); - break; - case 2: - Notify.error("Upload failed."); - break; - } - }, removeFeedIcon: function(id) { if (confirm(__("Remove stored feed icon?"))) { Notify.progress("Removing feed icon...", true); @@ -40,6 +21,11 @@ define(["dojo/_base/declare"], function (declare) { else Feeds.reload(); + const icon = $$(".feed-editor-icon")[0]; + + if (icon) + icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); + }); } @@ -52,7 +38,35 @@ define(["dojo/_base/declare"], function (declare) { 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; + + const xhr = new XMLHttpRequest(); + + xhr.open( 'POST', 'backend.php', true ); + xhr.onload = function () { + switch (parseInt(this.responseText)) { + case 0: + Notify.info("Upload complete."); + + if (App.isPrefs()) + dijit.byId("feedTree").reload(); + else + Feeds.reload(); + + const icon = $$(".feed-editor-icon")[0]; + + if (icon) + icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); + + break; + case 1: + Notify.error("Upload failed: icon is too big."); + break; + case 2: + Notify.error("Upload failed."); + break; + } + }; + xhr.send(new FormData($("feed_icon_upload_form"))); } return false; @@ -466,4 +480,4 @@ define(["dojo/_base/declare"], function (declare) { }; return CommonDialogs; -});
\ No newline at end of file +}); diff --git a/js/FeedStoreModel.js b/js/FeedStoreModel.js index 7f2af22ec..7d8020871 100644 --- a/js/FeedStoreModel.js +++ b/js/FeedStoreModel.js @@ -31,7 +31,7 @@ define(["dojo/_base/declare", "dijit/tree/ForestStoreModel"], function (declare) }, getFeedUnread: function (feed, is_cat) { const unread = parseInt(this.getFeedValue(feed, is_cat, 'unread')); - return (isNaN(unread)) ? 0 : unread; + return (isNaN(unread)) ? -1 : unread; }, setFeedUnread: function (feed, is_cat, unread) { return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread)); diff --git a/js/FeedTree.js b/js/FeedTree.js index b8e50872a..1dcbae3f9 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -2,7 +2,10 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct) { return declare("fox.FeedTree", dijit.Tree, { - _onKeyPress: function(/* Event */ e) { + _onContainerKeydown: function(/* Event */ e) { + return; // Stop dijit.Tree from interpreting keystrokes + }, + _onContainerKeypress: function(/* Event */ e) { return; // Stop dijit.Tree from interpreting keystrokes }, _createTreeNode: function(args) { @@ -64,6 +67,13 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], CommonDialogs.editFeed(this.getParent().row_id, false); }})); + menu.addChild(new dijit.MenuItem({ + label: __("Debug feed"), + onClick: function() { + window.open("backend.php?op=feeds&method=update_debugger&feed_id=" + this.getParent().row_id + + "&csrf_token=" + App.getInitParam("csrf_token")); + }})); + /* menu.addChild(new dijit.MenuItem({ label: __("Update feed"), onClick: function() { @@ -125,7 +135,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], args.item.unread > 0 || args.item.auxcounter > 0 ? Element.show(ctr) : Element.hide(ctr); - args.item.unread == 0 && args.item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); + args.item.unread <= 0 && args.item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); domConstruct.place(ctr, tnode.rowNode, 'first'); tnode.counterNode = ctr; @@ -161,7 +171,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], Element.show(ctr) : Element.hide(ctr); - item.unread == 0 && item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); + item.unread <= 0 && item.auxcounter > 0 ? ctr.addClassName("aux") : ctr.removeClassName("aux"); } } @@ -174,7 +184,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feed-icon"; }, getLabelClass: function (item, opened) { - return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread"; + return (item.unread <= 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread"; }, getRowClass: function (item, opened) { let rc = (!item.error || item.error == '') ? "dijitTreeRow" : @@ -343,7 +353,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], if (node) { const check_unread = tree.model.getFeedUnread(bare_id, true); - if (hide && cat_unread == 0 && check_unread == 0 && (id != "CAT:-1" || !show_special)) { + if (hide && cat_unread <= 0 && check_unread <= 0 && (id != "CAT:-1" || !show_special)) { Effect.Fade(node[0].rowNode, {duration : 0.3, queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }}); } else { @@ -387,7 +397,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], const node = tree._itemNodesMap[id]; if (node) { - if (hide && unread == 0 && !has_error && (bare_id > 0 || bare_id < _label_base_index || !show_special)) { + if (hide && unread <= 0 && !has_error && (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/Feeds.js b/js/Feeds.js index 401d669a7..07ec89452 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -3,7 +3,7 @@ define(["dojo/_base/declare"], function (declare) { Feeds = { counters_last_request: 0, - _active_feed_id: 0, + _active_feed_id: undefined, _active_feed_is_cat: false, infscroll_in_progress: 0, infscroll_disabled: 0, @@ -44,6 +44,8 @@ define(["dojo/_base/declare"], function (declare) { this._counters_prev = []; }, parseCounters: function (elems) { + PluginHost.run(PluginHost.HOOK_COUNTERS_RECEIVED, elems); + for (let l = 0; l < elems.length; l++) { if (Feeds._counters_prev[l] && this.counterEquals(elems[l], this._counters_prev[l])) { @@ -93,11 +95,13 @@ define(["dojo/_base/declare"], function (declare) { this.hideOrShowFeeds(App.getInitParam("hide_read_feeds") == 1); this._counters_prev = elems; + + PluginHost.run(PluginHost.HOOK_COUNTERS_PROCESSED); }, reloadCurrent: function(method) { - console.log("reloadCurrent: " + method); - if (this.getActive() != undefined) { + console.log("reloadCurrent: " + method); + this.open({feed: this.getActive(), is_cat: this.activeIsCat(), method: method}); } return false; // block unneeded form submits @@ -196,12 +200,16 @@ define(["dojo/_base/declare"], function (declare) { App.setLoadingProgress(50); document.onkeydown = (event) => { return App.hotkeyHandler(event) }; + document.onkeypress = (event) => { return App.hotkeyHandler(event) }; window.onresize = () => { Headlines.scrollHandler(); } - if (!this.getActive()) { - this.open({feed: -3}); + const hash_feed_id = hash_get('f'); + const hash_feed_is_cat = hash_get('c') == "1"; + + if (hash_feed_id != undefined) { + this.open({feed: hash_feed_id, is_cat: hash_feed_is_cat}); } else { - this.open({feed: this.getActive(), is_cat: this.activeIsCat()}); + this.open({feed: -3}); } this.hideOrShowFeeds(App.getInitParam("hide_read_feeds") == 1); @@ -245,6 +253,8 @@ define(["dojo/_base/declare"], function (declare) { return this._active_feed_id; }, setActive: function(id, is_cat) { + console.log('setActive', id, is_cat); + hash_set('f', id); hash_set('c', is_cat ? 1 : 0); @@ -542,6 +552,11 @@ define(["dojo/_base/declare"], function (declare) { execute: function () { if (this.validate()) { Feeds._search_query = this.attr('value'); + + // disallow empty queries + if (!Feeds._search_query.query) + Feeds._search_query = false; + this.hide(); Feeds.reloadCurrent(); } @@ -549,6 +564,21 @@ define(["dojo/_base/declare"], function (declare) { href: query }); + const tmph = dojo.connect(dialog, 'onLoad', function () { + dojo.disconnect(tmph); + + if (Feeds._search_query) { + if (Feeds._search_query.query) + dijit.byId('search_query') + .attr('value', Feeds._search_query.query); + + if (Feeds._search_query.search_language) + dijit.byId('search_language') + .attr('value', Feeds._search_query.search_language); + } + + }); + dialog.show(); }, updateRandom: function() { diff --git a/js/Headlines.js b/js/Headlines.js index 1414dd3c7..3c5ab2ee6 100755 --- a/js/Headlines.js +++ b/js/Headlines.js @@ -153,35 +153,59 @@ define(["dojo/_base/declare"], function (declare) { click: function (event, id, in_body) { in_body = in_body || false; - if (App.isCombinedMode()) { + if (event.shiftKey && Article.getActive()) { + Headlines.select('none'); - if (!in_body && (event.ctrlKey || id == Article.getActive() || App.getInitParam("cdm_expanded"))) { - Article.openInNewWindow(id); - Headlines.toggleUnread(id, 0); - return false; - } + const ids = Headlines.getRange(Article.getActive(), id); - if (Article.getActive() != id) { - Article.setActive(id); + console.log(Article.getActive(), id, ids); - if (!App.getInitParam("cdm_expanded")) - Article.cdmScrollToId(id); - } else if (in_body) { - Headlines.toggleUnread(id, 0); - } - - return in_body; + for (let i = 0; i < ids.length; i++) + Headlines.select('all', ids[i]); + } else if (event.ctrlKey) { + Headlines.select('invert', id); } else { - if (event.ctrlKey) { - Article.openInNewWindow(id); - Headlines.toggleUnread(id, 0); + if (App.isCombinedMode()) { + + if (event.altKey && !in_body) { + + Article.openInNewWindow(id); + Headlines.toggleUnread(id, 0); + + } else if (Article.getActive() != id) { + + Headlines.select('none'); + Article.setActive(id); + + if (App.getInitParam("cdm_expanded")) { + if (!in_body) + Article.openInNewWindow(id); + + Headlines.toggleUnread(id, 0); + } else { + Article.cdmScrollToId(id); + } + + } else if (in_body) { + Headlines.toggleUnread(id, 0); + } else { /* !in body */ + Article.openInNewWindow(id); + } + + return in_body; } else { - Article.view(id); + if (event.altKey) { + Article.openInNewWindow(id); + Headlines.toggleUnread(id, 0); + } else { + Headlines.select('none'); + Article.view(id); + } } - - return false; } + + return false; }, initScrollHandler: function () { $("headlines-frame").onscroll = (event) => { @@ -997,6 +1021,33 @@ define(["dojo/_base/declare"], function (declare) { row.removeClassName("Selected"); } }, + getRange: function (start, stop) { + if (start == stop) + return [start]; + + const rows = $$("#headlines-frame > div[id*=RROW]"); + const results = []; + let collecting = false; + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + const id = row.getAttribute('data-article-id'); + + if (id == start || id == stop) { + if (!collecting) { + collecting = true; + } else { + results.push(id); + break; + } + } + + if (collecting) + results.push(id); + } + + return results; + }, select: function (mode, articleId) { // mode = all,none,unread,invert,marked,published let query = "#headlines-frame > div[id*=RROW]"; diff --git a/js/PluginHost.js b/js/PluginHost.js index f76b73464..71596ad31 100644 --- a/js/PluginHost.js +++ b/js/PluginHost.js @@ -13,6 +13,8 @@ PluginHost = { HOOK_FLOATING_TITLE: 10, HOOK_INIT_COMPLETE: 11, HOOK_HEADLINE_RENDERED: 12, + HOOK_COUNTERS_RECEIVED: 13, + HOOK_COUNTERS_PROCESSED: 14, hooks: [], register: function (name, callback) { if (typeof(this.hooks[name]) == 'undefined') @@ -27,6 +29,11 @@ PluginHost = { for (let i = 0; i < this.hooks[name].length; i++) { this.hooks[name][i](args); } + }, + unregister: function (name, callback) { + for (var i = 0; i < this.hooks[name].length; i++) + if (this.hooks[name][i] == callback) + this.hooks[name].splice(i, 1); } }; diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js index c2c7751bf..3a5e33b2b 100644 --- a/js/PrefFeedTree.js +++ b/js/PrefFeedTree.js @@ -275,9 +275,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio if ($(label)) if (checkbox.checked) - $(label).removeClassName('insensitive'); + $(label).removeClassName('text-muted'); else - $(label).addClassName('insensitive'); + $(label).addClassName('text-muted'); }, execute: function () { diff --git a/js/PrefUsers.js b/js/PrefUsers.js index 4f24f67cf..55dc43dfa 100644 --- a/js/PrefUsers.js +++ b/js/PrefUsers.js @@ -70,7 +70,7 @@ define(["dojo/_base/declare"], function (declare) { xhrPost("backend.php", {op: "pref-users", method: "resetPass", id: id}, (transport) => { Notify.close(); - alert(transport.responseText); + Notify.info(transport.responseText, true); }); } diff --git a/js/Toolbar.js b/js/Toolbar.js new file mode 100755 index 000000000..6d2c20058 --- /dev/null +++ b/js/Toolbar.js @@ -0,0 +1,14 @@ +/* global dijit */ +define(["dojo/_base/declare", "dijit/Toolbar"], function (declare) { + return declare("fox.Toolbar", dijit.Toolbar, { + _onContainerKeydown: function(/* Event */ e) { + return; // Stop dijit.Toolbar from interpreting keystrokes + }, + _onContainerKeypress: function(/* Event */ e) { + return; // Stop dijit.Toolbar from interpreting keystrokes + }, + focus: function() { + return; // Stop dijit.Toolbar from focusing the first child on click + }, + }); +}); diff --git a/js/form/ComboButton.js b/js/form/ComboButton.js new file mode 100755 index 000000000..1084cda9c --- /dev/null +++ b/js/form/ComboButton.js @@ -0,0 +1,12 @@ +/* global dijit */ +define(["dojo/_base/declare", "dijit/form/ComboButton"], function (declare) { + return declare("fox.form.ComboButton", dijit.form.ComboButton, { + startup: function() { + this.inherited(arguments); + this.dropDown.autoFocus = true; // Allow dropdown menu to be focused on click + }, + focus: function() { + return; // Stop dijit.form.ComboButton from keeping focus after closing the menu + }, + }); +}); diff --git a/js/form/DropDownButton.js b/js/form/DropDownButton.js new file mode 100755 index 000000000..0c182772a --- /dev/null +++ b/js/form/DropDownButton.js @@ -0,0 +1,12 @@ +/* global dijit */ +define(["dojo/_base/declare", "dijit/form/DropDownButton"], function (declare) { + return declare("fox.form.DropDownButton", dijit.form.DropDownButton, { + startup: function() { + this.inherited(arguments); + this.dropDown.autoFocus = true; // Allow dropdown menu to be focused on click + }, + focus: function() { + return; // Stop dijit.form.DropDownButton from keeping focus after closing the menu + }, + }); +}); diff --git a/js/form/Select.js b/js/form/Select.js new file mode 100755 index 000000000..c62db1821 --- /dev/null +++ b/js/form/Select.js @@ -0,0 +1,8 @@ +/* global dijit */ +define(["dojo/_base/declare", "dijit/form/Select"], function (declare) { + return declare("fox.form.Select", dijit.form.Select, { + focus: function() { + return; // Stop dijit.form.Select from keeping focus after closing the menu + }, + }); +}); diff --git a/js/prefs.js b/js/prefs.js index b4ac9976e..844ce8c8a 100755 --- a/js/prefs.js +++ b/js/prefs.js @@ -53,7 +53,11 @@ require(["dojo/_base/kernel", "fox/PrefFilterStore", "fox/PrefFeedTree", "fox/PrefFilterTree", - "fox/PrefLabelTree"], function (dojo, declare, ready, parser, AppBase) { + "fox/PrefLabelTree", + "fox/Toolbar", + "fox/form/Select", + "fox/form/ComboButton", + "fox/form/DropDownButton"], function (dojo, declare, ready, parser, AppBase) { ready(function () { try { @@ -78,6 +82,7 @@ require(["dojo/_base/kernel", this.enableCsrfSupport(); document.onkeydown = (event) => { return App.hotkeyHandler(event) }; + document.onkeypress = (event) => { return App.hotkeyHandler(event) }; App.setLoadingProgress(50); Notify.close(); @@ -117,6 +122,10 @@ require(["dojo/_base/kernel", hotkeyHandler: function (event) { if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return; + // Arrow buttons and escape are not reported via keypress, handle them via keydown. + // escape = 27, left = 37, up = 38, right = 39, down = 40 + if (event.type == "keydown" && event.which != 27 && (event.which < 37 || event.which > 40)) return; + const action_name = App.keyeventToAction(event); if (action_name) { diff --git a/js/tt-rss.js b/js/tt-rss.js index 99b44549b..a31404426 100644 --- a/js/tt-rss.js +++ b/js/tt-rss.js @@ -54,7 +54,11 @@ require(["dojo/_base/kernel", "fox/Headlines", "fox/Article", "fox/FeedStoreModel", - "fox/FeedTree"], function (dojo, declare, ready, parser, AppBase) { + "fox/FeedTree", + "fox/Toolbar", + "fox/form/Select", + "fox/form/ComboButton", + "fox/form/DropDownButton"], function (dojo, declare, ready, parser, AppBase) { ready(function () { try { @@ -144,13 +148,6 @@ require(["dojo/_base/kernel", dijit.getEnclosingWidget(toolbar.order_by).attr('value', App.getInitParam("default_view_order_by")); - const hash_feed_id = hash_get('f'); - const hash_feed_is_cat = hash_get('c') == "1"; - - if (hash_feed_id != undefined) { - Feeds.setActive(hash_feed_id, hash_feed_is_cat); - } - App.setLoadingProgress(50); this._widescreen_mode = App.getInitParam("widescreen"); @@ -203,9 +200,13 @@ require(["dojo/_base/kernel", isCombinedMode: function() { return App.getInitParam("combined_display_mode"); }, - hotkeyHandler(event) { + hotkeyHandler: function(event) { if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return; + // Arrow buttons and escape are not reported via keypress, handle them via keydown. + // escape = 27, left = 37, up = 38, right = 39, down = 40 + if (event.type == "keydown" && event.which != 27 && (event.which < 37 || event.which > 40)) return; + const action_name = App.keyeventToAction(event); if (action_name) { @@ -412,6 +413,9 @@ require(["dojo/_base/kernel", dijit.byId("feedTree").collapseCat(Feeds.getActive()); } }; + this.hotkey_actions["goto_read"] = function () { + Feeds.open({feed: -6}); + }; this.hotkey_actions["goto_all"] = function () { Feeds.open({feed: -4}); }; |