File: /var/www/html/TriadGov/wp-content/plugins/wpforms/assets/pro/js/frontend/fields/richtext.js
/* global tinymce, tinyMCE, tinyMCEPreInit, wpforms_settings, wpforms */
/**
* Rich Text field.
*
* @since 1.7.0
*/
'use strict';
var WPFormsRichTextField = window.WPFormsRichTextField || ( function( document, window, $ ) {
/**
* Private functions and properties.
*
* @since 1.7.0
*
* @type {object}
*/
var vars = {
mediaPostIdUpdateEvent: false,
};
/**
* Public functions and properties.
*
* @since 1.7.0
*
* @type {object}
*/
var app = {
/**
* Start the engine.
*
* @since 1.7.0
*/
init() {
$( document )
.on( 'wpformsReady', app.customizeRichTextField )
.on( 'wpformsAjaxSubmitSuccessConfirmation', app.updateIframes );
// Re-initialize tinyMCE in Elementor's popups.
window.addEventListener( 'elementor/popup/show', function( event ) {
app.reInitRichTextFields( event.detail.instance.$element );
} );
},
/**
* Customize Rich Text field.
*
* @since 1.7.0
*/
customizeRichTextField: function() {
var $document = $( document );
$document.on( 'tinymce-editor-setup', function( event, editor ) {
// Validate hidden editor textarea on keyup.
editor.on( 'keyup', function() {
app.validateRichTextField( editor );
} );
editor.on( 'focus', function( e ) {
$( e.target.editorContainer ).closest( '.wp-editor-wrap' ).addClass( 'wpforms-focused' );
} );
editor.on( 'blur', function( e ) {
$( e.target.editorContainer ).closest( '.wp-editor-wrap' ).removeClass( 'wpforms-focused' );
} );
} );
// Validate on mutation (insert image or any other changes).
$document.on( 'wpformsRichTextContentChange', function( event, mutation, editor ) {
app.validateRichTextField( editor );
app.enableAddMediaButtons( mutation );
} );
// Init each field.
$document.on( 'tinymce-editor-init', function( event, editor ) {
const docStyle = editor.getDoc().body.style;
const $body = $( 'body' );
// Inherit body text font family.
docStyle.fontFamily = $body.css( 'font-family' );
docStyle.background = 'transparent';
app.initEditorModernMarkupMode( editor );
app.mediaPostIdUpdate();
app.observeEditorChanges( editor );
app.cleanImages( editor );
$document.trigger( 'wpformsRichTextEditorInit', [ editor ] );
} );
// Set `required` property for each of the hidden editor textarea.
$( 'textarea.wp-editor-area' ).each( function() {
const $this = $( this );
if ( $this.hasClass( 'wpforms-field-required' ) ) {
$this.prop( 'required', true );
}
} );
// Closing media modal on click.
$document.on( 'click', '.media-modal-close, .media-modal-backdrop', app.enableAddMediaButtons );
// Closing media modal via ESC key.
if ( typeof wp !== 'undefined' && typeof wp.media === 'function' ) {
wp.media.view.Modal.prototype.on( 'escape', function() {
app.enableAddMediaButtons( 'escapeEvent' );
} );
}
$document.on( 'click', '.switch-html', function() {
const $wrap = $( this ).closest( '.wp-editor-wrap' );
setTimeout( function() {
$wrap.find( '.wp-editor-area' ).trigger( 'focus' );
$wrap.addClass( 'wpforms-focused' );
}, 0 );
} );
$document.on( 'click', '.switch-tmce', function( e ) {
// Prevent the default action of the click event
e.preventDefault();
const $wrap = $( this ).closest( '.wp-editor-wrap' ),
textareaId = $wrap.find( '.wp-editor-area' ).attr( 'id' );
const editor = tinyMCE.get( textareaId );
if ( editor ) {
$wrap.addClass( 'wpforms-focused' );
// Focus on editor without causing the jump effect.
setTimeout( () => {
editor.focus( false );
}, 0 );
}
} );
$document.on( 'focus', '.wp-editor-area', function() {
$( this ).closest( '.wp-editor-wrap' ).addClass( 'wpforms-focused' );
} );
$document.on( 'blur', '.wp-editor-area', function( e ) {
$( this ).closest( '.wp-editor-wrap' ).removeClass( 'wpforms-focused' );
} );
},
/**
* Replace special characters in image attributes.
*
* @since 1.8.3
* @param {object} editor TinyMCE editor instance.
*/
cleanImages: function( editor ) {
// Get TinyMCE content in raw format.
const content = editor.getContent( { format: 'raw' } );
// Create a temporary element to manipulate the content.
const imageDiv = document.createElement( 'div' );
// Set the content to the temporary element.
imageDiv.innerHTML = content;
// Find all the images in the content.
const images = imageDiv.querySelectorAll( 'img' );
// Loop through all the images.
for ( let i = 0; i < images.length; i++ ) {
// Replace wrong quote characters.
images[ i ].outerHTML = images[ i ].outerHTML.replace( /"”|”"|"″|″"/g, '"' );
}
// Send clean image back to TinyMCE.
editor.setContent( imageDiv.innerHTML );
},
/**
* Add media button for WordPress 4.9.
*
* @since 1.7.0
* @deprecated 1.8.7
*
* @param {Object} editor TinyMCE editor instance.
*/
addMediaButton( editor ) {
// eslint-disable-next-line no-console
console.warn( 'WARNING! Function "WPFormsRichTextField.addMediaButton()" has been deprecated!' );
if ( wpforms_settings.richtext_add_media_button ) {
editor.addButton( 'wp_add_media', {
tooltip: 'Add Media',
icon: 'dashicon dashicons-admin-media',
cmd: 'WP_Medialib',
} );
}
},
/**
* Enable Add Media buttons.
*
* @since 1.7.0
*
* @param {object|string} mutation Mutation observer's record or event object.
*/
enableAddMediaButtons: function( mutation ) {
var isEscapeEvent = mutation === 'escapeEvent';
if ( ! isEscapeEvent && ! app.isCloseEvent( mutation ) && ! app.isMutationImage( mutation ) ) {
return;
}
$( '.mce-btn-group button i.dashicons-admin-media' ).closest( '.mce-btn' ).removeClass( 'mce-btn-disabled' );
},
/**
* Is it the close media library event?
*
* @since 1.7.0
*
* @param {object} mutation Mutation observer's record or event object.
*
* @returns {boolean} True if is the close event.
*/
isCloseEvent: function( mutation ) {
return typeof mutation.target !== 'undefined' && (
mutation.target.classList.contains( 'media-modal-icon' ) ||
mutation.target.classList.contains( 'media-modal-backdrop' )
);
},
/**
* Is it not mutation event?
*
* @since 1.7.0
*
* @param {object} mutation Mutation observer's record or event object.
*
* @returns {boolean} True if isn't mutation event.
*/
isMutationImage: function( mutation ) {
if ( typeof mutation.addedNodes === 'undefined' || typeof mutation.addedNodes[0] === 'undefined' ) {
return false;
}
var isMutationImage = false;
mutation.addedNodes.forEach( function( node ) {
if ( node.tagName === 'IMG' ) {
isMutationImage = true;
return false;
}
if ( node.tagName === 'A' && node.querySelector( 'img' ) ) {
isMutationImage = true;
return false;
}
} );
return isMutationImage;
},
/**
* Disable Add Media buttons.
*
* @since 1.7.0
*/
disableAddMediaButtons: function() {
$( '.mce-btn-group button i.dashicons-admin-media' ).closest( '.mce-btn' ).addClass( 'mce-btn-disabled' );
},
/**
* Update Fake Post ID according to the Field ID.
*
* @since 1.7.0
*/
mediaPostIdUpdate: function() {
if ( vars.mediaPostIdUpdateEvent ) {
return;
}
$( '.wpforms-field-richtext-media-enabled .mce-toolbar .mce-btn' ).on( 'click touchstart', function( e ) {
const $this = $( e.target );
if ( ! $this.hasClass( 'dashicons-admin-media' ) && $this.find( '.dashicons-admin-media' ).length === 0 ) {
return;
}
var formId = $this.closest( 'form' ).data( 'formid' ),
fieldId = $this.closest( '.wpforms-field-richtext' ).data( 'field-id' );
// Replace the digital parts with the current form and field IDs.
wp.media.model.settings.post.id = 'wpforms-' + formId + '-field_' + fieldId;
app.disableAddMediaButtons();
} );
vars.mediaPostIdUpdateEvent = true;
},
/**
* Observe changes inside editor's iframe.
*
* @since 1.7.0
*
* @param {object} editor TinyMCE editor instance.
*/
observeEditorChanges: function( editor ) {
// Observe changes inside editor's iframe.
var observer = new MutationObserver( function( mutationsList, observer ) {
for ( var key in mutationsList ) {
if ( mutationsList[ key ].type === 'childList' ) {
$( document ).trigger( 'wpformsRichTextContentChange', [ mutationsList[ key ], editor ] );
}
}
} );
observer.observe(
editor.iframeElement.contentWindow.document.body,
{
childList: true,
subtree: true,
attributes: true,
}
);
},
/**
* Validate Rich Text field.
*
* @since 1.7.0
*
* @param {object} editor TinyMCE editor instance.
*/
validateRichTextField: function( editor ) {
if ( ! editor || ! $( editor.iframeElement ).closest( 'form' ).data( 'validator' ) ) {
return;
}
var $textarea = $( '#' + editor.id );
// We should save and validate if only the editor's content has the real changes.
if ( editor.getContent() === $textarea.val() ) {
return;
}
editor.save();
$textarea.valid();
},
/**
* Re-initialize tinyMCEs in given form (container).
*
* @since 1.7.0
*
* @param {jQuery} $form Form container.
*/
reInitRichTextFields( $form ) {
if ( typeof tinyMCEPreInit === 'undefined' || typeof tinymce === 'undefined' ) {
return;
}
$form.find( '.wp-editor-area' ).each( function() {
const id = $( this ).attr( 'id' );
if ( tinymce.get( id ) ) {
// Remove existing editor.
tinyMCE.execCommand( 'mceRemoveEditor', false, id );
}
window.quicktags( tinyMCEPreInit.qtInit[ id ] );
$( '#' + id ).css( 'visibility', 'initial' );
tinymce.init( tinyMCEPreInit.mceInit[ id ] );
} );
},
/**
* Initialize tinyMCE in Modern Markup mode.
*
* @since 1.8.1
*
* @param {object} editor TinyMCE editor instance.
*/
initEditorModernMarkupMode: function( editor ) {
if ( ! wpforms.isModernMarkupEnabled() || window.WPFormsEditEntry || ! window.WPForms.FrontendModern ) {
return;
}
const docStyle = editor.getDoc().body.style;
const $el = $( editor.getElement() );
const $field = $el.closest( '.wpforms-field' );
const $form = $el.closest( '.wpforms-form' );
const cssVars = window.WPForms.FrontendModern.getCssVars( $form );
const inputHeight = cssVars['field-size-input-height'] ? cssVars['field-size-input-height'].replace( 'px', '' ) : 43;
const sizeK = {
'small' : 1.80,
'medium': 2.79,
'large' : 5.12,
};
let fieldSize = 'medium';
fieldSize = $field.hasClass( 'wpforms-field-small' ) ? 'small' : fieldSize;
fieldSize = $field.hasClass( 'wpforms-field-large' ) ? 'large' : fieldSize;
const width = editor.getWin().clientWidth;
const height = inputHeight * sizeK[ fieldSize ];
editor.theme.resizeTo( width, height );
docStyle.color = cssVars['field-text-color'];
docStyle.fontSize = cssVars['field-size-font-size'];
},
/**
* Create an iframe from a div inside the confirmation message.
*
* @since 1.9.2
*
* @param {Event} event Event instance from the `wpformsAjaxSubmitSuccessConfirmation` hook.
*/
updateIframes( event ) {
$( event.target ).find( '.wpforms-iframe' ).each( window?.WPFormsIframe?.update );
},
};
// Provide access to public functions/properties.
return app;
}( document, window, jQuery ) );
WPFormsRichTextField.init();