aboutsummaryrefslogtreecommitdiff
path: root/p/scripts/extra.js
diff options
context:
space:
mode:
Diffstat (limited to 'p/scripts/extra.js')
-rw-r--r--p/scripts/extra.js241
1 files changed, 241 insertions, 0 deletions
diff --git a/p/scripts/extra.js b/p/scripts/extra.js
new file mode 100644
index 000000000..c0d0c89e1
--- /dev/null
+++ b/p/scripts/extra.js
@@ -0,0 +1,241 @@
+"use strict";
+/* globals context, openNotification, xmlHttpRequestJson */
+/* jshint esversion:6, strict:global */
+
+//<crypto form (Web login)>
+function poormanSalt() { //If crypto.getRandomValues is not available
+ const base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz';
+ let text = '$2a$04$';
+ for (let i = 22; i > 0; i--) {
+ text += base.charAt(Math.floor(Math.random() * 64));
+ }
+ return text;
+}
+
+function init_crypto_form() {
+ /* globals dcodeIO */
+ const crypto_form = document.getElementById('crypto-form');
+ if (!crypto_form) {
+ return;
+ }
+
+ if (!(window.dcodeIO)) {
+ if (window.console) {
+ console.log('FreshRSS waiting for bcrypt.js…');
+ }
+ setTimeout(init_crypto_form, 100);
+ return;
+ }
+
+ crypto_form.onsubmit = function (e) {
+ const submit_button = this.querySelector('button[type="submit"]');
+ submit_button.disabled = true;
+ let success = false;
+
+ const req = new XMLHttpRequest();
+ req.open('GET', './?c=javascript&a=nonce&user=' + document.getElementById('username').value, false);
+ req.onerror = function () {
+ openNotification('Communication error!', 'bad');
+ };
+ req.send();
+ if (req.status == 200) {
+ const json = xmlHttpRequestJson(req);
+ if (!json.salt1 || !json.nonce) {
+ 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());
+ document.getElementById('challenge').value = c;
+ if (!s || !c) {
+ openNotification('Crypto error!', 'bad');
+ } else {
+ success = true;
+ }
+ } catch (ex) {
+ openNotification('Crypto exception! ' + ex, 'bad');
+ }
+ }
+ } else {
+ req.onerror();
+ }
+
+ submit_button.disabled = false;
+ return success;
+ };
+}
+//</crypto form (Web login)>
+
+function init_share_observers() {
+ let shares = document.querySelectorAll('.group-share').length;
+ const shareAdd = document.querySelector('.share.add');
+ if (shareAdd) {
+ shareAdd.onclick = function (ev) {
+ const s = this.parentElement.querySelector('select'),
+ opt = s.options[s.selectedIndex];
+ let row = this.closest('form').getAttribute('data-' + opt.getAttribute('data-form'));
+ row = row.replace(/##label##/g, opt.text);
+ row = row.replace(/##type##/g, opt.value);
+ row = row.replace(/##help##/g, opt.getAttribute('data-help'));
+ row = row.replace(/##key##/g, shares);
+ row = row.replace(/##method##/g, opt.getAttribute('data-method'));
+ row = row.replace(/##field##/g, opt.getAttribute('data-field'));
+ this.closest('.form-group').insertAdjacentHTML('beforebegin', row);
+ shares++;
+ return false;
+ };
+ }
+}
+
+
+function init_remove_observers() {
+ document.querySelectorAll('.post').forEach(function (div) {
+ div.onclick = function (ev) {
+ const a = ev.target.closest('a.remove');
+ if (a) {
+ const remove_what = a.getAttribute('data-remove');
+ if (remove_what !== undefined) {
+ const d = document.getElementById(remove_what);
+ if (d) {
+ d.remove();
+ }
+ }
+ return false;
+ }
+ };
+ });
+}
+
+function init_feed_observers() {
+ const s = document.getElementById('category');
+ if (s && s.matches('select')) {
+ s.onchange = function (ev) {
+ const detail = document.getElementById('new_category_name').parentElement;
+ if (this.value === 'nc') {
+ detail.setAttribute('aria-hidden', 'false');
+ detail.querySelector('input').focus();
+ } else {
+ detail.setAttribute('aria-hidden', 'true');
+ }
+ };
+ }
+}
+
+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;
+ };
+ });
+}
+
+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.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');
+ 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 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;
+ };
+ req.send();
+ return false;
+ }
+ }
+ };
+
+ closer.onclick = function (ev) {
+ closer.classList.remove('active');
+ slider.classList.remove('active');
+ return false;
+ };
+}
+
+function init_configuration_alert() {
+ window.onsubmit = function (e) {
+ window.hasSubmit = true;
+ };
+ window.onbeforeunload = function (e) {
+ if (window.hasSubmit) {
+ return;
+ }
+ const ds = document.querySelectorAll('[data-leave-validation]');
+ for (let i = ds.length - 1; i >= 0; i--) {
+ const input = ds[i];
+ if (input.type === 'checkbox' || input.type === 'radio') {
+ if (input.checked != input.getAttribute('data-leave-validation')) {
+ return false;
+ }
+ } else if (input.value != input.getAttribute('data-leave-validation')) {
+ return false;
+ }
+ }
+ };
+}
+
+function init_extra() {
+ if (!window.context) {
+ if (window.console) {
+ console.log('FreshRSS extra waiting for JS…');
+ }
+ window.setTimeout(init_extra, 50); //Wait for all js to be loaded
+ return;
+ }
+ init_crypto_form();
+ init_share_observers();
+ init_remove_observers();
+ init_feed_observers();
+ init_password_observers();
+ init_select_observers();
+ init_slider_observers();
+ init_configuration_alert();
+}
+
+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);
+}