]> git.wh0rd.org - tt-rss.git/blobdiff - js/functions.js
update perms
[tt-rss.git] / js / functions.js
old mode 100755 (executable)
new mode 100644 (file)
index dd70477..25aa26d
@@ -5,6 +5,9 @@ let _label_base_index = -1024;
 let loading_progress = 0;
 let notify_hide_timerid = false;
 
+let hotkey_prefix = 0;
+let hotkey_prefix_pressed = false;
+
 Ajax.Base.prototype.initialize = Ajax.Base.prototype.initialize.wrap(
        function (callOriginal, options) {
 
@@ -27,23 +30,23 @@ Ajax.Base.prototype.initialize = Ajax.Base.prototype.initialize.wrap(
 
 function xhrPost(url, params, complete) {
        console.log("xhrPost:", params);
-    new Ajax.Request(url, {
-        parameters: params,
-        onComplete: complete
-    });
+       return new Ajax.Request(url, {
+               parameters: params,
+               onComplete: complete
+       });
 }
 
 function xhrJson(url, params, complete) {
-    xhrPost(url, params, (reply) => {
-        try {
-            const obj = JSON.parse(reply.responseText);
-            complete(obj);
-        } catch (e) {
-            console.error("xhrJson", e, reply);
-            complete(null);
-        }
-
-    })
+       return xhrPost(url, params, (reply) => {
+               try {
+                       const obj = JSON.parse(reply.responseText);
+                       complete(obj);
+               } catch (e) {
+                       console.error("xhrJson", e, reply);
+                       complete(null);
+               }
+
+       })
 }
 
 /* add method to remove element from array */
@@ -243,15 +246,15 @@ function getCookie(name) {
        const prefix = name + "=";
        let begin = dc.indexOf("; " + prefix);
        if (begin == -1) {
-           begin = dc.indexOf(prefix);
-           if (begin != 0) return null;
+               begin = dc.indexOf(prefix);
+               if (begin != 0) return null;
        }
        else {
-           begin += 2;
+               begin += 2;
        }
        let end = document.cookie.indexOf(";", begin);
        if (end == -1) {
-           end = dc.length;
+               end = dc.length;
        }
        return unescape(dc.substring(begin + prefix.length, end));
 }
@@ -339,8 +342,8 @@ function displayDlg(title, id, param, callback) {
        const query = { op: "dlg", method: id, param: param };
 
        xhrPost("backend.php", query, (transport) => {
-        infobox_callback2(transport, title);
-        if (callback) callback(transport);
+               infobox_callback2(transport, title);
+               if (callback) callback(transport);
        });
 
        return false;
@@ -475,12 +478,8 @@ function loading_set_progress(p) {
                dijit.byId("loading_bar").update({progress: loading_progress});
 
        if (loading_progress >= 90)
-               remove_splash();
-
-}
+               Element.hide("overlay");
 
-function remove_splash() {
-       Element.hide("overlay");
 }
 
 function strip_tags(s) {
@@ -498,9 +497,6 @@ function hotkey_prefix_timeout() {
                hotkey_prefix = false;
                Element.hide('cmdline');
        }
-
-       setTimeout(hotkey_prefix_timeout, 1000);
-
 }
 
 function uploadIconHandler(rc) {
@@ -527,16 +523,16 @@ function removeFeedIcon(id) {
 
                notify_progress("Removing feed icon...", true);
 
-        const query = { op: "pref-feeds", method: "removeicon", feed_id: id };
+               const query = { op: "pref-feeds", method: "removeicon", feed_id: id };
 
                xhrPost("backend.php", query, (transport) => {
-            notify_info("Feed icon removed.");
-            if (inPreferences()) {
-                updateFeedList();
-            } else {
-                setTimeout('updateFeedList(false, false)', 50);
-            }
-        });
+                       notify_info("Feed icon removed.");
+                       if (inPreferences()) {
+                               updateFeedList();
+                       } else {
+                               setTimeout('updateFeedList(false, false)', 50);
+                       }
+               });
        }
 
        return false;
@@ -574,14 +570,14 @@ function addLabel(select, callback) {
                notify_progress("Loading, please wait...", true);
 
                xhrPost("backend.php", query, (transport) => {
-            if (callback) {
-                callback(transport);
-            } else if (inPreferences()) {
-                updateLabelList();
-            } else {
-                updateFeedList();
-            }
-        });
+                       if (callback) {
+                               callback(transport);
+                       } else if (inPreferences()) {
+                               updateLabelList();
+                       } else {
+                               updateFeedList();
+                       }
+               });
        }
 
 }
