PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.12
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.12
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
← All changes | js/admin/dom.js +185 -198 6.296.12 View file →
@@ -2,9 +2,9 @@
2 2 /** globals frmGlobal */
3 3
4 4 let __;
5 5
6 - if ( 'undefined' === typeof wp || wp.i18n === undefined || 'function' !== typeof wp.i18n.__ ) {
6 + if ( 'undefined' === typeof wp || 'undefined' === typeof wp.i18n || 'function' !== typeof wp.i18n.__ ) {
7 7 __ = text => text;
8 8 } else {
9 9 __ = wp.i18n.__;
10 10 }
@@ -9,17 +9,17 @@
9 9 __ = wp.i18n.__;
10 10 }
11 11
12 12 const modal = {
13 - maybeCreateModal: ( id, { title, content, footer, width, dialogClass } = {} ) => {
13 + maybeCreateModal: ( id, { title, content, footer, width } = {}) => {
14 14 let modal = document.getElementById( id );
15 15
16 16 if ( ! modal ) {
17 17 modal = createEmptyModal( id );
18 18
19 - const titleElement = div( {
19 + const titleElement = div({
20 20 className: 'frm-modal-title'
21 - } );
21 + });
22 22
23 23 if ( 'string' === typeof title ) {
24 24 titleElement.textContent = title;
25 25 }
@@ -26,30 +26,30 @@
26 26
27 27 const a = tag(
28 28 'a',
29 29 {
30 - child: svg( { href: '#frm_close_icon' } ),
30 + child: svg({ href: '#frm_close_icon' }),
31 31 className: 'dismiss'
32 32 }
33 33 );
34 34 const postbox = modal.querySelector( '.postbox' );
35 35
36 - postbox.append(
37 - div( {
36 + postbox.appendChild(
37 + div({
38 38 className: 'frm_modal_top',
39 39 children: [
40 40 titleElement,
41 - div( { child: a } )
41 + div({ child: a })
42 42 ]
43 - } )
43 + })
44 44 );
45 - postbox.append(
46 - div( { className: 'frm_modal_content' } )
45 + postbox.appendChild(
46 + div({ className: 'frm_modal_content' })
47 47 );
48 48
49 49 if ( footer ) {
50 - postbox.append(
51 - div( { className: 'frm_modal_footer' } )
50 + postbox.appendChild(
51 + div({ className: 'frm_modal_footer' })
52 52 );
53 53 }
54 54 } else if ( 'string' === typeof title ) {
55 55 const titleElement = modal.querySelector( '.frm-modal-title' );
@@ -56,9 +56,9 @@
56 56 titleElement.textContent = title;
57 57 }
58 58
59 59 if ( ! content && ! footer ) {
60 - makeModalIntoADialogAndOpen( modal, { width, dialogClass } );
60 + makeModalIntoADialogAndOpen( modal, { width });
61 61 return modal;
62 62 }
63 63
64 64 const postbox = modal.querySelector( '.postbox' );
@@ -71,9 +71,9 @@
71 71 if ( footer ) {
72 72 modalHelper( footer, 'frm_modal_footer' );
73 73 }
74 74
75 - makeModalIntoADialogAndOpen( modal, { width, dialogClass } );
75 + makeModalIntoADialogAndOpen( modal );
76 76 return modal;
77 77 },
78 78 footerButton: args => {
79 79 const output = a( args );
@@ -81,9 +81,9 @@
81 81 output.setAttribute( 'tabindex', 0 );
82 82 if ( args.buttonType ) {
83 83 output.classList.add( 'button' );
84 84
85 - if ( ! args.noDismiss && [ 'red', 'primary' ].includes( args.buttonType ) ) {
85 + if ( ! args.noDismiss && -1 !== [ 'red', 'primary' ].indexOf( args.buttonType ) ) {
86 86 // Primary and red buttons close modals by default on click.
87 87 // To disable this default behaviour you can use the noDismiss: 1 arg.
88 88 output.classList.add( 'dismiss' );
89 89 }
@@ -108,12 +108,12 @@
108 108 }
109 109 };
110 110
111 111 const ajax = {
112 - async doJsonFetch( action ) {
113 - let targetUrl = `${ ajaxurl }?action=frm_${ action }`;
114 - if ( ! targetUrl.includes( 'nonce=' ) ) {
115 - targetUrl += `&nonce=${ frmGlobal.nonce }`;
112 + doJsonFetch: async function( action ) {
113 + let targetUrl = ajaxurl + '?action=frm_' + action;
114 + if ( -1 === targetUrl.indexOf( 'nonce=' ) ) {
115 + targetUrl += '&nonce=' + frmGlobal.nonce;
116 116 }
117 117 const response = await fetch( targetUrl );
118 118 const json = await response.json();
119 119 if ( ! json.success ) {
@@ -120,9 +120,9 @@
120 120 return Promise.reject( json.data || 'JSON result is not successful' );
121 121 }
122 122 return Promise.resolve( json.data );
123 123 },
124 - async doJsonPost( action, formData, { signal } = {} ) {
124 + doJsonPost: async function( action, formData, { signal } = {}) {
125 125 formData.append( 'nonce', frmGlobal.nonce );
126 126 const init = {
127 127 method: 'POST',
128 128 body: formData
@@ -129,32 +129,32 @@
129 129 };
130 130 if ( signal ) {
131 131 init.signal = signal;
132 132 }
133 - const response = await fetch( `${ ajaxurl }?action=frm_${ action }`, init );
134 - const json = await response.json();
133 + const response = await fetch( ajaxurl + '?action=frm_' + action, init );
134 + const json = await response.json();
135 135 if ( ! json.success ) {
136 136 return Promise.reject( json.data || 'JSON result is not successful' );
137 137 }
138 - return Promise.resolve( json.data !== undefined ? json.data : json );
138 + return Promise.resolve( 'undefined' !== typeof json.data ? json.data : json );
139 139 }
140 140 };
141 141
142 142 const multiselect = {
143 - init() {
143 + init: function() {
144 144 const $select = jQuery( this );
145 145 const id = $select.is( '[id]' ) ? $select.attr( 'id' ).replace( '[]', '' ) : false;
146 146
147 - let labelledBy = id ? jQuery( `#for_${ id }` ) : false;
148 - labelledBy = id && labelledBy.length ? `aria-labelledby="${ labelledBy.attr( 'id' ) }"` : '';
147 + let labelledBy = id ? jQuery( '#for_' + id ) : false;
148 + labelledBy = id && labelledBy.length ? 'aria-labelledby="' + labelledBy.attr( 'id' ) + '"' : '';
149 149
150 150 // Set empty title attributes so that none of the dropdown options include title attributes.
151 151 $select.find( 'option' ).attr( 'title', ' ' );
152 - $select.multiselect( {
152 + $select.multiselect({
153 153 templates: {
154 - popupContainer: '<div class="multiselect-container frm-dropdown-menu dropdown-menu"></div>',
154 + popupContainer: '<div class="multiselect-container frm-dropdown-menu"></div>',
155 155 option: '<button type="button" class="multiselect-option dropdown-item frm_no_style_button"></button>',
156 - button: `<button type="button" class="multiselect dropdown-toggle btn" data-bs-toggle="dropdown" ${ labelledBy }><span class="multiselect-selected-text"></span> <b class="caret"></b></button>`
156 + button: '<button type="button" class="multiselect dropdown-toggle btn" data-toggle="dropdown" ' + labelledBy + '><span class="multiselect-selected-text"></span> <b class="caret"></b></button>'
157 157 },
158 158 buttonContainer: '<div class="btn-group frm-btn-group dropdown" />',
159 159 nonSelectedText: __( '— Select —', 'formidable' ),
160 160 // Prevent the dropdown from showing "All Selected" when every option is checked.
@@ -160,12 +160,12 @@
160 160 // Prevent the dropdown from showing "All Selected" when every option is checked.
161 161 allSelectedText: '',
162 162 // This is 3 by default. We want to show more options before it starts showing a count.
163 163 numberDisplayed: 8,
164 - onInitialized( _, $container ) {
164 + onInitialized: function( _, $container ) {
165 165 $container.find( '.multiselect.dropdown-toggle' ).removeAttr( 'title' );
166 166 },
167 - onDropdownShown( event ) {
167 + onDropdownShown: function( event ) {
168 168 const action = jQuery( event.currentTarget.closest( '.frm_form_action_settings, #frm-show-fields' ) );
169 169 if ( action.length ) {
170 170 jQuery( '#wpcontent' ).on( 'click', function() {
171 171 if ( jQuery( '.multiselect-container.frm-dropdown-menu' ).is( ':visible' ) ) {
@@ -170,16 +170,16 @@
170 170 jQuery( '#wpcontent' ).on( 'click', function() {
171 171 if ( jQuery( '.multiselect-container.frm-dropdown-menu' ).is( ':visible' ) ) {
172 172 jQuery( event.currentTarget ).removeClass( 'open' );
173 173 }
174 - } );
174 + });
175 175 }
176 176
177 177 const $dropdown = $select.next( '.frm-btn-group.dropdown' );
178 178 $dropdown.find( '.dropdown-item' ).each(
179 179 function() {
180 - const option = this;
181 - const dropdownInput = option.querySelector( 'input[type="checkbox"], input[type="radio"]' );
180 + const option = this;
181 + const dropdownInput = option.querySelector( 'input[type="checkbox"], input[type="radio"]' );
182 182 if ( dropdownInput ) {
183 183 option.setAttribute( 'role', 'checkbox' );
184 184 option.setAttribute( 'aria-checked', dropdownInput.checked ? 'true' : 'false' );
185 185 }
@@ -185,14 +185,14 @@
185 185 }
186 186 }
187 187 );
188 188 },
189 - onChange( $option, checked ) {
189 + onChange: function( $option, checked ) {
190 190 $select.trigger( 'frm-multiselect-changed', $option, checked );
191 191
192 - const $dropdown = $select.next( '.frm-btn-group.dropdown' );
193 - const optionValue = $option.val();
194 - const $dropdownItem = $dropdown.find( `input[value="${ optionValue }"]` ).closest( 'button.dropdown-item' );
192 + const $dropdown = $select.next( '.frm-btn-group.dropdown' );
193 + const optionValue = $option.val();
194 + const $dropdownItem = $dropdown.find( 'input[value="' + optionValue + '"]' ).closest( 'button.dropdown-item' );
195 195 if ( $dropdownItem.length ) {
196 196 $dropdownItem.attr( 'aria-checked', checked ? 'true' : 'false' );
197 197
198 198 // Delay a focus event so the screen reader reads the option value again.
@@ -199,26 +199,61 @@
199 199 // Without this, and without the setTimeout, it only reads "checked" or "unchecked".
200 200 setTimeout( () => $dropdownItem.get( 0 ).focus(), 0 );
201 201 }
202 202 }
203 - } );
203 + });
204 204 }
205 205 };
206 206
207 207 const bootstrap = {
208 - setupBootstrapDropdowns() {
209 - // This function is no longer necessary.
210 - // It's call in Pro though, so keep it to avoid any errors for now.
208 + setupBootstrapDropdowns( callback ) {
209 + if ( ! window.bootstrap || ! window.bootstrap.Dropdown ) {
210 + return;
211 + }
212 +
213 + window.bootstrap.Dropdown._getParentFromElement = getParentFromElement;
214 + window.bootstrap.Dropdown.prototype._getParentFromElement = getParentFromElement;
215 +
216 + function getParentFromElement( element ) {
217 + let parent;
218 + const selector = window.bootstrap.Util.getSelectorFromElement( element );
219 +
220 + if ( selector ) {
221 + parent = document.querySelector( selector );
222 + }
223 +
224 + const result = parent || element.parentNode;
225 + const frmDropdownMenu = result.querySelector( '.frm-dropdown-menu' );
226 +
227 + if ( ! frmDropdownMenu ) {
228 + // Not a formidable dropdown, treat like Bootstrap does normally.
229 + return result;
230 + }
231 +
232 + // Temporarily add dropdown-menu class so bootstrap can initialize.
233 + frmDropdownMenu.classList.add( 'dropdown-menu' );
234 + setTimeout(
235 + function() {
236 + frmDropdownMenu.classList.remove( 'dropdown-menu' );
237 + },
238 + 0
239 + );
240 +
241 + if ( 'function' === typeof callback ) {
242 + callback( frmDropdownMenu );
243 + }
244 +
245 + return result;
246 + }
211 247 },
212 248 multiselect
213 249 };
214 250
215 251 const autocomplete = {
216 - initSelectionAutocomplete( container ) {
252 + initSelectionAutocomplete: function() {
217 253 if ( jQuery.fn.autocomplete ) {
218 - autocomplete.initAutocomplete( 'page', container );
219 - autocomplete.initAutocomplete( 'user', container );
220 - autocomplete.initAutocomplete( 'custom', container );
254 + autocomplete.initAutocomplete( 'page' );
255 + autocomplete.initAutocomplete( 'user' );
221 256 }
222 257 },
223 258 /**
224 259 * Init autocomplete.
@@ -224,14 +259,14 @@
224 259 * Init autocomplete.
225 260 *
226 261 * @since 4.10.01 Add container param to init autocomplete elements inside an element.
227 262 *
228 - * @param {string} type Type of data. Accepts `page` or `user`.
229 - * @param {string|Object} container Container class or element. Default is null.
263 + * @param {String} type Type of data. Accepts `page` or `user`.
264 + * @param {String|Object} container Container class or element. Default is null.
230 265 */
231 - initAutocomplete( type, container ) {
232 - const basedUrlParams = `?action=frm_${ type }_search&nonce=${ frmGlobal.nonce }`;
233 - const elements = ! container ? jQuery( `.frm-${ type }-search` ) : jQuery( container ).find( `.frm-${ type }-search` );
266 + initAutocomplete: function( type, container ) {
267 + const basedUrlParams = '?action=frm_' + type + '_search&nonce=' + frmGlobal.nonce;
268 + const elements = ! container ? jQuery( '.frm-' + type + '-search' ) : jQuery( container ).find( '.frm-' + type + '-search' );
234 269
235 270 elements.each( initAutocompleteForElement );
236 271
237 272 function initAutocompleteForElement() {
@@ -239,24 +274,15 @@
239 274 const element = jQuery( this );
240 275
241 276 // Check if a custom post type is specific.
242 277 if ( element.attr( 'data-post-type' ) ) {
243 - urlParams += `&post_type=${ element.attr( 'data-post-type' ) }`;
278 + urlParams += '&post_type=' + element.attr( 'data-post-type' );
244 279 }
245 280
246 - let source = ajaxurl + urlParams;
247 -
248 - if ( this.dataset.source ) {
249 - const sourceData = JSON.parse( this.dataset.source );
250 - if ( sourceData ) {
251 - source = sourceData;
252 - }
253 - }
254 -
255 - element.autocomplete( {
281 + element.autocomplete({
256 282 delay: 100,
257 283 minLength: 0,
258 - source,
284 + source: ajaxurl + urlParams,
259 285 change: autocomplete.selectBlank,
260 286 select: autocomplete.completeSelectFromResults,
261 287 focus: () => false,
262 288 position: {
@@ -263,9 +289,9 @@
263 289 my: 'left top',
264 290 at: 'left bottom',
265 291 collision: 'flip'
266 292 },
267 - response( event, ui ) {
293 + response: function( event, ui ) {
268 294 if ( ! ui.content.length ) {
269 295 const noResult = {
270 296 value: '',
271 297 label: frm_admin_js.no_items_found
@@ -272,9 +298,9 @@
272 298 };
273 299 ui.content.push( noResult );
274 300 }
275 301 },
276 - create() {
302 + create: function() {
277 303 let $container = jQuery( this ).parent();
278 304
279 305 if ( $container.length === 0 ) {
280 306 $container = 'body';
@@ -281,48 +307,34 @@
281 307 }
282 308
283 309 jQuery( this ).autocomplete( 'option', 'appendTo', $container );
284 310 }
285 - } )
286 - .on( 'focus', function() {
311 + })
312 + .on( 'focus', function() {
287 313 // Show options on click to make it work more like a dropdown.
288 - if ( this.value === '' || this.nextElementSibling.value < 1 ) {
289 - jQuery( this ).autocomplete( 'search', this.value );
290 - }
291 - } )
292 - .data( 'ui-autocomplete' )._renderItem = function( ul, item ) {
293 - return jQuery( '<li>' )
294 - .attr( 'aria-label', item.label )
295 - .append( jQuery( '<div>' ).text( item.label ) )
296 - .appendTo( ul );
297 - };
314 + if ( this.value === '' || this.nextElementSibling.value < 1 ) {
315 + jQuery( this ).autocomplete( 'search', this.value );
316 + }
317 + })
318 + .data( 'ui-autocomplete' )._renderItem = function( ul, item ) {
319 + return jQuery( '<li>' )
320 + .attr( 'aria-label', item.label )
321 + .append( jQuery( '<div>' ).text( item.label ) )
322 + .appendTo( ul );
323 + };
298 324 }
299 325 },
300 326
301 - selectBlank( e, ui ) {
327 + selectBlank: function( e, ui ) {
302 328 if ( ui.item === null ) {
303 329 this.nextElementSibling.value = '';
304 -
305 - /**
306 - * Fires when an autocomplete value is cleared.
307 - *
308 - * @since 6.21
309 - */
310 - wp.hooks.doAction( 'frm_autocomplete_clear_value', e, ui, this );
311 330 }
312 331 },
313 332
314 - completeSelectFromResults( e, ui ) {
333 + completeSelectFromResults: function( e, ui ) {
315 334 e.preventDefault();
316 335 this.value = ui.item.value === '' ? '' : ui.item.label;
317 336 this.nextElementSibling.value = ui.item.value;
318 -
319 - /**
320 - * Fires when an autocomplete item is selected.
321 - *
322 - * @since 6.21
323 - */
324 - wp.hooks.doAction( 'frm_autocomplete_select', e, ui, this );
325 337 }
326 338 };
327 339
328 340 const search = {
@@ -340,15 +352,15 @@
340 352 {
341 353 className: 'frm-search',
342 354 children: [
343 355 label,
344 - span( { className: 'frmfont frm_search_icon' } ),
356 + span({ className: 'frmfont frm_search_icon' }),
345 357 searchInput
346 358 ]
347 359 }
348 360 );
349 361 },
350 - newSearchInput: ( id, placeholder, targetClassName, args = {} ) => {
362 + newSearchInput: ( id, placeholder, targetClassName, args = {}) => {
351 363 const input = getAutoSearchInput( id, placeholder );
352 364 const wrappedSearch = search.wrapInput( input, placeholder );
353 365 search.init( input, targetClassName, args );
354 366
@@ -361,9 +373,9 @@
361 373 }
362 374
363 375 return wrappedSearch;
364 376 },
365 - init: ( input, targetClassName, { handleSearchResult } = {} ) => {
377 + init: ( input, targetClassName, { handleSearchResult } = {}) => {
366 378 input.setAttribute( 'type', 'search' );
367 379 input.setAttribute( 'autocomplete', 'off' );
368 380
369 381 input.addEventListener( 'input', handleSearch );
@@ -377,9 +389,9 @@
377 389
378 390 let foundSomething = false;
379 391 items.forEach( toggleSearchClassesForItem );
380 392 if ( 'function' === typeof handleSearchResult ) {
381 - handleSearchResult( { foundSomething, notEmptySearchText }, event );
393 + handleSearchResult({ foundSomething, notEmptySearchText }, event );
382 394 }
383 395
384 396 function toggleSearchClassesForItem( item ) {
385 397 let itemText;
@@ -390,9 +402,9 @@
390 402 itemText = item.innerText.toLowerCase();
391 403 item.setAttribute( 'frm-search-text', itemText );
392 404 }
393 405
394 - const hide = notEmptySearchText && ! itemText.includes( searchText );
406 + const hide = notEmptySearchText && -1 === itemText.indexOf( searchText );
395 407 item.classList.toggle( 'frm_hidden', hide );
396 408
397 409 const isSearchResult = ! hide && notEmptySearchText;
398 410 if ( isSearchResult ) {
@@ -427,15 +439,15 @@
427 439 * Does the same as jQuery( document ).on( 'event', 'selector', handler ).
428 440 *
429 441 * @since 6.0
430 442 *
431 - * @param {string} event Event name.
432 - * @param {string} selector Selector.
443 + * @param {String} event Event name.
444 + * @param {String} selector Selector.
433 445 * @param {Function} handler Handler.
434 - * @param {boolean|Object} options Options to be added to `addEventListener()` method. Default is `false`.
446 + * @param {Boolean|Object} options Options to be added to `addEventListener()` method. Default is `false`.
435 447 */
436 448 documentOn: ( event, selector, handler, options ) => {
437 - if ( options === undefined ) {
449 + if ( 'undefined' === typeof options ) {
438 450 options = false;
439 451 }
440 452
441 453 document.addEventListener( event, function( e ) {
@@ -442,47 +454,19 @@
442 454 let target;
443 455
444 456 // loop parent nodes from the target to the delegation node.
445 457 for ( target = e.target; target && target != this; target = target.parentNode ) {
446 - if ( target.matches && target.matches( selector ) ) {
458 + if ( target && target.matches && target.matches( selector ) ) {
447 459 handler.call( target, e );
448 460 break;
449 461 }
450 462 }
451 463 }, options );
452 - },
453 -
454 - /**
455 - * Retrieves the value of a cookie by its name.
456 - *
457 - * @param {string} name - The name of the cookie.
458 - * @return {string|null} The value of the cookie, or undefined if the cookie does not exist.
459 - */
460 - getCookie: name => {
461 - const cookie = document.cookie.split( '; ' ).find( cookie => cookie.startsWith( `${ name }=` ) );
462 -
463 - if ( cookie ) {
464 - return cookie.split( '=' )[ 1 ];
465 - }
466 - return null;
467 - },
468 -
469 - /**
470 - * Sets a cookie with the specified name, value, and expiration time.
471 - *
472 - * @param {string} name - The name of the cookie.
473 - * @param {string} value - The value of the cookie.
474 - * @param {number} minutes - The number of minutes until the cookie expires.
475 - */
476 - setCookie: ( name, value, minutes ) => {
477 - const expires = new Date();
478 - expires.setTime( expires.getTime() + ( minutes * 60 * 1000 ) );
479 - document.cookie = `${ name }=${ value };expires=${ expires.toUTCString() };path=/`;
480 464 }
481 465 };
482 466
483 467 const wysiwyg = {
484 - init( editor, { setupCallback, height, addFocusEvents } = {} ) {
468 + init( editor, { setupCallback, height, addFocusEvents } = {}) {
485 469 if ( isTinyMceActive() ) {
486 470 setTimeout( resetTinyMce, 0 );
487 471 } else {
488 472 initQuickTagsButtons();
@@ -491,25 +475,25 @@
491 475 setUpTinyMceVisualButtonListener();
492 476 setUpTinyMceHtmlButtonListener();
493 477
494 478 function initQuickTagsButtons() {
495 - if ( 'function' !== typeof window.quicktags || window.QTags.instances[ editor.id ] !== undefined ) {
479 + if ( 'function' !== typeof window.quicktags || typeof window.QTags.instances[ editor.id ] !== 'undefined' ) {
496 480 return;
497 481 }
498 482
499 - const { id } = editor;
500 - window.quicktags( {
501 - name: `qt_${ id }`,
502 - id,
483 + const id = editor.id;
484 + window.quicktags({
485 + name: 'qt_' + id,
486 + id: id,
503 487 canvas: editor,
504 488 settings: { id },
505 - toolbar: document.getElementById( `qt_${ id }_toolbar` ),
489 + toolbar: document.getElementById( 'qt_' + id + '_toolbar' ),
506 490 theButtons: {}
507 - } );
491 + });
508 492 }
509 493
510 494 function initRichText() {
511 - const key = Object.keys( tinyMCEPreInit.mceInit )[ 0 ];
495 + const key = Object.keys( tinyMCEPreInit.mceInit )[0];
512 496 const orgSettings = tinyMCEPreInit.mceInit[ key ];
513 497
514 498 const settings = Object.assign(
515 499 {},
@@ -514,9 +498,9 @@
514 498 const settings = Object.assign(
515 499 {},
516 500 orgSettings,
517 501 {
518 - selector: `#${ editor.id }`,
502 + selector: '#' + editor.id,
519 503 body_class: orgSettings.body_class.replace( key, editor.id )
520 504 }
521 505 );
522 506
@@ -530,9 +514,9 @@
530 514 editor.on( 'focusin', focusInCallback );
531 515
532 516 editor.on( 'focusout', function() {
533 517 editor.on( 'focusin', focusInCallback );
534 - } );
518 + });
535 519 }
536 520 if ( setupCallback ) {
537 521 setupCallback( editor );
538 522 }
@@ -554,16 +538,16 @@
554 538 initRichText();
555 539 }
556 540
557 541 function isTinyMceActive() {
558 - const { id } = editor;
559 - const wrapper = document.getElementById( `wp-${ id }-wrap` );
542 + const id = editor.id;
543 + const wrapper = document.getElementById( 'wp-' + id + '-wrap' );
560 544 return null !== wrapper && wrapper.classList.contains( 'tmce-active' );
561 545 }
562 546
563 547 function setUpTinyMceVisualButtonListener() {
564 548 jQuery( document ).on(
565 - 'click', `#${ editor.id }-html`,
549 + 'click', '#' + editor.id + '-html',
566 550 function() {
567 551 editor.style.visibility = 'visible';
568 552 initQuickTagsButtons();
569 553 }
@@ -570,9 +554,9 @@
570 554 );
571 555 }
572 556
573 557 function setUpTinyMceHtmlButtonListener() {
574 - jQuery( `#${ editor.id }-tmce` ).on( 'click', handleTinyMceHtmlButtonClick );
558 + jQuery( '#' + editor.id + '-tmce' ).on( 'click', handleTinyMceHtmlButtonClick );
575 559 }
576 560
577 561 function handleTinyMceHtmlButtonClick() {
578 562 if ( isTinyMceActive() ) {
@@ -580,9 +564,9 @@
580 564 } else {
581 565 initRichText();
582 566 }
583 567
584 - const wrap = document.getElementById( `wp-${ editor.id }-wrap` );
568 + const wrap = document.getElementById( 'wp-' + editor.id + '-wrap' );
585 569 wrap.classList.add( 'tmce-active' );
586 570 wrap.classList.remove( 'html-active' );
587 571 }
588 572 }
@@ -589,15 +573,15 @@
589 573 };
590 574
591 575 function getModalHelper( modal, appendTo ) {
592 576 return function( child, uniqueClassName ) {
593 - let element = modal.querySelector( `.${ uniqueClassName }` );
577 + let element = modal.querySelector( '.' + uniqueClassName );
594 578 if ( null === element ) {
595 - element = div( {
596 - child,
579 + element = div({
580 + child: child,
597 581 className: uniqueClassName
598 - } );
599 - appendTo.append( element );
582 + });
583 + appendTo.appendChild( element );
600 584 } else {
601 585 redraw( element, child );
602 586 }
603 587 };
@@ -603,23 +587,23 @@
603 587 };
604 588 }
605 589
606 590 function createEmptyModal( id ) {
607 - const modal = div( { id, className: 'frm-modal' } );
608 - const postbox = div( { className: 'postbox' } );
609 - const metaboxHolder = div( { className: 'metabox-holder', child: postbox } );
610 - modal.append( metaboxHolder );
611 - document.body.append( modal );
591 + const modal = div({ id, className: 'frm-modal' });
592 + const postbox = div({ className: 'postbox' });
593 + const metaboxHolder = div({ className: 'metabox-holder', child: postbox });
594 + modal.appendChild( metaboxHolder );
595 + document.body.appendChild( modal );
612 596 return modal;
613 597 }
614 598
615 - function makeModalIntoADialogAndOpen( modal, { width, dialogClass = '' } = {} ) {
599 + function makeModalIntoADialogAndOpen( modal, { width } = {}) {
616 600 const bodyWithModalClassName = 'frm-body-with-open-modal';
617 601
618 602 const $modal = jQuery( modal );
619 603 if ( ! $modal.hasClass( 'frm-dialog' ) ) {
620 - $modal.dialog( {
621 - dialogClass: `frm-dialog ${ dialogClass }`,
604 + $modal.dialog({
605 + dialogClass: 'frm-dialog',
622 606 modal: true,
623 607 autoOpen: false,
624 608 closeOnEscape: true,
625 609 width: width || '550px',
@@ -624,9 +608,9 @@
624 608 closeOnEscape: true,
625 609 width: width || '550px',
626 610 resizable: false,
627 611 draggable: false,
628 - open() {
612 + open: function() {
629 613 jQuery( '.ui-dialog-titlebar' ).addClass( 'frm_hidden' ).removeClass( 'ui-helper-clearfix' );
630 614 jQuery( '#wpwrap' ).addClass( 'frm_overlay' );
631 615 jQuery( '.frm-dialog' ).removeClass( 'ui-widget ui-widget-content ui-corner-all' );
632 616
@@ -634,9 +618,9 @@
634 618
635 619 $modal.on( 'click', 'a.dismiss', function( event ) {
636 620 event.preventDefault();
637 621 $modal.dialog( 'close' );
638 - } );
622 + });
639 623
640 624 const overlay = document.querySelector( '.ui-widget-overlay' );
641 625 if ( overlay ) {
642 626 overlay.addEventListener(
@@ -647,14 +631,14 @@
647 631 }
648 632 );
649 633 }
650 634 },
651 - close() {
635 + close: function() {
652 636 document.body.classList.remove( bodyWithModalClassName );
653 637 jQuery( '#wpwrap' ).removeClass( 'frm_overlay' );
654 638 jQuery( '.spinner' ).css( 'visibility', 'hidden' );
655 639 }
656 - } );
640 + });
657 641 }
658 642
659 643 document.body.classList.add( bodyWithModalClassName );
660 644
@@ -669,9 +653,9 @@
669 653 function span( args ) {
670 654 return tag( 'span', args );
671 655 }
672 656
673 - function a( args = {} ) {
657 + function a( args = {}) {
674 658 const anchor = tag( 'a', args );
675 659 anchor.setAttribute( 'href', 'string' === typeof args.href ? args.href : '#' );
676 660 if ( 'string' === typeof args.target ) {
677 661 anchor.target = args.target;
@@ -678,9 +662,9 @@
678 662 }
679 663 return anchor;
680 664 }
681 665
682 - function img( args = {} ) {
666 + function img( args = {}) {
683 667 const output = tag( 'img', args );
684 668 if ( 'string' === typeof args.src ) {
685 669 output.setAttribute( 'src', args.src );
686 670 }
@@ -694,12 +678,12 @@
694 678 * Get a labelled text input and a matching label.
695 679 *
696 680 * @since 6.0
697 681 *
698 - * @param {string} inputId
699 - * @param {string} labelText
700 - * @param {string} inputName
701 - * @return {Element} The div element containing the label and input.
682 + * @param {String} inputId
683 + * @param {String} labelText
684 + * @param {String} inputName
685 + * @returns {Element}
702 686 */
703 687 function labelledTextInput( inputId, labelText, inputName ) {
704 688 const label = tag( 'label', labelText );
705 689 label.setAttribute( 'for', inputId );
@@ -713,9 +697,9 @@
713 697 );
714 698 input.type = 'text';
715 699 input.setAttribute( 'name', inputName );
716 700
717 - return div( { children: [ label, input ] } );
701 + return div({ children: [ label, input ] });
718 702 }
719 703
720 704 /**
721 705 * Build an element.
@@ -721,13 +705,13 @@
721 705 * Build an element.
722 706 *
723 707 * @since 6.4.1 Accept a string as one of `children` to append a text node inside the element.
724 708 *
725 - * @param {string} type Element tag name.
709 + * @param {String} type Element tag name.
726 710 * @param {Object} args The args.
727 - * @return {Object} The created DOM element.
711 + * @return {Object}
728 712 */
729 - function tag( type, args = {} ) {
713 + function tag( type, args = {}) {
730 714 const output = document.createElement( type );
731 715
732 716 if ( 'string' === typeof args ) {
733 717 // Support passing just a string to a tag for simple text elements.
@@ -745,27 +729,27 @@
745 729 }
746 730 if ( children ) {
747 731 children.forEach( child => {
748 732 if ( 'string' === typeof child ) {
749 - output.append( document.createTextNode( child ) );
733 + output.appendChild( document.createTextNode( child ) );
750 734 } else {
751 - output.append( child );
735 + output.appendChild( child )
752 736 }
753 737 } );
754 738 } else if ( child ) {
755 - output.append( child );
739 + output.appendChild( child );
756 740 } else if ( text ) {
757 741 output.textContent = text;
758 742 }
759 743 if ( data ) {
760 744 Object.keys( data ).forEach( function( dataKey ) {
761 - output.setAttribute( `data-${ dataKey }`, data[ dataKey ] );
762 - } );
745 + output.setAttribute( 'data-' + dataKey, data[dataKey] );
746 + });
763 747 }
764 748 return output;
765 749 }
766 750
767 - function svg( { href, classList } = {} ) {
751 + function svg({ href, classList } = {}) {
768 752 const namespace = 'http://www.w3.org/2000/svg';
769 753 const output = document.createElementNS( namespace, 'svg' );
770 754 if ( classList ) {
771 755 output.classList.add( ...classList );
@@ -773,9 +757,9 @@
773 757
774 758 if ( href ) {
775 759 const use = document.createElementNS( namespace, 'use' );
776 760 use.setAttribute( 'href', href );
777 - output.append( use );
761 + output.appendChild( use );
778 762 output.classList.add( 'frmsvg' );
779 763 }
780 764 return output;
781 765 }
@@ -783,21 +767,21 @@
783 767 /**
784 768 * Pop up a success message in the lower right corner.
785 769 * It then fades out and gets deleted automatically.
786 770 *
787 - * @param {HTMLElement|string} content
788 - * @return {void}
771 + * @param {HTMLElement|String} content
772 + * @returns {void}
789 773 */
790 774 function success( content ) {
791 - const container = document.getElementById( 'wpbody' );
792 - const notice = div( {
775 + const container = document.getElementById( 'wpbody' );
776 + const notice = div({
793 777 className: 'frm_updated_message frm-floating-success-message',
794 - child: div( {
778 + child: div({
795 779 className: 'frm-satisfied',
796 780 child: 'string' === typeof content ? document.createTextNode( content ) : content
797 - } )
798 - } );
799 - container.append( notice );
781 + })
782 + });
783 + container.appendChild( notice );
800 784
801 785 setTimeout(
802 786 () => jQuery( notice ).fadeOut( () => notice.remove() ),
803 787 2000
@@ -805,15 +789,15 @@
805 789 }
806 790
807 791 function setAttributes( element, attrs ) {
808 792 Object.entries( attrs ).forEach(
809 - ( [ key, value ] ) => element.setAttribute( key, value )
793 + ([ key, value ]) => element.setAttribute( key, value )
810 794 );
811 795 }
812 796
813 797 function redraw( element, child ) {
814 798 element.innerHTML = '';
815 - element.append( child );
799 + element.appendChild( child );
816 800 }
817 801
818 802 const allowedHtml = {
819 803 b: [],
@@ -827,9 +811,9 @@
827 811 a: [ 'href', 'class' ]
828 812 };
829 813
830 814 function cleanNode( node ) {
831 - if ( node.tagName === undefined ) {
815 + if ( 'undefined' === typeof node.tagName ) {
832 816 if ( '#text' === node.nodeName ) {
833 817 return document.createTextNode( node.textContent );
834 818 }
835 819 return document.createTextNode( '' );
@@ -842,20 +826,23 @@
842 826 classList: Array.from( node.classList )
843 827 };
844 828 const use = node.querySelector( 'use' );
845 829 if ( use ) {
846 - svgArgs.href = use.getAttribute( 'href' ) || use.getAttribute( 'xlink:href' );
830 + svgArgs.href = use.getAttribute( 'xlink:href' );
831 + if ( ! svgArgs.href ) {
832 + svgArgs.href = use.getAttribute( 'href' );
833 + }
847 834 }
848 835 return svg( svgArgs );
849 836 }
850 837
851 - if ( allowedHtml[ tagType ] === undefined ) {
838 + const newNode = document.createElement( tagType );
839 +
840 + if ( 'undefined' === typeof allowedHtml[ tagType ]) {
852 841 // Tag type is not allowed.
853 842 return document.createTextNode( '' );
854 843 }
855 844
856 - const newNode = document.createElement( tagType );
857 -
858 845 allowedHtml[ tagType ].forEach(
859 846 allowedTag => {
860 847 if ( node.hasAttribute( allowedTag ) ) {
861 848 newNode.setAttribute( allowedTag, node.getAttribute( allowedTag ) );
@@ -862,9 +849,9 @@
862 849 }
863 850 }
864 851 );
865 852
866 - node.childNodes.forEach( child => newNode.append( cleanNode( child ) ) );
853 + node.childNodes.forEach( child => newNode.appendChild( cleanNode( child ) ) );
867 854 return newNode;
868 855 }
869 856
870 857 window.frmDom = { tag, div, span, a, img, labelledTextInput, svg, setAttributes, success, modal, ajax, bootstrap, autocomplete, search, util, wysiwyg, cleanNode };