PageSourceSearch

https://offenerdialog-ev.de/wp-content/plugins/wp-accessibility/js/wp-accessibility.js?ver=71958

js offenerdialog-ev.de collected 2026-10-02 21:39:13 UTC 37,929 bytes, 1,012 lines download raw bytes

1(() => {
2	'use strict';
3	const html = document.querySelector( 'html' );
4	const body = document.querySelector( 'body' );
5	let errors = [];
6	if ( wpa.lang ) {
7		let lang   = html.getAttribute( 'lang' );
8		if ( ! lang ) {
9			html.setAttribute( 'lang', wpa.lang );
10			if ( wpa.errors || wpa.tracking ) {
11				errors.push( 'html-lang' );
12				console.log( 'HTML language set by WP Accessibility' );
13			}
14		}
15	}
16
17	if ( wpa.dir ) {
18		let dir  = html.getAttribute( 'dir' );
19		if ( ! dir && wpa.dir !== 'ltr' ) {
20			html.setAttributeattr( 'dir', wpa.dir );
21			if ( wpa.errors || wpa.tracking ) {
22				errors.push( 'html-lang-direction' );
23				console.log( 'HTML language direction set by WP Accessibility' );
24			}
25		}
26	}
27
28	if ( wpa.continue ) {
29		let readMore = document.querySelectorAll( '.wp-block-post-excerpt__more-link' );
30		if ( readMore.length !== 0 ) {
31			readMore.forEach( (el) => {
32				if ( ! el.hasAttribute( 'aria-describedby' ) ) {
33					let post = el.closest( '.wp-block-post' );
34					let readMoreId = post.getAttribute( 'class' );
35					readMoreId = readMoreId.replaceAll( ' ', '-' );
36					let heading = post.querySelector( '.wp-block-post-title' );
37					if ( heading ) {
38						if ( ! heading.hasAttribute( 'id' ) ) {
39							heading.setAttribute( 'id', readMoreId );
40						} else {
41							readMoreId = heading.getAttribute( 'id' );
42						}
43						el.setAttribute( 'aria-describedby', readMoreId );
44						if ( wpa.errors || wpa.tracking ) {
45							console.log( 'Continue Reading link description set by WP Accessibility' );
46						}
47					}
48				}
49			});
50		}
51	}
52
53	const viewport = document.querySelector( 'meta[name="viewport"]' );
54	if ( viewport && wpa.viewport ) {
55		let conditionsBefore = viewport.getAttribute( 'content' );
56		let conditionsAfter  = viewport.getAttribute( 'content' );
57		if ( conditionsBefore.search(/user-scalable=no/g) ) {
58			conditionsAfter = conditionsBefore.replace( 'user-scalable=no', 'user-scalable=yes' );
59			viewport.setAttribute( 'content', conditionsAfter );
60			if ( ( wpa.errors || wpa.tracking ) && conditionsAfter != conditionsBefore ) {
61				errors.push( 'viewport-scalable' );
62				console.log( 'Viewport made scalable by WP Accessibility' );
63			}
64		}
65		if ( conditionsBefore.search(/maximum-scale=1/g) ) {
66			conditionsAfter = conditionsBefore.replace( 'maximum-scale=1', 'maximum-scale=5' );
67			conditionsAfter = conditionsAfter.replace( 'maximum-scale=0', 'maximum-scale=5' );
68			viewport.setAttribute( 'content', conditionsAfter );
69			if ( ( wpa.errors || wpa.tracking ) && conditionsAfter != conditionsBefore  ) {
70				errors.push( 'viewport-maxscale' );
71				console.log( 'Viewport maximum scale set by WP Accessibility' );
72			}
73		}
74	}
75
76	if ( wpa.skiplinks.enabled ) {
77		body.insertAdjacentHTML( 'afterbegin', wpa.skiplinks.output );
78		if ( wpa.errors || wpa.tracking  ) {
79			errors.push( 'skiplinks' );
80			console.log( 'Skip links added by WP Accessibility' );
81		}
82	}
83
84	if ( wpa.current ) {
85		let current = document.querySelectorAll( '.current-menu-item a, .current_page_item a' );
86		if ( current.length !== 0 ) {
87			current.forEach((el) => {
88				el.setAttribute( 'aria-current', 'page' );
89			});
90			if ( wpa.errors || wpa.tracking  ) {
91				errors.push( 'aria-current' );
92				console.log( 'ARIA current added by WP Accessibility' );
93			}
94		}
95	}
96
97	if ( wpa.labels ) {
98		let wpa_names = [ 's', 'author', 'email', 'url', 'comment' ];
99		wpa_names.forEach((value) => {
100			let fields, field_id, implicit, aria, ariaId, ariaTarget, hasAria, hasAriaId, label, labelText;
101			if ( value == 'comment' ) {
102				fields = document.querySelectorAll( 'textarea[name=' + value + ']' );
103			} else {
104				fields = document.querySelectorAll( 'input[name=' + value + ']:not(#adminbar-search)' );
105			}
106			if ( fields.length !== 0 ) {
107				fields.forEach( (field) => {
108					if ( 0 !== field.length ) {
109						field_id = field.getAttribute( 'id' );
110						implicit = field.closest( 'label' );
111						aria = field.getAttribute( 'aria-label' );
112						ariaId = field.getAttribute( 'aria-labelledby' );
113						ariaTarget = {};
114						if ( ariaId ) {
115							ariaTarget = document.getElementById( ariaId );
116						}
117						hasAria   = ( null == aria || '' == aria || 'undefined' == typeof( aria ) ) ? false : true;
118						hasAriaId = ( null == ariaId || '' == ariaId || 'undefined' == typeof( ariaId ) ) ? false : true;
119						// Add label if aria label empty, aria labelledby empty, or aria reference ID does not exist.
120						if ( ( ! hasAria && ! hasAriaId ) || ( ! hasAria && ( hasAriaId && ! ariaTarget ) ) ) {
121							if ( field_id ) {
122								label = document.querySelector( 'label[for=' + field_id + ']' );
123								if ( label ) {
124									labelText = label.innerText;
125									if ( label && ! labelText ) {
126										label.innerText = wpa.wpalabels[value];
127										if ( wpa.errors || wpa.tracking ) {
128											errors.push( ['empty-label', wpa.wpalabels[value]] );
129											console.log( 'Empty label on ' + wpa.wpalabels[value] + ' added by WP Accessibility' );
130										}
131									}
132								}
133								if ( !label && !implicit ) {
134									field.insertAdjacentHTML( 'beforebegin', "<label for='" + field_id + "' class='wpa-screen-reader-text'>" + wpa.wpalabels[value] + "</label>" );
135									if ( wpa.errors || wpa.tracking ) {
136										errors.push( ['explicit-label', wpa.wpalabels[value]] );
137										console.log( 'Explicit label on ' + wpa.wpalabels[value] + ' added by WP Accessibility' );
138									}
139								}
140							} else {
141								if ( !implicit ) {
142									field.setAttribute( 'id', 'wpa_label_' + value );
143									field.insertAdjacentHTML( 'beforebegin', "<label for='wpa_label_" + value + "' class='wpa-screen-reader-text'>" + wpa.wpalabels[value] + "</label>" );
144									if ( wpa.errors || wpa.tracking ) {
145										errors.push( ['implicit-label', wpa.wpalabels[value]] );
146										console.log( 'Implicit label on ' + wpa.wpalabels[value] + ' added by WP Accessibility' );
147									}
148								}
149							}
150						}
151					}
152				});
153			}
154		});
155	}
156
157	if ( wpa.titles ) {
158		let images   = 0,
159			controls = 0,
160			fields   = 0,
161			noremove = false;
162		const els    = document.querySelectorAll( 'img, a, input, textarea, select, button' );
163		if ( els.length !== 0 ) {
164			els.forEach((el) => {
165				let title = el.getAttribute( 'title' );
166				if ( el.classList.contains( 'nturl' ) ) {
167					// Exempt title attributes from Translate WordPress - Google Language Translator, which uses them as a CSS hook.
168					noremove = true;
169				}
170				if ( title && '' !== title ) {
171					switch ( el.tagName ) {
172						case 'IMG':
173							// If image has alt, remove title. If not, set title as alt.
174							let alt = el.getAttribute( 'alt' );
175							title = el.getAttribute( 'title' );
176							if ( ! alt || '' === alt ) {
177								el.setAttribute( 'alt', title );
178								el.removeAttribute( 'title' );
179							} else {
180								if ( title === alt ) {
181									el.removeAttribute( 'title' );
182								}
183							}
184							images++;
185							break;
186						case 'A':
187						case 'BUTTON':
188							// If link or button has contained text or an img with alt, remove title. Otherwise, set title as aria-label unless element already has aria-label.
189							let linkText = wpaElementText(el);
190							if ( ! linkText || '' === linkText ) {
191								let ariaLabel = el.getAttribute( 'aria-label' );
192								if ( ! ariaLabel || '' === ariaLabel ) {
193									el.setAttribute( 'aria-label', title );
194									if ( ! noremove ) {
195										el.removeAttribute( 'title' );
196									}
197								}
198							} else {
199								el.removeAttribute( 'title' );
200							}
201							controls++;
202							break;
203						case 'INPUT':
204						case 'SELECT':
205						case 'TEXTAREA':
206							// If input field has an aria-label, aria-labelledby, associated label, or wrapping label, remove title. Else, add title as aria-label.
207							let ariaLabel        = el.getAttribute( 'aria-label' );
208							let ariaLabelled     = el.getAttribute( 'aria-labelledby' );
209							let ariaLabeller     = ( ariaLabelled ) ? document.getElementById( ariaLabelled ) : false;
210							let labelId          = el.getAttribute( 'id' );
211							let label            = ( labelId ) ? document.querySelector( 'label[for="' + labelId + '"]' ) : false;
212							let parentLabel      = el.closest( 'label' );
213							let hasAriaLabel     = ( ariaLabel && '' !== ariaLabel ) ? true : false;
214							let hasRealLabel     = ( label && '' !== wpaElementText( label ) ) ? true : false;
215							let hasImplicitLabel = ( parentLabel && '' !== wpaElementText( parentLabel ) ) ? true : false;
216							let hasAriaLabelled  = ( ariaLabeller && '' !== wpaElementText( ariaLabeller ) ) ? true : false;
217							if ( hasAriaLabel || hasRealLabel || hasImplicitLabel || hasAriaLabelled ) {
218								// This has a label.
219								el.removeAttribute( 'title' );
220							} else {
221								el.setAttribute( 'aria-label', title );
222								el.removeAttribute( 'title' );
223							}
224							fields++;
225							break;
226					}
227				}
228			});
229			if ( wpa.errors || wpa.tracking ) {
230				if ( images > 0 ) {
231					errors.push( ['images-titles', images] );
232					console.log( images + ' title attributes removed from images by WP Accessibility' );
233				}
234				if ( controls > 0 ) {
235					errors.push( ['control-titles', controls] );
236					console.log( controls + ' title attributes removed from links and buttons by WP Accessibility' );
237				}
238				if ( fields > 0 ) {
239					errors.push( ['input-titles', fields] );
240					console.log( fields + ' title attributes removed from input fields by WP Accessibility' );
241				}
242			}
243		}
244	}
245
246	if ( wpa.target ) {
247		let targeted      = document.querySelectorAll('a:not(.wpa-allow-target)');
248		let targetRemoved = 0;
249		if ( targeted.length !== 0 ) {
250			targeted.forEach( (el) => {
251				let target   = el.getAttribute( 'target' );
252				let href     = el.getAttribute( 'href' );
253
254				if ( target ) {
255					// For on-page fragments.
256					if ( href.startsWith( '#') ) {
257						el.removeAttribute( 'target' );
258					} else {
259						try {
260							let url      = new URL( href );
261							let hostname = url.hostname;
262							if ( ! hostname.includes( 'facebook' ) ) {
263								el.removeAttribute( 'target' );
264								targetRemoved++;
265							}
266						} catch (exception) {
267							console.log( "href value is not a URL or a fragment:", href );
268							// No action; the `href` attribute didn't resolve as a URL.
269						}
270					}
271				}
272			});
273			if ( targetRemoved > 0 && ( wpa.errors || wpa.tracking ) ) {
274				errors.push( ['link-targets', targetRemoved] );
275				console.log( targetRemoved + ' target attributes removed from links by WP Accessibility' );
276			}
277		}
278	}
279
280	if ( wpa.tabindex ) {
281		// Remove tabindex from elements that should be natively focusable.
282		let focusable  = document.querySelectorAll('input:not(.wpa-ignore-tabindex),a[href]:not(.wpa-ignore-tabindex),select:not(.wpa-ignore-tabindex),textarea:not(.wpa-ignore-tabindex),button:not(.wpa-ignore-tabindex)');
283		let tabRemoved = 0;
284		if ( focusable.length !== 0 ) {
285			focusable.forEach( (el) => {
286				let tabindex = el.getAttribute('tabindex');
287				let skip = false;
288				// Check for intentionally hidden elements with tabindex of -1.
289				if ( el.hasAttribute('tabindex') && tabindex === '-1' ) {
290					let hasAriaHidden = el.getAttribute('aria-hidden');
291					let hasHidden = el.hasAttribute('hidden');
292					if ( hasAriaHidden === 'true' || hasHidden ) {
293						skip = true;
294					}
295				}
296				if ( tabindex && !skip ) {
297					el.removeAttribute('tabindex');
298					tabRemoved++;
299				}
300			});
301
302			if ( tabRemoved > 0 && ( wpa.errors || wpa.tracking ) ) {
303				errors.push( ['control-tabindex', tabRemoved] );
304				console.log( tabRemoved + ' tabindex attributes removed from links, buttons and inputs by WP Accessibility' );
305			}
306		}
307
308		// Add tabindex to elements that appear active but are not natively focusable.
309		let fakeButtons = document.querySelectorAll( '[role="button"]:not([tabindex]):not(a):not(button)' );
310		let buttonLinks = document.querySelectorAll( 'a[role="button"]:not([tabindex]):not([href])');
311		let fakeLinks = document.querySelectorAll( '[role="link"]:not([tabindex]):not(a)');
312		let linkLinks = document.querySelectorAll( 'a:not([href]):not([tabindex])' );
313		if ( fakeButtons.length !== 0 ) {
314			fakeButtons.forEach( (el) => {
315				el.setAttribute( 'tabindex', '0' );
316				el.classList.add('wpa-focusable');
317			});
318			if ( fakeButtons.length > 0 && ( wpa.errors || wpa.tracking ) ) {
319				errors.push( ['button-add-tabindex', fakeButtons.length] );
320				console.log( fakeButtons.length + ' tabindex attributes added to divs with the button role by WP Accessibility' );
321			}
322		}
323		if ( buttonLinks.length !== 0 ) {
324			buttonLinks.forEach( (el) => {
325				el.setAttribute( 'tabindex', '0' );
326				el.classList.add('wpa-focusable');
327			});
328			if ( buttonLinks.length > 0 && ( wpa.errors || wpa.tracking ) ) {
329				errors.push( ['link-add-tabindex', buttonLinks.length] );
330				console.log( buttonLinks.length + ' tabindex attributes added to anchor elements with the button role and no href value by WP Accessibility' );
331			}
332		}
333		if ( fakeLinks.length !== 0 ) {
334			fakeLinks.forEach( (el) => {
335				el.setAttribute( 'tabindex', '0' );
336				el.classList.add('wpa-focusable');
337			});
338			if ( fakeLinks.length > 0 && ( wpa.errors || wpa.tracking ) ) {
339				errors.push( ['fakelink-add-tabindex', fakeLinks.length] );
340				console.log( fakeLinks.length + ' tabindex attributes added to elements with the link role not using the a element by WP Accessibility' );
341			}
342		}
343		if ( linkLinks.length !== 0 ) {
344			linkLinks.forEach( (el) => {
345				el.setAttribute( 'tabindex', '0' );
346				el.classList.add('wpa-focusable');
347			});
348			if ( linkLinks.length > 0 && ( wpa.errors || wpa.tracking ) ) {
349				errors.push( ['links-add-tabindex', linkLinks.length] );
350				console.log( linkLinks.length + ' tabindex attributes added to a with no href attribute by WP Accessibility' );
351			}
352		}
353	}
354
355	// If stats are disabled, skip this.
356	if ( 'disabled' !== wpa.url ) {
357		/*
358		* fingerprintJS 0.1 - Fast browser fingerprint library
359		* https://github.com/Valve/fingerprintJS
360		* Copyright (c) 2013 Valentin Vasilyev ([email protected])
361		* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
362		* Modified by Joe Dolson 2023.
363		*/
364		class Fingerprint {
365			constructor(hasher) {
366				var nativeForEach = Array.prototype.forEach;
367				var nativeMap = Array.prototype.map;
368				this.each = function (obj, iterator, context) {
369					if (obj == null) return;
370					if (nativeForEach && obj.forEach === nativeForEach) {
371						obj.forEach(iterator, context);
372					} else if (obj.length === +obj.length) {
373						for (var i = 0, l = obj.length; i < l; i++) {
374							if (JSON.stringify(iterator.call(context, obj[i], i, obj)) === '{}') return;
375						}
376					} else {
377						for (var key in obj) {
378							if (obj.hasOwnProperty(key)) {
379								if (JSON.stringify(iterator.call(context, obj[key], key, obj)) === '{}') return;
380							}
381						}
382					}
383				};
384				this.map = function (obj, iterator, context) {
385					var results = [];
386					if (obj == null) return results;
387					if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
388					this.each(obj, function (value, index, list) {
389						results[results.length] = iterator.call(context, value, index, list);
390					});
391					return results;
392				};
393
394				if (hasher) {
395					this.hasher = hasher;
396				}
397			}
398			get() {
399				let keys = [];
400				keys.push(navigator.userAgent);
401				keys.push([screen.height, screen.width, screen.colorDepth].join('x'));
402				keys.push(new Date().getTimezoneOffset());
403				keys.push(!!window.sessionStorage);
404				keys.push(!!window.localStorage);
405				var pluginsString = this.map(navigator.plugins, function (p) {
406					var mimeTypes = this.map(p, function (mt) {
407						return [mt.type, mt.suffixes].join('~');
408					}).join(',');
409					return [p.name, p.description, mimeTypes].join('::');
410				}, this).join(';');
411				keys.push(pluginsString);
412				if (this.hasher) {
413					return this.hasher(keys.join('###'), 31);
414				} else {
415					return this.murmurhash3_32_gc(keys.join('###'), 31);
416				}
417			}
418			/**
419			 * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
420			 *
421			 * @author <a href="mailto:[email protected]">Gary Court</a>
422			 * @see http://github.com/garycourt/murmurhash-js
423			 * @author <a href="mailto:[email protected]">Austin Appleby</a>
424			 * @see http://sites.google.com/site/murmurhash/
425			 *
426			 * @param {string} key ASCII only
427			 * @param {number} seed Positive integer only
428			 * @return {number} 32-bit positive integer hash
429			 */
430			murmurhash3_32_gc(key, seed) {
431				let remainder, bytes, h1, h1b, c1, c2, k1, i;
432
433				remainder = key.length & 3; // key.length % 4
434				bytes = key.length - remainder;
435				h1 = seed;
436				c1 = 0xcc9e2d51;
437				c2 = 0x1b873593;
438				i = 0;
439
440				while (i < bytes) {
441					k1 =
442						((key.charCodeAt(i) & 0xff)) |
443						((key.charCodeAt(++i) & 0xff) << 8) |
444						((key.charCodeAt(++i) & 0xff) << 16) |
445						((key.charCodeAt(++i) & 0xff) << 24);
446					++i;
447
448					k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
449					k1 = (k1 << 15) | (k1 >>> 17);
450					k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
451
452					h1 ^= k1;
453					h1 = (h1 << 13) | (h1 >>> 19);
454					h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
455					h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
456				}
457
458				k1 = 0;
459
460				switch (remainder) {
461					case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
462					case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
463					case 1: k1 ^= (key.charCodeAt(i) & 0xff);
464
465						k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
466						k1 = (k1 << 15) | (k1 >>> 17);
467						k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
468						h1 ^= k1;
469				}
470
471				h1 ^= key.length;
472
473				h1 ^= h1 >>> 16;
474				h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
475				h1 ^= h1 >>> 13;
476				h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
477				h1 ^= h1 >>> 16;
478
479				return h1 >>> 0;
480			}
481		}
482
483		let fingerprint = new Fingerprint().get();
484
485		function logStats(event,fingerprint,type='event') {
486			event = JSON.stringify( event );
487			const data = new FormData();
488			data.append( 'action', wpa.action );
489			data.append( 'security', wpa.security );
490			data.append( 'stats', event );
491			data.append( 'post_id', wpa.post_id );
492			data.append( 'title', fingerprint );
493			data.append( 'type', type );
494			fetch( wpa.ajaxurl, {
495				method: 'POST',
496				body: data
497			});
498		}
499		let contrastButton = document.querySelector( '.toggle-contrast' );
500		if ( contrastButton ) {
501			contrastButton.addEventListener('click', function () {
502				let event;
503				// This fires after the contrast change happens, and the ID is already changed.
504				if ( this.getAttribute( 'data-id' ) == "is_normal_contrast") {
505					// high contrast turned on.
506					event = {'contrast' : 'disabled'};
507				} else {
508					// high contrast turned off.
509					event = {'contrast' : 'enabled'};
510				}
511				logStats(event,fingerprint);
512			});
513		}
514
515		let fontsizeButton = document.querySelector( '.toggle-fontsize' );
516		if ( fontsizeButton ) {
517			fontsizeButton.addEventListener('click', function () {
518				let event;
519				// This fires after the fontsize change happens, and the ID is already changed.
520				if ( this.getAttribute( 'data-id' ) == "is_normal_fontsize") {
521					// fontsizes turned on.
522					event = {'fontsize' : 'disabled'};
523				} else {
524					// fontsizes turned off.
525					event = {'fontsize' : 'enabled'};
526				}
527				logStats(event,fingerprint);
528			});
529		}
530
531		wpaWaitForElement('.wpa-ld button').then((el) => {
532			el.addEventListener( 'click', function(e) {
533				// For descriptions, we aren't concerned about state changes; just usage.
534				let visible = ( 'true' === el.getAttribute( 'aria-expanded' ) ) ? true : false;
535				if ( visible ) {
536					let img      = el.closest( 'div' );
537					let image_id = img.getAttribute( 'class' ).replace( 'wpa-ld wp-image-', '' );
538					let event    = { 'longdesc' : image_id };
539					logStats(event,fingerprint);
540				}
541			});
542		});
543
544		let altButtons = document.querySelectorAll( '.wpa-alt button' );
545		if ( altButtons.length > 0 ) {
546			altButtons.forEach( (el) => {
547				el.addEventListener( 'click', function(e) {
548					// For alt text, we aren't concerned about state changes; just usage.
549					let visible = ( 'true' === el.getAttribute( 'aria-expanded' ) ) ? true : false;
550					if ( visible ) {
551						let img      = el.closest( 'div' );
552						let image_id = img.getAttribute( 'class' ).replace( 'wpa-alt wp-image-', '' );
553						let event    = { 'alttext' : image_id };
554						logStats(event,fingerprint);
555					}
556				});
557			});
558		}
559		if ( wpa.tracking && errors.length >= 1 ) {
560			logStats(errors,wpa.url,'view');
561		}
562
563	}
564	if ( wpa.underline.enabled ) {
565		// Underline any link not inside a `nav` region. Using JS for this avoids problems with cascade precedence.
566		let targetEls = document.querySelectorAll( wpa.underline.target + ':not(nav ' + wpa.underline.target + '):not(#wpadminbar a), .wpa-focusable[role=link]' );
567		if ( targetEls.length > 0 ) {
568			targetEls.forEach( (el) => {
569				let originalOutline = el.style.outlineWidth;
570				let originalOffset  = el.style.outlineOffset;
571				let textColor       = el.style.color;
572				let originalColor   = el.style.outlineColor;
573				el.style.textDecoration = 'underline';
574				el.addEventListener( 'mouseenter', function() {
575					this.style.textDecoration = 'none';
576				});
577				el.addEventListener( 'mouseleave', function() {
578					this.style.textDecoration = 'underline';
579				});
580				el.addEventListener( 'focusin', function() {
581					let newOutline = '2px';
582					if ( originalOutline == '2px' ) {
583						newOutline = '4px';
584					}
585					// Ensure there's a visible change of appearance on hover or focus.
586					this.style.outlineWidth = newOutline;
587					this.style.outlineColor = textColor;
588					this.style.outlineOffset = '2px';
589				});
590				el.addEventListener( 'focusout', function() {
591					// Reset visible appearance on exit.
592					this.style.outlineWidth = originalOutline;
593					this.style.outlineColor = originalColor;
594					this.style.outlineOffset = originalOffset;
595				});
596			});
597		}
598	}
599
600	if ( wpa.videos ) {
601		// Add a pause/play button to autoplaying videos without controls.
602		let motionQuery = matchMedia( '(prefers-reduced-motion)' );
603		let initialState = 'false';
604		let autoplayVideos = document.querySelectorAll( 'video[autoplay]:not([controls])' );
605		if ( autoplayVideos.length > 0 ) {
606			autoplayVideos.forEach( (el) => {
607				if ( motionQuery.matches ) {
608					el.pause();
609					initialState = 'true';
610				}
611				let parentEl    = el.parentElement;
612				let pauseButton = document.createElement( 'button' );
613				let buttonIcon  = document.createElement( 'span' );
614				let buttonText  = document.createElement( 'span' );
615				pauseButton.setAttribute( 'type', 'button' );
616				pauseButton.classList.add( 'wpa-video' );
617				pauseButton.setAttribute( 'aria-pressed', initialState );
618				buttonIcon.classList.add( 'dashicons-controls-pause', 'dashicons' );
619				buttonIcon.setAttribute( 'aria-hidden', 'true' );
620				buttonText.classList.add( 'screen-reader-text' );
621				buttonText.innerText = wpa.pause;
622				pauseButton.append( buttonIcon, buttonText );
623				parentEl.append( pauseButton );
624				pauseButton.addEventListener( 'click', function() {
625					let pressed = this.getAttribute( 'aria-pressed' );
626					console.log( pressed );
627					if ( 'true' === pressed ) {
628						el.play();
629						this.setAttribute( 'aria-pressed', 'false' );
630					} else {
631						el.pause();
632						this.setAttribute( 'aria-pressed', 'true' );
633					}
634				});
635			});
636		}
637	}
638
639	if ( wpa.alt ) {
640		let selector = ( wpa.altSelector ) ? wpa.altSelector : '.hentry img[alt]:not([alt=""]), .comment-content img[alt]:not([alt=""]), #content img[alt]:not([alt=""]),.entry-content img[alt]:not([alt=""])';
641		let collection = document.querySelectorAll(  selector );
642		let wrap = (elem, wrapper) => {
643			elem.parentElement.insertBefore(wrapper, elem);
644			wrapper.appendChild(elem);
645		};
646		collection.forEach((el) => {
647			let img       = el;
648			let closestLink   = img.closest( 'a' );
649			let closestButton = img.closest( 'button' );
650			let inLink    = ( closestLink ) ? true : false;
651			let inButton  = ( closestButton ) ? true : false;
652			let width     = img.width;
653			let height    = img.height;
654			if ( width || height ) {
655				width    = ( ! width ) ? 56 : width; // Enough width for button to be visible.
656				height   = ( ! height ) ? 56 : height; // Enough height for button & first line to be visible.
657				let area = height * width;
658				if ( area < ( 150 * 300 ) ) {
659					// Small images won't get displayed alt text containers.
660					return;
661				}
662				if ( el.classList.contains( 'wpa-skip' ) || el.closest( '.wpa-skip' ) ) {
663					// Skip images that have been marked to skip.
664					return;
665				}
666			}
667			let alt = img.getAttribute('alt');
668
669			let classes = [...img.classList];
670			img.setAttribute('class', '');
671			let elContainer = document.createElement( 'div' );
672			elContainer.classList.add( 'wpa-alt' );
673			if ( inLink || inButton ) {
674				let wrapper = ( inLink ) ? closestLink : closestButton;
675				wrap( wrapper, elContainer );
676			} else {
677				wrap( img, elContainer );
678			}
679			classes.forEach(className => {
680				elContainer.classList.add(className);
681			});
682
683			elContainer.insertAdjacentHTML('afterbegin', '<button aria-expanded="false" type="button" class="wpa-toggle">alt</button>');
684			elContainer.insertAdjacentHTML('beforeend', '<div class="wpa-alt-text"></div>');
685			let container = elContainer.querySelector('.wpa-alt-text');
686			container.style.display = 'none';
687			container.innerText = alt;
688			let button = elContainer.querySelector('button');
689			button.addEventListener( 'click', function(e) {
690				let visible = container.checkVisibility();
691				if ( visible ) {
692					this.setAttribute( 'aria-expanded', 'false' );
693					container.style.display = 'none';
694				} else {
695					this.setAttribute( 'aria-expanded', 'true' );
696					container.style.display = 'block';
697				}
698			});
699		});
700	}
701
702	if ( wpa.ldType ) {
703		let wrap = (elem, wrapper) => {
704			elem.parentElement.insertBefore(wrapper, elem);
705			wrapper.appendChild(elem);
706		};
707
708		let longDescImgs = document.querySelectorAll( 'img[longdesc]' );
709		if ( 'link' === wpa.ldType ) {
710			// Links with an actual longdesc attribute.
711			if ( longDescImgs.length > 0 ) {
712				longDescImgs.forEach( (el) => {
713					let wrapper = document.createElement( 'div' );
714					wrapper.classList.add( 'wpa-ld' );
715					let longdesc = el.getAttribute('longdesc');
716					let alt = el.getAttribute('alt');
717					let classes = [...el.classList];
718					wrap(el,wrapper);
719					classes.forEach(className => {
720						wrapper.classList.add(className);
721					});
722					el.setAttribute('class', '');
723					let newLink = document.createElement( 'a' );
724					newLink.setAttribute( 'href', longdesc );
725					newLink.classList.add( 'longdesc-link' );
726					let span = document.createElement( 'span' );
727					span.classList.add( 'screen-reader-text' );
728					span.textContent = ' of ' + alt;
729					newLink.textContent = 'Description';
730					newLink.appendChild( span );
731					el.insertAdjacentElement( 'afterend', newLink );
732				});
733			}
734			// Links with the block style.
735			let hasStyleLongdesc = document.querySelectorAll( 'figure.is-style-longdesc' );
736			if ( hasStyleLongdesc.length > 0 ) {
737				hasStyleLongdesc.forEach( (el) => {
738					let img = el.querySelector( 'img' );
739					wpa_load_image_control( img );
740				});
741			}
742
743		} else {
744			// Handle longdescriptions with buttons.
745			if ( longDescImgs.length > 0 ) {
746				longDescImgs.forEach( (img) => {
747					wpa_load_image_control( img );
748				});
749			}
750
751			// Links with the block style.
752			let hasStyleLongdesc = document.querySelectorAll( 'figure.is-style-longdesc' );
753			if ( hasStyleLongdesc.length > 0 ) {
754				hasStyleLongdesc.forEach( (el) => {
755					let img = el.querySelector( 'img' );
756					wpa_load_image_control( img );
757				});
758			}
759		}
760
761		function wpa_load_image_control( img ) {
762			let classes = img.getAttribute( 'class' );
763			let idAtt   = img.getAttribute( 'id' );
764			let id;
765			if ( idAtt && idAtt.includes( 'longdesc' ) ) {
766				id = idAtt.replace( 'longdesc-return-', '' );
767			} else {
768				if ( null === classes || '' === classes ) {
769					parent  = img.closest( '.wpa-alt' );
770					classes = parent.getAttribute( 'class' ).replace( 'wpa-alt ', '' );
771				}
772
773				id = classes.replace( 'wp-image-', '' );
774			}
775			let api = wpa.restUrl + '/' + id;
776			fetch( api )
777				.then( response => response.json())
778				.then(data => {
779					let rawdesc = data.description.rendered;
780					rawdesc = rawdesc.replace(/(<([^>]+)>)/gi, '').trim();
781					if ( '' !== rawdesc ) {
782						let url = new URL( wpa.ldHome );
783						url.searchParams.set( 'longdesc', id );
784						url.searchParams.set( 'p', id );
785						url.toString();
786						wpa_draw_longdesc( img, id, url, rawdesc );
787					}
788				})
789				.catch( error => {
790					console.log( error );
791				});
792		}
793
794		function wpa_draw_longdesc( img, image_id, longdesc, rawdesc ) {
795			let wrapper = document.createElement( 'div' );
796			wrapper.classList.add( 'wpa-ld' );
797			let alt = img.getAttribute('alt');
798			if ( '' === alt ) {
799				alt = '<code>' + img.getAttribute('src').replace( wpa.ldHome, '' ) + '</code>';
800			}
801			let post_classes = document.body.className.split(/\s+/);
802			let post_id = '';
803
804			post_classes.forEach( (value) => {
805				if ( value.match( /postid-/gi ) ) {
806					post_id = value.replace( 'postid-', '', value );
807				}
808				if ( value.match( /page-id-/gi ) ) {
809					post_id = value.replace( 'page-id-', '', value );
810				}
811			});
812			let url = new URL(longdesc);
813			url.searchParams.set( 'referrer', post_id );
814			url.toString();
815			let classes = [...img.classList];
816			classes.forEach( (c) => {
817				wrapper.classList.add(c);
818			});
819			wrap( img, wrapper );
820
821			img.setAttribute('alt', '');
822			img.setAttribute('class', '');
823			let newLink = document.createElement( 'a' );
824			newLink.setAttribute( 'href', url );
825			newLink.classList.add( 'longdesc-link' );
826			let span = document.createElement( 'span' );
827			span.classList.add( 'screen-reader-text' );
828			span.textContent = ' of ' + alt;
829			newLink.textContent = 'Description';
830			newLink.appendChild( span );
831			if ( 'link' === wpa.ldType ) {
832				wrapper.insertAdjacentElement( 'beforeend', newLink );
833			} else {
834				wrapper.insertAdjacentHTML( 'beforeend', '<button aria-expanded="false" class="wpa-toggle">' + wpa.ldText + '</button>');
835				wrapper.insertAdjacentHTML( 'beforeend', '<div class="longdesc"></div>');
836				let container = wrapper.querySelector('.longdesc');
837				container.style.display = 'none';
838
839				fetch( longdesc )
840					.then( response => {
841						if ( response.ok ) {
842							return response.text();
843						} else {
844							container.insertAdjacentHTML( 'beforeend', rawdesc );
845						}
846					}).then (html => {
847						const parser = new DOMParser();
848						const doc = parser.parseFromString( html, "text/html" );
849						container.insertAdjacentElement( 'beforeend', doc.querySelector( '#desc_' + image_id ) );
850					});
851
852				wrapper.querySelector('button').addEventListener( 'click', function(e) {
853					let visible = container.checkVisibility();
854					if ( visible ) {
855						this.setAttribute( 'aria-expanded', 'false' );
856						container.style.display = 'none';
857					} else {
858						this.setAttribute( 'aria-expanded', 'true' );
859						container.style.display = 'block';
860					}
861				});
862			}
863		}
864	}
865
866	// Listen for the font size change event.
867	document.addEventListener( 'wpa_fontsize_changed', function(e) {
868		fontSizeModify( e.detail.change, e.detail.factor );
869	} );
870	/**
871	 * Modifies the font size of text nodes within the document body.
872	 *
873	 * @param {string} change increase or reset.
874	 * @param {float} factor The factor by which to increase the font size.
875	 */
876	function fontSizeModify( change = 'increase', factor = 1.6 ) {
877		const adminBar = document.getElementById( 'wpadminbar' );
878		const toolBar = document.querySelector( '.a11y-toolbar' );
879
880		const ancestorResized = (el) => {
881			while (el) {
882				// Don't resize text inside other already resized elements or in the adminbar.
883				if ( el.hasAttribute( 'data-wpa-resized' ) ) {
884					return true;
885				}
886				el = el.parentElement; // Moves up to the next parent
887			}
888			return false;
889		};
890
891		const resizeElement = (el) => {
892			// Extract the computed, rendered font-size.
893			const computedStyle = window.getComputedStyle( el );
894			const fontSize = computedStyle.getPropertyValue( 'font-size' ).replace( 'px', '' );
895			const cssString = 'font-size: ' + ( parseFloat(fontSize) * factor ) + 'px !important';
896			if ( ! ancestorResized( el ) && 'increase' === change ) {
897				let inlineFontSize = el.style.fontSize;
898				// if element has a font-size set inline, store it in the data-wpa-resized attribute.
899				if ( inlineFontSize ) {
900					el.setAttribute( 'data-wpa-resized', inlineFontSize );
901				} else {
902					el.setAttribute( 'data-wpa-resized', 'true' );
903				}
904				el.style.cssText += cssString;
905			}
906			if ( change === 'reset' ) {
907				el.style.removeProperty( 'font-size' );
908				// Restore the inline font-size if it was stored by the script.
909				if ( el.hasAttribute( 'data-wpa-resized' ) && el.getAttribute( 'data-wpa-resized' ) !== 'true' ) {
910					el.style.fontSize = el.getAttribute( 'data-wpa-resized' );
911				}
912				el.removeAttribute( 'data-wpa-resized' );
913			}
914		};
915
916		const walker = document.createTreeWalker(
917			document.body,
918			NodeFilter.SHOW_TEXT,
919			{
920				acceptNode: function(node) {
921					// Ignore scripts, styles, nodes with only whitespace, and the adminbar.
922					const parentTag = node.parentElement ? node.parentElement.tagName : '';
923					if (['SCRIPT', 'STYLE', 'NOSCRIPT', 'SVG'].includes( parentTag ) || ( adminBar && adminBar.contains(node) ) || ( toolBar && toolBar.contains(node) ) ) {
924						return NodeFilter.FILTER_REJECT;
925					}
926					return node.textContent.trim().length > 0 || node.nodeType === Node.ELEMENT_NODE ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
927				}
928			}
929		);
930
931		const seenElements = new Set();
932		// 2. Iterate through the text nodes
933		while ( walker.nextNode() ) {
934			const textNode = walker.currentNode;
935			const parentElement = textNode.parentElement;
936
937			// Prevent checking the same element multiple times
938			if ( parentElement && ! seenElements.has( parentElement ) ) {
939				seenElements.add( parentElement );
940				resizeElement( parentElement );
941			}
942		}
943
944		// Form controls (e.g. input) may have no text node children, so they need to be handled separately.
945		const formElements = document.body.querySelectorAll( 'input, select, textarea' );
946		formElements.forEach( (el) => {
947			if ( ( adminBar && adminBar.contains( el ) ) || ( toolBar && toolBar.contains( el ) ) || seenElements.has( el ) ) {
948				return;
949			}
950			seenElements.add( el );
951			resizeElement( el );
952		});
953	}
954})();
955
956/**
957 * Check whether an element contains text, including inspecting contained content for image alt attributes or aria-label attributes.
958 *
959 * @arg el DOM element to check.
960 *
961 * Based on work by Roger Johansson https://www.456bereastreet.com/archive/201105/get_element_text_including_alt_text_for_images_with_javascript/
962 */
963function wpaElementText(el) {
964	let text = '';
965	// Text node (3) or CDATA node (4) - return its text
966	if ( (el.nodeType === 3) || (el.nodeType === 4) ) {
967		text = el.nodeValue;
968	// If node is an element (1) and an img, input[type=image], or area element, return its alt text
969	} else if ( (el.nodeType === 1) && (
970			(el.tagName.toLowerCase() == 'img') ||
971			(el.tagName.toLowerCase() == 'area') ||
972			((el.tagName.toLowerCase() == 'input') && el.getAttribute('type') && (el.getAttribute('type').toLowerCase() == 'image'))
973			) ) {
974		text = el.getAttribute('alt') || '';
975	// Traverse children unless this is a script or style element
976	} else if ( (el.nodeType === 1) && !el.tagName.match(/^(script|style)$/i) ) {
977		let children = el.childNodes;
978		for (let i = 0, l = children.length; i < l; i++) {
979			// If an element has an aria-label, that will override any other contained text.
980			let ariaLabel = el.getAttribute( 'aria-label' );
981			text += ( ariaLabel ) ? ariaLabel : wpaElementText( children[i] ) + ' ';
982		}
983	}
984
985	return text;
986};
987
988/**
989 * Wait to see whether an element becomes available.
990 *
991 * @param {string} selector
992 * @returns
993 */
994function wpaWaitForElement(selector) {
995    return new Promise(resolve => {
996        if (document.querySelector(selector)) {
997            return resolve(document.querySelector(selector));
998        }
999
1000        const observer = new MutationObserver(mutations => {
1001            if (document.querySelector(selector)) {
1002                observer.disconnect();
1003                resolve(document.querySelector(selector));
1004            }
1005        });
1006
1007        observer.observe(document.body, {
1008            childList: true,
1009            subtree: true
1010        });
1011    });
vendor: 1 bytes, line 1012
1012}

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.