// Wspólne dane formularza między zakładkami (PRE-21). // // Problem: każdą zakładkę (Horoskop / Interpretacje / Kalendarz) wypełniało się // od nowa — te same imię, data, godzina, strefa i miejsce. Teraz raz wpisane // dane wędrują za użytkownikiem. // // Dlaczego localStorage, a nie sesja na serwerze: serwer zostaje BEZSTANOWY // (żadnego magazynu sesji, żadnych danych urodzeniowych trzymanych po stronie // usługi), a przy okazji dane synchronizują się też między osobnymi kartami // przeglądarki — zdarzenie `storage` daje to za darmo. // // UWAGA na kolejność: ten skrypt ładujemy w z `defer`, więc wykonuje się // PO sparsowaniu dokumentu, ale PRZED geo.js (skrypty defer idą w kolejności // dokumentu). Dzięki temu mapa startuje już z odtworzonymi współrzędnymi i nie // trzeba jej potem przestawiać. (function () { 'use strict'; var KEY = 'astrololo.form.v1'; // Pola wspólne dla zakładek. Nazwa pola formularza -> jak je znaleźć. // `geoSearch` (nazwa miejsca) nie ma atrybutu name — szukamy po id. // type: brak = zwykła wartość (.value); 'check' = pojedynczy checkbox (.checked); // 'multi' = kilka checkboxów o tej samej nazwie (lista zaznaczonych wartości). // Opcje (stacje, tabele, porównanie domów) są tu, żeby wybór z „Horoskopu" // wędrował na „Skompiluj" — inaczej podsumowanie liczyłoby się bez nich. var FIELDS = [ { key: 'person', sel: 'input[name=person]' }, { key: 'date', sel: 'input[name=date]' }, { key: 'time', sel: 'input[name=time]' }, { key: 'tz_offset', sel: 'input[name=tz_offset]' }, { key: 'lat', sel: 'input[name=lat]' }, { key: 'lon', sel: 'input[name=lon]' }, { key: 'house_system', sel: 'select[name=house_system]' }, { key: 'zodiac', sel: 'select[name=zodiac]' }, { key: 'place', sel: '#geoSearch' }, { key: 'stations', sel: 'input[name=stations]', type: 'check' }, { key: 'tables', sel: 'input[name=tables]', type: 'check' }, { key: 'house_systems', name: 'house_systems', type: 'multi' }, { key: 'aspect_orb', sel: 'input[name=aspect_orb]' }, { key: 'aspect_luminary_bonus', sel: 'input[name=aspect_luminary_bonus]' }, { key: 'aspect_minor', sel: 'input[name=aspect_minor]', type: 'check' } ]; function elementsOf(f) { if (f.type === 'multi') return Array.prototype.slice.call(document.querySelectorAll('[name=' + f.name + ']')); var el = document.querySelector(f.sel); return el ? [el] : []; } function load() { try { return JSON.parse(localStorage.getItem(KEY) || '{}') || {}; } catch (e) { return {}; // uszkodzony wpis nie może zablokować strony } } function save(state) { try { localStorage.setItem(KEY, JSON.stringify(state)); } catch (e) { /* tryb prywatny albo brak miejsca — trudno, formularz ma działać dalej */ } } function apply(state) { FIELDS.forEach(function (f) { var els = elementsOf(f); if (!els.length) return; var v = state[f.key]; if (v === undefined || v === null) return; if (f.type === 'multi') { if (!Array.isArray(v)) return; els.forEach(function (el) { el.checked = v.indexOf(el.value) !== -1; }); } else if (f.type === 'check') { els[0].checked = !!v; } else { if (v === '') return; if (els[0].value !== v) els[0].value = v; } }); } function collect() { var state = load(); FIELDS.forEach(function (f) { var els = elementsOf(f); if (!els.length) return; // pola nieobecnego na tej zakładce nie kasujemy if (f.type === 'multi') { state[f.key] = els.filter(function (el) { return el.checked; }).map(function (el) { return el.value; }); } else if (f.type === 'check') { state[f.key] = els[0].checked; } else { if (els[0].value === '' || els[0].value === null) return; state[f.key] = els[0].value; } }); return state; } // 1) odtwórz to, co użytkownik wpisał gdzie indziej apply(load()); // 2) zapisuj każdą zmianę (input dla wpisywania, change dla list, checkboxów, kalendarzy) FIELDS.forEach(function (f) { elementsOf(f).forEach(function (el) { ['input', 'change'].forEach(function (ev) { el.addEventListener(ev, function () { save(collect()); }); }); }); }); // 3) zapisz stan po wysłaniu formularza — po przeładowaniu strony pola mają // pokazywać to, co faktycznie policzyliśmy document.addEventListener('submit', function () { save(collect()); }, true); // 4) druga otwarta karta zmieniła dane -> dociągnij je tutaj na żywo window.addEventListener('storage', function (e) { if (e.key === KEY) apply(load()); }); // 5) geo.js ustawia lat/lon z mapy poza polami formularza — po takiej zmianie // też chcemy zapamiętać (zdarzenie leci z „Tu i teraz" oraz z mapy) document.addEventListener('astrololo:coords', function () { setTimeout(function () { save(collect()); }, 0); }); })();