ESLint upgrade from JSHint (#3906)

* ESLint upgrade from JSHint
* commit corresponding package.json
* `npm run fix` for automatic JS and CSS fixes
* Keep JSHint config for now
This commit is contained in:
Alexandre Alapetite 2021-10-21 11:44:03 +02:00 committed by GitHub
parent cfd625c559
commit b438d8bb3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 979 additions and 909 deletions

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
*.min.js
node_modules/
p/scripts/vendor/

26
.eslintrc.json Normal file
View File

@ -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
}

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
/bin /bin
/node_modules /node_modules
package*.json package-lock.json
constants.local.php constants.local.php
# Temp files # Temp files

View File

@ -1,8 +1,9 @@
{ {
"esversion" : 6, "esversion" : 8,
"browser" : true, "browser" : true,
"globals": { "globals": {
"confirm": true, "confirm": true,
"console": true "console": true
} },
"strict": "global"
} }

View File

@ -33,11 +33,9 @@
"no-eol-whitespace": true, "no-eol-whitespace": true,
"property-no-vendor-prefix": true, "property-no-vendor-prefix": true,
"rule-empty-line-before": [ "rule-empty-line-before": [
"always", "always", {
"except": [ "except": ["after-single-line-comment","first-nested"]
"after-single-line-comment", }
"first-nested"
]
], ],
"order/properties-order": [ "order/properties-order": [
"margin", "margin",

View File

@ -45,12 +45,9 @@ jobs:
env: env:
- HADOLINT="$HOME/hadolint" - HADOLINT="$HOME/hadolint"
install: 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} - curl -sL -o ${HADOLINT} "https://github.com/hadolint/hadolint/releases/download/v1.18.0/hadolint-$(uname -s)-$(uname -m)" && chmod 700 ${HADOLINT}
script: script:
- node_modules/jshint/bin/jshint . - npm test
# check SCSS separately
- stylelint --syntax scss "**/*.scss"
- stylelint "**/*.css"
- bash tests/shellchecks.sh - bash tests/shellchecks.sh
- git ls-files --exclude='*Dockerfile*' --ignored | xargs --max-lines=1 "$HADOLINT" - git ls-files --exclude='*Dockerfile*' --ignored | xargs --max-lines=1 "$HADOLINT"

View File

@ -1,6 +1,5 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* jshint esversion:6, strict:global */
function check(url, next) { function check(url, next) {
if (!url || !next) { if (!url || !next) {
@ -10,8 +9,8 @@ function check(url, next) {
req.open('GET', url, true); req.open('GET', url, true);
req.setRequestHeader('Authorization', 'GoogleLogin auth=test/1'); req.setRequestHeader('Authorization', 'GoogleLogin auth=test/1');
req.onerror = function (e) { req.onerror = function (e) {
next('FAIL: HTTP ' + e); next('FAIL: HTTP ' + e);
}; };
req.onload = function () { req.onload = function () {
if (this.status == 200) { if (this.status == 200) {
next(this.response); next(this.response);
@ -25,40 +24,40 @@ function check(url, next) {
const jsonVars = JSON.parse(document.getElementById('jsonVars').innerHTML); const jsonVars = JSON.parse(document.getElementById('jsonVars').innerHTML);
check(jsonVars.greader + '/check/compatibility', function next(result1) { check(jsonVars.greader + '/check/compatibility', function next(result1) {
const greaderOutput = document.getElementById('greaderOutput'); const greaderOutput = document.getElementById('greaderOutput');
if (result1 === 'PASS') { if (result1 === 'PASS') {
greaderOutput.innerHTML = '✔️ ' + result1; greaderOutput.innerHTML = '✔️ ' + result1;
} else { } else {
check(jsonVars.greader + '/check%2Fcompatibility', function next(result2) { check(jsonVars.greader + '/check%2Fcompatibility', function next(result2) {
if (result2 === 'PASS') { if (result2 === 'PASS') {
greaderOutput.innerHTML = '⚠️ WARN: no <code>%2F</code> support, so some clients will not work!'; greaderOutput.innerHTML = '⚠️ WARN: no <code>%2F</code> support, so some clients will not work!';
} else { } else {
check('./greader.php/check/compatibility', function next(result3) { check('./greader.php/check/compatibility', function next(result3) {
if (result3 === 'PASS') { if (result3 === 'PASS') {
greaderOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php'; greaderOutput.innerHTML = '⚠️ WARN: Probable invalid base URL in ./data/config.php';
} else { } else {
greaderOutput.innerHTML = '❌ ' + result1; 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;
} }
}); });
} }
}); });
}
});
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 // @license-end

View File

@ -1,16 +1,15 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* globals context */ /* globals context */
/* jshint esversion:6, strict:global */
var loading = false, let loading = false;
dnd_successful = false; let dnd_successful = false;
function dragend_process(t) { function dragend_process(t) {
t.setAttribute('draggable', 'false'); t.setAttribute('draggable', 'false');
if (loading) { if (loading) {
setTimeout(function() { setTimeout(function () {
dragend_process(t); dragend_process(t);
}, 50); }, 50);
return; return;
@ -25,13 +24,14 @@ function dragend_process(t) {
t.remove(); t.remove();
if (p.childElementCount <= 1) { if (p.childElementCount <= 1) {
p.insertAdjacentHTML('afterbegin', '<li class="item feed disabled" dropzone="move"><div class="alert-warn">' + context.i18n.category_empty + '</div></li>'); p.insertAdjacentHTML('afterbegin',
'<li class="item feed disabled" dropzone="move"><div class="alert-warn">' + context.i18n.category_empty + '</div></li>');
} }
} }
} }
var dragFeedId = '', let dragFeedId = '';
dragHtml = ''; let dragHtml = '';
function init_draggable() { function init_draggable() {
if (!window.context) { if (!window.context) {
@ -42,99 +42,99 @@ function init_draggable() {
return; return;
} }
const draggable = '[draggable="true"]', const draggable = '[draggable="true"]';
dropzone = '[dropzone="move"]', const dropzone = '[dropzone="move"]';
dropSection = document.querySelector('.drop-section'); const dropSection = document.querySelector('.drop-section');
dropSection.ondragstart = function(ev) { dropSection.ondragstart = function (ev) {
const li = ev.target.closest ? ev.target.closest(draggable) : null; const li = ev.target.closest ? ev.target.closest(draggable) : null;
if (li) { if (li) {
const drag = ev.target.closest('[draggable]'); const drag = ev.target.closest('[draggable]');
ev.dataTransfer.effectAllowed = 'move'; ev.dataTransfer.effectAllowed = 'move';
dragHtml = drag.outerHTML; dragHtml = drag.outerHTML;
dragFeedId = drag.getAttribute('data-feed-id'); dragFeedId = drag.getAttribute('data-feed-id');
ev.dataTransfer.setData('text', dragFeedId); ev.dataTransfer.setData('text', dragFeedId);
drag.style.opacity = 0.3; drag.style.opacity = 0.3;
dnd_successful = false; dnd_successful = false;
} }
}; };
dropSection.ondragend = function(ev) { dropSection.ondragend = function (ev) {
const li = ev.target.closest ? ev.target.closest(draggable) : null; const li = ev.target.closest ? ev.target.closest(draggable) : null;
if (li) { if (li) {
dragend_process(li); dragend_process(li);
} }
}; };
dropSection.ondragenter = function(ev) { dropSection.ondragenter = function (ev) {
const li = ev.target.closest ? ev.target.closest(dropzone) : null; const li = ev.target.closest ? ev.target.closest(dropzone) : null;
if (li) { if (li) {
li.classList.add('drag-hover'); li.classList.add('drag-hover');
return false; return false;
} }
}; };
dropSection.onddragleave = function(ev) { dropSection.onddragleave = function (ev) {
const li = ev.target.closest ? ev.target.closest(dropzone) : null; const li = ev.target.closest ? ev.target.closest(dropzone) : null;
if (li) { if (li) {
const scroll_top = document.documentElement.scrollTop, const scroll_top = document.documentElement.scrollTop;
top = li.offsetTop, const top = li.offsetTop;
left = li.offsetLeft, const left = li.offsetLeft;
right = left + li.clientWidth, const right = left + li.clientWidth;
bottom = top + li.clientHeight, const bottom = top + li.clientHeight;
mouse_x = ev.screenX, const mouse_x = ev.screenX;
mouse_y = ev.clientY + scroll_top; 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) { top <= mouse_y && mouse_y <= bottom) {
// HACK because dragleave is triggered when hovering children! // HACK because dragleave is triggered when hovering children!
return; 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) { li.classList.remove('drag-hover');
const li = ev.target.closest ? ev.target.closest(dropzone) : null; return false;
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;
}
};
} }
function archiving() { function archiving() {
@ -143,7 +143,7 @@ function archiving() {
if (e.target.id === 'use_default_purge_options') { if (e.target.id === 'use_default_purge_options') {
slider.querySelectorAll('.archiving').forEach(function (element) { slider.querySelectorAll('.archiving').forEach(function (element) {
element.hidden = e.target.checked; 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
}); });
} }
}); });

View File

@ -1,8 +1,7 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* jshint esversion:6, strict:global */
const init_draggable_list = function() { const init_draggable_list = function () {
if (!window.context) { if (!window.context) {
if (window.console) { if (window.console) {
console.log('FreshRSS draggable list waiting for JS…'); console.log('FreshRSS draggable list waiting for JS…');

View File

@ -1,7 +1,6 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* globals context, openNotification, openPopupWithSource, xmlHttpRequestJson */ /* globals context, openNotification, openPopupWithSource, xmlHttpRequestJson */
/* jshint esversion:6, strict:global */
function fix_popup_preview_selector() { function fix_popup_preview_selector() {
const link = document.getElementById('popup-preview-selector'); const link = document.getElementById('popup-preview-selector');
@ -20,8 +19,8 @@ function fix_popup_preview_selector() {
}); });
} }
//<crypto form (Web login)> // <crypto form (Web login)>
function poormanSalt() { //If crypto.getRandomValues is not available function poormanSalt() { // If crypto.getRandomValues is not available
const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz'; const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz';
let text = '$2a$04$'; let text = '$2a$04$';
for (let i = 22; i > 0; i--) { for (let i = 22; i > 0; i--) {
@ -61,8 +60,8 @@ function init_crypto_form() {
const req = new XMLHttpRequest(); const req = new XMLHttpRequest();
req.open('GET', './?c=javascript&a=nonce&user=' + document.getElementById('username').value, false); req.open('GET', './?c=javascript&a=nonce&user=' + document.getElementById('username').value, false);
req.onerror = function () { req.onerror = function () {
openNotification('Communication error!', 'bad'); openNotification('Communication error!', 'bad');
}; };
req.send(); req.send();
if (req.status == 200) { if (req.status == 200) {
const json = xmlHttpRequestJson(req); const json = xmlHttpRequestJson(req);
@ -70,9 +69,9 @@ function init_crypto_form() {
openNotification('Invalid user!', 'bad'); openNotification('Invalid user!', 'bad');
} else { } else {
try { try {
const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), const strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function');
s = dcodeIO.bcrypt.hashSync(document.getElementById('passwordPlain').value, json.salt1), const s = dcodeIO.bcrypt.hashSync(document.getElementById('passwordPlain').value, json.salt1);
c = dcodeIO.bcrypt.hashSync(json.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt()); const c = dcodeIO.bcrypt.hashSync(json.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt());
document.getElementById('challenge').value = c; document.getElementById('challenge').value = c;
if (!s || !c) { if (!s || !c) {
openNotification('Crypto error!', 'bad'); openNotification('Crypto error!', 'bad');
@ -91,83 +90,83 @@ function init_crypto_form() {
return success; return success;
}; };
} }
//</crypto form (Web login)> // </crypto form (Web login)>
function init_password_observers() { function init_password_observers() {
document.querySelectorAll('.toggle-password').forEach(function (a) { document.querySelectorAll('.toggle-password').forEach(function (a) {
a.onmousedown = function (ev) { a.onmousedown = function (ev) {
const passwordField = document.getElementById(this.getAttribute('data-toggle')); const passwordField = document.getElementById(this.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'text'); passwordField.setAttribute('type', 'text');
this.classList.add('active'); this.classList.add('active');
return false; return false;
}; };
a.onmouseup = function (ev) { a.onmouseup = function (ev) {
const passwordField = document.getElementById(this.getAttribute('data-toggle')); const passwordField = document.getElementById(this.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'password'); passwordField.setAttribute('type', 'password');
this.classList.remove('active'); this.classList.remove('active');
return false; return false;
}; };
}); });
} }
function init_select_observers() { function init_select_observers() {
document.querySelectorAll('.select-change').forEach(function (s) { document.querySelectorAll('.select-change').forEach(function (s) {
s.onchange = function (ev) { s.onchange = function (ev) {
const opt = s.options[s.selectedIndex], const opt = s.options[s.selectedIndex];
url = opt.getAttribute('data-url'); const url = opt.getAttribute('data-url');
if (url) { if (url) {
s.disabled = true; s.disabled = true;
s.value = ''; s.value = '';
if (s.form) { if (s.form) {
s.form.querySelectorAll('[type=submit]').forEach(function (b) { s.form.querySelectorAll('[type=submit]').forEach(function (b) {
b.disabled = true; b.disabled = true;
}); });
} }
location.href = url; location.href = url;
} }
}; };
}); });
} }
function init_slider_observers() { function init_slider_observers() {
const slider = document.getElementById('slider'), const slider = document.getElementById('slider');
closer = document.getElementById('close-slider'); const closer = document.getElementById('close-slider');
if (!slider) { if (!slider) {
return; return;
} }
document.querySelector('.post').onclick = function (ev) { document.querySelector('.post').onclick = function (ev) {
const a = ev.target.closest('.open-slider'); const a = ev.target.closest('.open-slider');
if (a) { if (a) {
if (!context.ajax_loading) { if (!context.ajax_loading) {
context.ajax_loading = true; context.ajax_loading = true;
const req = new XMLHttpRequest(); const req = new XMLHttpRequest();
req.open('GET', a.href + '&ajax=1', true); req.open('GET', a.href + '&ajax=1', true);
req.responseType = 'document'; req.responseType = 'document';
req.onload = function (e) { req.onload = function (e) {
slider.innerHTML = this.response.body.innerHTML; slider.innerHTML = this.response.body.innerHTML;
slider.classList.add('active'); slider.classList.add('active');
closer.classList.add('active'); closer.classList.add('active');
context.ajax_loading = false; context.ajax_loading = false;
fix_popup_preview_selector(); fix_popup_preview_selector();
}; };
req.send(); 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; 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() { function data_leave_validation() {
@ -187,16 +186,16 @@ function data_leave_validation() {
function init_configuration_alert() { function init_configuration_alert() {
window.onsubmit = function (e) { window.onsubmit = function (e) {
window.hasSubmit = true; window.hasSubmit = true;
}; };
window.onbeforeunload = function (e) { window.onbeforeunload = function (e) {
if (window.hasSubmit) { if (window.hasSubmit) {
return; return;
} }
if (!data_leave_validation()) { if (!data_leave_validation()) {
return false; return false;
} }
}; };
} }
function init_extra() { function init_extra() {
@ -204,7 +203,7 @@ function init_extra() {
if (window.console) { if (window.console) {
console.log('FreshRSS extra waiting for JS…'); 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; return;
} }
init_crypto_form(); init_crypto_form();
@ -219,10 +218,10 @@ if (document.readyState && document.readyState !== 'loading') {
init_extra(); init_extra();
} else { } else {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
if (window.console) { if (window.console) {
console.log('FreshRSS extra waiting for DOMContentLoaded…'); console.log('FreshRSS extra waiting for DOMContentLoaded…');
} }
init_extra(); init_extra();
}, false); }, false);
} }
// @license-end // @license-end

View File

@ -1,9 +1,8 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @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 */ /* 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) { function load_panel(link) {
if (panel_loading) { if (panel_loading) {
@ -16,63 +15,63 @@ function load_panel(link) {
req.open('GET', link, true); req.open('GET', link, true);
req.responseType = 'document'; req.responseType = 'document';
req.onload = function (e) { req.onload = function (e) {
if (this.status != 200) { if (this.status != 200) {
return; 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); panel_loading = false;
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;
};
req.send(); req.send();
} }
function init_close_panel() { function init_close_panel() {
const panel = document.getElementById('panel'); const panel = document.getElementById('panel');
document.querySelector('#overlay .close').onclick = function (ev) { document.querySelector('#overlay .close').onclick = function (ev) {
panel.innerHTML = ''; panel.innerHTML = '';
panel.classList.remove('visible'); panel.classList.remove('visible');
document.getElementById('overlay').classList.remove('visible'); document.getElementById('overlay').classList.remove('visible');
return false; return false;
}; };
document.addEventListener('keydown', ev => { document.addEventListener('keydown', ev => {
const k = (ev.key.trim() || ev.code).toUpperCase(); const k = (ev.key.trim() || ev.code).toUpperCase();
if (k === 'ESCAPE' || k === 'ESC') { if (k === 'ESCAPE' || k === 'ESC') {
@ -85,15 +84,15 @@ function init_close_panel() {
function init_global_view() { function init_global_view() {
// TODO: should be based on generic classes // TODO: should be based on generic classes
document.querySelectorAll('.box a').forEach(function (a) { document.querySelectorAll('.box a').forEach(function (a) {
a.onclick = function (ev) { a.onclick = function (ev) {
load_panel(a.href); load_panel(a.href);
return false; return false;
}; };
}); });
document.querySelectorAll('.nav_menu #nav_menu_read_all, .nav_menu .toggle_aside').forEach(function (el) { document.querySelectorAll('.nav_menu #nav_menu_read_all, .nav_menu .toggle_aside').forEach(function (el) {
el.remove(); el.remove();
}); });
const panel = document.getElementById('panel'); const panel = document.getElementById('panel');
init_stream(panel); init_stream(panel);
@ -104,7 +103,7 @@ function init_all_global_view() {
if (window.console) { if (window.console) {
console.log('FreshRSS Global view waiting for JS…'); 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; return;
} }
init_global_view(); init_global_view();

View File

@ -1,6 +1,5 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* jshint esversion:6, strict:global */
function show_password(ev) { function show_password(ev) {
const button = ev.currentTarget; const button = ev.currentTarget;
@ -13,7 +12,7 @@ function hide_password(ev) {
const button = ev.currentTarget; const button = ev.currentTarget;
const passwordField = document.getElementById(button.getAttribute('data-toggle')); const passwordField = document.getElementById(button.getAttribute('data-toggle'));
passwordField.setAttribute('type', 'password'); passwordField.setAttribute('type', 'password');
button.className = button.className.replace(/(?:^|\s)active(?!\S)/g , ''); button.className = button.className.replace(/(?:^|\s)active(?!\S)/g, '');
return false; return false;
} }
const toggles = document.getElementsByClassName('toggle-password'); 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'); const auth_type = document.getElementById('auth_type');
function auth_type_change() { function auth_type_change() {
if (auth_type) { if (auth_type) {
const auth_value = auth_type.value, const auth_value = auth_type.value;
password_input = document.getElementById('passwordPlain'); const password_input = document.getElementById('passwordPlain');
if (auth_value === 'form') { if (auth_value === 'form') {
password_input.required = true; password_input.required = true;

View File

@ -1,8 +1,7 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* jshint esversion:6, strict:global */
const init_integration = function() { const init_integration = function () {
if (!window.context) { if (!window.context) {
if (window.console) { if (window.console) {
console.log('FreshRSS integration waiting for JS…'); console.log('FreshRSS integration waiting for JS…');

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,10 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* jshint esversion:6, strict:global */
let rendered_node = null,
rendered_view = null,
raw_node = null,
raw_view = null;
let rendered_node = null;
let rendered_view = null;
let raw_node = null;
let raw_view = null;
function update_ui() { function update_ui() {
if (rendered_node.checked && !raw_node.checked) { if (rendered_node.checked && !raw_node.checked) {
@ -29,7 +27,6 @@ function init_afterDOM() {
raw_node.addEventListener('click', update_ui); raw_node.addEventListener('click', update_ui);
} }
if (document.readyState && document.readyState !== 'loading') { if (document.readyState && document.readyState !== 'loading') {
init_afterDOM(); init_afterDOM();
} else { } else {

View File

@ -1,7 +1,6 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0 // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
"use strict"; 'use strict';
/* globals Chart */ /* globals Chart */
/* jshint esversion:6, strict:global */
function initCharts() { function initCharts() {
if (!window.Chart) { if (!window.Chart) {
@ -14,13 +13,13 @@ function initCharts() {
const jsonData = document.getElementsByClassName('jsonData-stats'); const jsonData = document.getElementsByClassName('jsonData-stats');
var jsonDataParsed; let jsonDataParsed;
var chartConfig; let chartConfig;
for (var i = 0; i < jsonData.length; i++) { for (let i = 0; i < jsonData.length; i++) {
jsonDataParsed = JSON.parse(jsonData[i].innerHTML); jsonDataParsed = JSON.parse(jsonData[i].innerHTML);
switch(jsonDataParsed.charttype) { switch (jsonDataParsed.charttype) {
case 'bar': case 'bar':
chartConfig = jsonChartBar(jsonDataParsed.label, jsonDataParsed.data, jsonDataParsed.xAxisLabels); chartConfig = jsonChartBar(jsonDataParsed.label, jsonDataParsed.data, jsonDataParsed.xAxisLabels);
break; break;
@ -28,13 +27,13 @@ function initCharts() {
chartConfig = jsonChartDoughnut(jsonDataParsed.labels, jsonDataParsed.data); chartConfig = jsonChartDoughnut(jsonDataParsed.labels, jsonDataParsed.data);
break; break;
case 'barWithAverage': 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( /* eslint-disable no-new */
document.getElementById(jsonDataParsed.canvasID), new Chart(document.getElementById(jsonDataParsed.canvasID), chartConfig);
chartConfig /* eslint-enable no-new */
);
} }
if (window.console) { if (window.console) {
@ -55,25 +54,25 @@ function jsonChartBar(label, data, xAxisLabels = '') {
barPercentage: 1.0, barPercentage: 1.0,
categoryPercentage: 1.0, categoryPercentage: 1.0,
order: 2, order: 2,
}] }],
}, },
options: { options: {
scales: { scales: {
y: { y: {
beginAtZero: true beginAtZero: true,
}, },
x: { x: {
grid: { grid: {
display: false, display: false,
} },
} },
}, },
plugins: { plugins: {
legend: { legend: {
display: false, display: false,
} },
} },
} },
}; };
} }
@ -84,22 +83,22 @@ function jsonChartDoughnut(labels, data) {
labels: labels, labels: labels,
datasets: [{ datasets: [{
backgroundColor: [ backgroundColor: [
'#0b84a5', //petrol '#0b84a5', // petrol
'#f6c85f', // sand '#f6c85f', // sand
'#6f4e7c', //purple '#6f4e7c', // purple
'#9dd866', //green '#9dd866', // green
'#ca472f', //red '#ca472f', // red
'#ffa056', //orange '#ffa056', // orange
'#8dddd0', // turkis '#8dddd0', // turkis
'#f6c85f', // sand '#f6c85f', // sand
'#6f4e7c', //purple '#6f4e7c', // purple
'#9dd866', //green '#9dd866', // green
'#ca472f', //red '#ca472f', // red
'#ffa056', //orange '#ffa056', // orange
'#8dddd0', // turkis '#8dddd0', // turkis
], ],
data: data, data: data,
}] }],
}, },
options: { options: {
layout: { layout: {
@ -109,9 +108,9 @@ function jsonChartDoughnut(labels, data) {
legend: { legend: {
position: 'bottom', position: 'bottom',
align: 'start', align: 'start',
} },
} },
} },
}; };
} }
@ -133,15 +132,15 @@ function jsonChartBarWithAvarage(labelBarChart, dataBarChart, labelAverage, data
{ {
// average line chart // average line chart
type: 'line', type: 'line',
label: labelAverage, // Todo: i18n label: labelAverage, // Todo: i18n
borderColor: 'rgb(192,216,0)', borderColor: 'rgb(192,216,0)',
data: { data: {
'-30' : dataAverage, '-30': dataAverage,
'-1' : dataAverage, '-1': dataAverage,
}, },
order: 1, order: 1,
} },
] ],
}, },
options: { options: {
@ -151,41 +150,41 @@ function jsonChartBarWithAvarage(labelBarChart, dataBarChart, labelAverage, data
}, },
x: { x: {
ticks: { ticks: {
callback: function(val){ callback: function (val) {
if (xAxisLabels.length > 0) { if (xAxisLabels.length > 0) {
return xAxisLabels[val]; return xAxisLabels[val];
} else { } else {
return val; return val;
} }
} },
}, },
grid: { grid: {
display: false, display: false,
} },
} },
}, },
elements: { elements: {
point: { point: {
radius: 0, radius: 0,
} },
}, },
plugins: { plugins: {
tooltip: { tooltip: {
callbacks: { callbacks: {
title: function(tooltipitem) { title: function (tooltipitem) {
if (xAxisLabels.length > 0) { if (xAxisLabels.length > 0) {
return xAxisLabels[tooltipitem[0].dataIndex]; return xAxisLabels[tooltipitem[0].dataIndex];
} else { } else {
return tooltipitem[0].label; return tooltipitem[0].label;
} }
} },
} },
}, },
legend: { legend: {
display: false, display: false,
} },
} },
} },
}; };
} }

View File

@ -879,7 +879,7 @@ input[type="search"] {
} }
.subtitle > div:not(:first-of-type)::before { .subtitle > div:not(:first-of-type)::before {
content: ' · '; content: ' · ';
} }
br { br {

View File

@ -465,7 +465,7 @@ a.btn {
/*=== Boxes */ /*=== Boxes */
.box { .box {
margin: 20px 10px; margin: 20px 0 20px 20px;
display: inline-block; display: inline-block;
max-width: 95%; max-width: 95%;
width: 20rem; width: 20rem;
@ -473,6 +473,11 @@ a.btn {
vertical-align: top; vertical-align: top;
} }
.box.visible-semi {
border-style: dashed;
opacity: 0.5;
}
.box .box-title { .box .box-title {
position: relative; position: relative;
font-size: 1.2rem; font-size: 1.2rem;
@ -874,7 +879,7 @@ input[type="search"] {
} }
.subtitle > div:not(:first-of-type)::before { .subtitle > div:not(:first-of-type)::before {
content: ' · '; content: ' · ';
} }
br { br {
@ -1114,7 +1119,7 @@ br {
display: none; display: none;
position: fixed; position: fixed;
top: 2%; bottom: 2%; top: 2%; bottom: 2%;
left: 3%; right: 3%; right: 3%; left: 3%;
overflow: auto; overflow: auto;
} }

42
package.json Normal file
View File

@ -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"
}
}