diff options
Diffstat (limited to 'p/scripts/extra.js')
| -rw-r--r-- | p/scripts/extra.js | 241 |
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); +} |