@@ -616,75 +612,75 @@ function quickAddFeed() {
                                Element.hide("fadd_error_message");
 
                                xhrPost("backend.php", this.attr('value'), (transport) => {
-                    try {
-
-                        try {
-                            var reply = JSON.parse(transport.responseText);
-                        } catch (e) {
-                            Element.hide("feed_add_spinner");
-                            alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."));
-                            console.log('quickAddFeed, backend returned:' + transport.responseText);
-                            return;
-                        }
-
-                        const rc = reply['result'];
-
-                        notify('');
-                        Element.hide("feed_add_spinner");
-
-                        console.log(rc);
-
-                        switch (parseInt(rc['code'])) {
-                            case 1:
-                                dialog.hide();
-                                notify_info(__("Subscribed to %s").replace("%s", feed_url));
-
-                                updateFeedList();
-                                break;
-                            case 2:
-                                dialog.show_error(__("Specified URL seems to be invalid."));
-                                break;
-                            case 3:
-                                dialog.show_error(__("Specified URL doesn't seem to contain any feeds."));
-                                break;
-                            case 4:
-                                const feeds = rc['feeds'];
-
-                                Element.show("fadd_multiple_notify");
-
-                                const select = dijit.byId("feedDlg_feedContainerSelect");
-
-                                while (select.getOptions().length > 0)
-                                    select.removeOption(0);
-
-                                select.addOption({value: '', label: __("Expand to select feed")});
-
-                                let count = 0;
-                                for (const feedUrl in feeds) {
-                                    select.addOption({value: feedUrl, label: feeds[feedUrl]});
-                                    count++;
-                                }
-
-                                Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
-
-                                break;
-                            case 5:
-                                dialog.show_error(__("Couldn't download the specified URL: %s").
-                                replace("%s", rc['message']));
-                                break;
-                            case 6:
-                                dialog.show_error(__("XML validation failed: %s").
-                                replace("%s", rc['message']));
-                                break;
-                            case 0:
-                                dialog.show_error(__("You are already subscribed to this feed."));
-                                break;
-                        }
-
-                    } catch (e) {
-                        console.error(transport.responseText);
-                        exception_error(e);
-                    }
+                                       try {
+
+                                               try {
+                                                       var reply = JSON.parse(transport.responseText);
+                                               } catch (e) {
+                                                       Element.hide("feed_add_spinner");
+                                                       alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."));
+                                                       console.log('quickAddFeed, backend returned:' + transport.responseText);
+                                                       return;
+                                               }
+
+                                               const rc = reply['result'];
+
+                                               notify('');
+                                               Element.hide("feed_add_spinner");
+
+                                               console.log(rc);
+
+                                               switch (parseInt(rc['code'])) {
+                                                       case 1:
+                                                               dialog.hide();
+                                                               notify_info(__("Subscribed to %s").replace("%s", feed_url));
+
+                                                               updateFeedList();
+                                                               break;
+                                                       case 2:
+                                                               dialog.show_error(__("Specified URL seems to be invalid."));
+                                                               break;
+                                                       case 3:
+                                                               dialog.show_error(__("Specified URL doesn't seem to contain any feeds."));
+                                                               break;
+                                                       case 4:
+                                                               const feeds = rc['feeds'];
+
+                                                               Element.show("fadd_multiple_notify");
+
+                                                               const select = dijit.byId("feedDlg_feedContainerSelect");
+
+                                                               while (select.getOptions().length > 0)
+                                                                       select.removeOption(0);
+
+                                                               select.addOption({value: '', label: __("Expand to select feed")});
+
+                                                               let count = 0;
+                                                               for (const feedUrl in feeds) {
+                                                                       select.addOption({value: feedUrl, label: feeds[feedUrl]});
+                                                                       count++;
+                                                               }
+
+                                                               Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
+
+                                                               break;
+                                                       case 5:
+                                                               dialog.show_error(__("Couldn't download the specified URL: %s").
+                                                               replace("%s", rc['message']));
+                                                               break;
+                                                       case 6:
+                                                               dialog.show_error(__("XML validation failed: %s").
+                                                               replace("%s", rc['message']));
+                                                               break;
+                                                       case 0:
+                                                               dialog.show_error(__("You are already subscribed to this feed."));
+                                                               break;
+                                               }
+
+                                       } catch (e) {
+                                               console.error(transport.responseText);
+                                               exception_error(e);
+                                       }
                                });
                        }
                },
