PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.5.7
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.5.7
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / js / admin / embed.js

embed.js in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 5.5.7, at js/admin/embed.js

506 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function() {
2 /** globals ajaxurl, wp, frmDom */
3
4 if ( 'undefined' === typeof ajaxurl || 'undefined' === typeof wp || 'undefined' === typeof frmDom ) {
5 return;
6 }
7
8 const __ = wp.i18n.__;
9 const { div, tag, svg } = frmDom;
10 const { maybeCreateModal, footerButton } = frmDom.modal;
11
12 let autoId = 0;
13 let modal;
14
15 const state = {
16 type: 'form',
17 objectId: 0,
18 objectKey: ''
19 };
20
21 initEmbedModal();
22
23 function initEmbedModal() {
24 document.addEventListener( 'click', listenForEmbedClick );
25 }
26
27 function listenForEmbedClick( event ) {
28 let clicked = false;
29
30 const element = event.target;
31 const tag = element.tagName.toLowerCase();
32
33 switch ( tag ) {
34 case 'a':
35 clicked = 'frm-embed-action' === element.id || element.classList.contains( 'frm-embed-form' );
36
37 if ( clicked ) {
38 state.type = 'form';
39 } else {
40 clicked = element.classList.contains( 'frm-embed-view' );
41 if ( clicked ) {
42 state.type = 'view';
43 }
44 }
45 break;
46
47 case 'svg':
48 case 'use':
49 clicked = null !== element.closest( '.frm-embed-form' );
50 if ( clicked ) {
51 state.type = 'form';
52 }
53 break;
54 }
55
56 if ( clicked ) {
57 event.preventDefault();
58
59 const hookName = 'frm_before_embed_modal';
60 const initialIds = [ 0, 0 ];
61 const hookArgs = {
62 element,
63 type: state.type
64 };
65 const [ objectId, objectKey ] = wp.hooks.applyFilters( hookName, initialIds, hookArgs );
66
67 if ( objectId && objectKey ) {
68 state.objectId = objectId;
69 state.objectKey = objectKey;
70 openEmbedModal();
71 }
72 }
73 }
74
75 function openEmbedModal() {
76 /* translators: %s type: ie form, view. */
77 const title = __( 'Embed %s', 'formidable' ).replace( '%s', getTypeDescription() );
78
79 modal = maybeCreateModal(
80 'frm_embed_modal',
81 {
82 title,
83 content: getModalOptions(),
84 footer: getModalFooter()
85 }
86 );
87 modal.classList.add( 'frm_common_modal' );
88 modal.classList.remove( 'frm-on-page-2' );
89
90 const $modal = jQuery( modal );
91 offsetModalY( $modal, '50px' );
92 $modal.parent().addClass( 'frm-embed-modal-wrapper' );
93 }
94
95 function getModalFooter() {
96 const doneButton = footerButton({
97 text: __( 'Done', 'formidable' ),
98 buttonType: 'primary'
99 });
100
101 const cancelButton = footerButton({
102 text: __( 'Back', 'formidable' ),
103 buttonType: 'cancel'
104 });
105 cancelButton.addEventListener(
106 'click',
107 function( event ) {
108 event.preventDefault();
109 openEmbedModal();
110 }
111 );
112
113 return div({
114 children: [ doneButton, cancelButton ]
115 });
116 }
117
118 function offsetModalY( $modal, amount ) {
119 const position = {
120 my: 'top',
121 at: 'top+' + amount,
122 of: window
123 };
124 $modal.dialog( 'option', 'position', position );
125 }
126
127 function getModalOptions() {
128 const content = div({ className: 'frm-embed-modal-content frm_wrap' });
129 const typeDescription = getTypeDescription();
130
131 /* translators: %s type: ie form, view. */
132 const existingPageDescription = __( 'Embed your %s into an existing page.', 'formidable' ).replace( '%s', typeDescription );
133
134 /* translators: %s type: ie form, view. */
135 const newPageDescription = __( 'Put your %s on a newly created page.', 'formidable' ).replace( '%s', typeDescription );
136
137 /* translators: %s type: ie form, view. */
138 const insertManuallyDescription = __( 'Use WP shortcodes or PHP code to put the %s in any place.', 'formidable' ).replace( '%s', typeDescription );
139
140 const options = [
141 {
142 icon: '#frm_file_icon',
143 label: __( 'Select existing page', 'formidable' ),
144 description: existingPageDescription,
145 callback: () => {
146 content.innerHTML = '';
147
148 const spinner = tag( 'span' );
149 spinner.className = 'frm-wait frm_spinner';
150 spinner.style.visibility = 'visible';
151 content.appendChild( spinner );
152
153 const gap = div();
154 gap.style.height = '20px';
155 content.appendChild( gap );
156
157 content.classList.add( 'frm-loading-page-options' );
158
159 jQuery.ajax({
160 type: 'POST',
161 url: ajaxurl,
162 data: {
163 action: 'get_page_dropdown',
164 nonce: frmGlobal.nonce
165 },
166 dataType: 'json',
167 success: addExistingPageDropdown
168 });
169
170 function addExistingPageDropdown( response ) {
171 if ( 'object' !== typeof response || 'string' !== typeof response.html ) {
172 return;
173 }
174
175 content.classList.remove( 'frm-loading-page-options' );
176 content.innerHTML = '';
177
178 const typeDescription = getTypeDescription();
179
180 /* translators: %s: type (ie. view, form). */
181 const titleText = __( 'Select the page you want to embed your %s into.', 'formidable' ).replace( '%s', typeDescription );
182
183 const title = getLabel( titleText );
184 title.setAttribute( 'for', 'frm_page_dropdown' );
185 content.appendChild( title );
186
187 let editPageUrl;
188
189 doneButton = modal.querySelector( '.frm_modal_footer .button-primary' );
190 doneButton.classList.remove( 'dismiss' );
191 /* translators: %s: type (ie. view, form). */
192 doneButton.textContent = __( 'Insert %s', 'formidable' ).replace( '%s', typeDescription );
193 doneButton.addEventListener( 'click', redirectToExistingPageWithInjectedShortcode );
194
195 const dropdownWrapper = div();
196 dropdownWrapper.innerHTML = response.html;
197 content.appendChild( dropdownWrapper );
198
199 if ( 'form' === state.type ) {
200 editPageUrl = response.edit_page_url + '&frmForm=' + state.objectId;
201 } else {
202 const hookName = 'frm_embed_edit_page_url';
203 const hookArgs = {
204 objectId: state.objectId,
205 type: state.type
206 };
207 editPageUrl = wp.hooks.applyFilters( hookName, response.edit_page_url, hookArgs );
208 }
209
210 frmDom.autocomplete.initAutocomplete( 'page', dropdownWrapper );
211
212 function redirectToExistingPageWithInjectedShortcode( event ) {
213 event.preventDefault();
214
215 const pageDropdown = modal.querySelector( '[name="frm_page_dropdown"]' );
216 modal.querySelectorAll( '.frm_error_style' ).forEach( error => error.remove() );
217
218 const pageId = pageDropdown.value;
219
220 if ( '0' === pageId || '' === pageId ) {
221 const error = div({ className: 'frm_error_style' });
222 error.setAttribute( 'role', 'alert' );
223 error.textContent = __( 'Please select a page', 'formidable' );
224 content.insertBefore( error, title.nextElementSibling );
225 return;
226 }
227
228 window.location.href = editPageUrl.replace( 'post=0', 'post=' + pageId );
229 }
230 }
231 }
232 },
233 {
234 icon: '#frm_plus_icon',
235 label: __( 'Create new page', 'formidable' ),
236 description: newPageDescription,
237 callback: () => {
238 content.innerHTML = '';
239
240 const wrapper = div({ className: 'field-group' });
241 const form = tag( 'form' );
242
243 const createPageWithShortcode = () => {
244 const hookName = 'frm_create_page_with_shortcode_data';
245 const data = wp.hooks.applyFilters(
246 hookName,
247 {
248 action: 'frm_create_page_with_shortcode',
249 object_id: state.objectId,
250 type: state.type,
251 name: input.value,
252 nonce: frmGlobal.nonce
253 }
254 );
255 jQuery.ajax({
256 type: 'POST',
257 url: ajaxurl,
258 data,
259 dataType: 'json',
260 success: function( response ) {
261 if ( 'object' === typeof response && 'string' === typeof response.redirect ) {
262 window.location.href = response.redirect;
263 }
264 }
265 });
266 };
267
268 form.addEventListener(
269 'submit',
270 function( event ) {
271 event.preventDefault();
272 createPageWithShortcode();
273 return false;
274 },
275 true
276 );
277
278 const title = getLabel( __( 'What will you call the new page?', 'formidable' ) );
279 title.setAttribute( 'for', 'frm_name_your_page' );
280 form.appendChild( title );
281
282 const input = tag( 'input' );
283 input.id = 'frm_name_your_page';
284 input.placeholder = __( 'Name your page', 'formidable' );
285 form.appendChild( input );
286
287 wrapper.appendChild( form );
288 content.appendChild( wrapper );
289
290 input.type = 'text';
291 input.focus();
292
293 doneButton = modal.querySelector( '.frm_modal_footer .button-primary' );
294 doneButton.textContent = __( 'Create page', 'formidable' );
295 doneButton.addEventListener(
296 'click',
297 function( event ) {
298 event.preventDefault();
299 createPageWithShortcode();
300 }
301 );
302 }
303 },
304 {
305 icon: '#frm_code_icon',
306 label: __( 'Insert manually', 'formidable' ),
307 description: insertManuallyDescription,
308 callback: () => {
309 content.innerHTML = '';
310
311 if ( 'form' === state.type ) {
312 getEmbedFormManualExamples().forEach( example => content.appendChild( getEmbedExample( example ) ) );
313 } else {
314 const hookName = 'frm_embed_examples';
315 const hookArgs = {
316 type: state.type,
317 objectId: state.objectId,
318 objectKey: state.objectKey
319 };
320 wp.hooks.applyFilters( hookName, [], hookArgs ).forEach(
321 example => content.appendChild( getEmbedExample( example ) )
322 );
323 }
324 }
325 }
326 ];
327
328 options.forEach(
329 option => content.appendChild( getModalOption( option ) )
330 );
331
332 return content;
333 }
334
335 function getTypeDescription() {
336 switch ( state.type ) {
337 case 'view':
338 return __( 'view', 'formidable' );
339 case 'form':
340 default:
341 return __( 'form', 'formidable' );
342 }
343 }
344
345 function getModalOption({ icon, label, description, callback }) {
346 const output = div();
347 output.appendChild( wrapModalOptionIcon( icon ) );
348 output.className = 'frm-embed-modal-option';
349 output.setAttribute( 'tabindex', 0 );
350 output.setAttribute( 'role', 'button' );
351
352 const textWrapper = div();
353 textWrapper.appendChild( getLabel( label ) );
354 textWrapper.appendChild( div( description ) );
355 output.appendChild( textWrapper );
356
357 output.addEventListener(
358 'click',
359 function() {
360 modal.classList.add( 'frm-on-page-2' );
361 callback();
362 }
363 );
364 return output;
365 }
366
367 function wrapModalOptionIcon( iconHref ) {
368 return div({
369 className: 'frm-embed-modal-icon-wrapper',
370 child: svg({ href: iconHref })
371 });
372 }
373
374 function getEmbedFormManualExamples() {
375 const formId = state.objectId;
376 const formKey = state.objectKey;
377
378 let examples = [
379 {
380 label: __( 'WordPress shortcode', 'formidable' ),
381 example: '[formidable id=' + formId + ']',
382 link: 'https://formidableforms.com/knowledgebase/publish-a-form/#kb-insert-the-shortcode-manually',
383 linkLabel: __( 'How to use shortcodes in WordPress', 'formidable' )
384 },
385 {
386 label: __( 'Use PHP code', 'formidable' ),
387 example: '<?php echo FrmFormsController::get_form_shortcode( array( \'id\' => ' + formId + ' ) ); ?>'
388 }
389 ];
390
391 const filterArgs = { formId, formKey };
392 examples = wp.hooks.applyFilters( 'frmEmbedFormExamples', examples, filterArgs );
393
394 return examples;
395 }
396
397 function getEmbedExample({ label, example, link, linkLabel }) {
398 let unique, element, labelElement, exampleElement, linkElement;
399
400 unique = getAutoId();
401 element = div();
402
403 labelElement = getLabel( label );
404 labelElement.id = 'frm_embed_example_label_' + unique;
405 element.appendChild( labelElement );
406
407 if ( example.length > 80 ) {
408 exampleElement = tag( 'textarea' );
409 } else {
410 exampleElement = tag( 'input' );
411 exampleElement.type = 'text';
412 }
413
414 exampleElement.id = 'frm_embed_example_' + unique;
415 exampleElement.className = 'frm_embed_example';
416 exampleElement.value = example;
417 exampleElement.readOnly = true;
418 exampleElement.setAttribute( 'tabindex', -1 );
419
420 if ( 'undefined' !== typeof link && 'undefined' !== typeof linkLabel ) {
421 linkElement = tag( 'a' );
422 linkElement.href = link;
423 linkElement.textContent = linkLabel;
424 linkElement.setAttribute( 'target', '_blank' );
425 element.appendChild( linkElement );
426 }
427
428 element.appendChild( exampleElement );
429 element.appendChild( getCopyIcon( label ) );
430
431 return element;
432 }
433
434 function getLabel( text ) {
435 const args = { text };
436 return tag( 'label', args );
437 }
438
439 function getCopyIcon( label ) {
440 const icon = svg({ href: '#frm_clone_icon' });
441 icon.id = 'frm_copy_embed_' + getAutoId();
442 icon.setAttribute( 'tabindex', 0 );
443 icon.setAttribute( 'role', 'button' );
444 /* translators: %s: Example type (ie. WordPress shortcode, API Form script) */
445 icon.setAttribute( 'aria-label', __( 'Copy %s', 'formidable' ).replace( '%s', label ) );
446 icon.addEventListener(
447 'click',
448 () => copyExampleToClipboard( icon.parentNode.querySelector( '.frm_embed_example' ) )
449 );
450 return icon;
451 }
452
453 function copyExampleToClipboard( example ) {
454 if ( navigator.clipboard ) {
455 navigator.clipboard.writeText( example.value ).then( handleCopySuccess );
456 return;
457 }
458
459 let copySuccess;
460
461 example.focus();
462 example.select();
463 example.setSelectionRange( 0, 99999 );
464
465 try {
466 copySuccess = document.execCommand( 'copy' );
467 } catch ( error ) {
468 copySuccess = false;
469 }
470
471 if ( copySuccess ) {
472 handleCopySuccess();
473 }
474
475 return copySuccess;
476 }
477
478 function handleCopySuccess() {
479 speak( __( 'Successfully copied embed example', 'formidable' ) );
480 }
481
482 function speak( message ) {
483 const element = document.createElement( 'div' );
484 const id = 'speak-' + getAutoId();
485
486 element.setAttribute( 'aria-live', 'assertive' );
487 element.setAttribute( 'id', id );
488 element.className = 'frm_screen_reader frm_hidden';
489 element.textContent = message;
490 document.body.appendChild( element );
491
492 setTimeout( () => document.body.removeChild( element ), 1000 );
493 }
494
495 /**
496 * Get a unique id that automatically increments with every function call.
497 * Can be used for any UI that requires a unique id.
498 * Not to be used in data.
499 *
500 * @returns {integer}
501 */
502 function getAutoId() {
503 return ++autoId;
504 }
505 }() );
506