PageSourceSearch

https://www.hochkoenig.at/js/mw-core/mw-core-selectfield.js

js hochkoenig.at collected 2026-10-02 09:56:17 UTC 7,994 bytes, 375 lines download raw bytes

1import mwCore from "/js/mw-core/mw-core.js";
2import "/js/mw-core/mw-core-icon.js";
3
4class mwCoreSelectfield extends mwCore {
5	// livecycle methods
6
7	updated() {
8		// cache DOM
9
10		this.cacheDOM();
11
12		// register eventListener
13
14		this.registerEventListener();
15
16		// set value
17
18		if (this.value) {
19			this._dom.select.value = this.value;
20		} else if (this._dom.select.value) {
21			// set value from first option field if not empty
22
23			this.value = this._dom.select.value;
24		}
25	}
26
27	static get observedAttributes() {
28		return [
29			"name",
30			"label",
31			"messageerror",
32			"disabled",
33			"validate",
34			"readonly",
35			"labelinline",
36			"error",
37			"optionallabel",
38		];
39	}
40
41	// css
42
43	styles() {
44		return [
45			`<link href="/css/styleguide.css" rel="stylesheet">`,
46			`
47				* {
48					user-select: none;
49				}
50				*:focus-visible {
51					outline: 2px solid black !important;
52					outline-offset: -2px !important;
53					transition: none !important;
54				}
55				label {
56					display: inline-block;
57					margin: 0 0 4px;
58				}
59				:host([error]) label:after {
60					color: var(--mw-core-color-state-error);
61					content: "•";
62					margin: 0 0 0 4px;
63				}
64				.form-row.focus label {
65					color: var(--mw-core-color-brand1);
66				}
67				:host([disabled]) label {
68					color: var(--mw-core-color-action-disabled);
69				}
70				select {
71					-moz-appearance: none;
72					-webkit-appearance: none;
73					appearance: none;
74					background: none;
75					border: var(--mw-core-color-form-field-stroke);
76					display: block;
77					height: 48px;
78					margin: 0;
79					outline: none;
80					padding: 0 36px 0 16px;
81					position: relative;
82					width: 100%;
83					z-index: 2;
84				}
85				:host([error]) select,
86				.form-row.focus select {
87					border-color: transparent;
88				}
89				:host([disabled]) select {
90					background: var(--mw-core-color-action-disabled);
91					border-color: transparent;
92					opacity: 0.3;
93				}
94				:host([readonly]) select {
95					border: var(--mw-core-color-form-field-stroke);
96					border-style: dashed;
97				}
98				.form-value-container {
99					background: var(--mw-core-color-form-field-background);
100					overflow: hidden;
101					position: relative;
102				}
103				.form-value-container:after {
104					background: var(--mw-core-color-overlay-dark10);
105					content: "";
106					display: block;
107					height: 100%;
108					left: 0;
109					opacity: 0;
110					position: absolute;
111					top: 0;
112					transform: translate(-100%, 0px);
113					transition: transform 0.15s, opacity 0.2s;
114					width: 100%;
115				}
116				:host([error]) .form-value-container:after {
117					background: var(--mw-core-color-state-error);
118					opacity: 0.1 !important;
119					transform: translate(0px, 0px);
120				}
121				.form-row.focus .form-value-container:after {
122					opacity: 1;
123					transform: translate(0px, 0px);
124				}
125				:host([readonly]) .form-value-container:after {
126					transform: translate(0px, 0px);
127					z-index: 2;
128				}
129				.error-message {
130					display: none;
131				}
132				:host([error]) .error-message {
133					color: var(--mw-core-color-state-error);
134					display: block;
135					margin: 4px 0;
136				}
137				:host([error][labelinline]) .error-message {
138					font-size: 12px;
139					left: 20px;
140					line-height: 1;
141					margin: 0;
142					pointer-events: none;
143					position: absolute;
144					top: -6px;
145				}
146				:host([error][labelinline]) .error-message:before,
147				:host([error][labelinline]) .error-message:after {
148					background: var(--mw-core-color-state-error);
149					content: "";
150					display: block;
151					height: 1px;
152					left: -12px;
153					margin: -0.5px 0 0 0;
154					position: absolute;
155					top: 50%;
156					width: 10px;
157				}
158				:host([error][labelinline]) .error-message:after {
159					left: auto;
160					right: -12px;
161				}
162				mw-core-icon.trigger {
163					align-items: center;
164					bottom: 0;
165					display: flex;
166					position: absolute;
167					right: 10px;
168					top: 0;
169					z-index: 0;
170				}
171				
172				@media all and (min-width: 769px) {
173				
174					select {
175						padding: 0 40px 0 20px;
176					}
177					
178				}
179				
180			`,
181		];
182	}
183
184	// render template
185
186	render() {
187		let template = this.querySelector("template");
188		let options = ``;
189
190		if (template) {
191			let $options = template.content.querySelectorAll("option");
192
193			for (let $option of $options) {
194				let tmp = document.createElement("div");
195				tmp.appendChild($option.cloneNode(true));
196
197				options += tmp.innerHTML;
198			}
199		}
200
201		let name = this.name ? this.name : "";
202		let label = this.label ? this.label : "";
203		let id = Math.random().toString(16).slice(2);
204
205		if (this.optionallabel && !this.validate) {
206			label += " " + this.optionallabel;
207		}
208
209		// Für aria-describedby die ID der Fehlermeldung erstellen
210		let errorId = `error-${id}`;
211
212		return `
213			<div class="form-row">
214				${!this.labelinline ? `<label class="form-label" for="${id}">${label}</label>` : ``}
215				<div class="form-value-container effect-border-radius">
216					<select
217						id="${id}"
218						${name ? `name="${name}"` : ``}
219						class="form-value effect-border-radius"
220						${this.disabled ? `disabled aria-disabled="true"` : ``}
221						${this.readonly ? `disabled aria-readonly="true"` : ``} 
222						${this.labelinline ? `aria-label="${label}"` : ``} 
223						aria-invalid="${this.error ? "true" : "false"}"
224						aria-describedby="${this.error && this.messageerror ? errorId : ""}"
225					>${options}</select>
226					<mw-core-icon class="trigger" name="chevrondown" aria-hidden="true"></mw-core-icon>
227				</div>
228				${this.error && this.messageerror ? `<p id="${errorId}" class="error-message small-text" role="alert">${this.messageerror}</p>` : ``}
229			</div>
230		`;
231	}
232
233	// getter and setter
234
235	get name() {
236		return this._getAttribute("name");
237	}
238
239	set name(val) {
240		this._setAttribute("name", val);
241	}
242
243	get label() {
244		return this._getAttribute("label");
245	}
246
247	set label(val) {
248		this._setAttribute("label", val);
249	}
250
251	get messageerror() {
252		return this._getAttribute("messageerror");
253	}
254
255	set messageerror(val) {
256		this._setAttribute("messageerror", val);
257	}
258
259	get disabled() {
260		return this._getAttribute("disabled");
261	}
262
263	set disabled(val) {
264		this._setAttribute("disabled", val);
265	}
266
267	get validate() {
268		return this._getAttribute("validate");
269	}
270
271	set validate(val) {
272		this._setAttribute("validate", val);
273	}
274
275	get readonly() {
276		return this._getAttribute("readonly");
277	}
278
279	set readonly(val) {
280		this._setAttribute("readonly", val);
281	}
282
283	get labelinline() {
284		return this._getAttribute("labelinline");
285	}
286
287	set labelinline(val) {
288		this._setAttribute("labelinline", val);
289	}
290
291	get error() {
292		return this._getAttribute("error");
293	}
294
295	set error(val) {
296		this._setAttribute("error", val);
297	}
298
299	get value() {
300		return this._getAttribute("value");
301	}
302
303	set value(val) {
304		this._setAttribute("value", val);
305	}
306
307	get optionallabel() {
308		return this._getAttribute("optionallabel");
309	}
310
311	set optionallabel(val) {
312		this._setAttribute("optionallabel", val);
313	}
314
315	// custom methods
316
317	cacheDOM() {
318		// cache dom elements for faster access
319
320		this._dom = {
321			select: this.shadowRoot.querySelector("select"),
322			clearIcon: this.shadowRoot.querySelector("mw-core-icon.clear-value"),
323		};
324	}
325
326	checkValue() {
327		if (this.value) {
328			this.error = false;
329		} else {
330			this.error = true;
331		}
332	}
333
334	registerEventListener() {
335		if (this._dom.select) {
336			// focus
337
338			this._dom.select.addEventListener("focus", (event) => {
339				if (this.disabled || this.readonly) {
340					return;
341				}
342				this._dom.select.closest(".form-row").classList.add("focus");
343			});
344
345			// blur (leave)
346
347			this._dom.select.addEventListener("blur", (event) => {
348				this._dom.select.closest(".form-row").classList.remove("focus");
349
350				// field check
351
352				if (this.validate) {
353					setTimeout(() => {
354						this.checkValue();
355					}, 100);
356				}
357			});
358
359			// set value
360
361			this._dom.select.addEventListener("change", (event) => {
362				this.value = this._dom.select.value;
363				this.fireEvent();
364			});
365		}
366	}
367
368	fireEvent() {
369		// fires custom event (change)
370
371		this.dispatchEvent(new CustomEvent("change"));
372	}
373}
374
375customElements.define("mw-core-selectfield", mwCoreSelectfield);

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.