PageSourceSearch

https://www.thecanadianpress.com/app/plugins/wp-accessibility/js/wp-accessibility.js?ver=27618

js thecanadianpress.com collected 2026-09-24 19:01:28 UTC 16,154 bytes, 427 lines download raw bytes

1(function( $ ) { 'use strict';
2	var html   = document.querySelector( 'html' );
3	var errors = [];
4	if ( wpa.lang ) {
5		var lang   = html.getAttribute( 'lang' );
6		if ( ! lang ) {
7			$('html').attr( 'lang', wpa.lang );
8			if ( wpa.errors || wpa.tracking ) {
9				errors.push( 'html-lang' );
10				console.log( 'HTML language set by WP Accessibility' );
11			}
12		}
13	}
14
15	if ( wpa.dir ) {
16		var dir  = html.getAttribute( 'dir' );
17		if ( ! dir ) {
18			$('html').attr( 'dir', wpa.dir );
19			if ( wpa.errors || wpa.tracking ) {
20				errors.push( 'html-lang-direction' );
21				console.log( 'HTML language direction set by WP Accessibility' );
22			}
23		}
24	}
25
26	var viewport = document.querySelector( 'meta[name="viewport"]' );
27	if ( viewport ) {
28		var conditionsBefore = viewport.getAttribute( 'content' );
29		var conditionsAfter  = viewport.getAttribute( 'content' );
30		if ( conditionsBefore.search(/user-scalable=no/g) ) {
31			conditionsAfter = conditionsBefore.replace( 'user-scalable=no', 'user-scalable=yes' );
32			viewport.setAttribute( 'content', conditionsAfter );
33			if ( ( wpa.errors || wpa.tracking ) && conditionsAfter != conditionsBefore ) {
34				errors.push( 'viewport-scalable' );
35				console.log( 'Viewport made scalable by WP Accessibility' );
36			}
37		}
38		if ( conditionsBefore.search(/maximum-scale=1/g) ) {
39			conditionsAfter = conditionsBefore.replace( 'maximum-scale=1', 'maximum-scale=5' );
40			conditionsAfter = conditionsAfter.replace( 'maximum-scale=0', 'maximum-scale=5' );
41			viewport.setAttribute( 'content', conditionsAfter );
42			if ( ( wpa.errors || wpa.tracking ) && conditionsAfter != conditionsBefore  ) {
43				errors.push( 'viewport-maxscale' );
44				console.log( 'Viewport maximum scale set by WP Accessibility' );
45			}
46		}
47	}
48
49	if ( wpa.skiplinks.enabled ) {
50		$('body').prepend( wpa.skiplinks.output );
51		if ( wpa.errors || wpa.tracking  ) {
52			errors.push( 'skiplinks' );
53			console.log( 'Skip links added by WP Accessibility' );
54		}
55	}
56
57	if ( wpa.current ) {
58		$(function() {
59			$( '.current-menu-item a, .current_page_item a' ).attr( 'aria-current', 'page' );
60		});
61		if ( wpa.errors || wpa.tracking  ) {
62			errors.push( 'aria-current' );
63			console.log( 'ARIA current added by WP Accessibility' );
64		}
65	}
66
67	if ( wpa.labels ) {
68		var wpa_names = [ 's', 'author', 'email', 'url', 'comment' ];
69		$.each( wpa_names, function( index, value ) {
70			if ( value == 'comment' ) {
71				var field = $( 'textarea[name=' + value + ']' );
72			} else {
73				var field = $( 'input[name=' + value + ']' ).not( '#adminbar-search' );
74			}
75			if ( 0 !== field.length ) {
76				var field_id = field.attr( 'id' );
77				var implicit = $( field ).parent( 'label' );
78				var aria = $( field ).attr( 'aria-label' );
79				var ariaId = $( field ).attr( 'aria-labelledby' );
80				var ariaTarget = {};
81				if ( ariaId ) {
82					ariaTarget = $( '#' + ariaId );
83				}
84				var hasAria   = ( '' == aria || 'undefined' == typeof( aria ) ) ? false : true;
85				var hasAriaId = ( '' == ariaId || 'undefined' == typeof( ariaId ) ) ? false : true;
86				// Add label if aria label empty, aria labelledby empty, or aria reference ID does not exist.
87				if ( ( ! hasAria && ! hasAriaId ) || ( ! hasAria && ( hasAriaId && 0 === ariaTarget.length ) ) ) {
88					if ( field_id ) {
89						var label = $( 'label[for=' + field_id + ']' );
90						if ( !label.length && !implicit.length ) {
91							field.before( "<label for='" + field_id + "' class='wpa-screen-reader-text'>" + wpa.wpalabels[value] + "</label>" );
92							if ( wpa.errors || wpa.tracking ) {
93								errors.push( ['explicit-label', wpa.wpalabels[value]] );
94								console.log( 'Explicit label on ' + wpa.wpalabels[value] + 'added by WP Accessibility' );
95							}
96						}
97					} else {
98						if ( !implicit.length ) {
99							field.attr( 'id', 'wpa_label_' + value ).before( "<label for='wpa_label_" + value + "' class='wpa-screen-reader-text'>" + wpa.wpalabels[value] + "</label>" );
100							if ( wpa.errors || wpa.tracking ) {
101								errors.push( ['implicit-label', wpa.wpalabels[value]] );
102								console.log( 'Implicit label on ' + wpa.wpalabels[value] + 'added by WP Accessibility' );
103							}
104						}
105					}
106				}
107			}
108		});
109	}
110
111	if ( wpa.titles ) {
112		var images   = 0;
113		var controls = 0;
114		var fields   = 0;
115		const els    = document.querySelectorAll( 'img, a, input, textarea, select, button' );
116		els.forEach((el) => {
117			var title = el.getAttribute( 'title' );
118			if ( title && '' !== title ) {
119				switch ( el.tagName ) {
120					case 'IMG':
121						// If image has alt, remove title. If not, set title as alt.
122						var alt = el.getAttribute( 'alt' );
123						if ( ! alt || '' === alt ) {
124							el.setAttribute( 'alt', title );
125							el.removeAttribute( 'title' );
126						} else {
127							el.removeAttribute( 'title' );
128						}
129						images++;
130						break;
131					case 'A':
132					case 'BUTTON':
133						// 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.
134						var linkText = wpaElementText(el);
135						if ( ! linkText || '' === linkText ) {
136							var ariaLabel = el.getAttribute( 'aria-label' );
137							if ( ! ariaLabel || '' === ariaLabel ) {
138								el.setAttribute( 'aria-label', title );
139								el.removeAttribute( 'title' );
140							}
141						} else {
142							el.removeAttribute( 'title' );
143						}
144						controls++;
145						break;
146					case 'INPUT':
147					case 'SELECT':
148					case 'TEXTAREA':
149						// If input field has an aria-label, aria-labelledby, associated label, or wrapping label, remove title. Else, add title as aria-label.
150						var ariaLabel        = el.getAttribute( 'aria-label' );
151						var ariaLabelled     = el.getAttribute( 'aria-labelledby' );
152						var ariaLabeller     = ( ariaLabelled ) ? document.getElementById( ariaLabelled ) : false;
153						var labelId          = el.getAttribute( 'id' );
154						var label            = ( labelId ) ? document.querySelector( 'label[for="' + labelId + '"]' ) : false;
155						var parentLabel      = el.closest( 'label' );
156						var hasAriaLabel     = ( ariaLabel && '' !== ariaLabel ) ? true : false;
157						var hasRealLabel     = ( label && '' !== wpaElementText( label ) ) ? true : false;
158						var hasImplicitLabel = ( parentLabel && '' !== wpaElementText( parentLabel ) ) ? true : false;
159						var hasAriaLabelled  = ( ariaLabeller && '' !== wpaElementText( arialabeller ) ) ? true : false;
160						if ( hasAriaLabel || hasRealLabel || hasImplicitLabel || hasAriaLabelled ) {
161							// This has a label.
162							el.removeAttribute( 'title' );
163						} else {
164							el.setAttribute( 'aria-label', title );
165							el.removeAttribute( 'title' );
166						}
167						fields++;
168						break;
169				}
170			}
171		});
172		if ( wpa.errors || wpa.tracking ) {
173			if ( images > 0 ) {
174				errors.push( ['images-titles', images] );
175				console.log( images + ' title attributes removed from images by WP Accessibility' );
176			}
177			if ( controls > 0 ) {
178				errors.push( ['control-titles', controls] );
179				console.log( controls + ' title attributes removed from links and buttons by WP Accessibility' );
180			}
181			if ( fields > 0 ) {
182				errors.push( ['input-titles', fields] );
183				console.log( fields + ' title attributes removed from input fields by WP Accessibility' );
184			}
185		}
186	}
187
188	if ( wpa.target ) {
189		var targeted      = $('a:not(.wpa-allow-target)');
190		var targetRemoved = 0;
191		targeted.each( function() {
192			var target = $( this ).attr( 'target' );
193			if ( target ) {
194				$( this ).removeAttr( 'target' );
195				targetRemoved++;
196			}
197		});
198		if ( targetRemoved > 0 && ( wpa.errors || wpa.tracking ) ) {
199			errors.push( ['link-targets', targetRemoved] );
200			console.log( targetRemoved + ' target attributes removed from links by WP Accessibility' );
201		}
202	}
203
204	if ( wpa.tabindex ) {
205		// Remove tabindex from elements that should be natively focusable.
206		var focusable  = $('input,a,select,textarea,button').not('a:not([href])');
207		var tabRemoved = 0;
208		focusable.each( function() {
209			var tabindex = $( this ).attr( 'tabindex' );
210			if ( tabindex ) {
211				$( this ).removeAttr('tabindex');
212				tabRemoved++;
213			}
214		});
215
216		if ( tabRemoved > 0 && ( wpa.errors || wpa.tracking ) ) {
217			errors.push( ['control-tabindex', tabRemoved] );
218			console.log( tabRemoved + ' tabindex attributes removed from links, buttons and inputs by WP Accessibility' );
219		}
220
221		// Add tabindex to elements that appear active but are not natively focusable.
222		var fakeButtons = $('div[role="button"]').not('div[tabindex]' );
223		var buttonLinks = $('a[role="button"]').not('a[tabindex],a[href]');
224		fakeButtons.attr( 'tabindex', '0' ).addClass('wpa-focusable');
225		if ( fakeButtons.length > 0 && ( wpa.errors || wpa.tracking ) ) {
226			errors.push( ['button-add-tabindex', fakeButtons.length] );
227			console.log( fakeButtons.length + ' tabindex attributes added to divs with the button role by WP Accessibility' );
228		}
229		buttonLinks.attr( 'tabindex', '0' ).addClass('wpa-focusable');
230		if ( buttonLinks.length > 0 && ( wpa.errors || wpa.tracking ) ) {
231			errors.push( ['link-add-tabindex', buttonLinks.length] );
232			console.log( buttonLinks.length + ' tabindex attributes added to anchor elements with the button role and no href value by WP Accessibility' );
233		}
234	}
235	var fingerprint = new Fingerprint().get();
236	
237	// If stats are disabled, skip this.
238	if ( 'disabled' !== wpa.url ) {
239		$('.toggle-contrast').on('click', function (e) {
240			// This fires after the contrast change happens, and the ID is already changed.
241			if ($(this).attr('id') == "is_normal_contrast") {
242				// high contrast turned on.
243				var event = {'contrast' : 'disabled'};
244			} else {
245				// high contrast turned off.
246				var event = {'contrast' : 'enabled'};
247			}
248			var data = {
249				'action' : wpa.action,
250				'security' : wpa.security,
251				'stats' : event,
252				'post_id' : wpa.post_id,
253				'title' : fingerprint,
254				'type' : 'event'
255			};
256			$.post( wpa.ajaxurl, data, function () {}, "json" );
257		});
258
259		$('.toggle-fontsize').on('click', function (e) {
260			// This fires after the fontsize change happens, and the ID is already changed.
261			if ($(this).attr('id') == "is_normal_fontsize") {
262				// fontsizes turned on.
263				var event = {'fontsize' : 'disabled'};
264			} else {
265				// fontsizes turned off.
266				var event = {'fontsize' : 'enabled'};
267			}
268			var data = {
269				'action' : wpa.action,
270				'security' : wpa.security,
271				'stats' : event,
272				'post_id' : wpa.post_id,
273				'title' : fingerprint,
274				'type' : 'event'
275			};
276			$.post( wpa.ajaxurl, data, function () {}, "json" );
277		});
278
279		waitForElement('.wpa-ld button').then((elm) => {
280			$('.wpa-ld button').on( 'click', function(e) {
281				// For descriptions, we aren't concerned about state changes; just usage.
282				var visible = ( 'true' === $( this ).attr( 'aria-expanded' ) ) ? true : false;
283				if ( visible ) {
284					var img      = $( this ).parent( 'div' );
285					var image_id = img.attr( 'class' ).replace( 'wpa-ld wp-image-', '' );
286					var event    = { 'longdesc' : image_id };
287					var data     = {
288						'action' : wpa.action,
289						'security' : wpa.security,
290						'stats' : event,
291						'post_id' : wpa.post_id,
292						'title' : fingerprint,
293						'type' : 'event'
294					};
295					$.post( wpa.ajaxurl, data, function (response) { console.log( response ); }, "json" );
296				}
297			});
298		});
299
300		$('.wpa-alt button').on( 'click', function(e) {
301			// For alt text, we aren't concerned about state changes; just usage.
302			var visible = ( 'true' === $( this ).attr( 'aria-expanded' ) ) ? true : false;
303			if ( visible ) {
304				var img      = $( this ).parent( 'div' );
305				console.log( img );
306				var image_id = img.attr( 'class' ).replace( 'wpa-alt wp-image-', '' );
307				var event    = { 'alttext' : image_id };
308				var data     = {
309					'action' : wpa.action,
310					'security' : wpa.security,
311					'stats' : event,
312					'post_id' : wpa.post_id,
313					'title' : fingerprint,
314					'type' : 'event'
315				};
316				$.post( wpa.ajaxurl, data, function (response) { console.log( response ); }, "json" );
317			}
318		});
319
320		if ( wpa.tracking && errors.length >= 1 ) {
321			var data = {
322				'action' : wpa.action,
323				'security' : wpa.security,
324				'stats' : errors,
325				'post_id' : wpa.post_id,
326				'title' : wpa.url,
327				'type' : 'view'
328			};
329			$.post( wpa.ajaxurl, data, function (response) {
330				console.log( response );
331			}, "json" );
332		}
333
334	}
335	if ( wpa.underline.enabled ) {
336		// Underline any link not inside a `nav` region. Using JS for this avoids problems with cascade precedence.
337		var originalOutline = $( wpa.underline.target ).css( 'outline-width' );
338		var originalOffset  = $( wpa.underline.target ).css( 'outline-offset' );
339		var textColor       = $( wpa.underline.target ).css( 'color' );
340		var originalColor   = $( wpa.underline.target ).css( 'outline-color' );
341		$( wpa.underline.target ).not( 'nav ' + wpa.underline.target ).css( 'text-decoration', 'underline' );
342
343		$( wpa.underline.target ).on( 'mouseenter', function() {
344			$( this ).css( 'text-decoration', 'none' );
345		});
346		$(  wpa.underline.target ).on( 'mouseleave', function() {
347			// Reset visible appearance on exit.
348			$( this ).css( 'text-decoration', 'underline' );
349		});
350
351		$( wpa.underline.target ).on( 'focusin', function() {
352			var newOutline = '2px';
353			if ( originalOutline == '2px' ) {
354				newOutline = '4px';
355			}
356			// Ensure there's a visible change of appearance on hover or focus.
357			$(this).css( 'outline-width', newOutline );
358			$(this).css( 'outline-color', textColor );
359			$(this).css( 'outline-offset', '2px' );
360		});
361		$(  wpa.underline.target ).on( 'focusout', function() {
362			// Reset visible appearance on exit.
363			$(this).css( 'outline-width', originalOutline );
364			$(this).css( 'outline-color', originalColor );
365			$(this).css( 'outline-offset', originalOffset );
366		});
367	}
368}(jQuery));
369
370/**
371 * Check whether an element contains text, including inspecting contained content for image alt attributes or aria-label attributes.
372 *
373 *
374 * @arg el DOM element to check.
375 *
376 * Based on work by Roger Johansson https://www.456bereastreet.com/archive/201105/get_element_text_including_alt_text_for_images_with_javascript/
377 */
378function wpaElementText(el) {
379	var text = '';
380	// Text node (3) or CDATA node (4) - return its text
381	if ( (el.nodeType === 3) || (el.nodeType === 4) ) {
382		text = el.nodeValue;
383	// If node is an element (1) and an img, input[type=image], or area element, return its alt text
384	} else if ( (el.nodeType === 1) && (
385			(el.tagName.toLowerCase() == 'img') ||
386			(el.tagName.toLowerCase() == 'area') ||
387			((el.tagName.toLowerCase() == 'input') && el.getAttribute('type') && (el.getAttribute('type').toLowerCase() == 'image'))
388			) ) {
389		text = el.getAttribute('alt') || '';
390	// Traverse children unless this is a script or style element
391	} else if ( (el.nodeType === 1) && !el.tagName.match(/^(script|style)$/i) ) {
392		var children = el.childNodes;
393		for (var i = 0, l = children.length; i < l; i++) {
394			// If an element has an aria-label, that will override any other contained text.
395			var ariaLabel = el.getAttribute( 'aria-label' );
396			text += ( ariaLabel ) ? ariaLabel : wpaElementText( children[i] ) + ' ';
397		}
398	}
399
400	return text;
401};
402
403/**
404 * Wait to see whether an element becomes available. 
405 *
406 * @param {string} selector 
407 * @returns 
408 */
409function waitForElement(selector) {
410    return new Promise(resolve => {
411        if (document.querySelector(selector)) {
412            return resolve(document.querySelector(selector));
413        }
414
415        const observer = new MutationObserver(mutations => {
416            if (document.querySelector(selector)) {
417                observer.disconnect();
418                resolve(document.querySelector(selector));
419            }
420        });
421
422        observer.observe(document.body, {
423            childList: true,
424            subtree: true
425        });
426    });
427}

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.