PageSourceSearch

https://www.coptocam.org/wp-content/plugins/accordion-blocks/js/accordion-blocks.js?ver=1791146239

js coptocam.org collected 2026-10-04 20:38:48 UTC 8,666 bytes, 333 lines download raw bytes

1(function($) {
2	'use strict';
3
4	// Remove the 'no-js' class since JavaScript is enabled
5	$('.js-accordion-item').removeClass('no-js');
6
7
8
9	/**
10	 * Accordion Blocks plugin function
11	 *
12	 * @param object options Plugin settings to override the defaults
13	 */
14	$.fn.accordionBlockItem = function(options) {
15		var settings = $.extend({
16			// Set default settings
17			initiallyOpen: false,
18			autoClose:     true,
19			clickToClose:  true,
20			scroll:        false,
21			scrollOffset:  false,
22		}, options);
23
24		var duration = 250;
25		var hashID = window.location.hash.replace('#', '');
26
27		var item = {};
28
29		item.self       = $(this);
30		item.id         = $(this).attr('id');
31		item.controller = $(this).children('.js-accordion-controller');
32		item.uuid       = getAccordionItemUUID(item.self);
33		item.content    = $('#ac-' + item.uuid);
34		item.accordionGroupItems = [item.uuid];
35		item.accordionAncestorItems = [];
36
37
38
39		/**
40		 * Initial setup
41		 * Set the scroll offset, and figure out which items should be open by
42		 * default.
43		 */
44		(function initialSetup() {
45			/**
46			 * Set up some defaults for this controller
47			 * These cannot be set in the blocks `save` function because
48			 * WordPress strips `tabindex` and `aria-controls` attributes from
49			 * saved post content. See `_wp_add_global_attributes` function in
50			 * wp-includes/kses.php for list of allowed attributes.
51			 */
52			item.controller.attr({
53				'tabindex': 0,
54				'aria-controls': 'ac-' + item.uuid,
55			});
56
57			settings.scrollOffset = Math.floor(parseInt(settings.scrollOffset, 10)) || 0;
58
59			/**
60			 * Add any sibling accordion items to the accordionGroupItems array.
61			 */
62			$.each(item.self.siblings('.js-accordion-item'), function(index, ele) {
63				var uuid = getAccordionItemUUID(ele);
64
65				item.accordionGroupItems.push(uuid);
66			});
67
68			/**
69			 * Add any parent accordion items to the accordionAncestorItems array.
70			 */
71			$.each(item.self.parents('.js-accordion-item'), function(index, ele) {
72				var uuid = getAccordionItemUUID(ele);
73
74				item.accordionAncestorItems.push(uuid);
75			});
76
77			// If this item has `initially-open prop` set to true, open it
78			if (settings.initiallyOpen) {
79				/**
80				 * We aren't opening the item here (only setting open attributes)
81				 * because the openItem() function fires the `openAccordionItem`
82				 * event which, if `autoClose` is set, would override the users
83				 * defined initiallyOpen settings.
84				 *
85				 * Only setting open attributes is fine since the item's content
86				 * display (`display: none|block`) is already set by the plugin.
87				 */
88				setOpenItemAttributes();
89			}
90			// If the hash matches this item, open it
91			else if (item.id === hashID) {
92				/**
93				 * Unlike the `initiallyOpen` case above, if a hash is detected
94				 * that matches one of the accordion items, we probably _want_
95				 * the other items to close so the user can focus on this item.
96				 */
97				openItem();
98
99				// Open ancestors if necessary
100				$.each(item.accordionAncestorItems, function(index, uuid) {
101					$(document).trigger('openAncestorAccordionItem', uuid);
102				});
103			}
104			// Otherwise, close the item
105			else {
106				/**
107				 * Don't use closeItem() function call since it animates the
108				 * closing. Instead, we only need to set the closed attributes.
109				 */
110				setCloseItemAttributes();
111			}
112		})();
113
114
115
116		/**
117		 * Default click function
118		 * Called when an accordion controller is clicked.
119		 */
120		function clickHandler() {
121			// Only open the item if item isn't already open
122			if (!item.self.hasClass('is-open')) {
123				// Open clicked item
124				openItem();
125			}
126			// If item is open, and click to close is set, close it
127			else if (settings.clickToClose) {
128				closeItem();
129			}
130
131			return false;
132		}
133
134
135
136		/**
137		 * Get the accordion item UUID for a given accordion item DOM element.
138		 */
139		function getAccordionItemUUID(ele) {
140			return $(ele).children('.js-accordion-controller').attr('id').replace('at-', '');
141		}
142
143
144
145		/**
146		 * Opens an accordion item
147		 * Also handles accessibility attribute settings.
148		 */
149		function openItem() {
150			setOpenItemAttributes();
151
152			// Clear/stop any previous animations before revealing content
153			item.content.clearQueue().stop().slideDown(duration, function() {
154				// Scroll page to the title
155				if (settings.scroll) {
156					// Pause scrolling until other items have closed
157					setTimeout(function() {
158						$('html, body').animate({
159							scrollTop: item.self.offset().top - settings.scrollOffset
160						}, duration);
161					}, duration);
162				}
163			});
164
165			$(document).trigger('openAccordionItem', item);
166		}
167
168
169
170		/**
171		 * Set open item attributes
172		 * Mark accordion item as open and read and set aria attributes.
173		 */
174		function setOpenItemAttributes() {
175			item.self.addClass('is-open is-read');
176			item.controller.attr('aria-expanded', true);
177			item.content.prop('hidden', false);
178		}
179
180
181
182		/**
183		 * Closes an accordion item
184		 * Also handles accessibility attribute settings.
185		 */
186		function closeItem() {
187			// Close the item
188			item.content.slideUp(duration, function() {
189				setCloseItemAttributes();
190			});
191		}
192
193
194
195		/**
196		 * Set closed item attributes
197		 * Mark accordion item as closed and set aria attributes.
198		 */
199		function setCloseItemAttributes() {
200			item.self.removeClass('is-open');
201			item.controller.attr('aria-expanded', false);
202			item.content.attr('hidden', true);
203		}
204
205
206
207		/**
208		 * Close all items if auto close is enabled
209		 */
210		function maybeCloseItem() {
211			if (settings.autoClose && item.self.hasClass('is-open')) {
212				closeItem();
213			}
214		}
215
216
217
218		/**
219		 * Add event listeners
220		 */
221		item.controller.on('click', clickHandler);
222
223
224
225		/**
226		 * Listen for other accordion items opening
227		 *
228		 * The `openAccordionItem` event is fired whenever an accordion item is
229		 * opened after initial plugin setup.
230		 */
231		$(document).on('openAccordionItem', function(event, ele) {
232			/**
233			 * Only trigger potential close these conditions are met:
234			 *
235			 * 1. This isn't the item the user just clicked to open.
236			 * 2. This accordion is in the same group of accordions as the one
237			 *    that was just clicked to open.
238			 * 3. This accordion is not an ancestor of the item that was just
239			 *    clicked to open.
240			 *
241			 * This serves two purposes:
242			 *
243			 * 1. It allows nesting of accordions to work.
244			 * 2. It allows users to group accordions to control independently
245			 *    of other groups of accordions.
246			 * 3. It allows child accordions to be opened via hash change
247			 *    without automatically closing the parent accordion, therefore
248			 *    hiding the accordion the user just indicated they wanted open.
249			 */
250			if (
251				ele !== item &&
252				ele.accordionGroupItems.indexOf(item.uuid) > 0 &&
253				ele.accordionAncestorItems.indexOf(item.uuid) === -1
254			) {
255				maybeCloseItem();
256			}
257		});
258
259
260
261		/**
262		 * Listen for ancestor opening requests
263		 *
264		 * The `openAncestorAccordionItem` event is fired whenever a nested
265		 * accordion item is opened, but the ancestors may also need to be
266		 * opened.
267		 */
268		$(document).on('openAncestorAccordionItem', function(event, uuid) {
269			if (uuid === item.uuid) {
270				openItem();
271			}
272		});
273
274
275
276		item.controller.on('keydown', function(event) {
277			var code = event.which;
278
279			if (item.controller.prop('tagName') !== 'BUTTON') {
280				// 13 = Return, 32 = Space
281				if ((code === 13) || (code === 32)) {
282					// Simulate click on the controller
283					$(this).click();
284				}
285			}
286
287			// 27 = Esc
288			if (code === 27) {
289				maybeCloseItem();
290			}
291		});
292
293		// Listen for hash changes (in page jump links for accordions)
294		$(window).on('hashchange', function() {
295			hashID = window.location.hash.replace('#', '');
296
297			// Only open this item if the has matches the ID
298			if (hashID === item.id) {
299				var ele = $('#' + hashID);
300
301				// If there is a hash and the hash is on an accordion item
302				if (ele.length && ele.hasClass('js-accordion-item')) {
303					// Open clicked item
304					openItem();
305
306					// Open ancestors if necessary
307					$.each(item.accordionAncestorItems, function(index, uuid) {
308						$(document).trigger('openAncestorAccordionItem', uuid);
309					});
310				}
311			}
312		});
313
314		return this;
315	};
316
317
318
319	// Loop through accordion settings objects
320	// Wait for the entire page to load before loading the accordion
321	$(window).on('load', function() {
322		$('.js-accordion-item').each(function() {
323			$(this).accordionBlockItem({
324				// Set default settings
325				initiallyOpen: $(this).data('initially-open'),
326				autoClose:     $(this).data('auto-close'),
327				clickToClose:  $(this).data('click-to-close'),
328				scroll:        $(this).data('scroll'),
329				scrollOffset:  $(this).data('scroll-offset'),
330			});
331		});
332	});
333}(jQuery));

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.