TESZT 21
Hiba jelentkezett a sablon feldolgozása során.
The following has evaluated to null or missing:
==> cur_date.dateNeeded [in template "10155#10195#11925" at line 57, column 52]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: #if getterUtil.getBoolean(cur_date.da... [in template "10155#10195#11925" at line 57, column 25]
----
1<section id="${randomNamespace}nebih-carousel" class="carousel-tablist nebih-carousel" aria-roledescription="carousel" aria-label="Nebih kiemelt hírek">
2
3 <div class="carousel-inner">
4
5 <div class="controls">
6
7 <button class="rotation" type="button">
8 <svg width="40" height="30" version="1.1" xmlns="http://www.w3.org/2000/svg" class="svg-play">
9 <circle class="background" cx="20" cy="15" r="12"></circle>
10 <circle class="border" cx="20" cy="15" r="14"></circle>
11
12 <polygon class="pause" points="17 10 17 20"></polygon>
13
14 <polygon class="pause" points="24 10 24 20"></polygon>
15
16 <polygon class="play" points="15 10 15 20 27 14"></polygon>
17
18 </svg>
19 </button>
20
21 <div class="tab-wrapper">
22 <div role="tablist" aria-label="Slides">
23 <#list date.getSiblings() as cur_date>
24 <#assign tabindex = -1>
25 <#if cur_date?index == 0>
26 <#assign tabindex = 0>
27 </#if>
28 <button id="carousel-tab-${cur_date?index+1}" type="button" role="tab" tabindex="${tabindex}" aria-label="Slide ${cur_date?index+1}" aria-selected="true" aria-controls="carousel-item-${cur_date?index+1}">
29 <svg width="18" height="18" version="1.1" xmlns="http://www.w3.org/2000/svg">
30 <circle class="border" cx="8" cy="8" r="5"></circle>
31 <circle class="tab-background" cx="8" cy="8" r="4"></circle>
32 <circle class="tab" cx="8" cy="8" r="5"></circle>
33 </svg>
34 </button>
35 </#list>
36 </div>
37 </div>
38 </div>
39
40
41 <div id="nebih-carousel-items" class="carousel-items playing" aria-live="off">
42 <#list date.getSiblings() as cur_date>
43 <#assign activeClass = "">
44 <#if cur_date?index == 0>
45 <#assign activeClass = "active">
46 </#if>
47 <div class="carousel-item ${activeClass}" id="carousel-item-${cur_date?index+1}" role="tabpanel" aria-roledescription="slide" aria-label="${cur_date?index+1} / ${cur_date?size}">
48
49 <div class="carousel-image">
50 <div id="carousel-image-${cur_date?index+1}">
51 <img src="${cur_date.img.getData()}" alt="">
52 </div>
53 </div>
54
55 <div class="carousel-caption">
56 <span>
57 <#if getterUtil.getBoolean(cur_date.dateNeeded.getData())>
58 <#assign cur_date_Data = getterUtil.getString(cur_date.getData())>
59 <#assign cur_date_DateObj = dateUtil.parseDate("yyyy-MM-dd", cur_date_Data, locale)>
60 <#assign cur_date_Display = dateUtil.getDate(cur_date_DateObj, "yyyy. MMMM d., EEEE", locale)>
61 <time datetime="${cur_date_Display!""}"> ${cur_date_Display!""}</time>
62 </#if>
63 <h2>
64 <a href="${cur_date.url_.getData()}">
65 ${(cur_date.title.getData())!"-"}
66 </a>
67 </h2>
68 </span>
69 </div>
70 </div>
71
72 </#list>
73 </div>
74
75
76 </div>
77
78
79</section>
80
81<div class="col-sm-1"></div>
82
83
84
85<script>
86 /*
87 * File: carousel-tablist.js
88 *
89 * Desc: Carousel Tablist widget that implements ARIA Authoring Practices
90 *
91 */
92
93 'use strict';
94
95 // takes options object: { accessibleCaptions: boolean, autoplay: boolean, playButton: boolean }
96 // defaults are: { accessibleCaptions: true, autoplay: false, playButton: true }
97
98 var CarouselTablist = function (node, options) {
99 // merge passed options with defaults
100 options = Object.assign(
101 { moreaccessible: false, paused: false, norotate: false },
102 options || {}
103 );
104
105 // a prefers-reduced-motion user setting must always override autoplay
106 var hasReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
107 if (hasReducedMotion.matches) {
108 options.paused = true;
109 }
110
111 /* DOM properties */
112 this.domNode = node;
113
114 this.tablistNode = node.querySelector('[role=tablist]');
115 this.containerNode = node.querySelector('.carousel-items');
116
117 this.tabNodes = [];
118 this.tabpanelNodes = [];
119
120 this.liveRegionNode = node.querySelector('.carousel-items');
121 this.pausePlayButtonNode = document.querySelector(
122 '.carousel-tablist .controls button.rotation'
123 );
124
125 this.playLabel = 'Start automatic slide show';
126 this.pauseLabel = 'Stop automatic slide show';
127
128 /* State properties */
129 this.hasUserActivatedPlay = false; // set when the user activates the play/pause button
130 this.isAutoRotationDisabled = options.norotate; // This property for disabling auto rotation
131 this.isPlayingEnabled = !options.paused; // This property is also set in updatePlaying method
132 this.timeInterval = 5000; // length of slide rotation in ms
133 this.currentIndex = 0; // index of current slide
134 this.slideTimeout = null; // save reference to setTimeout
135
136 // initialize tabs
137 this.tablistNode.addEventListener('focusin', this.handleTabFocus.bind(this));
138 this.tablistNode.addEventListener('focusout', this.handleTabBlur.bind(this));
139
140 var nodes = node.querySelectorAll('[role="tab"]');
141
142 for (var i = 0; i < nodes.length; i++) {
143 var n = nodes[i];
144
145 this.tabNodes.push(n);
146
147 n.addEventListener('keydown', this.handleTabKeydown.bind(this));
148 n.addEventListener('click', this.handleTabClick.bind(this));
149
150 // initialize tabpanels
151
152 var tabpanelNode = document.getElementById(n.getAttribute('aria-controls'));
153
154 if (tabpanelNode) {
155 this.tabpanelNodes.push(tabpanelNode);
156
157 // support stopping rotation when any element receives focus in the tabpanel
158 tabpanelNode.addEventListener(
159 'focusin',
160 this.handleTabpanelFocusIn.bind(this)
161 );
162 tabpanelNode.addEventListener(
163 'focusout',
164 this.handleTabpanelFocusOut.bind(this)
165 );
166
167 var imageLink = tabpanelNode.querySelector('.carousel-image a');
168
169 if (imageLink) {
170 imageLink.addEventListener(
171 'focus',
172 this.handleImageLinkFocus.bind(this)
173 );
174 imageLink.addEventListener('blur', this.handleImageLinkBlur.bind(this));
175 }
176 } else {
177 this.tabpanelNodes.push(null);
178 }
179 }
180
181 // Pause Button
182 if (this.pausePlayButtonNode) {
183 this.pausePlayButtonNode.addEventListener(
184 'click',
185 this.handlePausePlayButtonClick.bind(this)
186 );
187 }
188
189 // Handle hover events
190 this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this));
191 this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this));
192
193 // initialize behavior based on options
194
195 this.enableOrDisableAutoRotation(options.norotate);
196 this.updatePlaying(!options.paused && !options.norotate);
197 this.setAccessibleStyling(options.moreaccessible);
198 this.rotateSlides();
199 };
200
201 /* Public function to disable/enable rotation and if false, hide pause/play button*/
202 CarouselTablist.prototype.enableOrDisableAutoRotation = function (disable) {
203 this.isAutoRotationDisabled = disable;
204 this.pausePlayButtonNode.hidden = disable;
205 };
206
207 /* Public function to update controls/caption styling */
208 CarouselTablist.prototype.setAccessibleStyling = function (accessible) {
209 if (accessible) {
210 this.domNode.classList.add('carousel-tablist-moreaccessible');
211 } else {
212 this.domNode.classList.remove('carousel-tablist-moreaccessible');
213 }
214 };
215
216 CarouselTablist.prototype.hideTabpanel = function (index) {
217 var tabNode = this.tabNodes[index];
218 var panelNode = this.tabpanelNodes[index];
219
220 tabNode.setAttribute('aria-selected', 'false');
221 tabNode.setAttribute('tabindex', '-1');
222
223 if (panelNode) {
224 panelNode.classList.remove('active');
225 }
226 };
227
228 CarouselTablist.prototype.showTabpanel = function (index, moveFocus) {
229 var tabNode = this.tabNodes[index];
230 var panelNode = this.tabpanelNodes[index];
231
232 tabNode.setAttribute('aria-selected', 'true');
233 tabNode.removeAttribute('tabindex');
234
235 if (panelNode) {
236 panelNode.classList.add('active');
237 }
238
239 if (moveFocus) {
240 tabNode.focus();
241 }
242 };
243
244 CarouselTablist.prototype.setSelectedTab = function (index, moveFocus) {
245 if (index === this.currentIndex) {
246 return;
247 }
248 this.currentIndex = index;
249
250 for (var i = 0; i < this.tabNodes.length; i++) {
251 this.hideTabpanel(i);
252 }
253
254 this.showTabpanel(index, moveFocus);
255 };
256
257 CarouselTablist.prototype.setSelectedToPreviousTab = function (moveFocus) {
258 var nextIndex = this.currentIndex - 1;
259
260 if (nextIndex < 0) {
261 nextIndex = this.tabNodes.length - 1;
262 }
263
264 this.setSelectedTab(nextIndex, moveFocus);
265 };
266
267 CarouselTablist.prototype.setSelectedToNextTab = function (moveFocus) {
268 var nextIndex = this.currentIndex + 1;
269
270 if (nextIndex >= this.tabNodes.length) {
271 nextIndex = 0;
272 }
273
274 this.setSelectedTab(nextIndex, moveFocus);
275 };
276
277 CarouselTablist.prototype.rotateSlides = function () {
278 if (!this.isAutoRotationDisabled) {
279 if (
280 (!this.hasFocus && !this.hasHover && this.isPlayingEnabled) ||
281 this.hasUserActivatedPlay
282 ) {
283 this.setSelectedToNextTab(false);
284 }
285 }
286
287 this.slideTimeout = setTimeout(
288 this.rotateSlides.bind(this),
289 this.timeInterval
290 );
291 };
292
293 CarouselTablist.prototype.updatePlaying = function (play) {
294 this.isPlayingEnabled = play;
295
296 if (play) {
297 this.pausePlayButtonNode.setAttribute('aria-label', this.pauseLabel);
298 this.pausePlayButtonNode.classList.remove('play');
299 this.pausePlayButtonNode.classList.add('pause');
300 this.liveRegionNode.setAttribute('aria-live', 'off');
301 } else {
302 this.pausePlayButtonNode.setAttribute('aria-label', this.playLabel);
303 this.pausePlayButtonNode.classList.remove('pause');
304 this.pausePlayButtonNode.classList.add('play');
305 this.liveRegionNode.setAttribute('aria-live', 'polite');
306 }
307 };
308
309 /* Event Handlers */
310
311 CarouselTablist.prototype.handleImageLinkFocus = function () {
312 this.liveRegionNode.classList.add('focus');
313 };
314
315 CarouselTablist.prototype.handleImageLinkBlur = function () {
316 this.liveRegionNode.classList.remove('focus');
317 };
318
319 CarouselTablist.prototype.handleMouseOver = function (event) {
320 if (!this.pausePlayButtonNode.contains(event.target)) {
321 this.hasHover = true;
322 }
323 };
324
325 CarouselTablist.prototype.handleMouseOut = function () {
326 this.hasHover = false;
327 };
328
329 /* EVENT HANDLERS */
330
331 CarouselTablist.prototype.handlePausePlayButtonClick = function () {
332 this.hasUserActivatedPlay = !this.isPlayingEnabled;
333 this.updatePlaying(!this.isPlayingEnabled);
334 };
335
336 /* Event Handlers for Tabs*/
337
338 CarouselTablist.prototype.handleTabKeydown = function (event) {
339 var flag = false;
340
341 switch (event.key) {
342 case 'ArrowRight':
343 this.setSelectedToNextTab(true);
344 flag = true;
345 break;
346
347 case 'ArrowLeft':
348 this.setSelectedToPreviousTab(true);
349 flag = true;
350 break;
351
352 case 'Home':
353 this.setSelectedTab(0, true);
354 flag = true;
355 break;
356
357 case 'End':
358 this.setSelectedTab(this.tabNodes.length - 1, true);
359 flag = true;
360 break;
361
362 default:
363 break;
364 }
365
366 if (flag) {
367 event.stopPropagation();
368 event.preventDefault();
369 }
370 };
371
372 CarouselTablist.prototype.handleTabClick = function (event) {
373 var index = this.tabNodes.indexOf(event.currentTarget);
374 this.setSelectedTab(index, true);
375 };
376
377 CarouselTablist.prototype.handleTabFocus = function () {
378 this.tablistNode.classList.add('focus');
379 this.liveRegionNode.setAttribute('aria-live', 'polite');
380 this.hasFocus = true;
381 };
382
383 CarouselTablist.prototype.handleTabBlur = function () {
384 this.tablistNode.classList.remove('focus');
385 if (this.playState) {
386 this.liveRegionNode.setAttribute('aria-live', 'off');
387 }
388
389 this.hasFocus = false;
390 };
391
392 /* Event Handlers for Tabpanels*/
393
394 CarouselTablist.prototype.handleTabpanelFocusIn = function () {
395 this.hasFocus = true;
396 };
397
398 CarouselTablist.prototype.handleTabpanelFocusOut = function () {
399 this.hasFocus = false;
400 };
401
402 /* Initialize Carousel Tablists and options */
403
404 window.addEventListener(
405 'load',
406 function () {
407 var carouselEls = document.querySelectorAll('.carousel-tablist');
408 var carousels = [];
409
410 // set example behavior based on
411 // default setting of the checkboxes and the parameters in the URL
412 // update checkboxes based on any corresponding URL parameters
413 var checkboxes = document.querySelectorAll(
414 '.carousel-options input[type=checkbox]'
415 );
416 var urlParams = new URLSearchParams(location.search);
417 var carouselOptions = {};
418
419 // initialize example features based on
420 // default setting of the checkboxes and the parameters in the URL
421 // update checkboxes based on any corresponding URL parameters
422 checkboxes.forEach(function (checkbox) {
423 var checked = checkbox.checked;
424
425 if (urlParams.has(checkbox.value)) {
426 var urlParam = urlParams.get(checkbox.value);
427 if (typeof urlParam === 'string') {
428 checked = urlParam === 'true';
429 checkbox.checked = checked;
430 }
431 }
432
433 carouselOptions[checkbox.value] = checkbox.checked;
434 });
435
436 carouselEls.forEach(function (node) {
437 carousels.push(new CarouselTablist(node, carouselOptions));
438 });
439
440 // add change event to checkboxes
441 checkboxes.forEach(function (checkbox) {
442 var updateEvent;
443 switch (checkbox.value) {
444 case 'moreaccessible':
445 updateEvent = 'setAccessibleStyling';
446 break;
447 case 'norotate':
448 updateEvent = 'enableOrDisableAutoRotation';
449 break;
450 }
451
452 // update the carousel behavior and URL when a checkbox state changes
453 checkbox.addEventListener('change', function (event) {
454 urlParams.set(event.target.value, event.target.checked + '');
455 window.history.replaceState(
456 null,
457 '',
458 window.location.pathname + '?' + urlParams
459 );
460
461 if (updateEvent) {
462 carousels.forEach(function (carousel) {
463 carousel[updateEvent](event.target.checked);
464 });
465 }
466 });
467 });
468 },
469 false
470 );
471
472</script>