diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..4af5f2ccf
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,3 @@
+*.min.js
+node_modules/
+p/scripts/vendor/
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 000000000..a528c8f59
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,26 @@
+{
+ "env": {
+ "browser": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "standard"
+ ],
+ "rules": {
+ "camelcase": "off",
+ "comma-dangle": ["warn", "always-multiline"],
+ "eqeqeq": "off",
+ "indent": ["warn", "tab", { "SwitchCase": 1 }],
+ "linebreak-style": ["error", "unix"],
+ "max-len": ["warn", 165],
+ "no-tabs": "off",
+ "semi": ["warn", "always"],
+ "space-before-function-paren": ["warn", {
+ "anonymous": "always",
+ "named": "never",
+ "asyncArrow": "always"
+ }],
+ "yoda": "off"
+ },
+ "root": true
+}
diff --git a/.gitignore b/.gitignore
index 6228619ed..c6ef860c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
/bin
/node_modules
-package*.json
+package-lock.json
constants.local.php
# Temp files
diff --git a/.jshintrc b/.jshintrc
index 07d282b1c..36d4e3ff3 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,8 +1,9 @@
{
- "esversion" : 6,
+ "esversion" : 8,
"browser" : true,
"globals": {
"confirm": true,
"console": true
- }
+ },
+ "strict": "global"
}
diff --git a/.stylelintrc b/.stylelintrc
index c8efe2ca9..b14138d3a 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -33,11 +33,9 @@
"no-eol-whitespace": true,
"property-no-vendor-prefix": true,
"rule-empty-line-before": [
- "always",
- "except": [
- "after-single-line-comment",
- "first-nested"
- ]
+ "always", {
+ "except": ["after-single-line-comment","first-nested"]
+ }
],
"order/properties-order": [
"margin",
diff --git a/.travis.yml b/.travis.yml
index 9a8bbac0a..015c84a04 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -45,12 +45,9 @@ jobs:
env:
- HADOLINT="$HOME/hadolint"
install:
- - npm install --save-dev jshint stylelint stylelint-order stylelint-scss stylelint-config-recommended-scss
+ - npm install
- curl -sL -o ${HADOLINT} "https://github.com/hadolint/hadolint/releases/download/v1.18.0/hadolint-$(uname -s)-$(uname -m)" && chmod 700 ${HADOLINT}
script:
- - node_modules/jshint/bin/jshint .
- # check SCSS separately
- - stylelint --syntax scss "**/*.scss"
- - stylelint "**/*.css"
+ - npm test
- bash tests/shellchecks.sh
- git ls-files --exclude='*Dockerfile*' --ignored | xargs --max-lines=1 "$HADOLINT"
diff --git a/p/scripts/api.js b/p/scripts/api.js
index f9dcabf01..ce52c50ad 100644
--- a/p/scripts/api.js
+++ b/p/scripts/api.js
@@ -1,6 +1,5 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
+'use strict';
function check(url, next) {
if (!url || !next) {
@@ -10,8 +9,8 @@ function check(url, next) {
req.open('GET', url, true);
req.setRequestHeader('Authorization', 'GoogleLogin auth=test/1');
req.onerror = function (e) {
- next('FAIL: HTTP ' + e);
- };
+ next('FAIL: HTTP ' + e);
+ };
req.onload = function () {
if (this.status == 200) {
next(this.response);
@@ -25,40 +24,40 @@ function check(url, next) {
const jsonVars = JSON.parse(document.getElementById('jsonVars').innerHTML);
check(jsonVars.greader + '/check/compatibility', function next(result1) {
- const greaderOutput = document.getElementById('greaderOutput');
- if (result1 === 'PASS') {
- greaderOutput.innerHTML = '✔️ ' + result1;
- } else {
- check(jsonVars.greader + '/check%2Fcompatibility', function next(result2) {
- if (result2 === 'PASS') {
- greaderOutput.innerHTML = '⚠️ WARN: no %2F
support, so some clients will not work!';
- } else {
- check('./greader.php/check/compatibility', function next(result3) {
- if (result3 === 'PASS') {
- greaderOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php';
- } else {
- greaderOutput.innerHTML = '❌ ' + result1;
- }
- });
- }
- });
- }
- });
-
-check(jsonVars.fever + '?api', function next(result1) {
- const feverOutput = document.getElementById('feverOutput');
- try {
- JSON.parse(result1);
- feverOutput.innerHTML = '✔️ PASS';
- } catch (ex) {
- check('./fever.php?api', function next(result2) {
- try {
- JSON.parse(result2);
- feverOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php';
- } catch (ex) {
- feverOutput.innerHTML = '❌ ' + result1;
+ const greaderOutput = document.getElementById('greaderOutput');
+ if (result1 === 'PASS') {
+ greaderOutput.innerHTML = '✔️ ' + result1;
+ } else {
+ check(jsonVars.greader + '/check%2Fcompatibility', function next(result2) {
+ if (result2 === 'PASS') {
+ greaderOutput.innerHTML = '⚠️ WARN: no %2F
support, so some clients will not work!';
+ } else {
+ check('./greader.php/check/compatibility', function next(result3) {
+ if (result3 === 'PASS') {
+ greaderOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php';
+ } else {
+ greaderOutput.innerHTML = '❌ ' + result1;
}
});
- }
- });
+ }
+ });
+ }
+});
+
+check(jsonVars.fever + '?api', function next(result1) {
+ const feverOutput = document.getElementById('feverOutput');
+ try {
+ JSON.parse(result1);
+ feverOutput.innerHTML = '✔️ PASS';
+ } catch (ex) {
+ check('./fever.php?api', function next(result2) {
+ try {
+ JSON.parse(result2);
+ feverOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php';
+ } catch (ex) {
+ feverOutput.innerHTML = '❌ ' + result1;
+ }
+ });
+ }
+});
// @license-end
diff --git a/p/scripts/category.js b/p/scripts/category.js
index 2a24bc47d..e75c04571 100644
--- a/p/scripts/category.js
+++ b/p/scripts/category.js
@@ -1,16 +1,15 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
+'use strict';
/* globals context */
-/* jshint esversion:6, strict:global */
-var loading = false,
- dnd_successful = false;
+let loading = false;
+let dnd_successful = false;
function dragend_process(t) {
t.setAttribute('draggable', 'false');
if (loading) {
- setTimeout(function() {
+ setTimeout(function () {
dragend_process(t);
}, 50);
return;
@@ -25,13 +24,14 @@ function dragend_process(t) {
t.remove();
if (p.childElementCount <= 1) {
- p.insertAdjacentHTML('afterbegin', '
' + context.i18n.category_empty + '
');
+ p.insertAdjacentHTML('afterbegin',
+ '' + context.i18n.category_empty + '
');
}
}
}
-var dragFeedId = '',
- dragHtml = '';
+let dragFeedId = '';
+let dragHtml = '';
function init_draggable() {
if (!window.context) {
@@ -42,99 +42,99 @@ function init_draggable() {
return;
}
- const draggable = '[draggable="true"]',
- dropzone = '[dropzone="move"]',
- dropSection = document.querySelector('.drop-section');
+ const draggable = '[draggable="true"]';
+ const dropzone = '[dropzone="move"]';
+ const dropSection = document.querySelector('.drop-section');
- dropSection.ondragstart = function(ev) {
- const li = ev.target.closest ? ev.target.closest(draggable) : null;
- if (li) {
- const drag = ev.target.closest('[draggable]');
- ev.dataTransfer.effectAllowed = 'move';
- dragHtml = drag.outerHTML;
- dragFeedId = drag.getAttribute('data-feed-id');
- ev.dataTransfer.setData('text', dragFeedId);
- drag.style.opacity = 0.3;
- dnd_successful = false;
- }
- };
+ dropSection.ondragstart = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(draggable) : null;
+ if (li) {
+ const drag = ev.target.closest('[draggable]');
+ ev.dataTransfer.effectAllowed = 'move';
+ dragHtml = drag.outerHTML;
+ dragFeedId = drag.getAttribute('data-feed-id');
+ ev.dataTransfer.setData('text', dragFeedId);
+ drag.style.opacity = 0.3;
+ dnd_successful = false;
+ }
+ };
- dropSection.ondragend = function(ev) {
- const li = ev.target.closest ? ev.target.closest(draggable) : null;
- if (li) {
- dragend_process(li);
- }
- };
+ dropSection.ondragend = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(draggable) : null;
+ if (li) {
+ dragend_process(li);
+ }
+ };
- dropSection.ondragenter = function(ev) {
- const li = ev.target.closest ? ev.target.closest(dropzone) : null;
- if (li) {
- li.classList.add('drag-hover');
- return false;
- }
- };
+ dropSection.ondragenter = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(dropzone) : null;
+ if (li) {
+ li.classList.add('drag-hover');
+ return false;
+ }
+ };
- dropSection.onddragleave = function(ev) {
- const li = ev.target.closest ? ev.target.closest(dropzone) : null;
- if (li) {
- const scroll_top = document.documentElement.scrollTop,
- top = li.offsetTop,
- left = li.offsetLeft,
- right = left + li.clientWidth,
- bottom = top + li.clientHeight,
- mouse_x = ev.screenX,
- mouse_y = ev.clientY + scroll_top;
+ dropSection.onddragleave = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(dropzone) : null;
+ if (li) {
+ const scroll_top = document.documentElement.scrollTop;
+ const top = li.offsetTop;
+ const left = li.offsetLeft;
+ const right = left + li.clientWidth;
+ const bottom = top + li.clientHeight;
+ const mouse_x = ev.screenX;
+ const mouse_y = ev.clientY + scroll_top;
- if (left <= mouse_x && mouse_x <= right &&
+ if (left <= mouse_x && mouse_x <= right &&
top <= mouse_y && mouse_y <= bottom) {
- // HACK because dragleave is triggered when hovering children!
- return;
+ // HACK because dragleave is triggered when hovering children!
+ return;
+ }
+ li.classList.remove('drag-hover');
+ }
+ };
+
+ dropSection.ondragover = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(dropzone) : null;
+ if (li) {
+ ev.dataTransfer.dropEffect = 'move';
+ return false;
+ }
+ };
+
+ dropSection.ondrop = function (ev) {
+ const li = ev.target.closest ? ev.target.closest(dropzone) : null;
+ if (li) {
+ loading = true;
+
+ const req = new XMLHttpRequest();
+ req.open('POST', './?c=feed&a=move', true);
+ req.responseType = 'json';
+ req.onload = function (e) {
+ if (this.status == 200) {
+ li.insertAdjacentHTML('afterend', dragHtml);
+ if (li.classList.contains('disabled')) {
+ li.remove();
+ }
+ dnd_successful = true;
}
- li.classList.remove('drag-hover');
- }
- };
+ };
+ req.onloadend = function (e) {
+ loading = false;
+ dragFeedId = '';
+ dragHtml = '';
+ };
+ req.setRequestHeader('Content-Type', 'application/json');
+ req.send(JSON.stringify({
+ f_id: dragFeedId,
+ c_id: li.parentElement.getAttribute('data-cat-id'),
+ _csrf: context.csrf,
+ }));
- dropSection.ondragover = function(ev) {
- const li = ev.target.closest ? ev.target.closest(dropzone) : null;
- if (li) {
- ev.dataTransfer.dropEffect = "move";
- return false;
- }
- };
-
- dropSection.ondrop = function(ev) {
- const li = ev.target.closest ? ev.target.closest(dropzone) : null;
- if (li) {
- loading = true;
-
- const req = new XMLHttpRequest();
- req.open('POST', './?c=feed&a=move', true);
- req.responseType = 'json';
- req.onload = function (e) {
- if (this.status == 200) {
- li.insertAdjacentHTML('afterend', dragHtml);
- if (li.classList.contains('disabled')) {
- li.remove();
- }
- dnd_successful = true;
- }
- };
- req.onloadend = function (e) {
- loading = false;
- dragFeedId = '';
- dragHtml = '';
- };
- req.setRequestHeader('Content-Type', 'application/json');
- req.send(JSON.stringify({
- f_id: dragFeedId,
- c_id: li.parentElement.getAttribute('data-cat-id'),
- _csrf: context.csrf,
- }));
-
- li.classList.remove('drag-hover');
- return false;
- }
- };
+ li.classList.remove('drag-hover');
+ return false;
+ }
+ };
}
function archiving() {
@@ -143,7 +143,7 @@ function archiving() {
if (e.target.id === 'use_default_purge_options') {
slider.querySelectorAll('.archiving').forEach(function (element) {
element.hidden = e.target.checked;
- if (!e.target.checked) element.style.visibility = 'visible'; //Help for Edge 44
+ if (!e.target.checked) element.style.visibility = 'visible'; // Help for Edge 44
});
}
});
diff --git a/p/scripts/draggable.js b/p/scripts/draggable.js
index d9d1d1cc0..8b98346f6 100644
--- a/p/scripts/draggable.js
+++ b/p/scripts/draggable.js
@@ -1,8 +1,7 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
+'use strict';
-const init_draggable_list = function() {
+const init_draggable_list = function () {
if (!window.context) {
if (window.console) {
console.log('FreshRSS draggable list waiting for JS…');
diff --git a/p/scripts/extra.js b/p/scripts/extra.js
index a78b5b10d..3aa1b6d46 100644
--- a/p/scripts/extra.js
+++ b/p/scripts/extra.js
@@ -1,7 +1,6 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
+'use strict';
/* globals context, openNotification, openPopupWithSource, xmlHttpRequestJson */
-/* jshint esversion:6, strict:global */
function fix_popup_preview_selector() {
const link = document.getElementById('popup-preview-selector');
@@ -20,8 +19,8 @@ function fix_popup_preview_selector() {
});
}
-//
-function poormanSalt() { //If crypto.getRandomValues is not available
+//
+function poormanSalt() { // If crypto.getRandomValues is not available
const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz';
let text = '$2a$04$';
for (let i = 22; i > 0; i--) {
@@ -61,8 +60,8 @@ function init_crypto_form() {
const req = new XMLHttpRequest();
req.open('GET', './?c=javascript&a=nonce&user=' + document.getElementById('username').value, false);
req.onerror = function () {
- openNotification('Communication error!', 'bad');
- };
+ openNotification('Communication error!', 'bad');
+ };
req.send();
if (req.status == 200) {
const json = xmlHttpRequestJson(req);
@@ -70,9 +69,9 @@ function init_crypto_form() {
openNotification('Invalid user!', 'bad');
} else {
try {
- const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'),
- s = dcodeIO.bcrypt.hashSync(document.getElementById('passwordPlain').value, json.salt1),
- c = dcodeIO.bcrypt.hashSync(json.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt());
+ const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function');
+ const s = dcodeIO.bcrypt.hashSync(document.getElementById('passwordPlain').value, json.salt1);
+ const c = dcodeIO.bcrypt.hashSync(json.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt());
document.getElementById('challenge').value = c;
if (!s || !c) {
openNotification('Crypto error!', 'bad');
@@ -91,83 +90,83 @@ function init_crypto_form() {
return success;
};
}
-//
+//
function init_password_observers() {
document.querySelectorAll('.toggle-password').forEach(function (a) {
- a.onmousedown = function (ev) {
- const passwordField = document.getElementById(this.getAttribute('data-toggle'));
- passwordField.setAttribute('type', 'text');
- this.classList.add('active');
- return false;
- };
- a.onmouseup = function (ev) {
- const passwordField = document.getElementById(this.getAttribute('data-toggle'));
- passwordField.setAttribute('type', 'password');
- this.classList.remove('active');
- return false;
- };
- });
+ a.onmousedown = function (ev) {
+ const passwordField = document.getElementById(this.getAttribute('data-toggle'));
+ passwordField.setAttribute('type', 'text');
+ this.classList.add('active');
+ return false;
+ };
+ a.onmouseup = function (ev) {
+ const passwordField = document.getElementById(this.getAttribute('data-toggle'));
+ passwordField.setAttribute('type', 'password');
+ this.classList.remove('active');
+ return false;
+ };
+ });
}
function init_select_observers() {
document.querySelectorAll('.select-change').forEach(function (s) {
- s.onchange = function (ev) {
- const opt = s.options[s.selectedIndex],
- url = opt.getAttribute('data-url');
- if (url) {
- s.disabled = true;
- s.value = '';
- if (s.form) {
- s.form.querySelectorAll('[type=submit]').forEach(function (b) {
- b.disabled = true;
- });
- }
- location.href = url;
- }
- };
- });
+ s.onchange = function (ev) {
+ const opt = s.options[s.selectedIndex];
+ const url = opt.getAttribute('data-url');
+ if (url) {
+ s.disabled = true;
+ s.value = '';
+ if (s.form) {
+ s.form.querySelectorAll('[type=submit]').forEach(function (b) {
+ b.disabled = true;
+ });
+ }
+ location.href = url;
+ }
+ };
+ });
}
function init_slider_observers() {
- const slider = document.getElementById('slider'),
- closer = document.getElementById('close-slider');
+ const slider = document.getElementById('slider');
+ const closer = document.getElementById('close-slider');
if (!slider) {
return;
}
document.querySelector('.post').onclick = function (ev) {
- const a = ev.target.closest('.open-slider');
- if (a) {
- if (!context.ajax_loading) {
- context.ajax_loading = true;
+ const a = ev.target.closest('.open-slider');
+ if (a) {
+ if (!context.ajax_loading) {
+ context.ajax_loading = true;
- const req = new XMLHttpRequest();
- req.open('GET', a.href + '&ajax=1', true);
- req.responseType = 'document';
- req.onload = function (e) {
- slider.innerHTML = this.response.body.innerHTML;
- slider.classList.add('active');
- closer.classList.add('active');
- context.ajax_loading = false;
- fix_popup_preview_selector();
- };
- req.send();
- return false;
- }
- }
- };
-
- closer.onclick = function (ev) {
- if (data_leave_validation() || confirm(context.i18n.confirmation_default)) {
- slider.querySelectorAll('form').forEach(function (f) { f.reset(); });
- closer.classList.remove('active');
- slider.classList.remove('active');
- return true;
- } else {
+ const req = new XMLHttpRequest();
+ req.open('GET', a.href + '&ajax=1', true);
+ req.responseType = 'document';
+ req.onload = function (e) {
+ slider.innerHTML = this.response.body.innerHTML;
+ slider.classList.add('active');
+ closer.classList.add('active');
+ context.ajax_loading = false;
+ fix_popup_preview_selector();
+ };
+ req.send();
return false;
}
- };
+ }
+ };
+
+ closer.onclick = function (ev) {
+ if (data_leave_validation() || confirm(context.i18n.confirmation_default)) {
+ slider.querySelectorAll('form').forEach(function (f) { f.reset(); });
+ closer.classList.remove('active');
+ slider.classList.remove('active');
+ return true;
+ } else {
+ return false;
+ }
+ };
}
function data_leave_validation() {
@@ -187,16 +186,16 @@ function data_leave_validation() {
function init_configuration_alert() {
window.onsubmit = function (e) {
- window.hasSubmit = true;
- };
+ window.hasSubmit = true;
+ };
window.onbeforeunload = function (e) {
- if (window.hasSubmit) {
- return;
- }
- if (!data_leave_validation()) {
- return false;
- }
- };
+ if (window.hasSubmit) {
+ return;
+ }
+ if (!data_leave_validation()) {
+ return false;
+ }
+ };
}
function init_extra() {
@@ -204,7 +203,7 @@ function init_extra() {
if (window.console) {
console.log('FreshRSS extra waiting for JS…');
}
- window.setTimeout(init_extra, 50); //Wait for all js to be loaded
+ window.setTimeout(init_extra, 50); // Wait for all js to be loaded
return;
}
init_crypto_form();
@@ -219,10 +218,10 @@ if (document.readyState && document.readyState !== 'loading') {
init_extra();
} else {
document.addEventListener('DOMContentLoaded', function () {
- if (window.console) {
- console.log('FreshRSS extra waiting for DOMContentLoaded…');
- }
- init_extra();
- }, false);
+ if (window.console) {
+ console.log('FreshRSS extra waiting for DOMContentLoaded…');
+ }
+ init_extra();
+ }, false);
}
// @license-end
diff --git a/p/scripts/global_view.js b/p/scripts/global_view.js
index e9515be6a..e3a07382a 100644
--- a/p/scripts/global_view.js
+++ b/p/scripts/global_view.js
@@ -1,9 +1,8 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
+'use strict';
/* globals context, init_load_more, init_posts, init_stream */
-/* jshint esversion:6, strict:global */
-var panel_loading = false;
+let panel_loading = false;
function load_panel(link) {
if (panel_loading) {
@@ -16,63 +15,63 @@ function load_panel(link) {
req.open('GET', link, true);
req.responseType = 'document';
req.onload = function (e) {
- if (this.status != 200) {
- return;
+ if (this.status != 200) {
+ return;
+ }
+ const html = this.response;
+ const foreign = html.querySelectorAll('.nav_menu, #stream .day, #stream .flux, #stream .pagination, #stream.prompt');
+ const panel = document.getElementById('panel');
+ foreign.forEach(function (el) {
+ panel.appendChild(document.adoptNode(el));
+ });
+ panel.querySelectorAll('.nav_menu > :not([id="nav_menu_read_all"])').forEach(function (el) {
+ el.remove();
+ });
+
+ init_load_more(panel);
+ init_posts();
+
+ document.getElementById('overlay').classList.add('visible');
+ panel.classList.add('visible');
+
+ // force le démarrage du scroll en haut.
+ // Sans ça, si l'on scroll en lisant une catégorie par exemple,
+ // en en ouvrant une autre ensuite, on se retrouve au même point de scroll
+ panel.scrollTop = 0;
+ document.documentElement.scrollTop = 0;
+
+ // We already have a click listener in main.js
+ panel.addEventListener('click', function (ev) {
+ const b = ev.target.closest('#nav_menu_read_all button, #bigMarkAsRead');
+ if (b) {
+ console.log(b.formAction);
+
+ const req2 = new XMLHttpRequest();
+ req2.open('POST', b.formAction, false);
+ req2.setRequestHeader('Content-Type', 'application/json');
+ req2.send(JSON.stringify({
+ _csrf: context.csrf,
+ }));
+ if (req2.status == 200) {
+ location.reload(false);
+ return false;
+ }
}
- const html = this.response,
- foreign = html.querySelectorAll('.nav_menu, #stream .day, #stream .flux, #stream .pagination, #stream.prompt'),
- panel = document.getElementById('panel');
- foreign.forEach(function (el) {
- panel.appendChild(document.adoptNode(el));
- });
- panel.querySelectorAll('.nav_menu > :not([id="nav_menu_read_all"])').forEach(function (el) {
- el.remove();
- });
+ });
- init_load_more(panel);
- init_posts();
-
- document.getElementById('overlay').classList.add('visible');
- panel.classList.add('visible');
-
- // force le démarrage du scroll en haut.
- // Sans ça, si l'on scroll en lisant une catégorie par exemple,
- // en en ouvrant une autre ensuite, on se retrouve au même point de scroll
- panel.scrollTop = 0;
- document.documentElement.scrollTop = 0;
-
- //We already have a click listener in main.js
- panel.addEventListener('click', function (ev) {
- const b = ev.target.closest('#nav_menu_read_all button, #bigMarkAsRead');
- if (b) {
- console.log(b.formAction);
-
- const req2 = new XMLHttpRequest();
- req2.open('POST', b.formAction, false);
- req2.setRequestHeader('Content-Type', 'application/json');
- req2.send(JSON.stringify({
- _csrf: context.csrf,
- }));
- if (req2.status == 200) {
- location.reload(false);
- return false;
- }
- }
- });
-
- panel_loading = false;
- };
+ panel_loading = false;
+ };
req.send();
}
function init_close_panel() {
const panel = document.getElementById('panel');
document.querySelector('#overlay .close').onclick = function (ev) {
- panel.innerHTML = '';
- panel.classList.remove('visible');
- document.getElementById('overlay').classList.remove('visible');
- return false;
- };
+ panel.innerHTML = '';
+ panel.classList.remove('visible');
+ document.getElementById('overlay').classList.remove('visible');
+ return false;
+ };
document.addEventListener('keydown', ev => {
const k = (ev.key.trim() || ev.code).toUpperCase();
if (k === 'ESCAPE' || k === 'ESC') {
@@ -85,15 +84,15 @@ function init_close_panel() {
function init_global_view() {
// TODO: should be based on generic classes
document.querySelectorAll('.box a').forEach(function (a) {
- a.onclick = function (ev) {
- load_panel(a.href);
- return false;
- };
- });
+ a.onclick = function (ev) {
+ load_panel(a.href);
+ return false;
+ };
+ });
document.querySelectorAll('.nav_menu #nav_menu_read_all, .nav_menu .toggle_aside').forEach(function (el) {
- el.remove();
- });
+ el.remove();
+ });
const panel = document.getElementById('panel');
init_stream(panel);
@@ -104,7 +103,7 @@ function init_all_global_view() {
if (window.console) {
console.log('FreshRSS Global view waiting for JS…');
}
- window.setTimeout(init_all_global_view, 50); //Wait for all js to be loaded
+ window.setTimeout(init_all_global_view, 50); // Wait for all js to be loaded
return;
}
init_global_view();
diff --git a/p/scripts/install.js b/p/scripts/install.js
index 448f70b56..7c802531e 100644
--- a/p/scripts/install.js
+++ b/p/scripts/install.js
@@ -1,6 +1,5 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
+'use strict';
function show_password(ev) {
const button = ev.currentTarget;
@@ -13,7 +12,7 @@ function hide_password(ev) {
const button = ev.currentTarget;
const passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'password');
- button.className = button.className.replace(/(?:^|\s)active(?!\S)/g , '');
+ button.className = button.className.replace(/(?:^|\s)active(?!\S)/g, '');
return false;
}
const toggles = document.getElementsByClassName('toggle-password');
@@ -25,8 +24,8 @@ for (let i = 0; i < toggles.length; i++) {
const auth_type = document.getElementById('auth_type');
function auth_type_change() {
if (auth_type) {
- const auth_value = auth_type.value,
- password_input = document.getElementById('passwordPlain');
+ const auth_value = auth_type.value;
+ const password_input = document.getElementById('passwordPlain');
if (auth_value === 'form') {
password_input.required = true;
diff --git a/p/scripts/integration.js b/p/scripts/integration.js
index bf9ac1ca6..acd629573 100644
--- a/p/scripts/integration.js
+++ b/p/scripts/integration.js
@@ -1,8 +1,7 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
+'use strict';
-const init_integration = function() {
+const init_integration = function () {
if (!window.context) {
if (window.console) {
console.log('FreshRSS integration waiting for JS…');
diff --git a/p/scripts/main.js b/p/scripts/main.js
index f44692103..13a49060b 100644
--- a/p/scripts/main.js
+++ b/p/scripts/main.js
@@ -1,12 +1,14 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
+'use strict';
-//
+//
if (!document.scrollingElement) document.scrollingElement = document.documentElement;
if (!NodeList.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach;
-if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.webkitMatchesSelector;
-if (!Element.prototype.closest) Element.prototype.closest = function (s) {
+if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.webkitMatchesSelector;
+}
+if (!Element.prototype.closest) {
+ Element.prototype.closest = function (s) {
let el = this;
do {
if (el.matches(s)) return el;
@@ -14,13 +16,14 @@ if (!Element.prototype.closest) Element.prototype.closest = function (s) {
} while (el);
return null;
};
+}
if (!Element.prototype.remove) Element.prototype.remove = function () { if (this.parentNode) this.parentNode.removeChild(this); };
-//
+//
-//
+//
function xmlHttpRequestJson(req) {
let json = req.response;
- if (req.responseType !== 'json') { //IE11
+ if (req.responseType !== 'json') { // IE11
try {
json = JSON.parse(req.responseText);
} catch (ex) {
@@ -29,14 +32,14 @@ function xmlHttpRequestJson(req) {
}
return json;
}
-//
+//
-//
-var context;
+//
+let context;
(function parseJsonVars() {
- const jsonVars = document.getElementById('jsonVars'),
- json = JSON.parse(jsonVars.innerHTML);
+ const jsonVars = document.getElementById('jsonVars');
+ const json = JSON.parse(jsonVars.innerHTML);
jsonVars.outerHTML = '';
context = json.context;
context.ajax_loading = false;
@@ -48,7 +51,7 @@ var context;
context.icons.unread = decodeURIComponent(context.icons.unread);
context.extensions = json.extensions;
}());
-//
+//
function badAjax(reload) {
openNotification(context.i18n.notif_request_failed, 'bad');
@@ -59,11 +62,13 @@ function badAjax(reload) {
}
function needsScroll(elem) {
- const winBottom = document.scrollingElement.scrollTop + document.scrollingElement.clientHeight,
- elemTop = elem.offsetParent.offsetTop + elem.offsetTop,
- elemBottom = elemTop + elem.offsetHeight;
- return (elemTop < document.scrollingElement.scrollTop || elemBottom > winBottom) ?
- elemTop - (document.scrollingElement.clientHeight / 2) : 0;
+ const winBottom = document.scrollingElement.scrollTop + document.scrollingElement.clientHeight;
+ const elemTop = elem.offsetParent.offsetTop + elem.offsetTop;
+ const elemBottom = elemTop + elem.offsetHeight;
+ if (elemTop < document.scrollingElement.scrollTop || elemBottom > winBottom) {
+ return elemTop - (document.scrollingElement.clientHeight / 2);
+ }
+ return 0;
}
function str2int(str) {
@@ -79,9 +84,9 @@ function numberFormat(nStr) {
}
// http://www.mredkj.com/javascript/numberFormat.html
nStr += '';
- const x = nStr.split('.'),
- x2 = x.length > 1 ? '.' + x[1] : '',
- rgx = /(\d+)(\d{3})/;
+ const x = nStr.split('.');
+ const x2 = x.length > 1 ? '.' + x[1] : '';
+ const rgx = /(\d+)(\d{3})/;
let x1 = x[0];
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1 $2');
@@ -95,10 +100,10 @@ function incLabel(p, inc, spaceAfter) {
}
function incUnreadsFeed(article, feed_id, nb) {
- //Update unread: feed
- let elem = document.getElementById(feed_id),
- feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0,
- feed_priority = elem ? str2int(elem.getAttribute('data-priority')) : 0;
+ // Update unread: feed
+ let elem = document.getElementById(feed_id);
+ let feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
+ const feed_priority = elem ? str2int(elem.getAttribute('data-priority')) : 0;
if (elem) {
elem.setAttribute('data-unread', feed_unreads + nb);
elem = elem.querySelector('.item-title');
@@ -107,7 +112,7 @@ function incUnreadsFeed(article, feed_id, nb) {
}
}
- //Update unread: category
+ // Update unread: category
elem = document.getElementById(feed_id).closest('.category');
feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
if (elem) {
@@ -118,7 +123,7 @@ function incUnreadsFeed(article, feed_id, nb) {
}
}
- //Update unread: all
+ // Update unread: all
if (feed_priority > 0) {
elem = document.querySelector('#aside_feed .all .title');
if (elem) {
@@ -127,7 +132,7 @@ function incUnreadsFeed(article, feed_id, nb) {
}
}
- //Update unread: favourites
+ // Update unread: favourites
if (article && article.closest('div').classList.contains('favorite')) {
elem = document.querySelector('#aside_feed .favorites .title');
if (elem) {
@@ -138,7 +143,7 @@ function incUnreadsFeed(article, feed_id, nb) {
let isCurrentView = false;
// Update unread: title
- document.title = document.title.replace(/^((?:\([ 0-9]+\) )?)/, function (m, p1) {
+ document.title = document.title.replace(/^((?:\([\s0-9]+\) )?)/, function (m, p1) {
const feed = document.getElementById(feed_id);
if (article || feed.closest('.active')) {
isCurrentView = true;
@@ -156,13 +161,13 @@ function incUnreadsFeed(article, feed_id, nb) {
function incUnreadsTag(tag_id, nb) {
let t = document.getElementById(tag_id);
if (t) {
- let unreads = str2int(t.getAttribute('data-unread'));
+ const unreads = str2int(t.getAttribute('data-unread'));
t.setAttribute('data-unread', unreads + nb);
t.querySelector('.item-title').setAttribute('data-unread', numberFormat(unreads + nb));
}
t = document.querySelector('.category.tags .title');
if (t) {
- let unreads = str2int(t.getAttribute('data-unread'));
+ const unreads = str2int(t.getAttribute('data-unread'));
t.setAttribute('data-unread', numberFormat(unreads + nb));
}
}
@@ -173,8 +178,8 @@ function removeArticle(div) {
}
let scrollTop = box_to_follow.scrollTop;
let dirty = false;
- const p = div.previousElementSibling,
- n = div.nextElementSibling;
+ const p = div.previousElementSibling;
+ const n = div.nextElementSibling;
if (p && p.classList.contains('day') && n && n.classList.contains('day')) {
scrollTop -= p.offsetHeight;
dirty = true;
@@ -190,80 +195,80 @@ function removeArticle(div) {
}
}
-var pending_entries = {},
- mark_read_queue = [];
+const pending_entries = {};
+let mark_read_queue = [];
function send_mark_read_queue(queue, asRead, callback) {
const req = new XMLHttpRequest();
req.open('POST', '.?c=entry&a=read' + (asRead ? '' : '&is_read=0'), true);
req.responseType = 'json';
req.onerror = function (e) {
- for (let i = queue.length - 1; i >= 0; i--) {
- delete pending_entries['flux_' + queue[i]];
- }
- badAjax(this.status == 403);
- };
+ for (let i = queue.length - 1; i >= 0; i--) {
+ delete pending_entries['flux_' + queue[i]];
+ }
+ badAjax(this.status == 403);
+ };
req.onload = function (e) {
- if (this.status != 200) {
- return req.onerror(e);
- }
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return req.onerror(e);
- }
- for (let i = queue.length - 1; i >= 0; i--) {
- const div = document.getElementById('flux_' + queue[i]),
- myIcons = context.icons;
- let inc = 0;
- if (div.classList.contains('not_read')) {
- div.classList.remove('not_read');
- div.querySelectorAll('a.read').forEach(function (a) {
- a.href = a.href.replace('&is_read=0', '') + '&is_read=1';
- });
- div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; });
- inc--;
- if (context.auto_remove_article) {
- removeArticle(div);
- }
- } else {
- div.classList.add('not_read');
- div.classList.add('keep_unread'); //Split for IE11
- div.querySelectorAll('a.read').forEach(function (a) {
- a.href = a.href.replace('&is_read=1', '');
- });
- div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.unread; });
- inc++;
+ if (this.status != 200) {
+ return req.onerror(e);
+ }
+ const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return req.onerror(e);
+ }
+ for (let i = queue.length - 1; i >= 0; i--) {
+ const div = document.getElementById('flux_' + queue[i]);
+ const myIcons = context.icons;
+ let inc = 0;
+ if (div.classList.contains('not_read')) {
+ div.classList.remove('not_read');
+ div.querySelectorAll('a.read').forEach(function (a) {
+ a.href = a.href.replace('&is_read=0', '') + '&is_read=1';
+ });
+ div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.read; });
+ inc--;
+ if (context.auto_remove_article) {
+ removeArticle(div);
}
- let feed_link = div.querySelector('.website > a, a.website');
- if (feed_link) {
- const feed_url = feed_link.href,
- feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
- incUnreadsFeed(div, feed_id, inc);
- }
- delete pending_entries['flux_' + queue[i]];
+ } else {
+ div.classList.add('not_read');
+ div.classList.add('keep_unread'); // Split for IE11
+ div.querySelectorAll('a.read').forEach(function (a) {
+ a.href = a.href.replace('&is_read=1', '');
+ });
+ div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = myIcons.unread; });
+ inc++;
}
- faviconNbUnread();
- if (json.tags) {
- const tagIds = Object.keys(json.tags);
- for (let i = tagIds.length - 1; i >= 0; i--) {
- let tagId = tagIds[i];
- incUnreadsTag(tagId, (asRead ? -1 : 1) * json.tags[tagId].length);
- }
+ const feed_link = div.querySelector('.website > a, a.website');
+ if (feed_link) {
+ const feed_url = feed_link.href;
+ const feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
+ incUnreadsFeed(div, feed_id, inc);
}
- onScroll();
- if (callback) {
- callback();
+ delete pending_entries['flux_' + queue[i]];
+ }
+ faviconNbUnread();
+ if (json.tags) {
+ const tagIds = Object.keys(json.tags);
+ for (let i = tagIds.length - 1; i >= 0; i--) {
+ const tagId = tagIds[i];
+ incUnreadsTag(tagId, (asRead ? -1 : 1) * json.tags[tagId].length);
}
- };
+ }
+ onScroll();
+ if (callback) {
+ callback();
+ }
+ };
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify({
- ajax: true,
- _csrf: context.csrf,
- id: queue,
- }));
+ ajax: true,
+ _csrf: context.csrf,
+ id: queue,
+ }));
}
-var send_mark_read_queue_timeout = 0;
+let send_mark_read_queue_timeout = 0;
function send_mark_queue_tick(callback) {
send_mark_read_queue_timeout = 0;
@@ -271,7 +276,7 @@ function send_mark_queue_tick(callback) {
mark_read_queue = [];
send_mark_read_queue(queue, true, callback);
}
-var delayedFunction = send_mark_queue_tick;
+const delayedFunction = send_mark_queue_tick;
function delayedClick(a) {
if (a) {
@@ -289,15 +294,15 @@ function mark_read(div, only_not_read, asBatch) {
}
pending_entries[div.id] = true;
- const asRead = div.classList.contains('not_read'),
- entryId = div.id.replace(/^flux_/, '');
+ const asRead = div.classList.contains('not_read');
+ const entryId = div.id.replace(/^flux_/, '');
if (asRead && asBatch) {
mark_read_queue.push(entryId);
if (send_mark_read_queue_timeout == 0) {
send_mark_read_queue_timeout = setTimeout(function () { send_mark_queue_tick(null); }, 1000);
}
} else {
- const queue = [ entryId ];
+ const queue = [entryId];
send_mark_read_queue(queue, asRead);
}
}
@@ -314,8 +319,8 @@ function mark_favorite(div) {
return false;
}
- let a = div.querySelector('a.bookmark'),
- url = a ? a.href : '';
+ const a = div.querySelector('a.bookmark');
+ const url = a ? a.href : '';
if (!url) {
return false;
}
@@ -329,53 +334,53 @@ function mark_favorite(div) {
req.open('POST', url, true);
req.responseType = 'json';
req.onerror = function (e) {
- delete pending_entries[div.id];
- badAjax(this.status == 403);
- };
+ delete pending_entries[div.id];
+ badAjax(this.status == 403);
+ };
req.onload = function (e) {
- if (this.status != 200) {
- return req.onerror(e);
- }
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return req.onerror(e);
- }
- let inc = 0;
- if (div.classList.contains('favorite')) {
- div.classList.remove('favorite');
- inc--;
- } else {
- div.classList.add('favorite');
- inc++;
- }
- div.querySelectorAll('a.bookmark').forEach(function (a) { a.href = json.url; });
- div.querySelectorAll('a.bookmark > .icon').forEach(function (img) { img.outerHTML = json.icon; });
+ if (this.status != 200) {
+ return req.onerror(e);
+ }
+ const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return req.onerror(e);
+ }
+ let inc = 0;
+ if (div.classList.contains('favorite')) {
+ div.classList.remove('favorite');
+ inc--;
+ } else {
+ div.classList.add('favorite');
+ inc++;
+ }
+ div.querySelectorAll('a.bookmark').forEach(function (a) { a.href = json.url; });
+ div.querySelectorAll('a.bookmark > .icon').forEach(function (img) { img.outerHTML = json.icon; });
- const favourites = document.querySelector('#aside_feed .favorites .title');
- if (favourites) {
- favourites.textContent = favourites.textContent.replace(/((?: \([ 0-9]+\))?\s*)$/, function (m, p1) {
- return incLabel(p1, inc, false);
- });
- }
+ const favourites = document.querySelector('#aside_feed .favorites .title');
+ if (favourites) {
+ favourites.textContent = favourites.textContent.replace(/((?: \([\s0-9]+\))?\s*)$/, function (m, p1) {
+ return incLabel(p1, inc, false);
+ });
+ }
- if (div.classList.contains('not_read')) {
- const elem = document.querySelector('#aside_feed .favorites .title'),
- feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
- if (elem) {
- elem.setAttribute('data-unread', numberFormat(feed_unreads + inc));
- }
+ if (div.classList.contains('not_read')) {
+ const elem = document.querySelector('#aside_feed .favorites .title');
+ const feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
+ if (elem) {
+ elem.setAttribute('data-unread', numberFormat(feed_unreads + inc));
}
+ }
- delete pending_entries[div.id];
- };
+ delete pending_entries[div.id];
+ };
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify({
- ajax: true,
- _csrf: context.csrf,
- }));
+ ajax: true,
+ _csrf: context.csrf,
+ }));
}
-var freshrssOpenArticleEvent = document.createEvent('Event');
+const freshrssOpenArticleEvent = document.createEvent('Event');
freshrssOpenArticleEvent.initEvent('freshrss:openArticle', true, true);
function toggleContent(new_active, old_active, skipping) {
@@ -398,7 +403,7 @@ function toggleContent(new_active, old_active, skipping) {
new_active.classList.add('current');
if (old_active) {
old_active.classList.remove('active');
- old_active.classList.remove('current'); //Split for IE11
+ old_active.classList.remove('current'); // Split for IE11
if (context.auto_remove_article) {
removeArticle(old_active);
}
@@ -407,12 +412,12 @@ function toggleContent(new_active, old_active, skipping) {
new_active.classList.toggle('active');
}
- const relative_move = context.current_view === 'global',
- box_to_move = relative_move ? document.getElementById('panel') : document.scrollingElement;
+ const relative_move = context.current_view === 'global';
+ const box_to_move = relative_move ? document.getElementById('panel') : document.scrollingElement;
- if (context.sticky_post) { //Stick the article to the top when opened
- let prev_article = new_active.previousElementSibling,
- new_pos = new_active.offsetParent.offsetTop + new_active.offsetTop;
+ if (context.sticky_post) { // Stick the article to the top when opened
+ const prev_article = new_active.previousElementSibling;
+ let new_pos = new_active.offsetParent.offsetTop + new_active.offsetTop;
if (prev_article && new_active.offsetTop - prev_article.offsetTop <= 150) {
new_pos = prev_article.offsetParent.offsetTop + prev_article.offsetTop;
@@ -627,8 +632,8 @@ function toggle_media() {
}
function user_filter(key) {
- const filter = document.getElementById('dropdown-query'),
- filters = filter.parentElement.querySelectorAll('.dropdown-menu > .query > a');
+ const filter = document.getElementById('dropdown-query');
+ const filters = filter.parentElement.querySelectorAll('.dropdown-menu > .query > a');
if (typeof key === 'undefined') {
if (!filters.length) {
return;
@@ -683,7 +688,7 @@ function auto_share(key) {
}
}
-var box_to_follow;
+let box_to_follow;
function onScroll() {
if (!box_to_follow) {
@@ -692,11 +697,11 @@ function onScroll() {
if (context.auto_mark_scroll) {
const minTop = 40 + box_to_follow.scrollTop;
document.querySelectorAll('.not_read:not(.keep_unread)').forEach(function (div) {
- if (div.offsetHeight > 0 &&
+ if (div.offsetHeight > 0 &&
div.offsetParent.offsetTop + div.offsetTop + div.offsetHeight < minTop) {
- mark_read(div, true, true);
- }
- });
+ mark_read(div, true, true);
+ }
+ });
}
if (context.auto_load_more) {
const pagination = document.getElementById('mark-read-pagination');
@@ -710,8 +715,8 @@ function onScroll() {
function init_posts() {
if (context.auto_load_more || context.auto_mark_scroll || context.auto_remove_article) {
box_to_follow = context.current_view === 'global' ? document.getElementById('panel') : document.scrollingElement;
- let lastScroll = 0, //Throttle
- timerId = 0;
+ let lastScroll = 0; // Throttle
+ let timerId = 0;
(box_to_follow === document.scrollingElement ? window : box_to_follow).onscroll = function () {
clearTimeout(timerId);
if (lastScroll + 500 < Date.now()) {
@@ -750,10 +755,10 @@ function init_column_categories() {
return;
}
- //Restore sidebar scroll position
+ // Restore sidebar scroll position
document.getElementById('sidebar').scrollTop = +sessionStorage.getItem('FreshRSS_sidebar_scrollTop');
- //Restore open categories
+ // Restore open categories
if (context.display_categories === 'remember') {
const open_categories = JSON.parse(localStorage.getItem('FreshRSS_open_categories') || '{}');
Object.keys(open_categories).forEach(function (category_id) {
@@ -784,21 +789,21 @@ function init_column_categories() {
}
}
ul.classList.toggle('active');
- //CSS transition does not work on max-height:auto
+ // CSS transition does not work on max-height:auto
ul.style.maxHeight = ul.classList.contains('active') ? (nbVisibleItems * 4) + 'em' : 0;
return false;
}
a = ev.target.closest('.tree-folder-items > .feed .dropdown-toggle');
if (a) {
- const itemId = a.closest('.item').id,
- templateId = itemId.substring(0, 2) === 't_' ? 'tag_config_template' : 'feed_config_template',
- id = itemId.substr(2),
- feed_web = a.getAttribute('data-fweb'),
- div = a.parentElement,
- dropdownMenu = div.querySelector('.dropdown-menu'),
- template = document.getElementById(templateId)
- .innerHTML.replace(/------/g, id).replace('http://example.net/', feed_web);
+ const itemId = a.closest('.item').id;
+ const templateId = itemId.substring(0, 2) === 't_' ? 'tag_config_template' : 'feed_config_template';
+ const id = itemId.substr(2);
+ const feed_web = a.getAttribute('data-fweb');
+ const div = a.parentElement;
+ const dropdownMenu = div.querySelector('.dropdown-menu');
+ const template = document.getElementById(templateId)
+ .innerHTML.replace(/------/g, id).replace('http://example.net/', feed_web);
if (!dropdownMenu) {
a.href = '#dropdown-' + id;
div.querySelector('.dropdown-target').id = 'dropdown-' + id;
@@ -822,137 +827,137 @@ function init_column_categories() {
function init_shortcuts() {
Object.keys(context.shortcuts).forEach(function (k) {
- context.shortcuts[k] = (context.shortcuts[k] || '').toUpperCase();
- });
+ context.shortcuts[k] = (context.shortcuts[k] || '').toUpperCase();
+ });
document.addEventListener('keydown', ev => {
- if (ev.target.closest('input, textarea') ||
+ if (ev.target.closest('input, textarea') ||
ev.ctrlKey || ev.metaKey || (ev.altKey && ev.shiftKey)) {
- return true;
- }
-
- const s = context.shortcuts;
- let k = (ev.key.trim() || ev.code || 'Space').toUpperCase();
-
- //IE11
- if (k === 'SPACEBAR') k = 'SPACE';
- else if (k === 'DEL') k = 'DELETE';
- else if (k === 'ESC') k = 'ESCAPE';
-
- if (location.hash.match(/^#dropdown-/)) {
- const n = parseInt(k);
- if (n) {
- if (location.hash === '#dropdown-query') {
- user_filter(n);
- } else {
- auto_share(n);
- }
- return false;
- }
- }
- if (k === s.next_entry) {
- if (ev.altKey) {
- next_category();
- } else if (ev.shiftKey) {
- next_feed();
- } else {
- next_entry(false);
- }
- return false;
- }
- if (k === s.next_unread_entry) {
- if (ev.altKey) {
- next_unread_category();
- } else if (ev.shiftKey) {
- next_feed();
- } else {
- next_unread_entry(false);
- }
- return false;
- }
- if (k === s.prev_entry) {
- if (ev.altKey) {
- prev_category();
- } else if (ev.shiftKey) {
- prev_feed();
- } else {
- prev_entry(false);
- }
- return false;
- }
- if (k === s.mark_read) {
- if (ev.altKey) {
- mark_previous_read(document.querySelector('.flux.current'));
- } else if (ev.shiftKey) {
- document.querySelector('.nav_menu .read_all').click();
- } else { // Toggle the read state
- mark_read(document.querySelector('.flux.current'), false, false);
- }
- return false;
- }
- if (k === s.first_entry) {
- if (ev.altKey) {
- first_category();
- } else if (ev.shiftKey) {
- first_feed();
- } else {
- const old_active = document.querySelector('.flux.current'),
- first = document.querySelector('.flux');
- if (first.classList.contains('flux')) {
- toggleContent(first, old_active, false);
- }
- }
- return false;
- }
- if (k === s.last_entry) {
- if (ev.altKey) {
- last_category();
- } else if (ev.shiftKey) {
- last_feed();
- } else {
- const old_active = document.querySelector('.flux.current'),
- last = document.querySelector('.flux:last-of-type');
- if (last.classList.contains('flux')) {
- toggleContent(last, old_active, false);
- }
- }
- return false;
- }
-
- if (ev.altKey || ev.shiftKey) {
- return true;
- }
- if (k === s.mark_favorite) { // Toggle the favorite state
- mark_favorite(document.querySelector('.flux.current'));
- return false;
- }
- if (k === s.go_website) {
- if (context.auto_mark_site) {
- mark_read(document.querySelector('.flux.current'), true, false);
- }
- const newWindow = window.open();
- if (newWindow) {
- newWindow.opener = null;
- newWindow.location = document.querySelector('.flux.current a.go_website').href;
- }
- return false;
- }
- if (k === s.skip_next_entry) { next_entry(true); return false; }
- if (k === s.skip_prev_entry) { prev_entry(true); return false; }
- if (k === s.collapse_entry) { collapse_entry(); return false; }
- if (k === s.auto_share) { auto_share(); return false; }
- if (k === s.user_filter) { user_filter(); return false; }
- if (k === s.load_more) { load_more_posts(); return false; }
- if (k === s.close_dropdown) { location.hash = null; return false; }
- if (k === s.help) { window.open(context.urls.help); return false; }
- if (k === s.focus_search) { document.getElementById('search').focus(); return false; }
- if (k === s.normal_view) { delayedClick(document.querySelector('#nav_menu_views .view-normal')); return false; }
- if (k === s.reading_view) { delayedClick(document.querySelector('#nav_menu_views .view-reader')); return false; }
- if (k === s.global_view) { delayedClick(document.querySelector('#nav_menu_views .view-global')); return false; }
- if (k === s.rss_view) { delayedClick(document.querySelector('#nav_menu_views .view-rss')); return false; }
- if (k === s.toggle_media) { toggle_media(); return false; }
return true;
- });
+ }
+
+ const s = context.shortcuts;
+ let k = (ev.key.trim() || ev.code || 'Space').toUpperCase();
+
+ // IE11
+ if (k === 'SPACEBAR') k = 'SPACE';
+ else if (k === 'DEL') k = 'DELETE';
+ else if (k === 'ESC') k = 'ESCAPE';
+
+ if (location.hash.match(/^#dropdown-/)) {
+ const n = parseInt(k);
+ if (n) {
+ if (location.hash === '#dropdown-query') {
+ user_filter(n);
+ } else {
+ auto_share(n);
+ }
+ return false;
+ }
+ }
+ if (k === s.next_entry) {
+ if (ev.altKey) {
+ next_category();
+ } else if (ev.shiftKey) {
+ next_feed();
+ } else {
+ next_entry(false);
+ }
+ return false;
+ }
+ if (k === s.next_unread_entry) {
+ if (ev.altKey) {
+ next_unread_category();
+ } else if (ev.shiftKey) {
+ next_feed();
+ } else {
+ next_unread_entry(false);
+ }
+ return false;
+ }
+ if (k === s.prev_entry) {
+ if (ev.altKey) {
+ prev_category();
+ } else if (ev.shiftKey) {
+ prev_feed();
+ } else {
+ prev_entry(false);
+ }
+ return false;
+ }
+ if (k === s.mark_read) {
+ if (ev.altKey) {
+ mark_previous_read(document.querySelector('.flux.current'));
+ } else if (ev.shiftKey) {
+ document.querySelector('.nav_menu .read_all').click();
+ } else { // Toggle the read state
+ mark_read(document.querySelector('.flux.current'), false, false);
+ }
+ return false;
+ }
+ if (k === s.first_entry) {
+ if (ev.altKey) {
+ first_category();
+ } else if (ev.shiftKey) {
+ first_feed();
+ } else {
+ const old_active = document.querySelector('.flux.current');
+ const first = document.querySelector('.flux');
+ if (first.classList.contains('flux')) {
+ toggleContent(first, old_active, false);
+ }
+ }
+ return false;
+ }
+ if (k === s.last_entry) {
+ if (ev.altKey) {
+ last_category();
+ } else if (ev.shiftKey) {
+ last_feed();
+ } else {
+ const old_active = document.querySelector('.flux.current');
+ const last = document.querySelector('.flux:last-of-type');
+ if (last.classList.contains('flux')) {
+ toggleContent(last, old_active, false);
+ }
+ }
+ return false;
+ }
+
+ if (ev.altKey || ev.shiftKey) {
+ return true;
+ }
+ if (k === s.mark_favorite) { // Toggle the favorite state
+ mark_favorite(document.querySelector('.flux.current'));
+ return false;
+ }
+ if (k === s.go_website) {
+ if (context.auto_mark_site) {
+ mark_read(document.querySelector('.flux.current'), true, false);
+ }
+ const newWindow = window.open();
+ if (newWindow) {
+ newWindow.opener = null;
+ newWindow.location = document.querySelector('.flux.current a.go_website').href;
+ }
+ return false;
+ }
+ if (k === s.skip_next_entry) { next_entry(true); return false; }
+ if (k === s.skip_prev_entry) { prev_entry(true); return false; }
+ if (k === s.collapse_entry) { collapse_entry(); return false; }
+ if (k === s.auto_share) { auto_share(); return false; }
+ if (k === s.user_filter) { user_filter(); return false; }
+ if (k === s.load_more) { load_more_posts(); return false; }
+ if (k === s.close_dropdown) { location.hash = null; return false; }
+ if (k === s.help) { window.open(context.urls.help); return false; }
+ if (k === s.focus_search) { document.getElementById('search').focus(); return false; }
+ if (k === s.normal_view) { delayedClick(document.querySelector('#nav_menu_views .view-normal')); return false; }
+ if (k === s.reading_view) { delayedClick(document.querySelector('#nav_menu_views .view-reader')); return false; }
+ if (k === s.global_view) { delayedClick(document.querySelector('#nav_menu_views .view-global')); return false; }
+ if (k === s.rss_view) { delayedClick(document.querySelector('#nav_menu_views .view-rss')); return false; }
+ if (k === s.toggle_media) { toggle_media(); return false; }
+ return true;
+ });
}
function init_stream(stream) {
@@ -990,9 +995,9 @@ function init_stream(stream) {
}
el = ev.target.closest('.item.share > a[data-type="print"]');
- if (el) { //Print
+ if (el) { // Print
const tmp_window = window.open();
- for (var i = 0; i < document.styleSheets.length; i++) {
+ for (let i = 0; i < document.styleSheets.length; i++) {
tmp_window.document.writeln('');
}
tmp_window.document.writeln(el.closest('.flux_content').querySelector('.content').innerHTML);
@@ -1004,13 +1009,13 @@ function init_stream(stream) {
}
el = ev.target.closest('.item.share > a[data-type="clipboard"]');
- if (el && navigator.clipboard) { //Clipboard
+ if (el && navigator.clipboard) { // Clipboard
navigator.clipboard.writeText(el.href);
return false;
}
el = ev.target.closest('.item.share > a[href="POST"]');
- if (el) { //Share by POST
+ if (el) { // Share by POST
const f = el.parentElement.querySelector('form');
f.disabled = false;
f.submit();
@@ -1018,7 +1023,7 @@ function init_stream(stream) {
}
el = ev.target.closest('.flux_header, .flux_content');
- if (el) { //flux_toggle
+ if (el) { // flux_toggle
if (ev.target.closest('.content, .item.website, .item.link, .dropdown-menu')) {
return true;
}
@@ -1026,9 +1031,9 @@ function init_stream(stream) {
// setting for not-closing after clicking outside article area
return false;
}
- const old_active = document.querySelector('.flux.current'),
- new_active = el.parentNode;
- if (ev.target.tagName.toUpperCase() === 'A') { //Leave real links alone
+ const old_active = document.querySelector('.flux.current');
+ const new_active = el.parentNode;
+ if (ev.target.tagName.toUpperCase() === 'A') { // Leave real links alone
if (context.auto_mark_article) {
mark_read(new_active, true, false);
}
@@ -1047,14 +1052,14 @@ function init_stream(stream) {
let el = ev.target.closest('.item.title > a');
if (el) {
if (ev.which == 1) {
- if (ev.ctrlKey) { //Control+click
+ if (ev.ctrlKey) { // Control+click
if (context.auto_mark_site) {
mark_read(el.closest('.flux'), true, false);
}
} else {
- el.parentElement.click(); //Normal click, just toggle article.
+ el.parentElement.click(); // Normal click, just toggle article.
}
- } else if (ev.which == 2 && !ev.ctrlKey) { //Simple middle click: same behaviour as CTRL+click
+ } else if (ev.which == 2 && !ev.ctrlKey) { // Simple middle click: same behaviour as CTRL+click
if (context.auto_mark_article) {
const new_active = el.closest('.flux');
mark_read(new_active, true, false);
@@ -1077,68 +1082,68 @@ function init_stream(stream) {
};
stream.onchange = function (ev) {
- const checkboxTag = ev.target.closest('.checkboxTag');
- if (checkboxTag) { //Dynamic tags
- ev.stopPropagation();
- const isChecked = checkboxTag.checked,
- tagId = checkboxTag.name.replace(/^t_/, ''),
- tagName = checkboxTag.nextElementSibling ? checkboxTag.nextElementSibling.value : '',
- entry = checkboxTag.closest('div.flux'),
- entryId = entry.id.replace(/^flux_/, '');
- checkboxTag.disabled = true;
+ const checkboxTag = ev.target.closest('.checkboxTag');
+ if (checkboxTag) { // Dynamic tags
+ ev.stopPropagation();
+ const isChecked = checkboxTag.checked;
+ const tagId = checkboxTag.name.replace(/^t_/, '');
+ const tagName = checkboxTag.nextElementSibling ? checkboxTag.nextElementSibling.value : '';
+ const entry = checkboxTag.closest('div.flux');
+ const entryId = entry.id.replace(/^flux_/, '');
+ checkboxTag.disabled = true;
- const req = new XMLHttpRequest();
- req.open('POST', './?c=tag&a=tagEntry', true);
- req.responseType = 'json';
- req.onerror = function (e) {
- checkboxTag.checked = !isChecked;
- badAjax(this.status == 403);
- };
- req.onload = function (e) {
- if (this.status != 200) {
- return req.onerror(e);
- }
- if (entry.classList.contains('not_read')) {
- incUnreadsTag('t_' + tagId, isChecked ? 1 : -1);
- }
- };
- req.onloadend = function (e) {
- checkboxTag.disabled = false;
- if (tagId == 0) {
- loadDynamicTags(checkboxTag.closest('div.dropdown'));
- }
- };
- req.setRequestHeader('Content-Type', 'application/json');
- req.send(JSON.stringify({
- _csrf: context.csrf,
- id_tag: tagId,
- name_tag: tagId == 0 ? tagName : '',
- id_entry: entryId,
- checked: isChecked,
- }));
- }
- };
+ const req = new XMLHttpRequest();
+ req.open('POST', './?c=tag&a=tagEntry', true);
+ req.responseType = 'json';
+ req.onerror = function (e) {
+ checkboxTag.checked = !isChecked;
+ badAjax(this.status == 403);
+ };
+ req.onload = function (e) {
+ if (this.status != 200) {
+ return req.onerror(e);
+ }
+ if (entry.classList.contains('not_read')) {
+ incUnreadsTag('t_' + tagId, isChecked ? 1 : -1);
+ }
+ };
+ req.onloadend = function (e) {
+ checkboxTag.disabled = false;
+ if (tagId == 0) {
+ loadDynamicTags(checkboxTag.closest('div.dropdown'));
+ }
+ };
+ req.setRequestHeader('Content-Type', 'application/json');
+ req.send(JSON.stringify({
+ _csrf: context.csrf,
+ id_tag: tagId,
+ name_tag: tagId == 0 ? tagName : '',
+ id_entry: entryId,
+ checked: isChecked,
+ }));
+ }
+ };
}
function init_nav_entries() {
const nav_entries = document.getElementById('nav_entries');
if (nav_entries) {
nav_entries.querySelector('.previous_entry').onclick = function (e) {
- prev_entry(false);
- return false;
- };
+ prev_entry(false);
+ return false;
+ };
nav_entries.querySelector('.next_entry').onclick = function (e) {
- next_entry(false);
- return false;
- };
+ next_entry(false);
+ return false;
+ };
nav_entries.querySelector('.up').onclick = function (e) {
- const active_item = (document.querySelector('.flux.current') || document.querySelector('.flux')),
- windowTop = document.scrollingElement.scrollTop,
- item_top = active_item.offsetParent.offsetTop + active_item.offsetTop;
+ const active_item = (document.querySelector('.flux.current') || document.querySelector('.flux'));
+ const windowTop = document.scrollingElement.scrollTop;
+ const item_top = active_item.offsetParent.offsetTop + active_item.offsetTop;
- document.scrollingElement.scrollTop = windowTop > item_top ? item_top : 0;
- return false;
- };
+ document.scrollingElement.scrollTop = windowTop > item_top ? item_top : 0;
+ return false;
+ };
}
}
@@ -1151,32 +1156,32 @@ function loadDynamicTags(div) {
req.open('GET', './?c=tag&a=getTagsForEntry&id_entry=' + entryId, true);
req.responseType = 'json';
req.onerror = function (e) {
- div.querySelectorAll('li.item').forEach(function (li) { li.remove(); });
- div.classList.add('dynamictags');
- };
+ div.querySelectorAll('li.item').forEach(function (li) { li.remove(); });
+ div.classList.add('dynamictags');
+ };
req.onload = function (e) {
- if (this.status != 200) {
- return req.onerror(e);
- }
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return req.onerror(e);
- }
- let html = '';
- if (json && json.length) {
- for (let i = 0; i < json.length; i++) {
- const tag = json[i];
- html += '';
- }
}
- div.querySelector('.dropdown-menu').insertAdjacentHTML('beforeend', html);
- };
+ }
+ div.querySelector('.dropdown-menu').insertAdjacentHTML('beforeend', html);
+ };
req.send();
}
//
-var feed_processed = 0;
+let feed_processed = 0;
function updateFeed(feeds, feeds_count) {
const feed = feeds.pop();
@@ -1186,34 +1191,34 @@ function updateFeed(feeds, feeds_count) {
const req = new XMLHttpRequest();
req.open('POST', feed.url, true);
req.onloadend = function (e) {
- if (this.status != 200) {
- return badAjax(false);
- }
- feed_processed++;
- const div = document.getElementById('actualizeProgress');
- div.querySelector('.progress').innerHTML = feed_processed + ' / ' + feeds_count;
- div.querySelector('.title').innerHTML = feed.title;
- if (feed_processed === feeds_count) {
- //Empty request to commit new articles
- const req2 = new XMLHttpRequest();
- req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true);
- req2.onloadend = function (e) {
- delayedFunction(function () { location.reload(); });
- };
- req2.setRequestHeader('Content-Type', 'application/json');
- req2.send(JSON.stringify({
- _csrf: context.csrf,
- noCommit: 0,
- }));
- } else {
- updateFeed(feeds, feeds_count);
- }
- };
+ if (this.status != 200) {
+ return badAjax(false);
+ }
+ feed_processed++;
+ const div = document.getElementById('actualizeProgress');
+ div.querySelector('.progress').innerHTML = feed_processed + ' / ' + feeds_count;
+ div.querySelector('.title').innerHTML = feed.title;
+ if (feed_processed === feeds_count) {
+ // Empty request to commit new articles
+ const req2 = new XMLHttpRequest();
+ req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true);
+ req2.onloadend = function (e) {
+ delayedFunction(function () { location.reload(); });
+ };
+ req2.setRequestHeader('Content-Type', 'application/json');
+ req2.send(JSON.stringify({
+ _csrf: context.csrf,
+ noCommit: 0,
+ }));
+ } else {
+ updateFeed(feeds, feeds_count);
+ }
+ };
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify({
- _csrf: context.csrf,
- noCommit: 1,
- }));
+ _csrf: context.csrf,
+ noCommit: 1,
+ }));
}
function init_actualize() {
@@ -1234,46 +1239,46 @@ function init_actualize() {
req.open('POST', './?c=javascript&a=actualize', true);
req.responseType = 'json';
req.onload = function (e) {
- if (this.status != 200) {
- return badAjax(false);
- }
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return badAjax(false);
- }
- if (auto && json.feeds.length < 1) {
- auto = false;
+ if (this.status != 200) {
+ return badAjax(false);
+ }
+ const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return badAjax(false);
+ }
+ if (auto && json.feeds.length < 1) {
+ auto = false;
+ context.ajax_loading = false;
+ return false;
+ }
+ if (json.feeds.length === 0) {
+ openNotification(json.feedback_no_refresh, 'good');
+ // Empty request to commit new articles
+ const req2 = new XMLHttpRequest();
+ req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true);
+ req2.onloadend = function (e) {
context.ajax_loading = false;
- return false;
- }
- if (json.feeds.length === 0) {
- openNotification(json.feedback_no_refresh, 'good');
- //Empty request to commit new articles
- const req2 = new XMLHttpRequest();
- req2.open('POST', './?c=feed&a=actualize&id=-1&ajax=1', true);
- req2.onloadend = function (e) {
- context.ajax_loading = false;
- };
- req2.setRequestHeader('Content-Type', 'application/json');
- req2.send(JSON.stringify({
- _csrf: context.csrf,
- noCommit: 0,
- }));
- return;
- }
- //Progress bar
- const feeds_count = json.feeds.length;
- document.body.insertAdjacentHTML('beforeend', '' +
+ };
+ req2.setRequestHeader('Content-Type', 'application/json');
+ req2.send(JSON.stringify({
+ _csrf: context.csrf,
+ noCommit: 0,
+ }));
+ return;
+ }
+ // Progress bar
+ const feeds_count = json.feeds.length;
+ document.body.insertAdjacentHTML('beforeend', '
' +
json.feedback_actualize + '
/
0 / ' +
feeds_count + '
');
- for (let i = 10; i > 0; i--) {
- updateFeed(json.feeds, feeds_count);
- }
- };
+ for (let i = 10; i > 0; i--) {
+ updateFeed(json.feeds, feeds_count);
+ }
+ };
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify({
- _csrf: context.csrf,
- }));
+ _csrf: context.csrf,
+ }));
return false;
};
@@ -1286,9 +1291,9 @@ function init_actualize() {
//
//
-var notification = null,
- notification_interval = null,
- notification_working = false;
+let notification = null;
+let notification_interval = null;
+let notification_working = false;
function openNotification(msg, status) {
if (notification_working === true) {
@@ -1312,9 +1317,9 @@ function init_notifications() {
notification = document.getElementById('notification');
notification.querySelector('a.close').onclick = function () {
- closeNotification();
- return false;
- };
+ closeNotification();
+ return false;
+ };
if (notification.querySelector('.msg').innerHTML.length > 0) {
notification_working = true;
@@ -1324,12 +1329,14 @@ function init_notifications() {
//
//
-let popup = null,
- popup_iframe_container = null,
- popup_iframe = null,
- popup_txt = null,
- popup_working = false;
+let popup = null;
+let popup_iframe_container = null;
+let popup_iframe = null;
+let popup_txt = null;
+let popup_working = false;
+/* eslint-disable no-unused-vars */
+// TODO: Re-enable no-unused-vars
function openPopupWithMessage(msg) {
if (popup_working === true) {
return false;
@@ -1355,6 +1362,7 @@ function openPopupWithSource(source) {
popup_iframe_container.style.display = 'table-row';
popup.style.display = 'block';
}
+/* eslint-enable no-unused-vars */
function closePopup() {
popup.style.display = 'none';
@@ -1367,7 +1375,7 @@ function closePopup() {
}
function init_popup() {
- //Fetch elements.
+ // Fetch elements.
popup = document.getElementById('popup');
popup_iframe_container = document.getElementById('popup-iframe-container');
@@ -1375,12 +1383,12 @@ function init_popup() {
popup_txt = document.getElementById('popup-txt');
- //Configure close button.
+ // Configure close button.
document.getElementById('popup-close').addEventListener('click', function (ev) {
closePopup();
});
- //Configure close-on-click.
+ // Configure close-on-click.
window.addEventListener('click', function (ev) {
if (ev.target == popup) {
closePopup();
@@ -1390,7 +1398,7 @@ function init_popup() {
//
//
-var notifs_html5_permission = 'denied';
+let notifs_html5_permission = 'denied';
function notifs_html5_is_supported() {
return window.Notification !== undefined;
@@ -1414,12 +1422,12 @@ function notifs_html5_show(nb) {
});
notification.onclick = function () {
- delayedFunction(function() {
- location.reload();
- window.focus();
- notification.close();
- });
- };
+ delayedFunction(function () {
+ location.reload();
+ window.focus();
+ notification.close();
+ });
+ };
if (context.html5_notif_timeout !== 0) {
setTimeout(function () {
@@ -1442,61 +1450,61 @@ function refreshUnreads() {
req.open('GET', './?c=javascript&a=nbUnreadsPerFeed', true);
req.responseType = 'json';
req.onload = function (e) {
- const json = xmlHttpRequestJson(this);
- if (!json) {
- return badAjax(false);
- }
- const isAll = document.querySelector('.category.all.active');
- let new_articles = false;
+ const json = xmlHttpRequestJson(this);
+ if (!json) {
+ return badAjax(false);
+ }
+ const isAll = document.querySelector('.category.all.active');
+ let new_articles = false;
- Object.keys(json.feeds).forEach(function (feed_id) {
- const nbUnreads = json.feeds[feed_id];
- feed_id = 'f_' + feed_id;
- const elem = document.getElementById(feed_id),
- feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
+ Object.keys(json.feeds).forEach(function (feed_id) {
+ const nbUnreads = json.feeds[feed_id];
+ feed_id = 'f_' + feed_id;
+ const elem = document.getElementById(feed_id);
+ const feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
- if ((incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads) || isAll) && //Update of current view?
+ if ((incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads) || isAll) && // Update of current view?
(nbUnreads - feed_unreads > 0)) {
- const newArticle = document.getElementById('new-article');
- newArticle.setAttribute('aria-hidden', 'false');
- newArticle.style.display = 'block';
- new_articles = true;
- }
- });
-
- let nbUnreadTags = 0;
-
- Object.keys(json.tags).forEach(function (tag_id) {
- const nbUnreads = json.tags[tag_id];
- nbUnreadTags += nbUnreads;
- const tag = document.getElementById('t_' + tag_id);
- if (tag) {
- tag.setAttribute('data-unread', nbUnreads);
- tag.querySelector('.item-title').setAttribute('data-unread', numberFormat(nbUnreads));
- }
- });
-
- const tags = document.querySelector('.category.tags');
- if (tags) {
- tags.setAttribute('data-unread', nbUnreadTags);
- tags.querySelector('.title').setAttribute('data-unread', numberFormat(nbUnreadTags));
+ const newArticle = document.getElementById('new-article');
+ newArticle.setAttribute('aria-hidden', 'false');
+ newArticle.style.display = 'block';
+ new_articles = true;
}
+ });
- const title = document.querySelector('.category.all .title'),
- nb_unreads = title ? str2int(title.getAttribute('data-unread')) : 0;
+ let nbUnreadTags = 0;
- if (nb_unreads > 0 && new_articles) {
- faviconNbUnread(nb_unreads);
- notifs_html5_show(nb_unreads);
+ Object.keys(json.tags).forEach(function (tag_id) {
+ const nbUnreads = json.tags[tag_id];
+ nbUnreadTags += nbUnreads;
+ const tag = document.getElementById('t_' + tag_id);
+ if (tag) {
+ tag.setAttribute('data-unread', nbUnreads);
+ tag.querySelector('.item-title').setAttribute('data-unread', numberFormat(nbUnreads));
}
- };
+ });
+
+ const tags = document.querySelector('.category.tags');
+ if (tags) {
+ tags.setAttribute('data-unread', nbUnreadTags);
+ tags.querySelector('.title').setAttribute('data-unread', numberFormat(nbUnreadTags));
+ }
+
+ const title = document.querySelector('.category.all .title');
+ const nb_unreads = title ? str2int(title.getAttribute('data-unread')) : 0;
+
+ if (nb_unreads > 0 && new_articles) {
+ faviconNbUnread(nb_unreads);
+ notifs_html5_show(nb_unreads);
+ }
+ };
req.send();
}
-//
-var url_load_more = '',
- load_more = false,
- box_load_more = null;
+//
+let url_load_more = '';
+let load_more = false;
+let box_load_more = null;
function load_more_posts() {
if (load_more || !url_load_more || !box_load_more) {
@@ -1509,50 +1517,50 @@ function load_more_posts() {
req.open('GET', url_load_more, true);
req.responseType = 'document';
req.onload = function (e) {
- const html = this.response,
- formPagination = document.getElementById('mark-read-pagination');
+ const html = this.response;
+ const formPagination = document.getElementById('mark-read-pagination');
- const streamAdopted = document.adoptNode(html.getElementById('stream'));
- streamAdopted.querySelectorAll('.flux, .day').forEach(function (div) {
- box_load_more.insertBefore(div, formPagination);
- });
+ const streamAdopted = document.adoptNode(html.getElementById('stream'));
+ streamAdopted.querySelectorAll('.flux, .day').forEach(function (div) {
+ box_load_more.insertBefore(div, formPagination);
+ });
- const paginationOld = formPagination.querySelector('.pagination'),
- paginationNew = streamAdopted.querySelector('.pagination');
- formPagination.replaceChild(paginationNew, paginationOld);
+ const paginationOld = formPagination.querySelector('.pagination');
+ const paginationNew = streamAdopted.querySelector('.pagination');
+ formPagination.replaceChild(paginationNew, paginationOld);
- const bigMarkAsRead = document.getElementById('bigMarkAsRead');
- if (bigMarkAsRead) {
- if (context.display_order === 'ASC') {
- document.querySelector('#nav_menu_read_all .read_all').formAction = bigMarkAsRead.formAction;
- } else {
- bigMarkAsRead.formAction = document.querySelector('#nav_menu_read_all .read_all').formAction;
- }
+ const bigMarkAsRead = document.getElementById('bigMarkAsRead');
+ if (bigMarkAsRead) {
+ if (context.display_order === 'ASC') {
+ document.querySelector('#nav_menu_read_all .read_all').formAction = bigMarkAsRead.formAction;
+ } else {
+ bigMarkAsRead.formAction = document.querySelector('#nav_menu_read_all .read_all').formAction;
}
+ }
- document.querySelectorAll('[id^=day_]').forEach(function (div) {
- const ids = document.querySelectorAll('[id="' + div.id + '"]');
- for (let i = ids.length - 1; i > 0; i--) { //Keep only the first
- ids[i].remove();
- }
- });
-
- init_load_more(box_load_more);
-
- const div_load_more = document.getElementById('load_more');
- if (bigMarkAsRead) {
- bigMarkAsRead.removeAttribute('disabled');
- }
- if (div_load_more) {
- div_load_more.classList.remove('loading');
+ document.querySelectorAll('[id^=day_]').forEach(function (div) {
+ const ids = document.querySelectorAll('[id="' + div.id + '"]');
+ for (let i = ids.length - 1; i > 0; i--) { // Keep only the first
+ ids[i].remove();
}
+ });
- load_more = false;
- };
+ init_load_more(box_load_more);
+
+ const div_load_more = document.getElementById('load_more');
+ if (bigMarkAsRead) {
+ bigMarkAsRead.removeAttribute('disabled');
+ }
+ if (div_load_more) {
+ div_load_more.classList.remove('loading');
+ }
+
+ load_more = false;
+ };
req.send();
}
-var freshrssLoadMoreEvent = document.createEvent('Event');
+const freshrssLoadMoreEvent = document.createEvent('Event');
freshrssLoadMoreEvent.initEvent('freshrss:load-more', true, true);
function init_load_more(box) {
@@ -1569,23 +1577,23 @@ function init_load_more(box) {
url_load_more = next_link.href;
next_link.onclick = function (e) {
- load_more_posts();
- return false;
- };
+ load_more_posts();
+ return false;
+ };
}
-//
+//
function init_confirm_action() {
document.body.onclick = function (ev) {
- const b = ev.target.closest('.confirm');
- if (b) {
- let str_confirmation = this.getAttribute('data-str-confirm');
- if (!str_confirmation) {
- str_confirmation = context.i18n.confirmation_default;
- }
- return confirm(str_confirmation);
+ const b = ev.target.closest('.confirm');
+ if (b) {
+ let str_confirmation = this.getAttribute('data-str-confirm');
+ if (!str_confirmation) {
+ str_confirmation = context.i18n.confirmation_default;
}
- };
+ return confirm(str_confirmation);
+ }
+ };
document.querySelectorAll('button.confirm').forEach(function (b) { b.disabled = false; });
}
@@ -1594,10 +1602,10 @@ function faviconNbUnread(n) {
const t = document.querySelector('.category.all .title');
n = t ? str2int(t.getAttribute('data-unread')) : 0;
}
- //http://remysharp.com/2010/08/24/dynamic-favicons/
- const canvas = document.createElement('canvas'),
- link = document.getElementById('favicon').cloneNode(true),
- ratio = window.devicePixelRatio;
+ // http://remysharp.com/2010/08/24/dynamic-favicons/
+ const canvas = document.createElement('canvas');
+ const link = document.getElementById('favicon').cloneNode(true);
+ const ratio = window.devicePixelRatio;
if (canvas.getContext && link) {
canvas.height = canvas.width = 16 * ratio;
const img = document.createElement('img');
@@ -1651,7 +1659,7 @@ function init_normal() {
window.onbeforeunload = function (e) {
const sidebar = document.getElementById('sidebar');
- if (sidebar) { //Save sidebar scroll position
+ if (sidebar) { // Save sidebar scroll position
sessionStorage.setItem('FreshRSS_sidebar_scrollTop', sidebar.scrollTop);
}
if (mark_read_queue && mark_read_queue.length > 0) {
@@ -1687,7 +1695,7 @@ function init_afterDOM() {
}
}
-init_beforeDOM(); //Can be called before DOM is fully loaded
+init_beforeDOM(); // Can be called before DOM is fully loaded
if (document.readyState && document.readyState !== 'loading') {
init_afterDOM();
diff --git a/p/scripts/preview.js b/p/scripts/preview.js
index d52657a5a..48675d42c 100644
--- a/p/scripts/preview.js
+++ b/p/scripts/preview.js
@@ -1,12 +1,10 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
-/* jshint esversion:6, strict:global */
-
-let rendered_node = null,
- rendered_view = null,
- raw_node = null,
- raw_view = null;
+'use strict';
+let rendered_node = null;
+let rendered_view = null;
+let raw_node = null;
+let raw_view = null;
function update_ui() {
if (rendered_node.checked && !raw_node.checked) {
@@ -29,7 +27,6 @@ function init_afterDOM() {
raw_node.addEventListener('click', update_ui);
}
-
if (document.readyState && document.readyState !== 'loading') {
init_afterDOM();
} else {
diff --git a/p/scripts/statsWithChartjs.js b/p/scripts/statsWithChartjs.js
index 0ca511132..2f5c39ce8 100644
--- a/p/scripts/statsWithChartjs.js
+++ b/p/scripts/statsWithChartjs.js
@@ -1,7 +1,6 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-"use strict";
+'use strict';
/* globals Chart */
-/* jshint esversion:6, strict:global */
function initCharts() {
if (!window.Chart) {
@@ -14,13 +13,13 @@ function initCharts() {
const jsonData = document.getElementsByClassName('jsonData-stats');
- var jsonDataParsed;
- var chartConfig;
+ let jsonDataParsed;
+ let chartConfig;
- for (var i = 0; i < jsonData.length; i++) {
+ for (let i = 0; i < jsonData.length; i++) {
jsonDataParsed = JSON.parse(jsonData[i].innerHTML);
- switch(jsonDataParsed.charttype) {
+ switch (jsonDataParsed.charttype) {
case 'bar':
chartConfig = jsonChartBar(jsonDataParsed.label, jsonDataParsed.data, jsonDataParsed.xAxisLabels);
break;
@@ -28,13 +27,13 @@ function initCharts() {
chartConfig = jsonChartDoughnut(jsonDataParsed.labels, jsonDataParsed.data);
break;
case 'barWithAverage':
- chartConfig = jsonChartBarWithAvarage(jsonDataParsed.labelBarChart, jsonDataParsed.dataBarChart, jsonDataParsed.labelAverage, jsonDataParsed.dataAverage, jsonDataParsed.xAxisLabels);
+ chartConfig = jsonChartBarWithAvarage(jsonDataParsed.labelBarChart, jsonDataParsed.dataBarChart,
+ jsonDataParsed.labelAverage, jsonDataParsed.dataAverage, jsonDataParsed.xAxisLabels);
}
- new Chart(
- document.getElementById(jsonDataParsed.canvasID),
- chartConfig
- );
+ /* eslint-disable no-new */
+ new Chart(document.getElementById(jsonDataParsed.canvasID), chartConfig);
+ /* eslint-enable no-new */
}
if (window.console) {
@@ -55,25 +54,25 @@ function jsonChartBar(label, data, xAxisLabels = '') {
barPercentage: 1.0,
categoryPercentage: 1.0,
order: 2,
- }]
+ }],
},
options: {
scales: {
y: {
- beginAtZero: true
+ beginAtZero: true,
},
x: {
grid: {
display: false,
- }
- }
+ },
+ },
},
plugins: {
legend: {
display: false,
- }
- }
- }
+ },
+ },
+ },
};
}
@@ -84,22 +83,22 @@ function jsonChartDoughnut(labels, data) {
labels: labels,
datasets: [{
backgroundColor: [
- '#0b84a5', //petrol
+ '#0b84a5', // petrol
'#f6c85f', // sand
- '#6f4e7c', //purple
- '#9dd866', //green
- '#ca472f', //red
- '#ffa056', //orange
+ '#6f4e7c', // purple
+ '#9dd866', // green
+ '#ca472f', // red
+ '#ffa056', // orange
'#8dddd0', // turkis
'#f6c85f', // sand
- '#6f4e7c', //purple
- '#9dd866', //green
- '#ca472f', //red
- '#ffa056', //orange
+ '#6f4e7c', // purple
+ '#9dd866', // green
+ '#ca472f', // red
+ '#ffa056', // orange
'#8dddd0', // turkis
],
data: data,
- }]
+ }],
},
options: {
layout: {
@@ -109,9 +108,9 @@ function jsonChartDoughnut(labels, data) {
legend: {
position: 'bottom',
align: 'start',
- }
- }
- }
+ },
+ },
+ },
};
}
@@ -133,15 +132,15 @@ function jsonChartBarWithAvarage(labelBarChart, dataBarChart, labelAverage, data
{
// average line chart
type: 'line',
- label: labelAverage, // Todo: i18n
+ label: labelAverage, // Todo: i18n
borderColor: 'rgb(192,216,0)',
data: {
- '-30' : dataAverage,
- '-1' : dataAverage,
+ '-30': dataAverage,
+ '-1': dataAverage,
},
order: 1,
- }
- ]
+ },
+ ],
},
options: {
@@ -151,41 +150,41 @@ function jsonChartBarWithAvarage(labelBarChart, dataBarChart, labelAverage, data
},
x: {
ticks: {
- callback: function(val){
+ callback: function (val) {
if (xAxisLabels.length > 0) {
return xAxisLabels[val];
} else {
return val;
}
- }
+ },
},
grid: {
display: false,
- }
- }
+ },
+ },
},
elements: {
point: {
radius: 0,
- }
+ },
},
plugins: {
tooltip: {
callbacks: {
- title: function(tooltipitem) {
+ title: function (tooltipitem) {
if (xAxisLabels.length > 0) {
return xAxisLabels[tooltipitem[0].dataIndex];
} else {
return tooltipitem[0].label;
}
- }
- }
+ },
+ },
},
legend: {
display: false,
- }
- }
- }
+ },
+ },
+ },
};
}
diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css
index 2ec7dea34..6d3279bcd 100644
--- a/p/themes/base-theme/template.css
+++ b/p/themes/base-theme/template.css
@@ -879,7 +879,7 @@ input[type="search"] {
}
.subtitle > div:not(:first-of-type)::before {
- content: ' · ';
+ content: ' · ';
}
br {
diff --git a/p/themes/base-theme/template.rtl.css b/p/themes/base-theme/template.rtl.css
index d6f0d0168..f74b9f9da 100644
--- a/p/themes/base-theme/template.rtl.css
+++ b/p/themes/base-theme/template.rtl.css
@@ -465,7 +465,7 @@ a.btn {
/*=== Boxes */
.box {
- margin: 20px 10px;
+ margin: 20px 0 20px 20px;
display: inline-block;
max-width: 95%;
width: 20rem;
@@ -473,6 +473,11 @@ a.btn {
vertical-align: top;
}
+.box.visible-semi {
+ border-style: dashed;
+ opacity: 0.5;
+}
+
.box .box-title {
position: relative;
font-size: 1.2rem;
@@ -874,7 +879,7 @@ input[type="search"] {
}
.subtitle > div:not(:first-of-type)::before {
- content: ' · ';
+ content: ' · ';
}
br {
@@ -1114,7 +1119,7 @@ br {
display: none;
position: fixed;
top: 2%; bottom: 2%;
- left: 3%; right: 3%;
+ right: 3%; left: 3%;
overflow: auto;
}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..4ae01c19a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "freshrss",
+ "description": "A free, self-hostable aggregator",
+ "homepage": "https://freshrss.org/",
+ "readmeFilename": "README.md",
+ "bugs": {
+ "url": "https://github.com/FreshRSS/FreshRSS/issues"
+ },
+ "keywords": [
+ "news",
+ "aggregator",
+ "RSS",
+ "Atom",
+ "WebSub"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/FreshRSS/FreshRSS.git"
+ },
+ "license": "AGPL-3.0",
+ "scripts": {
+ "eslint": "eslint --ext .js .",
+ "eslint_fix": "eslint --fix --ext .js .",
+ "rtlcss": "rtlcss -d p/themes && find . -type f -name '*.rtl.rtl.css' -delete",
+ "stylelint": "stylelint '**/*.css' && stylelint --syntax scss '**/*.scss'",
+ "stylelint_fix": "stylelint --fix '**/*.css' && stylelint --fix --syntax scss '**/*.scss'",
+ "test": "npm run eslint && npm run stylelint",
+ "fix": "npm run rtlcss && npm run stylelint_fix && npm run eslint_fix"
+ },
+ "devDependencies": {
+ "eslint": "^7.32.0",
+ "eslint-config-standard": "^16.0.3",
+ "eslint-plugin-import": "^2.24.2",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^5.1.0",
+ "rtlcss": "^3.4.0",
+ "stylelint": "^13.13.1",
+ "stylelint-config-recommended-scss": "^4.3.0",
+ "stylelint-order": "^4.1.0",
+ "stylelint-scss": "^3.21.0"
+ }
+}