diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/App.js | 70 | ||||
-rw-r--r-- | js/Article.js | 26 | ||||
-rw-r--r-- | js/CommonDialogs.js | 18 | ||||
-rw-r--r-- | js/CommonFilters.js | 5 | ||||
-rwxr-xr-x | js/FeedTree.js | 8 | ||||
-rwxr-xr-x | js/Headlines.js | 23 | ||||
-rwxr-xr-x | js/common.js | 78 |
7 files changed, 111 insertions, 117 deletions
@@ -1,8 +1,8 @@ 'use strict'; -/* global __, ngettext, Article, Headlines, Filters */ +/* global __, Article, Ajax, Headlines, Filters */ /* global xhrPost, xhrJson, dojo, dijit, PluginHost, Notify, $$, Feeds, Cookie */ -/* global CommonDialogs, CommonFilters, Plugins */ +/* global CommonDialogs, Plugins, Effect */ const App = { _initParams: [], @@ -12,8 +12,10 @@ const App = { hotkey_prefix_timeout: 0, global_unread: -1, _widescreen_mode: false, + _loading_progress: 0, hotkey_actions: {}, is_prefs: false, + LABEL_BASE_INDEX: -1024, Scrollable: { scrollByPages: function (elem, page_offset) { if (!elem) return; @@ -46,8 +48,14 @@ const App = { return elem.offsetTop + elem.offsetHeight <= ctr.scrollTop + ctr.offsetHeight && elem.offsetTop >= ctr.scrollTop; } - }, - getInitParam: function(k) { + }, + label_to_feed_id: function(label) { + return this.LABEL_BASE_INDEX - 1 - Math.abs(label); + }, + feed_to_label_id: function(feed) { + return this.LABEL_BASE_INDEX - 1 + Math.abs(feed); + }, + getInitParam: function(k) { return this._initParams[k]; }, setInitParam: function(k, v) { @@ -130,12 +138,12 @@ const App = { return this._rpc_seq; }, setLoadingProgress: function(p) { - loading_progress += p; + this._loading_progress += p; if (dijit.byId("loading_bar")) - dijit.byId("loading_bar").update({progress: loading_progress}); + dijit.byId("loading_bar").update({progress: this._loading_progress}); - if (loading_progress >= 90) { + if (this._loading_progress >= 90) { $("overlay").hide(); } @@ -223,8 +231,27 @@ const App = { $$("#" + root + " *").each(function (i) { i.parentNode ? i.parentNode.removeChild(i) : true; }); - }, - helpDialog: function(topic) { + }, + // htmlspecialchars()-alike for headlines data-content attribute + escapeHtml: function(text) { + const map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + return text.replace(/[&<>"']/g, function(m) { return map[m]; }); + }, + displayIfChecked: function(checkbox, elemId) { + if (checkbox.checked) { + Effect.Appear(elemId, {duration : 0.5}); + } else { + Effect.Fade(elemId, {duration : 0.5}); + } + }, + helpDialog: function(topic) { const query = "backend.php?op=backend&method=help&topic=" + encodeURIComponent(topic); if (dijit.byId("helpDlg")) @@ -418,7 +445,7 @@ const App = { if (params.hasOwnProperty(k)) { switch (k) { case "label_base_index": - LABEL_BASE_INDEX = parseInt(params[k]); + this.LABEL_BASE_INDEX = parseInt(params[k]); break; case "cdm_auto_catchup": if (params[k] == 1) { @@ -429,16 +456,17 @@ const App = { 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]) { - if (params[k][1].hasOwnProperty(sequence)) { - const filtered = sequence.replace(/\|.*$/, ""); - tmp[filtered] = params[k][1][sequence]; - } - } - - params[k][1] = tmp; + { + const tmp = []; + for (const sequence in params[k][1]) { + if (params[k][1].hasOwnProperty(sequence)) { + const filtered = sequence.replace(/\|.*$/, ""); + tmp[filtered] = params[k][1][sequence]; + } + } + + params[k][1] = tmp; + } break; } @@ -587,7 +615,7 @@ const App = { ['MutationObserver'].each(function(wf) { if (!(wf in window)) { errorMsg = `Browser feature check failed: <code>window.${wf}</code> not found.`; - throw $break; + throw new Error(errorMsg); } }); diff --git a/js/Article.js b/js/Article.js index 5044b6e0e..e7946776e 100644 --- a/js/Article.js +++ b/js/Article.js @@ -1,6 +1,6 @@ 'use strict' -/* global __, ngettext, App, Headlines, xhrPost, xhrJson, dojo, dijit, PluginHost, Notify, $$, escapeHtml */ +/* global __, ngettext, App, Headlines, xhrPost, xhrJson, dojo, dijit, PluginHost, Notify, $$, Ajax */ const Article = { _scroll_reset_timeout: false, @@ -86,6 +86,22 @@ const Article = { } } }, + popupOpenUrl: function(url) { + const w = window.open(""); + + w.opener = null; + w.location = url; + }, + /* popupOpenArticle: function(id) { + const w = window.open("", + "ttrss_article_popup", + "height=900,width=900,resizable=yes,status=no,location=no,menubar=no,directories=no,scrollbars=yes,toolbar=no"); + + if (w) { + w.opener = null; + w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token"); + } + }, */ cdmUnsetActive: function (event) { const row = $("RROW-" + Article.getActive()); @@ -157,14 +173,14 @@ const Article = { comments_msg = hl.num_comments + " " + ngettext("comment", "comments", hl.num_comments) } - comments = `<a href="${escapeHtml(hl.comments ? hl.comments : hl.link)}">(${comments_msg})</a>`; + comments = `<a href="${App.escapeHtml(hl.comments ? hl.comments : hl.link)}">(${comments_msg})</a>`; } return comments; }, formatOriginallyFrom: function(hl) { return hl.orig_feed ? `<span> - ${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${escapeHtml(hl.orig_feed[1])}">${hl.orig_feed[0]}</a> + ${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${App.escapeHtml(hl.orig_feed[1])}">${hl.orig_feed[0]}</a> </span>` : ""; }, unpack: function(row) { @@ -213,8 +229,8 @@ const Article = { <div class="header"> <div class="row"> <div class="title"><a target="_blank" rel="noopener noreferrer" - title="${escapeHtml(hl.title)}" - href="${escapeHtml(hl.link)}">${hl.title}</a></div> + title="${App.escapeHtml(hl.title)}" + href="${App.escapeHtml(hl.link)}">${hl.title}</a></div> <div class="date">${hl.updated_long}</div> </div> <div class="row"> diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js index ea178ffca..d3ad35161 100644 --- a/js/CommonDialogs.js +++ b/js/CommonDialogs.js @@ -46,18 +46,20 @@ const CommonDialogs = { xhr.onload = function () { switch (parseInt(this.responseText)) { case 0: - Notify.info("Upload complete."); + { + Notify.info("Upload complete."); - if (App.isPrefs()) - dijit.byId("feedTree").reload(); - else - Feeds.reload(); + if (App.isPrefs()) + dijit.byId("feedTree").reload(); + else + Feeds.reload(); - const icon = $$(".feed-editor-icon")[0]; + const icon = $$(".feed-editor-icon")[0]; - if (icon) - icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); + if (icon) + icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); + } break; case 1: Notify.error("Upload failed: icon is too big."); diff --git a/js/CommonFilters.js b/js/CommonFilters.js index c34380526..9676abe9e 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -1,7 +1,7 @@ 'use strict' -/* global __, ngettext, App, Article, Lists */ -/* global xhrPost, xhrJson, dojo, dijit, Notify, $$, Feeds */ +/* global __, App, Article, Lists, Effect */ +/* global xhrPost, dojo, dijit, Notify, $$, Feeds */ const Filters = { filterDlgCheckAction: function(sender) { @@ -337,6 +337,7 @@ const Filters = { }); if (!App.isPrefs()) { + /* global getSelectionText */ const selectedText = getSelectionText(); const lh = dojo.connect(dialog, "onLoad", function () { diff --git a/js/FeedTree.js b/js/FeedTree.js index 4e8f5930e..ae39728bb 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -1,4 +1,4 @@ -/* global dojo, dijit, define, App, Feeds, CommonDialogs, LABEL_BASE_INDEX */ +/* global dojo, dijit, define, App, Feeds, CommonDialogs */ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct) { @@ -34,7 +34,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], const id = args.item.id[0]; const bare_id = parseInt(id.substr(id.indexOf(':')+1)); - if (bare_id < LABEL_BASE_INDEX) { + if (bare_id < App.LABEL_BASE_INDEX) { const label = dojo.create('i', { className: "material-icons icon icon-label", innerHTML: "label" }); //const fg_color = args.item.fg_color[0]; @@ -164,9 +164,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], if (item.auxcounter > 0) rc += " Has_Aux"; if (item.markedcounter > 0) rc += " Has_Marked"; if (item.updates_disabled > 0) rc += " UpdatesDisabled"; - if (item.bare_id >= LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id == 0 && !is_cat) rc += " Special"; + if (item.bare_id >= App.LABEL_BASE_INDEX && item.bare_id < 0 && !is_cat || item.bare_id == 0 && !is_cat) rc += " Special"; if (item.bare_id == -1 && is_cat) rc += " AlwaysVisible"; - if (item.bare_id < LABEL_BASE_INDEX) rc += " Label"; + if (item.bare_id < App.LABEL_BASE_INDEX) rc += " Label"; return rc; }, diff --git a/js/Headlines.js b/js/Headlines.js index 1e6fc4268..b98098c33 100755 --- a/js/Headlines.js +++ b/js/Headlines.js @@ -1,7 +1,7 @@ 'use strict'; -/* global __, ngettext, Article, App, escapeHtml */ -/* global xhrPost, xhrJson, dojo, dijit, PluginHost, Notify, $$, Feeds */ +/* global __, ngettext, Article, App */ +/* global xhrPost, dojo, dijit, PluginHost, Notify, $$, Feeds */ /* global CommonDialogs */ const Headlines = { @@ -402,7 +402,7 @@ const Headlines = { if (headlines.vfeed_group_enabled) row_class += " vgrlf"; if (headlines.vfeed_group_enabled && hl.feed_title && this.vgroup_last_feed != hl.feed_id) { - let vgrhdr = `<div data-feed-id='${hl.feed_id}' class='feed-title'> + const vgrhdr = `<div data-feed-id='${hl.feed_id}' class='feed-title'> <div style='float : right'>${hl.feed_icon}</div> <a class="title" href="#" onclick="Feeds.open({feed:${hl.feed_id}})">${hl.feed_title} <a class="catchup" title="${__('mark feed as read')}" onclick="Feeds.catchupFeedInGroup(${hl.feed_id})" href="#"><i class="icon-done material-icons">done_all</i></a> @@ -426,9 +426,9 @@ const Headlines = { id="RROW-${hl.id}" data-article-id="${hl.id}" data-orig-feed-id="${hl.feed_id}" - data-content="${escapeHtml(hl.content)}" + data-content="${App.escapeHtml(hl.content)}" data-score="${hl.score}" - data-article-title="${escapeHtml(hl.title)}" + data-article-title="${App.escapeHtml(hl.title)}" onmouseover="Article.mouseIn(${hl.id})" onmouseout="Article.mouseOut(${hl.id})"> <div class="header-sticky-guard"></div> @@ -440,7 +440,7 @@ const Headlines = { </div> <span onclick="return Headlines.click(event, ${hl.id});" data-article-id="${hl.id}" class="titleWrap hlMenuAttach"> - <a class="title" title="${escapeHtml(hl.title)}" target="_blank" rel="noopener noreferrer" href="${escapeHtml(hl.link)}"> + <a class="title" title="${App.escapeHtml(hl.title)}" target="_blank" rel="noopener noreferrer" href="${App.escapeHtml(hl.link)}"> ${hl.title}</a> <span class="author">${hl.author}</span> ${hl.labels} @@ -457,7 +457,7 @@ const Headlines = { <div class="right"> <i class="material-icons icon-score" title="${hl.score}" onclick="Article.setScore(${hl.id}, this)">${Article.getScorePic(hl.score)}</i> - <span style="cursor : pointer" title="${escapeHtml(hl.feed_title)}" onclick="Feeds.open({feed:${hl.feed_id}})"> + <span style="cursor : pointer" title="${App.escapeHtml(hl.feed_title)}" onclick="Feeds.open({feed:${hl.feed_id}})"> ${hl.feed_icon}</span> </div> @@ -497,7 +497,7 @@ const Headlines = { data-orig-feed-id="${hl.feed_id}" data-article-id="${hl.id}" data-score="${hl.score}" - data-article-title="${escapeHtml(hl.title)}" + data-article-title="${App.escapeHtml(hl.title)}" onmouseover="Article.mouseIn(${hl.id})" onmouseout="Article.mouseOut(${hl.id})"> <div class="left"> @@ -507,7 +507,7 @@ const Headlines = { </div> <div onclick="return Headlines.click(event, ${hl.id})" class="title"> <span data-article-id="${hl.id}" class="hl-content hlMenuAttach"> - <a class="title" href="${escapeHtml(hl.link)}">${hl.title} <span class="preview">${hl.content_preview}</span></a> + <a class="title" href="${App.escapeHtml(hl.link)}">${hl.title} <span class="preview">${hl.content_preview}</span></a> <span class="author">${hl.author}</span> ${hl.labels} </span> @@ -520,7 +520,7 @@ const Headlines = { </div> <div class="right"> <i class="material-icons icon-score" title="${hl.score}" onclick="Article.setScore(${hl.id}, this)">${Article.getScorePic(hl.score)}</i> - <span onclick="Feeds.open({feed:${hl.feed_id}})" style="cursor : pointer" title="${escapeHtml(hl.feed_title)}">${hl.feed_icon}</span> + <span onclick="Feeds.open({feed:${hl.feed_id}})" style="cursor : pointer" title="${App.escapeHtml(hl.feed_title)}">${hl.feed_icon}</span> </div> </div> `; @@ -685,7 +685,7 @@ const Headlines = { console.log("no headlines received, infscroll_disabled=", Feeds.infscroll_disabled, 'first_id_changed=', first_id_changed); - let hsp = $("headlines-spacer"); + const hsp = $("headlines-spacer"); if (hsp) { if (first_id_changed) { @@ -1207,6 +1207,7 @@ const Headlines = { } }, onActionChanged: function (elem) { + // eslint-disable-next-line no-eval eval(elem.value); elem.attr('value', 'false'); }, diff --git a/js/common.js b/js/common.js index 69b528a1c..c17e8bc45 100755 --- a/js/common.js +++ b/js/common.js @@ -1,21 +1,19 @@ -'use strict' -/* global dijit, __ */ +'use strict'; -let LABEL_BASE_INDEX = -1024; /* not const because it's assigned at least once (by backend) */ -let loading_progress = 0; +/* global dijit, __, App, Ajax */ /* error reporting shim */ - // TODO: deprecated; remove -function exception_error(e, e_compat, filename, lineno, colno) { +/* function exception_error(e, e_compat, filename, lineno, colno) { if (typeof e == "string") e = e_compat; App.Error.report(e, {filename: filename, lineno: lineno, colno: colno}); -} +} */ /* xhr shorthand helpers */ +/* exported xhrPost */ function xhrPost(url, params, complete) { console.log("xhrPost:", params); @@ -31,6 +29,7 @@ function xhrPost(url, params, complete) { }); } +/* exported xhrJson */ function xhrJson(url, params, complete) { return new Promise((resolve, reject) => { return xhrPost(url, params).then((reply) => { @@ -58,6 +57,7 @@ Array.prototype.remove = function(s) { /* common helpers not worthy of separate Dojo modules */ +/* exported Lists */ const Lists = { onRowChecked: function(elem) { const checked = elem.domNode ? elem.attr("checked") : elem.checked; @@ -87,7 +87,7 @@ const Lists = { }, }; -// noinspection JSUnusedGlobalSymbols +/* exported Tables */ const Tables = { onRowChecked: function(elem) { // account for dojo checkboxes @@ -133,6 +133,7 @@ const Tables = { } }; +/* exported Cookie */ const Cookie = { set: function (name, value, lifetime) { const d = new Date(); @@ -152,12 +153,12 @@ const Cookie = { }, delete: function(name) { const expires = "expires=Thu, 01-Jan-1970 00:00:01 GMT"; - document.cookie = name + "=" + "" + "; " + expires; + document.cookie = name + "=; " + expires; } }; /* runtime notifications */ - +/* exported Notify */ const Notify = { KIND_GENERIC: 0, KIND_INFO: 1, @@ -237,30 +238,8 @@ const Notify = { } }; -// noinspection JSUnusedGlobalSymbols -function displayIfChecked(checkbox, elemId) { - if (checkbox.checked) { - Effect.Appear(elemId, {duration : 0.5}); - } else { - Effect.Fade(elemId, {duration : 0.5}); - } -} - -/* function strip_tags(s) { - return s.replace(/<\/?[^>]+(>|$)/g, ""); -} */ - -// noinspection JSUnusedGlobalSymbols -function label_to_feed_id(label) { - return LABEL_BASE_INDEX - 1 - Math.abs(label); -} - -// noinspection JSUnusedGlobalSymbols -function feed_to_label_id(feed) { - return LABEL_BASE_INDEX - 1 + Math.abs(feed); -} - // http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac +/* exported getSelectionText */ function getSelectionText() { let text = ""; @@ -281,36 +260,3 @@ function getSelectionText() { return text.stripTags(); } - -// noinspection JSUnusedGlobalSymbols -function popupOpenUrl(url) { - const w = window.open(""); - - w.opener = null; - w.location = url; -} - -// noinspection JSUnusedGlobalSymbols -function popupOpenArticle(id) { - const w = window.open("", - "ttrss_article_popup", - "height=900,width=900,resizable=yes,status=no,location=no,menubar=no,directories=no,scrollbars=yes,toolbar=no"); - - if (w) { - w.opener = null; - w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token"); - } -} - -// htmlspecialchars()-alike for headlines data-content attribute -function escapeHtml(text) { - const map = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; - - return text.replace(/[&<>"']/g, function(m) { return map[m]; }); -} |