1(() => { 2 'use strict'; 3 const form = document.getElementById('company-create-form'); 4 if (!form) return; 5 const params = new URLSearchParams(location.search); 6 const switchKey = 'company-profile-switch'; 7 const draftKey = 'company-profile-draft:' + (form.dataset.companyMode || 'basic'); 8 const fields = Array.from(form.elements).filter(el => el.name && 9 !['hidden', 'password', 'button', 'submit'].includes(el.type)); 10 let busy = false; 11 let restoredFiles = true; 12 const notice = document.createElement('div'); 13 notice.setAttribute('role', 'alert'); 14 notice.style.cssText = 'display:none;background:#f8d7da;padding:12px;margin:12px 0'; 15 form.prepend(notice); 16 const message = text => { 17 notice.textContent = text; 18 notice.style.display = 'block'; 19 notice.scrollIntoView({ block: 'center' }); 20 }; 21 window.removeEventListener('beforeunload', window.saveFormData); 22 23 function database() { 24 return new Promise((resolve, reject) => { 25 const request = indexedDB.open('pdw-company-profile-state', 1); 26 request.onupgradeneeded = () => request.result.createObjectStore('transfers'); 27 request.onsuccess = () => resolve(request.result); 28 request.onerror = () => reject(request.error); 29 request.onblocked = () => reject(new Error('Storage blocked')); 30 }); 31 } 32 async function transfer(mode, token, value) { 33 const db = await database(); 34 try { 35 return await new Promise((resolve, reject) => { 36 const tx = db.transaction('transfers', 'readwrite'); 37 const store = tx.objectStore('transfers'); 38 let result; 39 if (mode === 'save') { 40 const cursor = store.openCursor(); 41 cursor.onsuccess = () => { 42 const entry = cursor.result; 43 if (!entry) return; 44 if (Date.now() - entry.value.timestamp > 10 * 60 * 1000) entry.delete(); 45 entry.continue(); 46 }; 47 store.put(value, token); 48 } else if (mode === 'remove') store.delete(token); 49 else { 50 const request = store.get(token); 51 request.onsuccess = () => { result = request.result; store.delete(token); }; 52 } 53 tx.oncomplete = () => resolve(result); 54 tx.onerror = () => reject(tx.error); 55 tx.onabort = () => reject(tx.error || new Error('Storage aborted')); 56 }); 57 } finally { db.close(); } 58 } 59 const token = () => Array.from(crypto.getRandomValues(new Uint32Array(4)), 60 value => value.toString(16).padStart(8, '0')).join(''); 61 const snapshot = path => ({ timestamp: Date.now(), path, 62 fields: fields.map(el => ({ name: el.name, type: el.type, 63 value: el.type === 'file' ? '' : el.value, checked: el.checked, 64 files: el.type === 'file' ? Array.from(el.files) : undefined })) }); 65 async function save(key, path) { 66 const id = token(); 67 sessionStorage.setItem(key, id); 68 await transfer('save', id, snapshot(path)); 69 } 70 function restoreSnapshot(saved) { 71 if (!saved || !Array.isArray(saved.fields) || saved.path !== location.pathname || 72 Date.now() - saved.timestamp > 10 * 60 * 1000) return; 73 fields.forEach(el => { 74 const entry = saved.fields.find(item => item.name === el.name && item.type === el.type && 75 (!['checkbox', 'radio'].includes(el.type) || item.value === el.value)); 76 if (!entry) return; 77 if (el.type === 'file') { 78 if (!entry.files?.length) return; 79 if (el.pdwUpload?.restoreFiles) el.pdwUpload.restoreFiles(entry.files); 80 else restoredFiles = false; 81 } else if (['checkbox', 'radio'].includes(el.type)) el.checked = entry.checked; 82 else el.value = entry.value; 83 }); 84 if (!restoredFiles) message('Einige hochgeladene Dateien konnten nicht wiederhergestellt werden. Bitte wählen Sie diese erneut aus.'); 85 } 86 function restoreEditor(editor) { 87 const element = editor.getElement(); 88 if (!form.contains(element)) return; 89 const setContent = () => editor.setContent(element.value); 90 if (editor.initialized) setContent(); 91 else editor.on('init', setContent); 92 } 93 const ready = (async () => { 94 try { 95 const switchToken = sessionStorage.getItem(switchKey); 96 if (switchToken) { 97 const saved = await transfer('read', switchToken); 98 sessionStorage.removeItem(switchKey); 99 restoreSnapshot(saved); 100 } 101 if (params.has('error')) { 102 const savedToken = sessionStorage.getItem(draftKey); 103 if (savedToken) { 104 const saved = await transfer('read', savedToken); 105 sessionStorage.removeItem(draftKey); 106 restoreSnapshot(saved); 107 } 108 } 109 if (window.tinymce) { 110 const editor = tinymce.get('editor'); 111 if (editor) restoreEditor(editor); 112 tinymce.on('AddEditor', event => restoreEditor(event.editor)); 113 } 114 } catch (_) { 115 message('Die gespeicherten Eingaben konnten nicht wiederhergestellt werden. Bitte wählen Sie Dateien gegebenenfalls erneut aus.'); 116 } 117 })(); 118 const invalid = new Set(params.has('error') ? (params.get('fields') || '').split(',') : []); 119 const style = document.createElement('style'); 120 style.textContent = '#company-create-form .company-invalid{background-color:#f8d7da!important;}#company-recaptcha.company-invalid{padding:8px;border:1px solid #dc3545;}'; 121 document.head.append(style); 122 fields.forEach(el => { 123 if (!invalid.has(el.name)) return; 124 const target = el.type === 'radio' ? el.closest('#anrede') : el; 125 target?.classList.add('company-invalid'); 126 target?.setAttribute('aria-invalid', 'true'); 127 }); 128 if (invalid.has('g-recaptcha-response')) { 129 const target = document.getElementById('company-recaptcha'); 130 target?.classList.add('company-invalid'); 131 target?.setAttribute('aria-invalid', 'true'); 132 } 133 ['basic-btn', 'premium-btn'].forEach(id => { 134 const link = document.getElementById(id); 135 if (!link) return; 136 link.addEventListener('click', async event => { 137 event.preventDefault(); 138 if (busy) return; 139 busy = true;
140 try { 141 await ready; 142 const destination = new URL(link.href, location.href); 143 if (destination.origin !== location.origin || destination.pathname === location.pathname) return; 144 if (window.tinymce) tinymce.triggerSave(); 145 await save(switchKey, destination.pathname); 146 location.assign(destination.href); 147 } catch (_) { 148 message('Der Profilwechsel konnte nicht gesichert werden. Ihre Eingaben bleiben hier erhalten. Bitte erlauben Sie den Browserspeicher und versuchen Sie es erneut.'); 149 } finally { busy = false; } 150 }); 151 }); 152 async function submit() { 153 await ready; 154 if (busy) return; 155 if (window.tinymce) tinymce.triggerSave(); 156 try { await save(draftKey, location.pathname); } 157 catch (_) { 158 message('Die Eingaben konnten nicht gesichert werden. Bitte erlauben Sie den Browserspeicher, bevor Sie erneut absenden. Ihre Eingaben bleiben auf dieser Seite erhalten.'); 159 return; 160 } 161 busy = true; 162 form.setAttribute('aria-busy', 'true'); 163 try { 164 const response = await fetch(form.action, { method: 'POST', body: new FormData(form), 165 credentials: 'same-origin', headers: { 'X-Company-Form': '1' } }); 166 const result = await response.json(); 167 if (!response.ok || typeof result.redirect !== 'string' || typeof result.created !== 'boolean') throw new Error('Unexpected response'); 168 const destination = new URL(result.redirect, location.href); 169 if (destination.origin !== location.origin) throw new Error('Unexpected destination'); 170 if (result.created) { 171 const savedToken = sessionStorage.getItem(draftKey); 172 if (savedToken) await transfer('remove', savedToken); 173 sessionStorage.removeItem(draftKey); 174 } 175 location.assign(destination.href); 176 } catch (_) { 177 message('Die Ãbermittlung konnte nicht bestätigt werden. Ihre Eingaben bleiben erhalten. Bitte prüfen Sie vor erneutem Absenden, ob das Unternehmensprofil bereits angelegt wurde.'); 178 busy = false; 179 form.removeAttribute('aria-busy'); 180 } 181 } 182 window.BsubmitForm = submit; 183 form.addEventListener('submit', event => { event.preventDefault(); submit(); }); 184})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.