@@ -1087,8 +1083,25 @@ function backend_sanity_check_callback(transport) {
                console.log('reading init-params...');
 
                for (const k in params) {
-                       console.log("IP: " + k + " => " + JSON.stringify(params[k]));
-                       if (k == "label_base_index") _label_base_index = parseInt(params[k]);
+                       switch (k) {
+                               case "label_base_index":
+                                       _label_base_index = parseInt(params[k])
+                                       break;
+                               case "hotkeys":
+                                       // filter mnemonic definitions (used for help panel) from hotkeys map
+                                       // i.e. *(191)|Ctrl-/ -> *(191)
+
+                                       const tmp = [];
+                                       for (const sequence in params[k][1]) {
+                                               const filtered = sequence.replace(/\|.*$/, "");
+                                               tmp[filtered] = params[k][1][sequence];
+                                       }
+
+                                       params[k][1] = tmp;
+                                       break;
+                       }
+
+                       console.log("IP:", k, "=>", params[k]);
                }
 
                init_params = params;
@@ -1101,9 +1114,7 @@ function backend_sanity_check_callback(transport) {
 }
 
 function genUrlChangeKey(feed, is_cat) {
-       const ok = confirm(__("Generate new syndication address for this feed?"));
-
-       if (ok) {
+       if (confirm(__("Generate new syndication address for this feed?"))) {
 
                notify_progress("Trying to change address...", true);
 
@@ -1375,22 +1386,18 @@ function showFeedsWithErrors() {
                removeSelected: function() {
                        const sel_rows = this.getSelectedFeeds();
 
-                       console.log(sel_rows);
-
                        if (sel_rows.length > 0) {
-                               const ok = confirm(__("Remove selected feeds?"));
-
-                               if (ok) {
+                               if (confirm(__("Remove selected feeds?"))) {
                                        notify_progress("Removing selected feeds...", true);
 
                                        const query = { op: "pref-feeds", method: "remove",
                                                ids: sel_rows.toString() };
 
                                        xhrPost("backend.php",  query, () => {
-                        notify('');
-                        dialog.hide();
-                        updateFeedList();
-                    });
+                                               notify('');
+                                               dialog.hide();
+                                               updateFeedList();
+                                       });
                                }
 
                        } else {
@@ -1428,70 +1435,6 @@ function helpDialog(topic) {
        dialog.show();
 }
 
-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 -&gt; &quot;</p>", 'ENT_NOQUOTES');
-  // *     returns 1: '<p>this -> &quot;</p>'
-  // *     example 2: htmlspecialchars_decode("&amp;quot;");
-  // *     returns 2: '&quot;'
-  let optTemp = 0,
-    i = 0,
-    noquotes = false;
-  if (typeof quote_style === 'undefined') {
-    quote_style = 2;
-  }
-  string = string.toString().replace(/&lt;/g, '<').replace(/&gt;/g, '>');
-  const 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(/&#0*39;/g, "'"); // PHP doesn't currently escape if more than one 0, but it should
-    // string = string.replace(/&apos;|&#x0*27;/g, "'"); // This would also be useful here, but not a part of PHP
-  }
-  if (!noquotes) {
-    string = string.replace(/&quot;/g, '"');
-  }
-  // Put this in last place to avoid escape being double-decoded
-  string = string.replace(/&amp;/g, '&');
-
-  return string;
-}
-
-
 function label_to_feed_id(label) {
        return _label_base_index - 1 - Math.abs(label);
 }
@@ -1537,3 +1480,58 @@ function openArticlePopup(id) {
        w.opener = null;
        w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + getInitParam("csrf_token");
 }
+
+function keyevent_to_action(e) {
+
+       const hotkeys_map = getInitParam("hotkeys");
+       const keycode = e.which;
+       const keychar = String.fromCharCode(keycode).toLowerCase();
+
+       if (keycode == 27) { // escape and drop prefix
+               hotkey_prefix = false;
+       }
+
+       if (keycode == 16 || keycode == 17) return; // ignore lone shift / ctrl
+
+       if (!hotkey_prefix && hotkeys_map[0].indexOf(keychar) != -1) {
+
+               const date = new Date();
+               const ts = Math.round(date.getTime() / 1000);
+
+               hotkey_prefix = keychar;
+               hotkey_prefix_pressed = ts;
+
+               $("cmdline").innerHTML = keychar;
+               Element.show("cmdline");
+
+               e.stopPropagation();
+
+               return false;
+       }
+
+       Element.hide("cmdline");
+
+       let hotkey_name = keychar.search(/[a-zA-Z0-9]/) != -1 ? keychar : "(" + keycode + ")";
+
+       // ensure ^*char notation
+       if (e.shiftKey) hotkey_name = "*" + hotkey_name;
+       if (e.ctrlKey) hotkey_name = "^" + hotkey_name;
+       if (e.altKey) hotkey_name = "+" + hotkey_name;
+       if (e.metaKey) hotkey_name = "%" + hotkey_name;
+
+       const hotkey_full = hotkey_prefix ? hotkey_prefix + " " + hotkey_name : hotkey_name;
+       hotkey_prefix = false;
+
+       let action_name = false;
+
+       for (const sequence in hotkeys_map[1]) {
+               if (sequence == hotkey_full) {
+                       action_name = hotkeys_map[1][sequence];
+                       break;
+               }
+       }
+
+       console.log('keyevent_to_action', hotkey_full, '=>', action_name);
+
+       return action_name;
+}
\ No newline at end of file