PageSourceSearch

https://www.gewobag.de/wp-content/plugins/dd-wbs-calculator/assets/js/wbs-calculator.js?ver=1.1.0

js gewobag.de collected 2026-10-02 06:46:51 UTC 12,542 bytes, 294 lines download raw bytes

1class WBSCalculator {
2	constructor(el) {
3		this.container = el;
4
5		this.senateCalculatorUrl = 'https://ssl.stadtentwicklung.berlin.de/wohnen/wbs/wbsformular.shtml';
6		this.currentImmoProjectsUrl = 'https://www.gewobag.de/bauen-in-berlin/bauprojekte#aktuell';
7		this.searchSubscriptionUrl = 'https://www.gewobag.de/suchauftrag';
8		this.officialRequestUrl = 'https://service.berlin.de/dienstleistung/120671/';
9		this.privacyPolicyUrl = 'http://www.gewobag.de/datenschutz';
10		this.apartmentsUrl = 'https://www.gewobag.de/mieten';
11
12		this.form = this.container.querySelector('.js-dd-wbs-calculator-form');
13		this.resultContainer = this.container.querySelector('.js-dd-wbs-calculator-result');
14		this.resultComponent = this.resultContainer.querySelector('.gw-wbs-result');
15		this.errorMessageContainer = this.container.querySelector('.js-dd-wbs-calculator-error');
16		this.topAnchor = this.container.querySelector('.js-dd-wbs-calculator-top-anchor');
17		this.disabledPersonsCount = 0;
18		this.init();
19	}
20
21	init() {
22		this.initSubmitButton();
23		this.initResetButton();
24		this.initDynamicFields();
25		this.initToggles();
26		this.initChildrenSelect();
27		this.initQuestionInfo();
28	}
29
30	initSubmitButton() {
31		const submitButton = this.container.querySelector('.js-dd-wbs-calculator-submit');
32
33		submitButton.addEventListener('click', (e) => {
34			e.preventDefault();
35			const validation = this.validateForm();
36			if (validation.validates) {
37				this.errorMessageContainer.innerHTML = '';
38				this.showResult();
39			} else {
40				this.errorMessageContainer.innerHTML = validation.errorMessages.join(' ');
41			}
42		});
43	}
44
45	initResetButton() {
46		const resetButton = this.container.querySelector('.js-dd-wbs-calculator-reset');
47		resetButton.addEventListener('click', (e) => {
48			e.preventDefault();
49			this.resetForm();
50		});
51	}
52
53	initChildrenSelect() {
54		const childrenSelect = this.container.querySelector('.js-dd-wbs-calculator-children-count');
55		const childrenExtraCostsSection = this.container.querySelector('.js-dd-wbs-calculator-children-extra-costs-section');
56
57		childrenExtraCostsSection.classList.add('d-none');
58		childrenSelect.addEventListener('change', (e) => {
59			const childrenCount = this.getFieldValue('dd-wbs-calculator-children-count', '0');
60			childrenExtraCostsSection.classList[childrenCount > 0 ? 'remove' : 'add']('d-none');
61		})
62	}
63
64	validateForm() {
65		let errorMessages = [];
66		const netIncome = this.getFieldValue('dd-wbs-calculator-net-income', '0');
67
68		if (netIncome === 0) errorMessages.push('Bitte geben Sie ihr monatliches Einkommen an.')
69
70		if (errorMessages.length > 0) {
71			return {
72				validates: false,
73				errorMessages
74			}
75		} else {
76			return {
77				validates: true
78			}
79		}
80	}
81
82	getFieldValue(fieldName, defaultValue = null) {
83		let field = this.container.querySelector(`[name=${fieldName}]`);
84		if (field.getAttribute('type') === 'radio') {
85			field = this.container.querySelector(`[name=${fieldName}]:checked`);
86		}
87		return parseInt(field ? field.value : defaultValue);
88	}
89
90	showResult() {
91		const income = this.calculate();
92		const threshold = this.getThreshold();
93		let wbsResult;
94		let wbsNumber = 0;
95		const wbsNumbers = [220, 180, 160, 140, 100];
96
97		if (income < threshold) {
98			wbsNumber = 100;
99		} else if (income < threshold * 1.4) {
100			wbsNumber = 140;
101		} else if (income < threshold * 1.6) {
102			wbsNumber = 160;
103		} else if (income < threshold * 1.8) {
104			wbsNumber = 180;
105		} else if (income < threshold * 2.2) {
106			wbsNumber = 220;
107		} else {
108			wbsNumber = 0;
109		}
110
111		const resultMessage = this.container.querySelector('.js-dd-wbs-calculator-result-message');
112		const resultNotice = this.container.querySelector('.js-dd-wbs-calculator-result-notice');
113		const resultLevels = this.container.querySelector('.js-dd-wbs-calculator-result-levels');
114		Array.from(resultLevels?.children || []).forEach(level => {
115			level.classList.remove('gw-wbs-result__level--active');
116		});
117
118		if (wbsNumber) {
119			const nthChild = resultLevels.querySelector(`:nth-child(${wbsNumbers.indexOf(wbsNumber) + 1})`);
120			if (nthChild) {
121				nthChild.classList.add('gw-wbs-result__level--active');
122			}
123			wbsResult = 'Sie haben vermutlich Anspruch auf einen WBS ' + wbsNumber;
124
125			resultMessage.innerHTML = `Falls Sie noch keinen WBS besitzen oder beantragt haben, können Sie hier einen <a href="${this.officialRequestUrl}" target="_blank" rel="noreferrer noopener">WBS-Antrag stellen</a>. BesitzerInnen eines WBS ${wbsNumber} können sich neben freifinanzierten Wohnungen auch auf geförderte Wohnungen bewerben. Bitte beachten Sie unsere entsprechenden <a target="_blank" href="${this.apartmentsUrl}">Wohnungsinserate</a>. Hier können Sie einen entsprechenden <a href="${this.searchSubscriptionUrl}">Suchauftrag anlegen</a>. Beachten Sie insbesondere unsere  <a href="${this.currentImmoProjectsUrl}">Neubauprojekte</a>, bei welchen ein großer Anteil der Wohnungen WBS-BesitzerInnen vorbehalten ist.`;
126			resultNotice.innerHTML = `<strong>Wichtig</strong>: Für die Bewerbung auf eine WBS-Wohnung ist es nicht ausreichend, dass ein/e BewerberIn die Einkommensgrenzen einhält oder einen WBS-Antrag gestellt hat. Der WBS muss zum Zeitpunkt der Bewerbung <strong>bereits vorliegen</strong>. Bevor Sie einen WBS-Antrag stellen, sollten Sie ebenfalls den <a target="_blank" href="${this.senate
126CalculatorUrl}">WBS-Rechner</a> des Berliner Senats heranziehen.<br><a href="${this.privacyPolicyUrl}">Disclaimer Datenschutz</a>`;
127		} else {
128			wbsResult = 'Sie haben vermutlich keinen Anspruch auf einen WBS';
129			resultMessage.innerHTML = `Während wir Ihnen vermutlich keine belegungsgebundene Wohnung anbieten können, würden wir uns sehr über Ihre Bewerbung auf eine freifinanzierte Wohnung freuen. <br>Bitte beachten Sie unsere entsprechenden <a target="_blank" href="${this.apartmentsUrl}">Wohnungsinserate</a>. Hier können Sie einen entsprechenden <a href="${this.searchSubscriptionUrl}">Suchauftrag anlegen</a>. Beachten Sie insbesondere unsere <a href="${this.currentImmoProjectsUrl}">Neubauprojekte</a>, bei welchen ein Anteil der Wohnungen auch ohne WBS angemietet werden kann.`;
130			resultNotice.innerHTML = `<strong>Wichtig</strong>: Bitte überprüfen Sie Ihren WBS-Anspruch ebenfalls mit dem <a target="_blank" href="${this.senateCalculatorUrl}">WBS-Rechner</a> des Berliner Senats.<br><a href="${this.privacyPolicyUrl}">Disclaimer Datenschutz</a>`;
131		}
132
133		const resultTitle = this.container.querySelector('.js-dd-wbs-calculator-result-title');
134		resultTitle.innerHTML = wbsResult;
135		this.resultContainer.classList.remove('d-none');
136		this.resultComponent.classList.remove('gw-wbs-result--failed');
137		if (wbsNumber === 0) this.resultComponent.classList.add('gw-wbs-result--failed');
138		this.form.classList.add('d-none');
139		this.topAnchor.scrollIntoView({ behavior: 'smooth' });
140	}
141
142	getThreshold() {
143		let parentCount = this.getFieldValue('dd-wbs-calculator-parent-count');
144		let childrenCount = this.getFieldValue('dd-wbs-calculator-children-count', '0');
145		const personCount = parentCount + childrenCount;
146		let threshold = 12000;
147
148		threshold += personCount > 1 ? 6000 : 0;
149		threshold += personCount > 2 ? (personCount - 2) * 4100 : 0;
150		threshold += childrenCount * 500;
151
152		return threshold;
153	}
154
155	calculate() {
156		let parentCount = this.getFieldValue('dd-wbs-calculator-parent-count');
157		let childrenCount = this.getFieldValue('dd-wbs-calculator-children-count', '0');
158		let netIncome = this.getFieldValue('dd-wbs-calculator-net-income', '0');
159		let childrenExtraCosts = this.getFieldValue('dd-wbs-calculator-extra-costs', '0');
160		let childrenExtraCostsValue = this.getFieldValue('dd-wbs-calculator-children-extra-costs', '0');
161		let alimony = this.getFieldValue('dd-wbs-calculator-alimony', '0');
162		let partnerAlimonyValue = this.getFieldValue('dd-wbs-calculator-partner-alimony', '0');
163		let childrenAlimonyValue = this.getFieldValue('dd-wbs-calculator-children-alimony', '0');
164		let allowanceYoungCouples = this.getFieldValue('dd-wbs-calculator-allowance-young-couples');
165		let disability = this.getFieldValue('dd-wbs-calculator-disability');
166
167		let disabledPersonsStatus = (() => {
168			const fields = this.container.querySelectorAll('.js-dd-wbs-calculator-disabled-person-field');
169			return Array.from(fields).map((field) => parseInt(field.value));
170		})();
171
172		const deductibleChildrenExtraCosts = Math.min(childrenCount > 0 && childrenExtraCosts ? childrenCount * 4000 : 0, (childrenCount > 0 && childrenExtraCosts && childrenExtraCostsValue > 0) ? childrenExtraCostsValue * 12 * 0.667 : 0);
173		const deductibleAlimony = alimony ? (childrenAlimonyValue > 0 ? childrenAlimonyValue * 12 : 0) + (partnerAlimonyValue > 0 ? partnerAlimonyValue * 12 : 0) : 0;
174
175		let result = (netIncome * 12)
176			- (parentCount === 1 ? 1230 : 2460)
177			- deductibleChildrenExtraCosts
178			- (childrenCount > 0 ? childrenCount * 600 : 0)
179			- deductibleAlimony
180			- (allowanceYoungCouples === 1 ? 4000 : 0);
181
182		if (disability === 1) {
183			disabledPersonsStatus.forEach(status => {
184				result = result - ([1, 2].includes(status) ? 4500 : (status === 3 ? 2100 : 0));
185			});
186		}
187
188		return result;
189	}
190
191	addDynamicField() {
192		const container = this.container.querySelector('.js-dd-wbs-calculator-disabled-person-fields');
193		const field = this.container.querySelector('.js-dd-wbs-calculator-disabled-person-field-template').innerHTML;
194		const personField = document.createElement('div');
195		this.disabledPersonsCount++;
196
197		personField.classList.add('third-set');
198		personField.insertAdjacentHTML('beforeend', field);
199
200		const personLabel = personField.querySelector('.js-dd-wbs-calculator-disabled-person-field-label');
201		personLabel.textContent = `Person ${this.disabledPersonsCount}`;
202
203		container.insertAdjacentHTML('beforeend', personField.outerHTML);
204	}
205
206	initDynamicFields() {
207		const button = this.container.querySelector('.js-dd-wbs-calculator-disabled-person-add');
208		button.addEventListener('click', (e) => {
209			e.preventDefault();
210			this.addDynamicField();
211		});
212		this.addDynamicField();
213	}
214
215	initToggles() {
216		const toggles = this.container.querySelectorAll('.js-dd-wbs-calculator-toggle');
217
218		toggles.forEach(toggle => {
219			const sections = toggle.dataset.toggle.split(',').map(section => this.container.querySelector(`.${section}`));
220			const yesRadio = toggle.querySelector("[value='1']");
221			const noRadio = toggle.querySelector("[value='0']");
222
223			yesRadio.addEventListener("change", (e) => {
224				sections.forEach((section) => {
225					if (yesRadio.checked) {
226						section.classList.remove('d-none');
227					}
228				});
229			});
230
231			noRadio.addEventListener("change", (e) => {
232				sections.forEach((section) => {
233					if (noRadio.checked) {
234						section.classList.add('d-none');
235					}
236				});
237			});
238
239			sections.forEach((section) => {
240				section.classList.add('d-none');
241			});
242		});
243	}
244
245	initQuestionInfo() {
246		const infoButtons = this.container.querySelectorAll('.js-dd-question-info');
247		const closeAllButtons = () => infoButtons.forEach(infoButton => {
248			const overlay = infoButton.querySelector('.dd-question-info__overlay');
249			overlay.classList.add('d-none');
250			infoButton.classList.remove('dd-question-info--active');
251		});
252		infoButtons.forEach(infoButton => {
253			const overlay = infoButton.querySelector('.dd-question-info__overlay');
254			const openOverlay = () => {
255				closeAllButtons();
256				overlay.classList.remove('d-none');
257				infoButton.classList.add('dd-question-info--active');
258			};
259			const closeOverlay = () => {
260				overlay.classList.add('d-none');
261				infoButton.classList.remove('dd-question-info--active');
262			};
263			infoButton.addEventListener('click', () => infoButton.classList.contains('dd-question-info--active') ? closeOverlay() : openOverlay());
264			infoButton.addEventListener('keydown', (event) => {
265				if (event.key === 'Enter' || event.key === ' ') {
266					event.preventDefault();
267					if (infoButton.classList.contains('dd-question-info--active')) {
268						closeOverlay();
269					} else {
270						openOverlay();
271					}
272				}
273				if (event.key === 'Escape' || event.key === 'Tab') {
274					closeOverlay();
275				}
276			});
277			const closeButton = overlay.querySelector('.dd-question-info__overlay-close');
278			closeButton.addEventListener('click', (e) => {
279				e.stopPropagation();
280				closeOverlay();
281			});
282		});
283	}
284
285	resetForm() {
286		this.form.classList.remove('d-none');
287		this.resultContainer.classList.add('d-none');
288		this.topAnchor.scrollIntoView({ behavior: 'smooth' });
289	}
290}
291
292document.querySelectorAll('.js-dd-wbs-calculator').forEach(calculatorInstance => {
293	new WBSCalculator(calculatorInstance);
294});

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.