editor.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. window.wp = window.wp || {};
  2. ( function( $, wp ) {
  3. wp.editor = wp.editor || {};
  4. /**
  5. * @summary Utility functions for the editor.
  6. *
  7. * @since 2.5.0
  8. */
  9. function SwitchEditors() {
  10. var tinymce, $$,
  11. exports = {};
  12. function init() {
  13. if ( ! tinymce && window.tinymce ) {
  14. tinymce = window.tinymce;
  15. $$ = tinymce.$;
  16. /**
  17. * @summary Handles onclick events for the Visual/Text tabs.
  18. *
  19. * @since 4.3.0
  20. *
  21. * @returns {void}
  22. */
  23. $$( document ).on( 'click', function( event ) {
  24. var id, mode,
  25. target = $$( event.target );
  26. if ( target.hasClass( 'wp-switch-editor' ) ) {
  27. id = target.attr( 'data-wp-editor-id' );
  28. mode = target.hasClass( 'switch-tmce' ) ? 'tmce' : 'html';
  29. switchEditor( id, mode );
  30. }
  31. });
  32. }
  33. }
  34. /**
  35. * @summary Returns the height of the editor toolbar(s) in px.
  36. *
  37. * @since 3.9.0
  38. *
  39. * @param {Object} editor The TinyMCE editor.
  40. * @returns {number} If the height is between 10 and 200 return the height,
  41. * else return 30.
  42. */
  43. function getToolbarHeight( editor ) {
  44. var node = $$( '.mce-toolbar-grp', editor.getContainer() )[0],
  45. height = node && node.clientHeight;
  46. if ( height && height > 10 && height < 200 ) {
  47. return parseInt( height, 10 );
  48. }
  49. return 30;
  50. }
  51. /**
  52. * @summary Switches the editor between Visual and Text mode.
  53. *
  54. * @since 2.5.0
  55. *
  56. * @memberof switchEditors
  57. *
  58. * @param {string} id The id of the editor you want to change the editor mode for. Default: `content`.
  59. * @param {string} mode The mode you want to switch to. Default: `toggle`.
  60. * @returns {void}
  61. */
  62. function switchEditor( id, mode ) {
  63. id = id || 'content';
  64. mode = mode || 'toggle';
  65. var editorHeight, toolbarHeight, iframe,
  66. editor = tinymce.get( id ),
  67. wrap = $$( '#wp-' + id + '-wrap' ),
  68. $textarea = $$( '#' + id ),
  69. textarea = $textarea[0];
  70. if ( 'toggle' === mode ) {
  71. if ( editor && ! editor.isHidden() ) {
  72. mode = 'html';
  73. } else {
  74. mode = 'tmce';
  75. }
  76. }
  77. if ( 'tmce' === mode || 'tinymce' === mode ) {
  78. // If the editor is visible we are already in `tinymce` mode.
  79. if ( editor && ! editor.isHidden() ) {
  80. return false;
  81. }
  82. // Insert closing tags for any open tags in QuickTags.
  83. if ( typeof( window.QTags ) !== 'undefined' ) {
  84. window.QTags.closeAllTags( id );
  85. }
  86. editorHeight = parseInt( textarea.style.height, 10 ) || 0;
  87. if ( editor ) {
  88. editor.show();
  89. // No point to resize the iframe in iOS.
  90. if ( ! tinymce.Env.iOS && editorHeight ) {
  91. toolbarHeight = getToolbarHeight( editor );
  92. editorHeight = editorHeight - toolbarHeight + 14;
  93. // Sane limit for the editor height.
  94. if ( editorHeight > 50 && editorHeight < 5000 ) {
  95. editor.theme.resizeTo( null, editorHeight );
  96. }
  97. }
  98. } else {
  99. tinymce.init( window.tinyMCEPreInit.mceInit[id] );
  100. }
  101. wrap.removeClass( 'html-active' ).addClass( 'tmce-active' );
  102. $textarea.attr( 'aria-hidden', true );
  103. window.setUserSetting( 'editor', 'tinymce' );
  104. } else if ( 'html' === mode ) {
  105. // If the editor is hidden (Quicktags is shown) we don't need to switch.
  106. if ( editor && editor.isHidden() ) {
  107. return false;
  108. }
  109. if ( editor ) {
  110. // Don't resize the textarea in iOS. The iframe is forced to 100% height there, we shouldn't match it.
  111. if ( ! tinymce.Env.iOS ) {
  112. iframe = editor.iframeElement;
  113. editorHeight = iframe ? parseInt( iframe.style.height, 10 ) : 0;
  114. if ( editorHeight ) {
  115. toolbarHeight = getToolbarHeight( editor );
  116. editorHeight = editorHeight + toolbarHeight - 14;
  117. // Sane limit for the textarea height.
  118. if ( editorHeight > 50 && editorHeight < 5000 ) {
  119. textarea.style.height = editorHeight + 'px';
  120. }
  121. }
  122. }
  123. editor.hide();
  124. } else {
  125. // There is probably a JS error on the page. The TinyMCE editor instance doesn't exist. Show the textarea.
  126. $textarea.css({ 'display': '', 'visibility': '' });
  127. }
  128. wrap.removeClass( 'tmce-active' ).addClass( 'html-active' );
  129. $textarea.attr( 'aria-hidden', false );
  130. window.setUserSetting( 'editor', 'html' );
  131. }
  132. }
  133. /**
  134. * @summary Replaces <p> tags with two line breaks. "Opposite" of wpautop().
  135. *
  136. * Replaces <p> tags with two line breaks except where the <p> has attributes.
  137. * Unifies whitespace.
  138. * Indents <li>, <dt> and <dd> for better readability.
  139. *
  140. * @since 2.5.0
  141. *
  142. * @memberof switchEditors
  143. *
  144. * @param {string} html The content from the editor.
  145. * @return {string} The content with stripped paragraph tags.
  146. */
  147. function removep( html ) {
  148. var blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure',
  149. blocklist1 = blocklist + '|div|p',
  150. blocklist2 = blocklist + '|pre',
  151. preserve_linebreaks = false,
  152. preserve_br = false,
  153. preserve = [];
  154. if ( ! html ) {
  155. return '';
  156. }
  157. // Protect script and style tags.
  158. if ( html.indexOf( '<script' ) !== -1 || html.indexOf( '<style' ) !== -1 ) {
  159. html = html.replace( /<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function( match ) {
  160. preserve.push( match );
  161. return '<wp-preserve>';
  162. } );
  163. }
  164. // Protect pre tags.
  165. if ( html.indexOf( '<pre' ) !== -1 ) {
  166. preserve_linebreaks = true;
  167. html = html.replace( /<pre[^>]*>[\s\S]+?<\/pre>/g, function( a ) {
  168. a = a.replace( /<br ?\/?>(\r\n|\n)?/g, '<wp-line-break>' );
  169. a = a.replace( /<\/?p( [^>]*)?>(\r\n|\n)?/g, '<wp-line-break>' );
  170. return a.replace( /\r?\n/g, '<wp-line-break>' );
  171. });
  172. }
  173. // Remove line breaks but keep <br> tags inside image captions.
  174. if ( html.indexOf( '[caption' ) !== -1 ) {
  175. preserve_br = true;
  176. html = html.replace( /\[caption[\s\S]+?\[\/caption\]/g, function( a ) {
  177. return a.replace( /<br([^>]*)>/g, '<wp-temp-br$1>' ).replace( /[\r\n\t]+/, '' );
  178. });
  179. }
  180. // Normalize white space characters before and after block tags.
  181. html = html.replace( new RegExp( '\\s*</(' + blocklist1 + ')>\\s*', 'g' ), '</$1>\n' );
  182. html = html.replace( new RegExp( '\\s*<((?:' + blocklist1 + ')(?: [^>]*)?)>', 'g' ), '\n<$1>' );
  183. // Mark </p> if it has any attributes.
  184. html = html.replace( /(<p [^>]+>.*?)<\/p>/g, '$1</p#>' );
  185. // Preserve the first <p> inside a <div>.
  186. html = html.replace( /<div( [^>]*)?>\s*<p>/gi, '<div$1>\n\n' );
  187. // Remove paragraph tags.
  188. html = html.replace( /\s*<p>/gi, '' );
  189. html = html.replace( /\s*<\/p>\s*/gi, '\n\n' );
  190. // Normalize white space chars and remove multiple line breaks.
  191. html = html.replace( /\n[\s\u00a0]+\n/g, '\n\n' );
  192. // Replace <br> tags with line breaks.
  193. html = html.replace( /(\s*)<br ?\/?>\s*/gi, function( match, space ) {
  194. if ( space && space.indexOf( '\n' ) !== -1 ) {
  195. return '\n\n';
  196. }
  197. return '\n';
  198. });
  199. // Fix line breaks around <div>.
  200. html = html.replace( /\s*<div/g, '\n<div' );
  201. html = html.replace( /<\/div>\s*/g, '</div>\n' );
  202. // Fix line breaks around caption shortcodes.
  203. html = html.replace( /\s*\[caption([^\[]+)\[\/caption\]\s*/gi, '\n\n[caption$1[/caption]\n\n' );
  204. html = html.replace( /caption\]\n\n+\[caption/g, 'caption]\n\n[caption' );
  205. // Pad block elements tags with a line break.
  206. html = html.replace( new RegExp('\\s*<((?:' + blocklist2 + ')(?: [^>]*)?)\\s*>', 'g' ), '\n<$1>' );
  207. html = html.replace( new RegExp('\\s*</(' + blocklist2 + ')>\\s*', 'g' ), '</$1>\n' );
  208. // Indent <li>, <dt> and <dd> tags.
  209. html = html.replace( /<((li|dt|dd)[^>]*)>/g, ' \t<$1>' );
  210. // Fix line breaks around <select> and <option>.
  211. if ( html.indexOf( '<option' ) !== -1 ) {
  212. html = html.replace( /\s*<option/g, '\n<option' );
  213. html = html.replace( /\s*<\/select>/g, '\n</select>' );
  214. }
  215. // Pad <hr> with two line breaks.
  216. if ( html.indexOf( '<hr' ) !== -1 ) {
  217. html = html.replace( /\s*<hr( [^>]*)?>\s*/g, '\n\n<hr$1>\n\n' );
  218. }
  219. // Remove line breaks in <object> tags.
  220. if ( html.indexOf( '<object' ) !== -1 ) {
  221. html = html.replace( /<object[\s\S]+?<\/object>/g, function( a ) {
  222. return a.replace( /[\r\n]+/g, '' );
  223. });
  224. }
  225. // Unmark special paragraph closing tags.
  226. html = html.replace( /<\/p#>/g, '</p>\n' );
  227. // Pad remaining <p> tags whit a line break.
  228. html = html.replace( /\s*(<p [^>]+>[\s\S]*?<\/p>)/g, '\n$1' );
  229. // Trim.
  230. html = html.replace( /^\s+/, '' );
  231. html = html.replace( /[\s\u00a0]+$/, '' );
  232. if ( preserve_linebreaks ) {
  233. html = html.replace( /<wp-line-break>/g, '\n' );
  234. }
  235. if ( preserve_br ) {
  236. html = html.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' );
  237. }
  238. // Restore preserved tags.
  239. if ( preserve.length ) {
  240. html = html.replace( /<wp-preserve>/g, function() {
  241. return preserve.shift();
  242. } );
  243. }
  244. return html;
  245. }
  246. /**
  247. * @summary Replaces two line breaks with a paragraph tag and one line break with a <br>.
  248. *
  249. * Similar to `wpautop()` in formatting.php.
  250. *
  251. * @since 2.5.0
  252. *
  253. * @memberof switchEditors
  254. *
  255. * @param {string} text The text input.
  256. * @returns {string} The formatted text.
  257. */
  258. function autop( text ) {
  259. var preserve_linebreaks = false,
  260. preserve_br = false,
  261. blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre' +
  262. '|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section' +
  263. '|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary';
  264. // Normalize line breaks.
  265. text = text.replace( /\r\n|\r/g, '\n' );
  266. if ( text.indexOf( '\n' ) === -1 ) {
  267. return text;
  268. }
  269. // Remove line breaks from <object>.
  270. if ( text.indexOf( '<object' ) !== -1 ) {
  271. text = text.replace( /<object[\s\S]+?<\/object>/g, function( a ) {
  272. return a.replace( /\n+/g, '' );
  273. });
  274. }
  275. // Remove line breaks from tags.
  276. text = text.replace( /<[^<>]+>/g, function( a ) {
  277. return a.replace( /[\n\t ]+/g, ' ' );
  278. });
  279. // Preserve line breaks in <pre> and <script> tags.
  280. if ( text.indexOf( '<pre' ) !== -1 || text.indexOf( '<script' ) !== -1 ) {
  281. preserve_linebreaks = true;
  282. text = text.replace( /<(pre|script)[^>]*>[\s\S]*?<\/\1>/g, function( a ) {
  283. return a.replace( /\n/g, '<wp-line-break>' );
  284. });
  285. }
  286. if ( text.indexOf( '<figcaption' ) !== -1 ) {
  287. text = text.replace( /\s*(<figcaption[^>]*>)/g, '$1' );
  288. text = text.replace( /<\/figcaption>\s*/g, '</figcaption>' );
  289. }
  290. // Keep <br> tags inside captions.
  291. if ( text.indexOf( '[caption' ) !== -1 ) {
  292. preserve_br = true;
  293. text = text.replace( /\[caption[\s\S]+?\[\/caption\]/g, function( a ) {
  294. a = a.replace( /<br([^>]*)>/g, '<wp-temp-br$1>' );
  295. a = a.replace( /<[^<>]+>/g, function( b ) {
  296. return b.replace( /[\n\t ]+/, ' ' );
  297. });
  298. return a.replace( /\s*\n\s*/g, '<wp-temp-br />' );
  299. });
  300. }
  301. text = text + '\n\n';
  302. text = text.replace( /<br \/>\s*<br \/>/gi, '\n\n' );
  303. // Pad block tags with two line breaks.
  304. text = text.replace( new RegExp( '(<(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '\n\n$1' );
  305. text = text.replace( new RegExp( '(</(?:' + blocklist + ')>)', 'gi' ), '$1\n\n' );
  306. text = text.replace( /<hr( [^>]*)?>/gi, '<hr$1>\n\n' );
  307. // Remove white space chars around <option>.
  308. text = text.replace( /\s*<option/gi, '<option' );
  309. text = text.replace( /<\/option>\s*/gi, '</option>' );
  310. // Normalize multiple line breaks and white space chars.
  311. text = text.replace( /\n\s*\n+/g, '\n\n' );
  312. // Convert two line breaks to a paragraph.
  313. text = text.replace( /([\s\S]+?)\n\n/g, '<p>$1</p>\n' );
  314. // Remove empty paragraphs.
  315. text = text.replace( /<p>\s*?<\/p>/gi, '');
  316. // Remove <p> tags that are around block tags.
  317. text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' );
  318. text = text.replace( /<p>(<li.+?)<\/p>/gi, '$1');
  319. // Fix <p> in blockquotes.
  320. text = text.replace( /<p>\s*<blockquote([^>]*)>/gi, '<blockquote$1><p>');
  321. text = text.replace( /<\/blockquote>\s*<\/p>/gi, '</p></blockquote>');
  322. // Remove <p> tags that are wrapped around block tags.
  323. text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '$1' );
  324. text = text.replace( new RegExp( '(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' );
  325. text = text.replace( /(<br[^>]*>)\s*\n/gi, '$1' );
  326. // Add <br> tags.
  327. text = text.replace( /\s*\n/g, '<br />\n');
  328. // Remove <br> tags that are around block tags.
  329. text = text.replace( new RegExp( '(</?(?:' + blocklist + ')[^>]*>)\\s*<br />', 'gi' ), '$1' );
  330. text = text.replace( /<br \/>(\s*<\/?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)>)/gi, '$1' );
  331. // Remove <p> and <br> around captions.
  332. text = text.replace( /(?:<p>|<br ?\/?>)*\s*\[caption([^\[]+)\[\/caption\]\s*(?:<\/p>|<br ?\/?>)*/gi, '[caption$1[/caption]' );
  333. // Make sure there is <p> when there is </p> inside block tags that can contain other blocks.
  334. text = text.replace( /(<(?:div|th|td|form|fieldset|dd)[^>]*>)(.*?)<\/p>/g, function( a, b, c ) {
  335. if ( c.match( /<p( [^>]*)?>/ ) ) {
  336. return a;
  337. }
  338. return b + '<p>' + c + '</p>';
  339. });
  340. // Restore the line breaks in <pre> and <script> tags.
  341. if ( preserve_linebreaks ) {
  342. text = text.replace( /<wp-line-break>/g, '\n' );
  343. }
  344. // Restore the <br> tags in captions.
  345. if ( preserve_br ) {
  346. text = text.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' );
  347. }
  348. return text;
  349. }
  350. /**
  351. * @summary Fires custom jQuery events `beforePreWpautop` and `afterPreWpautop` when jQuery is available.
  352. *
  353. * @since 2.9.0
  354. *
  355. * @memberof switchEditors
  356. *
  357. * @param {String} html The content from the visual editor.
  358. * @returns {String} the filtered content.
  359. */
  360. function pre_wpautop( html ) {
  361. var obj = { o: exports, data: html, unfiltered: html };
  362. if ( $ ) {
  363. $( 'body' ).trigger( 'beforePreWpautop', [ obj ] );
  364. }
  365. obj.data = removep( obj.data );
  366. if ( $ ) {
  367. $( 'body' ).trigger( 'afterPreWpautop', [ obj ] );
  368. }
  369. return obj.data;
  370. }
  371. /**
  372. * @summary Fires custom jQuery events `beforeWpautop` and `afterWpautop` when jQuery is available.
  373. *
  374. * @since 2.9.0
  375. *
  376. * @memberof switchEditors
  377. *
  378. * @param {String} text The content from the text editor.
  379. * @returns {String} filtered content.
  380. */
  381. function wpautop( text ) {
  382. var obj = { o: exports, data: text, unfiltered: text };
  383. if ( $ ) {
  384. $( 'body' ).trigger( 'beforeWpautop', [ obj ] );
  385. }
  386. obj.data = autop( obj.data );
  387. if ( $ ) {
  388. $( 'body' ).trigger( 'afterWpautop', [ obj ] );
  389. }
  390. return obj.data;
  391. }
  392. if ( $ ) {
  393. $( document ).ready( init );
  394. } else if ( document.addEventListener ) {
  395. document.addEventListener( 'DOMContentLoaded', init, false );
  396. window.addEventListener( 'load', init, false );
  397. } else if ( window.attachEvent ) {
  398. window.attachEvent( 'onload', init );
  399. document.attachEvent( 'onreadystatechange', function() {
  400. if ( 'complete' === document.readyState ) {
  401. init();
  402. }
  403. } );
  404. }
  405. wp.editor.autop = wpautop;
  406. wp.editor.removep = pre_wpautop;
  407. exports = {
  408. go: switchEditor,
  409. wpautop: wpautop,
  410. pre_wpautop: pre_wpautop,
  411. _wp_Autop: autop,
  412. _wp_Nop: removep
  413. };
  414. return exports;
  415. }
  416. /**
  417. * @namespace {SwitchEditors} switchEditors
  418. * Expose the switch editors to be used globally.
  419. */
  420. window.switchEditors = new SwitchEditors();
  421. /**
  422. * Initialize TinyMCE and/or Quicktags. For use with wp_enqueue_editor() (PHP).
  423. *
  424. * Intended for use with an existing textarea that will become the Text editor tab.
  425. * The editor width will be the width of the textarea container, height will be adjustable.
  426. *
  427. * Settings for both TinyMCE and Quicktags can be passed on initialization, and are "filtered"
  428. * with custom jQuery events on the document element, wp-before-tinymce-init and wp-before-quicktags-init.
  429. *
  430. * @since 4.8
  431. *
  432. * @param {string} id The HTML id of the textarea that is used for the editor.
  433. * Has to be jQuery compliant. No brackets, special chars, etc.
  434. * @param {object} settings Example:
  435. * settings = {
  436. * // See https://www.tinymce.com/docs/configure/integration-and-setup/.
  437. * // Alternatively set to `true` to use the defaults.
  438. * tinymce: {
  439. * setup: function( editor ) {
  440. * console.log( 'Editor initialized', editor );
  441. * }
  442. * }
  443. *
  444. * // Alternatively set to `true` to use the defaults.
  445. * quicktags: {
  446. * buttons: 'strong,em,link'
  447. * }
  448. * }
  449. */
  450. wp.editor.initialize = function( id, settings ) {
  451. var init;
  452. var defaults;
  453. if ( ! $ || ! id || ! wp.editor.getDefaultSettings ) {
  454. return;
  455. }
  456. defaults = wp.editor.getDefaultSettings();
  457. // Initialize TinyMCE by default
  458. if ( ! settings ) {
  459. settings = {
  460. tinymce: true
  461. };
  462. }
  463. // Add wrap and the Visual|Text tabs.
  464. if ( settings.tinymce && settings.quicktags ) {
  465. var $textarea = $( '#' + id );
  466. var $wrap = $( '<div>' ).attr( {
  467. 'class': 'wp-core-ui wp-editor-wrap tmce-active',
  468. id: 'wp-' + id + '-wrap'
  469. } );
  470. var $editorContainer = $( '<div class="wp-editor-container">' );
  471. var $button = $( '<button>' ).attr( {
  472. type: 'button',
  473. 'data-wp-editor-id': id
  474. } );
  475. $wrap.append(
  476. $( '<div class="wp-editor-tools">' )
  477. .append( $( '<div class="wp-editor-tabs">' )
  478. .append( $button.clone().attr({
  479. id: id + '-tmce',
  480. 'class': 'wp-switch-editor switch-tmce'
  481. }).text( window.tinymce.translate( 'Visual' ) ) )
  482. .append( $button.attr({
  483. id: id + '-html',
  484. 'class': 'wp-switch-editor switch-html'
  485. }).text( window.tinymce.translate( 'Text' ) ) )
  486. ).append( $editorContainer )
  487. );
  488. $textarea.after( $wrap );
  489. $editorContainer.append( $textarea );
  490. }
  491. if ( window.tinymce && settings.tinymce ) {
  492. if ( typeof settings.tinymce !== 'object' ) {
  493. settings.tinymce = {};
  494. }
  495. init = $.extend( {}, defaults.tinymce, settings.tinymce );
  496. init.selector = '#' + id;
  497. $( document ).trigger( 'wp-before-tinymce-init', init );
  498. window.tinymce.init( init );
  499. if ( ! window.wpActiveEditor ) {
  500. window.wpActiveEditor = id;
  501. }
  502. }
  503. if ( window.quicktags && settings.quicktags ) {
  504. if ( typeof settings.quicktags !== 'object' ) {
  505. settings.quicktags = {};
  506. }
  507. init = $.extend( {}, defaults.quicktags, settings.quicktags );
  508. init.id = id;
  509. $( document ).trigger( 'wp-before-quicktags-init', init );
  510. window.quicktags( init );
  511. if ( ! window.wpActiveEditor ) {
  512. window.wpActiveEditor = init.id;
  513. }
  514. }
  515. };
  516. /**
  517. * Remove one editor instance.
  518. *
  519. * Intended for use with editors that were initialized with wp.editor.initialize().
  520. *
  521. * @since 4.8
  522. *
  523. * @param {string} id The HTML id of the editor textarea.
  524. */
  525. wp.editor.remove = function( id ) {
  526. var mceInstance, qtInstance,
  527. $wrap = $( '#wp-' + id + '-wrap' );
  528. if ( window.tinymce ) {
  529. mceInstance = window.tinymce.get( id );
  530. if ( mceInstance ) {
  531. if ( ! mceInstance.isHidden() ) {
  532. mceInstance.save();
  533. }
  534. mceInstance.remove();
  535. }
  536. }
  537. if ( window.quicktags ) {
  538. qtInstance = window.QTags.getInstance( id );
  539. if ( qtInstance ) {
  540. qtInstance.remove();
  541. }
  542. }
  543. if ( $wrap.length ) {
  544. $wrap.after( $( '#' + id ) );
  545. $wrap.remove();
  546. }
  547. };
  548. /**
  549. * Get the editor content.
  550. *
  551. * Intended for use with editors that were initialized with wp.editor.initialize().
  552. *
  553. * @since 4.8
  554. *
  555. * @param {string} id The HTML id of the editor textarea.
  556. * @return The editor content.
  557. */
  558. wp.editor.getContent = function( id ) {
  559. var editor;
  560. if ( ! $ || ! id ) {
  561. return;
  562. }
  563. if ( window.tinymce ) {
  564. editor = window.tinymce.get( id );
  565. if ( editor && ! editor.isHidden() ) {
  566. editor.save();
  567. }
  568. }
  569. return $( '#' + id ).val();
  570. };
  571. }( window.jQuery, window.wp ));