PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.33
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.33
3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 2.44 All 141 releases
photonic / include / js / admin / wizard.js

wizard.js in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.33, at include/js/admin/wizard.js

1,181 lines 45.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 document.addEventListener('DOMContentLoaded', () => {
2 const PhotonicWizard = () => {
3 let photonicLastActiveScreen = 1;
4 let photonicMustPost = false;
5 let photonicPermittedGalleries = ['wp', 'default', 'flickr', 'smugmug', 'google', 'zenfolio', 'instagram'];
6 let photonicShortcodeObjectEditor;
7 let photonicParentShortcode = '';
8 let photonicParentSelectionError;
9 let photonicIFramePort;
10 let isEditor = false, isMCE = false, isWidget = false, isBlock = false;
11 let photonicActiveScreenElementMediaLibrary, photonicClickedNodeMediaLibrary;
12 let startupConnectionError;
13
14 // setWaitingVisibility(true);
15 window.addEventListener('message', initializeWizardPort);
16
17 function initializeWizardPort(event) {
18 // Perform a secure port transfer
19 if (event.ports[0] && event.origin === Photonic_Wizard_JS.safe_origin) {
20 photonicIFramePort = event.ports[0];
21 photonicIFramePort.onmessage = handleMessageFromParent;
22 }
23 else if (event.origin !== Photonic_Wizard_JS.safe_origin) {
24 startupConnectionError = '<strong>ERROR: </strong>Photonic wizard failed to initiate communication with main page. <ul><li>Main window is on ' + event.origin + '</li><li>Wizard is in ' + Photonic_Wizard_JS.safe_origin + '</li></ul>';
25 console.error('Photonic failed to initialize communication. Main window is in ' + event.origin + ', Wizard is in ' + Photonic_Wizard_JS.safe_origin);
26 if (startupConnectionError) {
27 document.querySelector('.photonic-editor-info').innerHTML += '<div>' + startupConnectionError + '</div>';
28 }
29 }
30 }
31
32 function handleMessageFromParent(event) {
33 if (event.data.type === 'photonicShortcode' || event.data.type === 'photonicMCENode' || event.data.type === 'photonicWidget' || event.data.type === 'photonicBlock') {
34 receiveEditorShortcode(event);
35 }
36 else if (event.data.type === 'photonicReceiveMediaLibrarySelections') {
37 receiveMediaLibrarySelections(event.data.selection, event.data.options);
38 }
39 }
40
41 function receiveEditorShortcode(event) {
42 let selection = event.data.object;
43 // Selection = null if something went wrong
44 // Selection = shortcode object if valid shortcode
45 // Selection = null shortcode object and error, if not a valid shortcode
46 // Selection = '' if nothing was selected
47 if (selection !== null && selection.shortcode !== undefined && selection.shortcode !== null) {
48 if (selection.shortcode.content !== undefined) { // Selection is a valid shortcode
49 photonicParentShortcode = selection.shortcode.content;
50 photonicShortcodeObjectEditor = selection.shortcode;
51 }
52 else {
53 photonicParentShortcode = selection.shortcode; // Selection = ''
54 }
55 }
56 else if (selection !== null && selection.error !== undefined) {
57 photonicParentSelectionError = selection.error;
58 }
59
60 isEditor = event.data.type === 'photonicShortcode';
61 isWidget = event.data.type === 'photonicWidget';
62 isBlock = event.data.type === 'photonicBlock';
63 isMCE = event.data.type === 'photonicMCENode';
64
65 photonicIFramePort.postMessage(event.data);
66 photonicIFramePort.postMessage({type: 'photonicAddTBClass'});
67
68 wizardLogic(1);
69 }
70
71 function post(url, args, callback) {
72 const xhr = new XMLHttpRequest();
73 xhr.open('POST', url);
74 xhr.onreadystatechange = function () {
75 if (xhr.readyState === 4) {
76 if (xhr.status === 200) {
77 const data = xhr.responseText;
78 callback(data);
79 }
80 }
81 };
82 let form = new FormData();
83 const parameters = new URLSearchParams(args);
84 for (const [key, value] of parameters.entries()) {
85 form.append(key, value);
86 }
87 xhr.send(form);
88 }
89
90 function getElement(value) {
91 const parser = new DOMParser();
92 const doc = parser.parseFromString(value, 'text/html');
93 return doc.body;
94 }
95
96 function log(value) {
97 if (console !== undefined && Photonic_Wizard_JS.debug_on !== '0' && Photonic_Wizard_JS.debug_on !== '') {
98 console.log(value);
99 }
100 }
101
102 const postFlowData = (activeScreen, nextScreen, activeScreenElement, screenParameters, parameters) => {
103 post(Photonic_Wizard_JS.ajaxurl, parameters, data => {
104 let ret = getElement(data);
105
106 if (ret.querySelector('.photonic-flow-error')) {
107 if (document.querySelector('.photonic-flow-error')) {
108 document.querySelector('.photonic-flow-error').remove();
109 }
110 document.querySelector('.photonic-flow-screen[data-screen="' + activeScreen + '"]').before(ret.querySelector('.photonic-flow-error'));
111 activeScreenElement.setAttribute('data-submitted', '');
112 log('Parameters causing failure: activeScreen = ' + activeScreen + ', nextScreen = ' + nextScreen);
113 log(screenParameters);
114 log(parameters);
115 }
116 else {
117 if (document.querySelector('.photonic-flow-error')) {
118 document.querySelector('.photonic-flow-error').style.display = 'none';
119 }
120
121 let forceScreen = ret.querySelector('input[name="force_next_screen"]');
122 if (forceScreen) {
123 if (parseInt(forceScreen.value, 10) > -1) {
124 nextScreen = parseInt(forceScreen.value, 10);
125 }
126 }
127
128 let nextScreenContent = document.querySelector('.photonic-flow-screen[data-screen="' + nextScreen + '"]');
129 nextScreenContent.replaceChildren();
130 nextScreenContent.insertAdjacentHTML('beforeend', data);
131
132 wizardLogic(nextScreen);
133 if (nextScreen <= 3) {
134 const existing = document.querySelector('input[name="existing_selection"]') ? document.querySelector('input[name="existing_selection"]').value : undefined;
135 const selection = document.querySelector('input[name="selected_data"]');
136 const passworded = document.querySelector('input[name="selection_passworded"]');
137 if (existing !== undefined && existing !== '') {
138 selection.value = existing;
139 }
140 else {
141 selection.value = '';
142 passworded.value = '';
143 }
144 }
145 photonicLastActiveScreen = nextScreen;
146 activeScreenElement.setAttribute('data-submitted', screenParameters);
147 photonicMustPost = false;
148 }
149 setWaitingVisibility(false);
150 });
151 };
152
153 function receiveMediaLibrarySelections(selected_data, options) {
154 document.querySelector('input[name="selected_data"]').value = selected_data
155
156 const form = document.getElementById('photonic-flow');
157 const formData = new FormData(form);
158 let formParameters = new URLSearchParams(formData).toString();
159 formParameters += ((formParameters === '') ? '' : '&') + 'action=photonic_wizard_next_screen&screen=' + (options.activeScreen) + '&_ajax_nonce=' + photonicClickedNodeMediaLibrary.getAttribute('data-photonic-nonce');
160
161 postFlowData(options.activeScreen, options.nextScreen, photonicActiveScreenElementMediaLibrary, options.screenParameters, formParameters);
162
163 if (selected_data !== '') {
164 wizardLogic(options.nextScreen);
165 }
166 }
167
168 const initializeWPMediaLibrary = (activeScreen, nextScreen, activeScreenElement, screenParameters, clicked) => {
169 let mode = document.querySelector('select[name="display_type"]').value;
170 if (mode === '') {
171 alert(Photonic_Wizard_JS.error_mandatory);
172 }
173 else {
174 mode = mode === 'single-photo' ? 'single' : 'add';
175
176 // These 2 are needed as we cannot pass elements to postMessage -->
177 photonicActiveScreenElementMediaLibrary = activeScreenElement;
178 photonicClickedNodeMediaLibrary = clicked;
179 // <--
180
181 photonicIFramePort.postMessage({
182 type: 'photonicInitializeMediaLibrary',
183 mediaOptions: {
184 multiple: mode,
185 title: Photonic_Wizard_JS.media_library_title,
186 library: {type: 'image'},
187 button: {text: Photonic_Wizard_JS.media_library_button}
188 },
189 photonicOptions: {
190 shortcodeTag: Photonic_Wizard_JS.shortcode,
191 activeScreen: activeScreen,
192 nextScreen: nextScreen,
193 screenParameters: screenParameters,
194 currentShortcode: photonicParentShortcode,
195 selectedIds: document.querySelector('input[name="selected_data"]').value,
196 isBlock: isBlock
197 }
198 });
199 }
200 };
201
202 const checkCondition = (conditions) => {
203 let conditionMet = true;
204 Object.entries(conditions).forEach(([key, condition]) => {
205 const keyField = document.querySelector('input[type="radio"][name="' + key + '"]:checked, select[name="' + key + '"], input[type="text"][name="' + key + '"], input[type="hidden"][name="' + key + '"]');
206 if (keyField === null) {
207 conditionMet = false;
208 }
209 else {
210 conditionMet = conditionMet && condition.includes(keyField.value);
211 }
212 });
213 return conditionMet;
214 };
215
216 const updateSelection = (clicked) => {
217 const parent = clicked.closest('.photonic-flow-selector-container');
218 let selection = [];
219
220 parent.querySelectorAll('.photonic-flow-selector.selected .photonic-flow-selector-inner').forEach(item => {
221 selection.push(item.getAttribute('data-photonic-selection-id'));
222 });
223
224 selection = selection.join();
225 let selectorFor = parent.getAttribute('data-photonic-flow-selector-for');
226 photonicMustPost = true;
227 document.querySelector('input[name="' + selectorFor + '"]').value = selection;
228 };
229
230 const showConditionalFieldValues = (sibling) => {
231 const siblingFieldValues = sibling.querySelectorAll('input[type="radio"], option');
232 siblingFieldValues.forEach(input => {
233 if (input.getAttribute('data-photonic-option-condition')) {
234 const conditionMet = checkCondition(JSON.parse(input.getAttribute('data-photonic-option-condition')));
235 if (conditionMet) {
236 if (input.type === 'radio') {
237 input.closest('.photonic-flow-field-radio').style.display = 'block';
238 }
239 else {
240 input.style.display = 'block';
241 }
242 }
243 else {
244 if (input.type === 'radio') {
245 input.checked = false;
246 input.closest('.photonic-flow-field-radio').style.display = 'none';
247 }
248 else {
249 input.style.display = 'none';
250 }
251 }
252 }
253 });
254 };
255
256 // From https://developer.mozilla.org/en-US/docs/Glossary/Base64#solution_2_%E2%80%93_rewriting_atob_and_btoa_using_typedarrays_and_utf-8, to handle https://wordpress.org/support/topic/set-load-more-button-default/ ...
257
258 /*\
259 |*|
260 |*| Base64 / binary data / UTF-8 strings utilities
261 |*|
262 |*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
263 |*|
264 \*/
265
266 /* Array of bytes to Base64 string decoding */
267 const photonicB64ToUint6 = (nChr) => {
268 return nChr > 64 && nChr < 91 ?
269 nChr - 65
270 : nChr > 96 && nChr < 123 ?
271 nChr - 71
272 : nChr > 47 && nChr < 58 ?
273 nChr + 4
274 : nChr === 43 ?
275 62
276 : nChr === 47 ?
277 63
278 :
279 0;
280 };
281
282 const photonicBase64DecToArr = (sBase64, nBlocksSize) => {
283 let
284 sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
285 nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2,
286 taBytes = new Uint8Array(nOutLen);
287
288 for (let nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
289 nMod4 = nInIdx & 3;
290 nUint24 |= photonicB64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
291 if (nMod4 === 3 || nInLen - nInIdx === 1) {
292 for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
293 taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
294 }
295 nUint24 = 0;
296
297 }
298 }
299
300 return taBytes;
301 };
302
303 /* Base64 string to array encoding */
304 const photonicUint6ToB64 = (nUint6) => {
305
306 return nUint6 < 26 ?
307 nUint6 + 65
308 : nUint6 < 52 ?
309 nUint6 + 71
310 : nUint6 < 62 ?
311 nUint6 - 4
312 : nUint6 === 62 ?
313 43
314 : nUint6 === 63 ?
315 47
316 :
317 65;
318
319 };
320
321 const photonicBase64EncArr = (aBytes) => {
322 let nMod3 = 2, sB64Enc = "";
323
324 for (let nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
325 nMod3 = nIdx % 3;
326 if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) {
327 sB64Enc += "\r\n";
328 }
329 nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
330 if (nMod3 === 2 || aBytes.length - nIdx === 1) {
331 sB64Enc += String.fromCodePoint(photonicUint6ToB64(nUint24 >>> 18 & 63), photonicUint6ToB64(nUint24 >>> 12 & 63), photonicUint6ToB64(nUint24 >>> 6 & 63), photonicUint6ToB64(nUint24 & 63));
332 nUint24 = 0;
333 }
334 }
335
336 return sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? '' : nMod3 === 1 ? '=' : '==');
337
338 };
339
340 /* UTF-8 array to JS string and vice versa */
341 const photonicUTF8ArrToStr = (aBytes) => {
342 let sView = "";
343
344 for (let nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
345 nPart = aBytes[nIdx];
346 sView += String.fromCodePoint(
347 nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
348 /* (nPart - 252 << 30) may be not so safe in ECMAScript! So…: */
349 (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
350 : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
351 (nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
352 : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
353 (nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
354 : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
355 (nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
356 : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
357 (nPart - 192 << 6) + aBytes[++nIdx] - 128
358 : /* nPart < 127 ? */ /* one byte */
359 nPart
360 );
361 }
362
363 return sView;
364
365 };
366
367 const photonicStrToUTF8Arr = (sDOMStr) => {
368 let aBytes, nChr, nStrLen = sDOMStr.length, nArrLen = 0;
369
370 /* mapping… */
371
372 for (let nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) {
373 nChr = sDOMStr.codePointAt(nMapIdx);
374
375 if (nChr > 65536) {
376 nMapIdx++;
377 }
378
379 nArrLen += nChr < 0x80 ? 1 : nChr < 0x800 ? 2 : nChr < 0x10000 ? 3 : nChr < 0x200000 ? 4 : nChr < 0x4000000 ? 5 : 6;
380 }
381
382 aBytes = new Uint8Array(nArrLen);
383
384 /* transcription… */
385
386 for (let nIdx = 0, nChrIdx = 0; nIdx < nArrLen; nChrIdx++) {
387 nChr = sDOMStr.codePointAt(nChrIdx);
388 if (nChr < 128) {
389 /* one byte */
390 aBytes[nIdx++] = nChr;
391 }
392 else if (nChr < 0x800) {
393 /* two bytes */
394 aBytes[nIdx++] = 192 + (nChr >>> 6);
395 aBytes[nIdx++] = 128 + (nChr & 63);
396 }
397 else if (nChr < 0x10000) {
398 /* three bytes */
399 aBytes[nIdx++] = 224 + (nChr >>> 12);
400 aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
401 aBytes[nIdx++] = 128 + (nChr & 63);
402 }
403 else if (nChr < 0x200000) {
404 /* four bytes */
405 aBytes[nIdx++] = 240 + (nChr >>> 18);
406 aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
407 aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
408 aBytes[nIdx++] = 128 + (nChr & 63);
409 nChrIdx++;
410 }
411 else if (nChr < 0x4000000) {
412 /* five bytes */
413 aBytes[nIdx++] = 248 + (nChr >>> 24);
414 aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
415 aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
416 aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
417 aBytes[nIdx++] = 128 + (nChr & 63);
418 nChrIdx++;
419 }
420 else /* if (nChr <= 0x7fffffff) */ {
421 /* six bytes */
422 aBytes[nIdx++] = 252 + (nChr >>> 30);
423 aBytes[nIdx++] = 128 + (nChr >>> 24 & 63);
424 aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
425 aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
426 aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
427 aBytes[nIdx++] = 128 + (nChr & 63);
428 nChrIdx++;
429 }
430 }
431
432 return aBytes;
433
434 };
435
436 const wizardLogic = (screen) => {
437 const existing = document.querySelector('input[name="photonic-editor-shortcode"]').getAttribute('value');
438 const existingBlock = document.querySelector('input[name="photonic-editor-json"]').getAttribute('value');
439
440 if (screen === 1) {
441 if (existing === undefined || existing === null || existing === '') {
442 let shortcode = photonicShortcodeObjectEditor, attributes, type;
443
444 if (isEditor || isWidget || isMCE) {
445 if (typeof shortcode !== 'undefined' && shortcode !== null) {
446 let scParameter = photonicBase64EncArr(photonicStrToUTF8Arr(JSON.stringify(shortcode))); // To handle unicode in "more"; see https://developer.mozilla.org/en-US/docs/Glossary/Base64#solution_1_%E2%80%93_escaping_the_string_before_encoding_it
447 scParameter = scParameter.replace(/\n/g, '');
448 scParameter = scParameter.replace(/^=+|=+$/g, '');
449 attributes = shortcode.shortcode.attrs.named;
450 if (attributes['type'] !== undefined && photonicPermittedGalleries.indexOf(attributes['type']) !== -1) {
451 type = attributes['type'];
452 }
453 else if ((attributes['type'] === undefined && Photonic_Wizard_JS.shortcode !== 'gallery') || attributes['style'] !== undefined) {
454 type = 'wp';
455 }
456
457 if (type !== undefined) {
458 if (type === 'google') {
459 document.querySelector('.photonic-editor-info').innerHTML = '<div>' + Photonic_Wizard_JS.info_editor_google_shortcode + '</div>';
460 }
461 else {
462 document.querySelector('[name="photonic-editor-shortcode-raw"]').value = scParameter;
463 document.querySelector('[name="photonic-editor-shortcode"]').value = photonicParentShortcode;
464 document.querySelector('[data-photonic-selection-id="' + type + '"]').click();
465 document.querySelector('.photonic-editor-info').innerHTML = '';
466 }
467 }
468 else {
469 document.querySelector('.photonic-editor-info').innerHTML = '<div>' + Photonic_Wizard_JS.info_editor_not_shortcode + '</div>';
470 }
471 }
472 else if (photonicParentSelectionError !== undefined) {
473 document.querySelector('.photonic-editor-info').innerHTML = '<div>' + Photonic_Wizard_JS.info_editor_not_shortcode + '</div>';
474 }
475 }
476 else if (isBlock) { // Gutenberg
477 document.querySelector('[name="photonic-gutenberg-active"]').value = 1;
478
479 if (photonicParentShortcode !== undefined && photonicParentShortcode !== '') {
480 shortcode = photonicParentShortcode;
481 attributes = JSON.parse(shortcode);
482
483 if (attributes.type !== undefined && photonicPermittedGalleries.indexOf(attributes.type) !== -1) {
484 type = attributes.type;
485 }
486 else if (attributes.style !== undefined) {
487 type = 'wp';
488 }
489
490 if (type !== undefined) {
491 document.querySelector('[name="photonic-editor-json"]').value = shortcode;
492 document.querySelector('[data-photonic-selection-id="' + type + '"]').click();
493 document.querySelector('.photonic-editor-info').replaceChildren();
494 }
495 }
496 else {
497 document.querySelector('.photonic-editor-info').innerHTML = '<div>' + Photonic_Wizard_JS.info_editor_block_select + '</div>';
498 }
499 }
500 }
501 setWaitingVisibility(false);
502 }
503
504 if (screen === 6) {
505 if ((existing === undefined || existing === '') && (existingBlock === undefined || existingBlock === '')) {
506 document.getElementById('photonic-nav-next').innerHTML = Photonic_Wizard_JS.insert_gallery;
507 }
508 else {
509 document.getElementById('photonic-nav-next').innerHTML = Photonic_Wizard_JS.update_gallery;
510 }
511 }
512 else {
513 document.getElementById('photonic-nav-next').innerHTML = 'Next';
514 }
515
516 document.querySelectorAll('.photonic-flow-screen').forEach(screen => {
517 screen.style.display = 'none';
518 });
519
520 const activeScreen = document.querySelector('.photonic-flow-screen[data-screen="' + screen + '"]');
521 const fieldSequences = activeScreen.querySelectorAll('.photonic-flow-field[data-photonic-flow-sequence="1"]');
522 const displayType = activeScreen.querySelector('select[name="display_type"]');
523 const popupType = activeScreen.querySelector('select[name="popup"]');
524
525 fieldSequences.forEach(fieldSequence => {
526 const group = fieldSequence.getAttribute('data-photonic-flow-sequence-group');
527
528 document.querySelectorAll('.photonic-flow-field[data-photonic-flow-sequence-group="' + group + '"]').forEach((fieldContainer, idx) => {
529 let field = fieldContainer.querySelector('input, select');
530 let isRadio = false;
531
532 const fieldName = field.getAttribute('name');
533 let fieldSelection = document.querySelector('input[type="radio"][name="' + fieldName + '"]:checked') || document.querySelector('input[type="text"][name="' + fieldName + '"], select[name="' + fieldName + '"]');
534 const fieldValue = fieldSelection ? fieldSelection.value : undefined;
535
536 if (idx !== 0 && (fieldValue === '' || fieldValue === undefined)) {
537 fieldContainer.style.display = 'none';
538 }
539
540 // This has to happen after "fieldValue" is set
541 if (field.tagName === 'INPUT' && field.type === 'radio') {
542 field = field.closest('.photonic-flow-field-radio-group');
543 isRadio = true;
544 }
545
546
547 const siblings = fieldContainer.parentNode.children;
548 let sequence = parseInt(fieldContainer.getAttribute('data-photonic-flow-sequence'), 10);
549
550 field.addEventListener('change', () => {
551 if (isRadio) {
552 fieldSelection = document.querySelector('input[type="radio"][name="' + fieldName + '"]:checked');
553 }
554 const error = document.querySelector('.photonic-flow-error');
555 if (error) {
556 error.style.display = 'none';
557 }
558
559 if ((!isRadio && field.value !== '') || (isRadio && fieldSelection && fieldSelection.value !== undefined)) {
560 Array.from(siblings).forEach(sibling => {
561 let currSequence = parseInt(sibling.getAttribute('data-photonic-flow-sequence'), 10);
562 if (currSequence > sequence) {
563 if (sibling.getAttribute('data-photonic-condition')) {
564 const conditionMet = checkCondition(JSON.parse(sibling.getAttribute('data-photonic-condition')));
565 sibling.style.display = conditionMet ? 'block' : 'none';
566 }
567 else {
568 fadeIn(sibling);
569 }
570 showConditionalFieldValues(sibling);
571 }
572 });
573 }
574 else {
575 Array.from(siblings).forEach(sibling => {
576 let currSequence = parseInt(sibling.getAttribute('data-photonic-flow-sequence'), 10);
577 if (currSequence > sequence) {
578 fadeOut(sibling);
579 }
580 });
581 }
582 });
583 });
584 });
585
586 activeScreen.querySelectorAll('[data-photonic-condition] input, [data-photonic-condition] select').forEach(input => {
587 const fieldContainer = input.closest('.photonic-flow-field');
588 const sequences = input.closest('[data-photonic-flow-sequence]');
589 if (fieldContainer && !sequences) {
590 if (fieldContainer.getAttribute('data-photonic-condition') && fieldContainer.getAttribute('data-photonic-condition') !== '') {
591 const conditionMet = checkCondition(fieldContainer.getAttribute('data-photonic-condition'));
592 fieldContainer.style.display = conditionMet ? 'block' : 'none';
593 }
594 }
595 });
596
597 if (screen === 2) {
598 // One exception to the above ...
599 if (displayType && displayType.value !== '') {
600 const fieldContainer = document.querySelector('[name="for"]') ? document.querySelector('[name="for"]').closest('.photonic-flow-field') : undefined;
601 if (fieldContainer) {
602 showConditionalFieldValues(fieldContainer);
603 fadeIn(fieldContainer);
604 }
605 }
606 }
607 else if (screen === 5) {
608 // ... And another exception
609 if (popupType && popupType.value !== '' && popupType.value !== 'hide') {
610 const managedFields = document.querySelectorAll('[name="photo_count"], [name="photo_more"], [name="photo_layout"]');
611 managedFields.forEach(managedField => {
612 const fieldContainer = managedField.closest('.photonic-flow-field');
613 showConditionalFieldValues(fieldContainer);
614 fadeIn(fieldContainer);
615 });
616 }
617 }
618
619 activeScreen.style.display = 'block';
620 if (screen === 1) {
621 document.querySelector('.photonic-flow-navigation a.previous').classList.add('disabled');
622 }
623 else {
624 document.querySelector('.photonic-flow-navigation a.previous').classList.remove('disabled');
625 }
626 };
627
628 function fadeIn(el) {
629 if (!el.classList.contains('fade-in')) {
630 el.style.display = 'block';
631 el.style.visibility = 'visible';
632 el.classList.add('fade-in');
633 }
634 }
635
636 function fadeOut(el, duration) {
637 let s = el.style,
638 step = 25 / (duration || 500);
639 s.opacity = s.opacity || 1;
640 (function fade() {
641 s.opacity -= step;
642 if (s.opacity < 0) {
643 s.display = "none";
644 el.classList.remove('fade-in');
645 }
646 else {
647 setTimeout(fade, 25);
648 }
649 })();
650 }
651
652 function setWaitingVisibility(visible) {
653 const waiting = document.querySelector('.photonic-waiting');
654 waiting.style.display = visible ? 'block' : 'none';
655 }
656
657 document.querySelector('.photonic-flow-navigation a.disabled').addEventListener('click', (e) => {
658 e.preventDefault();
659 });
660
661 document.addEventListener('click', e => {
662 if (!(e.target instanceof Element) || !e.target.closest('.photonic-flow-navigation a')) {
663 return;
664 }
665
666 let clicked = e.target.closest('.photonic-flow-navigation a');
667 if (!clicked.classList.contains('disabled')) {
668 e.preventDefault();
669 setWaitingVisibility(true);
670 let activeScreen;
671 let flowScreens = document.querySelectorAll('.photonic-flow-screen');
672 flowScreens.forEach(f => {
673 if (f.checkVisibility()) {
674 activeScreen = parseInt(f.getAttribute('data-screen'), 10);
675 }
676 });
677
678 let nextScreen = activeScreen + 1;
679 let previousScreen = activeScreen - 1;
680
681 const form = document.getElementById('photonic-flow');
682 const formData = new FormData(form);
683 let formParameters = new URLSearchParams(formData).toString();
684
685 const activeScreenElement = document.querySelector('.photonic-flow-screen[data-screen="' + activeScreen + '"]');
686 if (clicked.classList.contains('next')) {
687 let shortcode = activeScreenElement.querySelector('#photonic_shortcode');
688 let submission = activeScreenElement.getAttribute('data-submitted');
689
690 let screenFormFields = new FormData();
691 activeScreenElement.querySelectorAll('input, select').forEach(input => {
692 // Only serialize fields with names that aren't disabled
693 if (input.name && !input.disabled) {
694 // Handle checkboxes and radios only if checked
695 if (['checkbox', 'radio'].includes(input.type)) {
696 if (input.checked) {
697 screenFormFields.append(input.name, input.value);
698 }
699 }
700 else {
701 screenFormFields.append(input.name, input.value);
702 }
703 }
704 });
705 let screenParameters = new URLSearchParams(screenFormFields).toString();
706
707 formParameters += ((formParameters === '') ? '' : '&') + 'action=photonic_wizard_next_screen&screen=' + activeScreen + '&_ajax_nonce=' + clicked.getAttribute('data-photonic-nonce');
708
709 // Make AJAX call if we are on the last screen, or if the current screen's parameters have changed since the last time.
710 // Otherwise just get the previously fetched screen. This saves a server call, and also helps preserve screen changes not sent to the back-end.
711 if (shortcode) {
712 if (isMCE) { // TinyMCE Editor
713 photonicIFramePort.postMessage({type: 'photonicUpdateGallery', html: shortcode.textContent});
714 }
715 else if (isBlock) { // Gutenberg
716 photonicIFramePort.postMessage({type: 'photonicUpdateGallery', props: shortcode.value});
717 }
718 else if (isWidget) {
719 photonicIFramePort.postMessage({type: 'photonicUpdateGallery', html: shortcode.textContent});
720 }
721 else {
722 photonicIFramePort.postMessage({type: 'photonicUpdateGallery', html: shortcode.textContent});
723 }
724 }
725 else if (activeScreen === 2
726 && document.querySelector('input[name="provider"]') && document.querySelector('input[name="provider"]').value === 'wp'
727 && document.querySelector('select[name="display_type"]') && document.querySelector('select[name="display_type"]').value === 'multi-photo') {
728 initializeWPMediaLibrary(activeScreen, nextScreen, activeScreenElement, screenParameters, clicked);
729 photonicIFramePort.postMessage({type: 'photonicOpenMediaLibrary'});
730 setWaitingVisibility(false);
731 }
732 else if (activeScreen === photonicLastActiveScreen || submission !== screenParameters || photonicMustPost) {
733 postFlowData(activeScreen, nextScreen, activeScreenElement, screenParameters, formParameters);
734 }
735 else {
736 wizardLogic(nextScreen);
737 setWaitingVisibility(false);
738 }
739 }
740 else if (clicked.classList.contains('previous')) {
741 let forceScreen = activeScreenElement.querySelector('input[name="force_previous_screen"]');
742 if (forceScreen && parseInt(forceScreen.value, 10) > -1) {
743 previousScreen = parseInt(forceScreen.value, 10);
744 }
745
746 wizardLogic(previousScreen);
747 setWaitingVisibility(false);
748 }
749 }
750 });
751
752 document.addEventListener('click', e => {
753 if (!(e.target instanceof Element) || !e.target.closest('.photonic-gallery a')) {
754 return;
755 }
756 e.preventDefault();
757 document.querySelectorAll('.photonic-gallery a').forEach(icon => {
758 icon.classList.remove('selected');
759 });
760 const clicked = e.target.closest('.photonic-gallery a');
761 clicked.classList.add('selected');
762 document.getElementById('provider').value = clicked.getAttribute('data-provider');
763 });
764
765 document.addEventListener('click', e => {
766 if (!(e.target instanceof Element) || !e.target.closest('.photonic-flow-selector')) {
767 return;
768 }
769 e.preventDefault();
770
771 const clicked = e.target.closest('.photonic-flow-selector');
772 const container = clicked.closest('.photonic-flow-selector-container');
773 const selectionMode = container.getAttribute('data-photonic-flow-selector-mode');
774
775 if (selectionMode === 'none') {
776 return;
777 }
778 else if (selectionMode === 'single' || selectionMode === 'single-no-plus') {
779 container.querySelectorAll('.photonic-flow-selector').forEach(selector => {
780 selector.classList.remove('selected');
781 });
782 container.querySelectorAll('.photonic-flow-selector .dashicons').forEach(selector => {
783 selector.remove();
784 });
785
786 if (container.getAttribute('data-photonic-flow-selector-for') === 'selected_data') {
787 const selectionPassworded = document.querySelector('input[name="selection_passworded"]');
788
789 if (clicked.classList.contains('passworded')) {
790 if (selectionPassworded.value === '') {
791 photonicMustPost = true;
792 }
793 selectionPassworded.value = '1';
794 }
795 else {
796 if (selectionPassworded.value === '1' || selectionPassworded.value === 1) {
797 photonicMustPost = true;
798 }
799 selectionPassworded.value = '';
800 }
801 }
802 }
803
804 if (selectionMode === 'multi') {
805 clicked.classList.add('selected');
806 addDashIcon(clicked);
807 }
808 else if (selectionMode === 'single-no-plus' || selectionMode === 'single') {
809 clicked.classList.add('selected');
810 }
811 updateSelection(clicked);
812 });
813
814 function addDashIcon(thumbnail) {
815 const icon = document.createElement("a");
816 icon.classList.add('dashicons', 'dashicons-plus');
817 icon.href = '#';
818 thumbnail.append(icon);
819 icon.addEventListener('click', ie => { // For some reason, doing this on document.addEventListener is unable to remove the dashicons.
820 ie.preventDefault();
821 ie.stopPropagation();
822 thumbnail.classList.remove('selected');
823 icon.remove();
824 updateSelection(thumbnail);
825 });
826
827 ['mouseenter', 'mouseleave'].forEach(eventType => {
828 icon.addEventListener(eventType, me => {
829 me.preventDefault();
830 me.stopPropagation();
831 icon.classList.toggle('dashicons-plus');
832 icon.classList.toggle('dashicons-minus');
833 });
834 });
835 }
836
837 document.addEventListener('click', e => {
838 if (!(e.target instanceof Element) || !e.target.closest('.photonic-mark')) {
839 return;
840 }
841 e.preventDefault();
842 const clicked = e.target.closest('.photonic-mark');
843 const markFor = clicked.getAttribute('data-photonic-mark-for');
844 const thumbnails = document.querySelectorAll('.photonic-flow-selector-container[data-photonic-flow-selector-for="' + markFor + '"] .photonic-flow-selector');
845 let selection = '';
846 thumbnails.forEach(thumbnail => {
847 if (clicked.classList.contains('photonic-mark-all') && !thumbnail.classList.contains('selected')) {
848 thumbnail.classList.add('selected');
849 addDashIcon(thumbnail);
850 selection += thumbnail.querySelector('.photonic-flow-selector-inner').getAttribute('data-photonic-selection-id') + ',';
851 }
852 else if (clicked.classList.contains('photonic-mark-none')) {
853 thumbnail.classList.remove('selected');
854 if (thumbnail.querySelector('.dashicons')) {
855 thumbnail.querySelector('.dashicons').remove();
856 }
857 }
858 });
859 if (selection !== '') {
860 selection = selection.replace(/^,+|,+$/g, '');
861 }
862 document.querySelector('input[name="' + markFor + '"]').value = selection;
863 });
864
865 document.addEventListener('click', e => {
866 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-add-date-filter')) {
867 return;
868 }
869 e.preventDefault();
870 const clicked = e.target.closest('a.photonic-add-date-filter');
871
872 const dateFilterField = clicked.getAttribute('data-photonic-add-date');
873 const list = document.querySelector('ol[data-photonic-date-filter="' + dateFilterField + '"]');
874 const dateFilterCount = parseInt(list.getAttribute('data-photonic-filter-count'), 10);
875 const currentCount = list.children.length;
876 const listItem = document.createElement("li");
877 const div = document.createElement('div');
878 div.classList.add('photonic-single-date');
879 const parts = ['Year', 'Month', 'Date'];
880 const texts = ['Year (0 - 9999)', 'Month (0 - 12)', 'Date (0 - 31)'];
881 parts.forEach((part, j) => {
882 div.insertAdjacentHTML('beforeend',
883 "<label class='photonic-date-filter'>" +
884 part.substring(0, 1) +
885 "<input type='text' class='photonic-date-" + part.toLowerCase() + "' name='" + dateFilterField + "_" + part.toLowerCase() + "[]' aria-describedby='date_filter_" + dateFilterField + "_" + currentCount + "_" + part.toLowerCase() + "-hint'/>" +
886 "<div class='photonic-flow-hint' role='tooltip' id='date_filter_" + dateFilterField + "_" + currentCount + "_" + part.toLowerCase() + "-hint'>" + texts[j] + "</div>" +
887 "</label>"
888 );
889 });
890 listItem.append(div);
891 listItem.insertAdjacentHTML('beforeend', "<a href='#' class='photonic-remove-date-filter' title='Remove filter'><span class=\"dashicons dashicons-no\"> </span></a>");
892 list.append(listItem);
893 if (list.children.length === dateFilterCount) {
894 clicked.style.display = 'none';
895 }
896 });
897
898 document.addEventListener('click', e => {
899 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-add-date-range-filter')) {
900 return;
901 }
902 e.preventDefault();
903 const clicked = e.target.closest('a.photonic-add-date-range-filter');
904
905 const dateFilterField = clicked.getAttribute('data-photonic-add-date-range');
906 const list = document.querySelector('ol[data-photonic-date-range-filter="' + dateFilterField + '"]');
907 const dateFilterCount = parseInt(list.getAttribute('data-photonic-filter-count'), 10);
908 const currentCount = list.children.length;
909 const listItem = document.createElement('li');
910 const parts = ['Year', 'Month', 'Date'];
911 const range_parts = ['start', 'finish'];
912 const texts = ['Year (0 - 9999)', 'Month (0 - 12)', 'Date (0 - 31)'];
913
914 range_parts.forEach(range_part => {
915 const div = document.createElement('div');
916 div.classList.add('photonic-single-date');
917 parts.forEach((part, counter) => {
918 div.insertAdjacentHTML('beforeend',
919 "<label class='photonic-date-filter'>" +
920 part.substr(0, 1) +
921 "<input type='text' class='photonic-date-" + part.toLowerCase() + "' name='" + dateFilterField + "_" + range_part + "_" + part.toLowerCase() + "[]' aria-describedby='date_range_filter_" + dateFilterField + "_" + currentCount + "_" + range_part + "_" + part.toLowerCase() + "-hint'/>" +
922 "<div class='photonic-flow-hint' role='tooltip' id='date_range_filter_" + dateFilterField + "_" + currentCount + "_" + range_part + "_" + part.toLowerCase() + "-hint'>" + texts[counter] + "</div>" +
923 "</label>"
924 );
925 });
926 listItem.append(div);
927 });
928
929 listItem.insertAdjacentHTML('beforeend', "<a href='#' class='photonic-remove-date-range-filter' title='Remove filter'><span class=\"dashicons dashicons-no\"> </span></a>");
930 list.append(listItem);
931 if (list.children.length === dateFilterCount) {
932 clicked.style.display = 'none';
933 }
934 });
935
936 document.addEventListener('click', e => {
937 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-remove-date-filter')) {
938 return;
939 }
940 e.preventDefault();
941 const clicked = e.target.closest('a.photonic-remove-date-filter');
942
943 const listItem = clicked.closest('li');
944 const list = listItem.parentElement;
945 const dateFilterField = list.getAttribute('data-photonic-date-filter');
946 const dateFilterCount = parseInt(list.getAttribute('data-photonic-filter-count'), 10);
947 let addButton = document.querySelector("a[data-photonic-add-date='" + dateFilterField + "']");
948 if (!addButton) {
949 addButton = document.createElement('a');
950 addButton.setAttribute('href', '#');
951 addButton.setAttribute('data-photonic-add-date', dateFilterField);
952 addButton.classList.add('photonic-add-date-filter');
953 addButton.insertAdjacentHTML('beforeend', "<span class=\"dashicons dashicons-plus-alt\"> </span> Add filter");
954
955 list.after(addButton);
956 addButton.style.display = 'none';
957 }
958 listItem.remove();
959 if (list.children.length < dateFilterCount) {
960 addButton.style.display = 'block';
961 }
962 });
963
964 document.addEventListener('click', e => {
965 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-remove-date-range-filter')) {
966 return;
967 }
968 e.preventDefault();
969 const clicked = e.target.closest('a.photonic-remove-date-range-filter');
970 const listItem = clicked.closest('li');
971 const list = listItem.parentElement;
972 const dateFilterField = list.getAttribute('data-photonic-date-range-filter');
973 const dateFilterCount = parseInt(list.getAttribute('data-photonic-filter-count'), 10);
974
975 let addButton = document.querySelector("a[data-photonic-add-date-range='" + dateFilterField + "']");
976 if (!addButton) {
977 addButton = document.createElement('a');
978 addButton.setAttribute('href', '#');
979 addButton.setAttribute('data-photonic-add-date-range', dateFilterField);
980 addButton.classList.add('photonic-add-date-range-filter');
981 addButton.insertAdjacentHTML('beforeend', "<span class=\"dashicons dashicons-plus-alt\"> </span> Add filter");
982
983 list.after(addButton);
984 addButton.style.display = 'none';
985 }
986
987 listItem.remove();
988 if (list.children.length < dateFilterCount) {
989 addButton.style.display = 'block';
990 }
991 });
992
993 document.addEventListener('change', e => {
994 if (!(e.target instanceof Element) || !e.target.closest('input[class^=photonic-date-]')) {
995 return;
996 }
997 e.preventDefault();
998 const changed = e.target.closest('input[class^=photonic-date-]');
999 const container = changed.closest('ol');
1000 if (container) {
1001 const range = container.getAttribute('data-photonic-date-range-filter') !== undefined;
1002 const dates = container.children;
1003 let listMerge = [];
1004
1005 dates.forEach(date => {
1006 let itemMerge = [];
1007 const dateFields = date.querySelectorAll('input');
1008 if (dateFields.length > 0) {
1009 itemMerge[itemMerge.length] = [];
1010 }
1011 if (dateFields.length > 3) {
1012 itemMerge[itemMerge.length] = [];
1013 }
1014 dateFields.forEach((d, i) => {
1015 const mod = Math.floor(i / 3);
1016 const div = i % 3;
1017 itemMerge[mod][div] = d.value === '' ? 0 : d.value;
1018 });
1019 itemMerge.forEach((d, i) => {
1020 itemMerge[i] = d.join('/');
1021 });
1022 listMerge.push(itemMerge.join('-'));
1023 });
1024 listMerge = listMerge.join();
1025 if (range) {
1026 document.querySelector('input[name="' + container.getAttribute('data-photonic-date-range-filter') + '"]').value = listMerge;
1027 }
1028 else {
1029 document.querySelector('input[name="' + container.getAttribute('data-photonic-date-filter') + '"]').value = listMerge;
1030 }
1031 }
1032 });
1033
1034 document.addEventListener('click', e => {
1035 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-flow-more')) {
1036 return;
1037 }
1038 e.preventDefault();
1039
1040 const clicked = e.target.closest('a.photonic-flow-more');
1041 const container = clicked.closest('.photonic-flow-selector-container');
1042 const link = clicked.getAttribute('data-photonic-more-link');
1043 const existing = document.querySelector('input[name="photonic-editor-shortcode"]') ? document.querySelector('input[name="photonic-editor-shortcode"]').value : undefined;
1044 const existingBlock = document.querySelector('input[name="photonic-editor-json"]') ? document.querySelector('input[name="photonic-editor-json"]').value : undefined;
1045
1046 let shortcode, attributes, albumFilter;
1047
1048 if (existing && !isBlock) {
1049 if (photonicShortcodeObjectEditor !== undefined) {
1050 attributes = photonicShortcodeObjectEditor.shortcode.attrs.named;
1051 if (attributes['filter']) {
1052 albumFilter = attributes['filter'];
1053 }
1054 }
1055 }
1056 else if (existingBlock && isBlock) { // Gutenberg
1057 if (photonicParentShortcode !== undefined && photonicParentShortcode !== '') {
1058 shortcode = photonicParentShortcode;
1059 attributes = JSON.parse(shortcode);
1060
1061 if (attributes.filter !== undefined) {
1062 albumFilter = attributes.filter;
1063 }
1064 }
1065 }
1066
1067 if (link !== undefined && link !== '') {
1068 setWaitingVisibility(true);
1069 let parameters = [];
1070 parameters['action'] = 'photonic_wizard_more';
1071 parameters['provider'] = clicked.getAttribute('data-photonic-provider');
1072 parameters['display_type'] = clicked.getAttribute('data-photonic-display-type');
1073 parameters['url'] = encodeURIComponent(clicked.getAttribute('data-photonic-more-link'));
1074
1075 if (albumFilter) {
1076 albumFilter = '&filter=' + albumFilter;
1077 }
1078 else {
1079 albumFilter = '';
1080 }
1081 parameters = 'action=photonic_wizard_more&provider=' + clicked.getAttribute('data-photonic-provider') + '&display_type=' + clicked.getAttribute('data-photonic-display-type') + '&url=' +
1082 btoa(clicked.getAttribute('data-photonic-more-link')) + albumFilter + '&_ajax_nonce=' + clicked.getAttribute('data-photonic-nonce');
1083
1084 post(Photonic_Wizard_JS.ajaxurl, parameters, function (data) {
1085 clicked.style.display = 'none';
1086 if (clicked.closest('.photonic-more-wrapper')) {
1087 clicked.closest('.photonic-more-wrapper').remove();
1088 }
1089 const currentSelectors = container.querySelectorAll('.photonic-flow-selector');
1090 const lastItem = currentSelectors.item(currentSelectors.length - 1);
1091
1092 if (lastItem) {
1093 lastItem.insertAdjacentHTML('afterend', data);
1094 }
1095
1096 const search = document.getElementById('thumb-search');
1097 search.focus();
1098 search.blur();
1099
1100 updateSelection(document.querySelector('.photonic-flow-selector:last-child'));
1101
1102 setWaitingVisibility(false);
1103 });
1104 }
1105 });
1106
1107 document.addEventListener('mouseover', e => {
1108 if (!(e.target instanceof Element) || !e.target.closest('input, select')) {
1109 return;
1110 }
1111 e.stopPropagation();
1112 const item = e.target;
1113 const tooltip = document.querySelector('#' + item.getAttribute('aria-describedby'));
1114 if (tooltip) {
1115 tooltip.setAttribute('aria-hidden', false);
1116 tooltip.style.display = 'block';
1117 fadeIn(tooltip);
1118 }
1119 });
1120
1121 document.addEventListener('mouseout', e => {
1122 if (!(e.target instanceof Element) || !e.target.closest('input, select, .photonic-flow-hint')) {
1123 return;
1124 }
1125 e.stopPropagation();
1126 const item = e.target;
1127 const tooltipId = item.classList.contains('photonic-flow-hint') ? item.getAttribute('id') : '#' + item.getAttribute('aria-describedby');
1128 const tooltip = document.querySelector(tooltipId);
1129 if (tooltip && !document.querySelector(tooltipId + ':hover')) {
1130 tooltip.setAttribute('aria-hidden', true);
1131 tooltip.style.display = 'none';
1132 }
1133 });
1134
1135 document.getElementById('photonic-flow').addEventListener('focusin', e => {
1136 if (!e.target.matches('#thumb-search')) {
1137 return;
1138 }
1139
1140 const search = e.target;
1141 const images = document.querySelectorAll('.photonic-flow-selector-container img');
1142 const cache = [];
1143
1144 images.forEach((image) => {
1145 cache.push({
1146 element: image,
1147 text: image.alt.trim().toLowerCase()
1148 });
1149 });
1150
1151 function filter(e) {
1152 const query = e.target.value.trim().toLowerCase();
1153 cache.forEach(image => {
1154 let index = 0;
1155 if (query) {
1156 index = image.text.indexOf(query);
1157 }
1158 if (index === -1) {
1159 image.element.closest('.photonic-flow-selector').style.display = 'none';
1160 }
1161 else {
1162 image.element.closest('.photonic-flow-selector').style.display = 'inline-block';
1163 }
1164 });
1165 }
1166
1167 search.addEventListener('input', filter);
1168 search.addEventListener('keyup', filter);
1169 });
1170
1171 document.addEventListener('change', e => {
1172 if (!(e.target instanceof Element) || !e.target.matches('[name="selected_data"],[name="selection_passworded"]')) {
1173 return;
1174 }
1175 photonicMustPost = true;
1176 });
1177 }
1178
1179 PhotonicWizard();
1180 });
1181