import Banner from '../components/Banner.html'; import {known_load, known_save} from './known_instances.js' (function settings_init(){ if(!('fetch' in window)){ return; } let status_timeout = null; let settings_section = document.querySelector('#settings-section'); let form = document.querySelector('form[name=settings]'); let inputs = Array.from(form.elements) let backoff_level = 0; let banner_el = document.querySelector('.main-banner'); banner_el.innerHTML = ''; let banner = new Banner({ target: banner_el, }); function hide_status(){ status_display.classList.remove('error', 'success', 'saving'); status_display.classList.add('hidden'); status_display.innerHTML=''; } function show_error(){ hide_status(); status_display.textContent='Could not save. Retrying...'; status_display.classList.add('error'); status_display.classList.remove('hidden'); } function show_success(){ hide_status(); status_display.textContent='Saved!'; status_display.classList.add('success'); status_display.classList.remove('hidden'); } function show_still_saving(){ status_display.textContent='Still saving...'; } function show_saving(){ hide_status(); status_display.textContent='Saving...'; status_display.classList.add('saving'); status_display.classList.remove('hidden'); status_timeout = setTimeout(show_still_saving, 5000); } function save(){ hide_status(); clearTimeout(status_timeout); status_timeout = setTimeout(show_saving, 70); let promise = send_settings(get_all_inputs()) .then(() => { show_success(); clearTimeout(status_timeout); status_timeout = setTimeout(hide_status, 3000); backoff_level = 0; }); promise.catch(() => { show_error(); clearTimeout(status_timeout); status_timeout = setTimeout(save, Math.pow(2, backoff_level)*1000); backoff_level += 1; backoff_level = Math.min(backoff_level, 5); }); promise.then(fetch_viewer).then(update_viewer); // remove server-rendered banner let banner = settings_section.querySelector('.banner'); if(banner){ settings_section.removeChild(banner); } } function get_all_inputs(){ let o = Object(); for(let input of inputs){ if(input.type != 'radio' || input.checked){ o[input.name] = input.value; } } return o; } function send_settings(body){ return fetch('/api/settings', { method:'PUT', credentials:'same-origin', headers: { 'content-type': 'application/json', }, body: JSON.stringify(body) }) .then(resp => { if(!resp.ok){ return Promise.reject(resp); } return resp; }) .then(resp => resp.json()) .then(data => { if(data.status == 'error'){ return Promise.reject(data); } return data; }); } for(let input of inputs){ input.addEventListener('change', save); } // remove submit button since we're doing live updates let submit = form.querySelector('input[type=submit]'); form.removeChild(submit); inputs.splice(inputs.indexOf(submit), 1); let status_display = document.createElement('span'); status_display.classList.add('status-display', 'hidden'); settings_section.insertBefore(status_display, settings_section.childNodes[0]); // silently send_settings in case the user changed settings while the page was loading send_settings(get_all_inputs()); let viewer_update_interval = 1500; function fetch_viewer(){ viewer_update_interval *= 2; viewer_update_interval = Math.min(30000, viewer_update_interval); return fetch('/api/viewer', { credentials: 'same-origin', }) .then(resp => { if(!resp.ok){ if(resp.status == 403){ // user was logged out in another client window.location = '/'; } return Promise.reject(resp); } return resp; }) .then(resp => resp.json()); } let last_viewer = {}; function update_viewer(viewer){ let dumped = JSON.stringify(viewer); if(last_viewer == dumped){ return; } last_viewer = dumped; document.querySelector('#post-count').textContent = viewer.post_count; document.querySelector('#eligible-estimate').textContent = viewer.eligible_for_delete_estimate; document.querySelector('#display-name').textContent = viewer.display_name || viewer.screen_name; document.querySelector('#display-name').title = '@' + viewer.screen_name; document.querySelector('#avatar').src = viewer.avatar_url; viewer_update_interval = 1500; if(viewer.next_delete){ viewer.next_delete = new Date(viewer.next_delete); } if(viewer.last_delete){ viewer.last_delete = new Date(viewer.last_delete); } banner.$set(viewer); } let viewer_from_dom = JSON.parse(document.querySelector('script[data-viewer]').textContent) update_viewer(viewer_from_dom) function set_viewer_timeout(){ setTimeout(() => fetch_viewer().then(update_viewer).then(set_viewer_timeout, set_viewer_timeout), viewer_update_interval); } set_viewer_timeout(); banner.$on('toggle', event => { let enabled = event.detail; send_settings({policy_enabled: enabled}).then(fetch_viewer).then(update_viewer); // TODO show error or spinner if it takes over a second }) let reason_banner = document.querySelector('.banner[data-reason]'); if(reason_banner){ let dismiss = reason_banner.querySelector('input[type=submit]'); dismiss.addEventListener('click', e => { e.preventDefault(); // we don't care if this succeeds or fails. worst // case scenario the banner appears again on a future page load fetch('/api/reason', {method: 'DELETE', credentials:'same-origin'}); reason_banner.parentElement.removeChild(reason_banner); }) } function bump_instance(service, instance_name){ let known_instances = known_load(); let found = false; for(let instance of known_instances[service]){ if(instance['instance'] == instance_name){ instance.hits ++; found = true; break; } } if(!found){ let instance = {"instance": instance_name, "hits": 1}; known_instances[service].push(instance); } known_save(known_instances); } if(location.hash == '#bump_instance' && ( viewer_from_dom['service'] == 'mastodon' || viewer_from_dom['service'] == 'misskey' )){ bump_instance(viewer_from_dom['service'], viewer_from_dom['id'].split('@')[1]) let url = new URL(location.href) url.hash = ''; history.replaceState('', '', url); } })();