wysiwyg.js (5499B)
1 ( function( $, wp, window, rwmb ) { 2 'use strict'; 3 4 /** 5 * Transform textarea into wysiwyg editor. 6 */ 7 function transform() { 8 var $this = $( this ), 9 $wrapper = $this.closest( '.wp-editor-wrap' ), 10 id = $this.attr( 'id' ), 11 isInBlock = $this.closest( '.wp-block, .components-panel' ).length > 0; 12 13 // Update the ID attribute if the editor is in a new block. 14 if ( isInBlock ) { 15 id = id + '_' + rwmb.uniqid(); 16 $this.attr( 'id', id ); 17 } 18 19 // Get current editor mode before updating the DOM. 20 var mode = $wrapper.hasClass( 'tmce-active' ) ? 'tmce' : 'html'; 21 22 // Update the DOM 23 $this.show(); 24 updateDom( $wrapper, id ); 25 26 // Get id of the original editor to get its tinyMCE and quick tags settings 27 var originalId = getOriginalId( this ), 28 settings = getEditorSettings( originalId ), 29 customSettings = $this.closest( '.rwmb-input' ).find( '.rwmb-wysiwyg-id' ).data( 'options' ); 30 31 // TinyMCE 32 if ( window.tinymce ) { 33 settings.tinymce.selector = '#' + id; 34 settings.tinymce.setup = function( editor ) { 35 editor.on( 'keyup change', function() { 36 editor.save(); // Required for live validation. 37 $this.trigger( 'change' ); 38 } ); 39 }; 40 41 // Set editor mode after initializing. 42 settings.tinymce.init_instance_callback = function() { 43 switchEditors.go( id, mode ); 44 }; 45 46 tinymce.remove( '#' + id ); 47 tinymce.init( $.extend( settings.tinymce, customSettings.tinymce ) ); 48 } 49 50 // Quick tags 51 if ( window.quicktags ) { 52 settings.quicktags.id = id; 53 quicktags( $.extend( settings.quicktags, customSettings.quicktags ) ); 54 QTags._buttonsInit(); 55 } 56 } 57 58 function getEditorSettings( id ) { 59 var settings = getDefaultEditorSettings(); 60 61 if ( id && tinyMCEPreInit.mceInit.hasOwnProperty( id ) ) { 62 settings.tinymce = tinyMCEPreInit.mceInit[ id ]; 63 } 64 if ( id && window.quicktags && tinyMCEPreInit.qtInit.hasOwnProperty( id ) ) { 65 settings.quicktags = tinyMCEPreInit.qtInit[ id ]; 66 } 67 68 return settings; 69 } 70 71 function getDefaultEditorSettings() { 72 var settings = wp.editor.getDefaultSettings(); 73 74 settings.tinymce.toolbar1 = 'formatselect,bold,italic,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv'; 75 settings.tinymce.toolbar2 = 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help'; 76 77 settings.quicktags.buttons = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close'; 78 79 return settings; 80 } 81 82 /** 83 * Get original ID of the textarea 84 * The ID will be used to reference to tinyMCE and quick tags settings 85 * @param el Current cloned textarea 86 */ 87 function getOriginalId( el ) { 88 return el.closest( '.rwmb-input' ).querySelector( '.rwmb-wysiwyg-id' ).dataset.id; 89 } 90 91 /** 92 * Update id, class, [data-] attributes, ... of the cloned editor. 93 * @param $wrapper Editor wrapper element 94 * @param id Editor ID 95 */ 96 function updateDom( $wrapper, id ) { 97 // Wrapper div and media buttons 98 $wrapper.attr( 'id', 'wp-' + id + '-wrap' ) 99 .find( '.mce-container' ).remove().end() // Remove rendered tinyMCE editor 100 .find( '.wp-editor-tools' ).attr( 'id', 'wp-' + id + '-editor-tools' ) 101 .find( '.wp-media-buttons' ).attr( 'id', 'wp-' + id + '-media-buttons' ) 102 .find( 'button' ).data( 'editor', id ).attr( 'data-editor', id ); 103 104 // Set default active mode. 105 $wrapper.removeClass( 'html-active tmce-active' ); 106 $wrapper.addClass( window.tinymce ? 'tmce-active' : 'html-active' ); 107 108 // Editor tabs 109 $wrapper.find( '.switch-tmce' ) 110 .attr( 'id', id + 'tmce' ) 111 .data( 'wp-editor-id', id ).attr( 'data-wp-editor-id', id ).end() 112 .find( '.switch-html' ) 113 .attr( 'id', id + 'html' ) 114 .data( 'wp-editor-id', id ).attr( 'data-wp-editor-id', id ); 115 116 // Quick tags 117 $wrapper.find( '.wp-editor-container' ).attr( 'id', 'wp-' + id + '-editor-container' ) 118 .find( '.quicktags-toolbar' ).attr( 'id', 'qt_' + id + '_toolbar' ).html( '' ); 119 } 120 121 function init( e ) { 122 $( e.target ).find( '.rwmb-wysiwyg' ).each( transform ); 123 } 124 125 /** 126 * Add required attribute for validation. 127 * 128 * this = textarea element. 129 */ 130 function addRequiredAttribute() { 131 if ( this.classList.contains( 'rwmb-wysiwyg-required' ) ) { 132 this.setAttribute( 'required', true ); 133 } 134 } 135 136 /** 137 * Setup events for the classic editor to make live validation work. 138 * 139 * When change: 140 * - Save content to textarea for live validation. 141 * - Trigger change event for compatibility. 142 * 143 * this = textarea element. 144 */ 145 function setupEvents() { 146 if ( !window.tinymce ) { 147 return; 148 } 149 var editor = tinymce.get( this.id ); 150 if ( !editor ) { 151 return; 152 } 153 var $this = $( this ); 154 editor.on( 'keyup change', function() { 155 editor.save(); // Required for live validation. 156 $this.trigger( 'change' ); 157 } ); 158 } 159 160 $( function() { 161 var $editors = $( '.rwmb-wysiwyg' ); 162 $editors.each( addRequiredAttribute ); 163 $editors.each( setupEvents ); 164 165 // Force re-render editors in Gutenberg. Use setTimeOut to run after all other code. Bug occurs in WP 5.6. 166 if ( rwmb.isGutenberg ) { 167 setTimeout( function() { 168 $editors.each( transform ); 169 }, 0 ); 170 } 171 } ); 172 173 rwmb.$document 174 .on( 'mb_blocks_edit', init ) 175 .on( 'mb_init_editors', init ) 176 .on( 'clone', '.rwmb-wysiwyg', function() { 177 /* 178 * Transform a textarea to an editor is a heavy task. 179 * Moving it to the end of task queue with setTimeout makes cloning faster. 180 */ 181 setTimeout( transform.bind( this ), 0 ); 182 } ); 183 } )( jQuery, wp, window, rwmb );