/* mulsu.js, part of nitpo, by Thomas Krichel */ const html_ns = 'http://www.w3.org/1999/xhtml'; const fields = ['emad']; const labins = ['label', 'input']; /* STATE VARIABLES */ /* subscriber email address if set as an emad */ var set_emad = null; /* the potential emad input by the user */ var emad_input = null; /* the current repcode */ var set_repcode = null; /* the signup text without decoration, usually 'Sign up' */ var bare_signup_text = null; /* the current emad set on the signup elements */ var emad_signup = null; /* CONF variables, read with read_conf() */ /* the nitpo_address, found in the HTML id="nitpo_address" */ var nitpo_address = null; /* the nitpo path start, found in the HTML id="nitpo_pathstart" */ var nitpo_pathstart = null; /* nitpo timeout, in miliseconds found in the HTML id="nitpo_timeout" */ var nitpo_timeout = null; /* mulsu wait phrase, displayed while the fetch is is progress found in the HTML id="mulsu_wait_start" */ var mulsu_wait_start = null; /* mulsu wait success phrase, displayed when the signup is successful found in the HTML id="mulsu_wait_success" */ var mulsu_wait_success = null; /* mulsu wait failure phrase, displayed when the signup has failed found in the HTML id="mulsu_wait_failure" */ var mulsu_wait_success = null; /* Phrase variables, read from the HTML file as text contents */ function read_conf() { /* conf variables, set to null at the start, set with read_conf */ /* the nitpo address, found in the HTML id="nitpo_address" if this is null, invoque read_conf */ nitpo_address = read_a_conf('nitpo_address'); nitpo_address = read_a_conf('nitpo_address'); mulsu_wait_start = read_a_conf('mulsu_wait_start'); nitpo_wait_success = read_a_conf('mulsu_wait_success'); mulsu_wait_failure = read_a_conf('mulsu_wait_failure'); } function read_a_conf(elid) { let ele = document.getElementById(elid); if(ele === null) { return null; } out = ele.textContent; return out; } /* called by HTML */ async function on_signup(ele) { /* must have id of form nitpo_REPCODE_signup */ /* read the configuration if the nitpo address is not set */ if(nitpo_address === null) { read_conf(); } elid = ele.getAttribute('id'); set_bare_text_on_former_selection(); /* if the email input on the current element has focus, we should */ /* do nothing here, but this is not (yet) implemented */ /* this is for setting at the start, should be onload= */ if(bare_signup_text === null) { bare_signup_text = ele.textContent; } const old_repcode = set_repcode; /* when the emad is not set, close the form there */ set_repcode = get_repcode_from_elid(elid); /* open the emad_input_form at start, or emad_input is not an emad */ if(set_emad === null) { if(old_repcode !== null) { close_emad_input_form(old_repcode); } /* fixme, this is not called with 'off' */ open_emad_input(ele); return false; } focus_on_signup(set_repcode); /* only redorate if emad_signup is not up-to-date */ if((emad_signup !== null) && (emad_signup !== set_emad)) { decorate_signups(emad_input); focus_on_signup(set_repcode); } const url = form_url(); console.log('CALL ' + url); ele.oldText = ele.textContents; ele.textContent = mulsu_wait_start + ' ' + set_emad + "…"; out = await fetchWithTimeout(url, ele, options = {}); let end = ''; if(! out) { end = mulsu_wait_failure; } else { mulsu_wait_success; } console.log('CALLed ' + url); ele.textContent += ' ' + end; ele.disabled = true; return true; } /* called by HTML */ function on_emad_input(ele) { /* must have id of form nitpo_REPCODE_emad_input */ const elid = ele.getAttribute('id'); emad_input = ele.value.trim(); const is_emad = is_it_emad(emad_input); if(emad_input !== null) { ele.value = emad_input; } if(is_emad === false) { cant_signup(set_repcode, emad_input); set_emad = null; decorate_signups(emad_input); return; } // console.log('* dig for emad' + elid); set_emad = dig_for_emad(emad_input); // console.log('* docorate ' + elid); call_again = false; decorate_signups(emad_input); } function set_bare_text_on_former_selection() { /* happens of we don't have a valid email on it, before it is changed */ if(set_emad !== null) { return false; } if(set_repcode === null) { return false; } if(bare_signup_text === null) { return false; } const elid = 'nitpo_' + set_repcode + '_emad_input' let signup_button_ele = document.getElementById(elid); if(signup_button_ele === null) { // console.log('g 4'); return false; } // console.log('reset ' + set_repcode); signup_button_ele.textContent = bare_signup_text; // console.log('done reset ' + set_repcode + ' ' + bare_signup_text); return true; } function dig_for_emad(string) { /* look for the email in something like */ /* Thomas Krichel */ const words = string.split(" "); let found = null; for (const word of words) { if(! is_it_emad(word)) { continue; } found = word; } if(found === null) { return null; } found = found.replace('<',''); found = found.replace('>',''); // console.log('dug emad "' + found + '"'); return found; } function form_url() { if(nitpo_address === null) { const nitpo_address_ele = document.getElementById('nitpo_address'); nitpo_address = nitpo_address_ele.textContent; } url = nitpo_address + set_repcode + '/' + set_emad; return url; } function open_emad_input(signup_ele) { let is_focus_set = false; for (const labin of labins) { for (const field of fields) { const elid = 'nitpo_' + set_repcode + '_' + field + '_' + labin const target_ele = document.getElementById(elid); if(target_ele === null) { continue } target_ele.style.display = 'initial'; if(labin !== 'input') { continue; } // console.log('set focus in target_form ' + elid); target_ele.focus(); /* target_ele.addEventListener('blur', function(event) { event.preventDefault(); console.log('blur happened'); signup_ele.focus(); }); console.log('event added'); */ is_focus_set = true; if(emad_input !== null) { target_ele.value = emad_input; } } } /* close_other_forms(set_repcode);*/ if(set_emad !== null && ! is_focus_set) { console.log('focus on ' + set_repcode); focus_on_signup(set_repcode); } } function cant_signup(repcode, string) { const signup_elid = 'nitpo_' + repcode + '_signup'; const signup_ele = document.getElementById(signup_elid); if(signup_ele === null) { return; } if(string === '') { /* just show the default */ signup_ele.textContent = bare_signup_text; } else { signup_ele.textContent = "I can’t sign up “" + string + "”"; } const input_elid = 'nitpo_' + repcode + '_emad_input'; const input_ele = document.getElementById(input_elid); if(repcode === set_repcode) { console.log('in cant, set focus on ' + input_elid); input_ele.focus(); } return false; } function focus_on_signup(repcode) { elid = 'nitpo_' + repcode + '_signup'; let signup_ele = document.getElementById(elid); if(signup_ele === null) { console.log("I can't see the element " + elid); return false; } signup_ele.focus(); signup_ele.value = emad_input; return false; } function close_emad_input_form(repcode) { if(set_repcode === null) { console.log("With no set repcode, I keep the input open."); return false; } for (const field of fields) { for (const labin of labins) { const elid = 'nitpo_' + repcode + '_' + field + '_' + labin; const target_ele = document.getElementById(elid); if(target_ele === null) { continue; } target_ele.style.display = 'none'; } } return true; } function decorate_signups() { // console.log('start of decorate at ' + set_repcode); button_eles = document.getElementsByTagNameNS(html_ns, 'button'); /* don't overwrite the current signup button */ const current_signup_elid = 'nitpo_' + set_repcode + '_signup'; for (const button_ele of button_eles) { if(button_ele.disabled) { continue; } const button_id = button_ele.getAttribute('id'); if(button_id.substr(0,6) !== 'nitpo_') { continue; } const button_end = button_id.substr(-7,7); if(button_end !== '_signup') { continue; } if(set_emad === null) { if(button_ele.getAttribute('id') != current_signup_elid) { button_ele.textContent = bare_signup_text; } } else { button_ele.textContent = bare_signup_text + " " + set_emad; repcode = get_repcode_from_elid(button_id); if(repcode == set_repcode) { console.log('set focus in decorate ' + set_repcode + ' ' + button_id); //console.log(button_ele); button_ele.focus(); console.log('done'); } } } /* this attempt to place the focus results in a loop if(call_again) { console.log('gone ' + set_repcode); return; } target_ele = document.getElementById(current_signup_elid); console.log('target ' + target_ele); target_ele.focus(); console.log('decorate ' + set_repcode); */ emad_signup = set_emad; } function is_it_emad(string) { /* this is the same check as used server-side, don't change */ const is_emad = /([^@]+@[^@]+\.[^@]+)/.test(string); return is_emad; } function has_emad(string) { const last_part = last_word(string); if(is_it_emad(last_part)) { return last_part; } return null; } function last_word(anchor_string) { const words = anchor_string.split(" "); return words[words.length - 1]; } function get_repcode_from_elid(elid) { // starts with nitpo_ const from_repcode_start = elid.substring(6); const end_of_repcode = from_repcode_start.indexOf('_') const repcode = from_repcode_start.substring(0, end_of_repcode) return repcode; } async function call_fetch(url) { try { let res = await fetch(url); return await res; } catch (error) { console.log(error); } } /* from https://dmitripavlutin.com/timeout-fetch-reqpuest/ */ async function fetchWithTimeout(url, button_ele, options = {}) { const { timeout = nitpo_timeout } = options; const controller = new AbortController(); const timeout_id = setTimeout(() => controller.abort(), timeout); const response = await call_fetch(url, { signal: controller.signal }); clearTimeout(timeout_id); return response; }