Changeset 39738
- Timestamp:
- 01/06/2017 02:13:44 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/editor.js
r38594 r39738 1 1 2 2 ( function( $ ) { 3 /** 4 * @summary Creates the tinyMCE editors. 5 * 6 * Creates the tinyMCE editor and binds all events used for switching 7 * from visual to text mode. 8 * 9 * @since 4.3.0 10 * 11 * @class 12 */ 3 13 function SwitchEditors() { 4 14 var tinymce, $$, 5 15 exports = {}; 6 16 17 /** 18 * @summary Initializes the event binding for switching editors. 19 * 20 * @since 4.3.0 21 * 22 * @returns {void} 23 */ 7 24 function init() { 8 25 if ( ! tinymce && window.tinymce ) { … … 10 27 $$ = tinymce.$; 11 28 29 /** 30 * @summary Handles onclick events for the editor buttons. 31 * 32 * @since 4.3.0 33 * 34 * Handles an onclick event on the document. 35 * Switches the editor between visual and text, 36 * if the clicked element has the 'wp-switch-editor' class. 37 * If the class name is switch-html switches to the HTML editor, 38 * if the class name is switch-tmce 39 * switches to the TMCE editor. 40 * 41 * @returns {void} 42 */ 12 43 $$( document ).on( 'click', function( event ) { 13 44 var id, mode, … … 23 54 } 24 55 56 /** 57 * @summary Retrieves the height of the toolbar based on the container the 58 * editor is placed in. 59 * 60 * @since 3.9.0 61 * 62 * @param {Object} editor The tinyMCE editor. 63 * @returns {number} If the height is between 10 and 200 return the height, 64 * else return 30. 65 */ 25 66 function getToolbarHeight( editor ) { 26 67 var node = $$( '.mce-toolbar-grp', editor.getContainer() )[0], … … 34 75 } 35 76 77 /** 78 * @summary Switches the editor between visual and text. 79 * 80 * @since 4.3.0 81 * 82 * @memberof switchEditors 83 * 84 * @param {string} id The id of the editor you want to change the editor mode for. 85 * If no id is given, it defaults to content. 86 * @param {string} mode The mode you want to switch to. 87 * If an undefined mode is given, it defaults to toggle. 88 * 89 * @returns {void} 90 */ 36 91 function switchEditor( id, mode ) { 37 92 id = id || 'content'; … … 44 99 textarea = $textarea[0]; 45 100 101 // Toggle the mode between visual and textual representation. 46 102 if ( 'toggle' === mode ) { 47 103 if ( editor && ! editor.isHidden() ) { … … 52 108 } 53 109 110 111 // If the mode is tmce or tinymce, show the editor. 54 112 if ( 'tmce' === mode || 'tinymce' === mode ) { 113 114 /* 115 * If the editor isn't hidden we are already in tmce mode 116 * and we don't need to switch. 117 * Return false to stop event bubbling. 118 */ 55 119 if ( editor && ! editor.isHidden() ) { 56 120 return false; 57 121 } 58 122 123 // Close the QuickTags toolbars if they are visible. 59 124 if ( typeof( window.QTags ) !== 'undefined' ) { 60 125 window.QTags.closeAllTags( id ); … … 66 131 editor.show(); 67 132 68 // No point resizing the iframe in iOS133 // Don't resize the iframe in iOS. 69 134 if ( ! tinymce.Env.iOS && editorHeight ) { 70 135 toolbarHeight = getToolbarHeight( editor ); 71 136 editorHeight = editorHeight - toolbarHeight + 14; 72 137 73 // height cannot be under 50 or over 5000138 // Height must be between 50 and 5000. 74 139 if ( editorHeight > 50 && editorHeight < 5000 ) { 75 140 editor.theme.resizeTo( null, editorHeight ); … … 84 149 window.setUserSetting( 'editor', 'tinymce' ); 85 150 151 // Hide the editor if mode is html. 86 152 } else if ( 'html' === mode ) { 153 154 /* 155 * If the editor is hidden we are already in html mode and 156 * we don't need to switch. 157 * Return false to stop event bubbling. 158 */ 87 159 if ( editor && editor.isHidden() ) { 88 160 return false; … … 90 162 91 163 if ( editor ) { 164 165 // Don't resize the iframe in iOS. 92 166 if ( ! tinymce.Env.iOS ) { 93 167 iframe = editor.iframeElement; … … 98 172 editorHeight = editorHeight + toolbarHeight - 14; 99 173 100 // height cannot be under 50 or over 5000174 // Height must be between 50 and 5000. 101 175 if ( editorHeight > 50 && editorHeight < 5000 ) { 102 176 textarea.style.height = editorHeight + 'px'; … … 107 181 editor.hide(); 108 182 } else { 109 // The TinyMCE instance doesn't exist, show the textarea 183 // The TinyMCE instance doesn't exist, show the textarea. 110 184 $textarea.css({ 'display': '', 'visibility': '' }); 111 185 } … … 117 191 } 118 192 119 // Replace paragraphs with double line breaks 193 /** 194 * @summary Replaces all paragraphs with double line breaks. 195 * 196 * Replaces all paragraphs with double line breaks. Taking into account 197 * the elements where the <p> should be preserved. 198 * Unifies all whitespaces. 199 * Adds indenting with tabs to li, dt and dd elements. 200 * Trims whitespaces from beginning and end of the html input. 201 * 202 * @since 4.3.0 203 * 204 * @memberof switchEditors 205 * 206 * @param {string} html The content from the editor. 207 * @return {string} The formatted html string. 208 */ 120 209 function removep( html ) { 121 210 var blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset', … … 130 219 } 131 220 132 // Preserve script and style tags. 221 /* 222 * Protect script and style tags by replacing them with <wp-preserve>. 223 * Push matches into the preserve array. 224 */ 133 225 if ( html.indexOf( '<script' ) !== -1 || html.indexOf( '<style' ) !== -1 ) { 134 226 html = html.replace( /<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function( match ) { … … 138 230 } 139 231 140 // Protect pre tags. 232 /* 233 * Protect pre tags by replacing all newlines and 234 * <br> tags with <wp-line-break>. 235 */ 141 236 if ( html.indexOf( '<pre' ) !== -1 ) { 142 237 preserve_linebreaks = true; … … 148 243 } 149 244 150 // keep <br> tags inside captions and remove line breaks 245 /* 246 * Keep <br> tags inside captions and remove line breaks by replacing 247 * them with <wp-temp-br>. 248 */ 151 249 if ( html.indexOf( '[caption' ) !== -1 ) { 152 250 preserve_br = true; … … 156 254 } 157 255 158 // Pretty it up for the source editor256 // Format the text to be readable in the source editor. 159 257 html = html.replace( new RegExp( '\\s*</(' + blocklist1 + ')>\\s*', 'g' ), '</$1>\n' ); 160 258 html = html.replace( new RegExp( '\\s*<((?:' + blocklist1 + ')(?: [^>]*)?)>', 'g' ), '\n<$1>' ); … … 163 261 html = html.replace( /(<p [^>]+>.*?)<\/p>/g, '$1</p#>' ); 164 262 165 // Separate <div> containing <p>263 // If the content of a container starts with a paragraph, replace the <p> tag with 2 newlines. 166 264 html = html.replace( /<div( [^>]*)?>\s*<p>/gi, '<div$1>\n\n' ); 167 265 168 // Remove <p> and < br />266 // Remove <p> and </p> tags. 169 267 html = html.replace( /\s*<p>/gi, '' ); 170 268 html = html.replace( /\s*<\/p>\s*/gi, '\n\n' ); 269 270 // Remove white spaces between newlines. u00a0 is a no breaking space. 171 271 html = html.replace( /\n[\s\u00a0]+\n/g, '\n\n' ); 272 273 // Remove <br> tags. 172 274 html = html.replace( /\s*<br ?\/?>\s*/gi, '\n' ); 173 275 174 // Fix some block element newline issues 276 /* 277 * Fix some block element newline issues. 278 * Replace white spaces with newlines in combination with <div> tags. 279 */ 175 280 html = html.replace( /\s*<div/g, '\n<div' ); 176 281 html = html.replace( /<\/div>\s*/g, '</div>\n' ); 282 283 // Replace white spaces with newlines in combination with [caption] shortcodes. 177 284 html = html.replace( /\s*\[caption([^\[]+)\[\/caption\]\s*/gi, '\n\n[caption$1[/caption]\n\n' ); 285 286 /* 287 * Limit the newlines in combination with [caption]'s to a maximum of 288 * two consecutive occurrences. 289 * . 290 */ 178 291 html = html.replace( /caption\]\n\n+\[caption/g, 'caption]\n\n[caption' ); 179 292 293 /* 294 * Replace white spaces with newlines in combination with 295 * all elements listed in blocklist2. 296 */ 180 297 html = html.replace( new RegExp('\\s*<((?:' + blocklist2 + ')(?: [^>]*)?)\\s*>', 'g' ), '\n<$1>' ); 181 298 html = html.replace( new RegExp('\\s*</(' + blocklist2 + ')>\\s*', 'g' ), '</$1>\n' ); 299 300 // Add indentation by adding a tab in front of <li>, <dt> and <dd> tags. 182 301 html = html.replace( /<((li|dt|dd)[^>]*)>/g, ' \t<$1>' ); 183 302 303 // Replace white spaces with newlines in combination with <select> and <option> tags. 184 304 if ( html.indexOf( '<option' ) !== -1 ) { 185 305 html = html.replace( /\s*<option/g, '\n<option' ); … … 187 307 } 188 308 309 // Replace white spaces with 2 newlines in combination with <hr> tags. 189 310 if ( html.indexOf( '<hr' ) !== -1 ) { 190 311 html = html.replace( /\s*<hr( [^>]*)?>\s*/g, '\n\n<hr$1>\n\n' ); 191 312 } 192 313 314 // Remove newlines in <object> tags. 193 315 if ( html.indexOf( '<object' ) !== -1 ) { 194 316 html = html.replace( /<object[\s\S]+?<\/object>/g, function( a ) { … … 197 319 } 198 320 199 // Unmark special paragraph closing tags 321 // Unmark special paragraph closing tags. 200 322 html = html.replace( /<\/p#>/g, '</p>\n' ); 323 324 325 // Add a new line before <p> tags when there is content inside the paragraph 201 326 html = html.replace( /\s*(<p [^>]+>[\s\S]*?<\/p>)/g, '\n$1' ); 202 327 203 // Trim whitespace 328 /* 329 * Remove whitespaces at the start and end of a string. 330 * u00a0 is a no breaking space. 331 */ 204 332 html = html.replace( /^\s+/, '' ); 205 333 html = html.replace( /[\s\u00a0]+$/, '' ); 206 334 207 // put back the line breaks in pre|script335 // Replace <wp-line-break> tags with a newline. 208 336 if ( preserve_linebreaks ) { 209 337 html = html.replace( /<wp-line-break>/g, '\n' ); 210 338 } 211 339 212 // and the <br> tags in captions340 // Restore the <wp-temp-br> with <br> tags. 213 341 if ( preserve_br ) { 214 342 html = html.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' ); 215 343 } 216 344 217 // Put backpreserved tags.345 // Restore preserved tags. 218 346 if ( preserve.length ) { 219 347 html = html.replace( /<wp-preserve>/g, function() { … … 225 353 } 226 354 227 // Similar to `wpautop()` in formatting.php 355 /** 356 * @summary Adds paragraph tags to the text. 357 * 358 * Adds paragraph tags to the text taking into account block level elements. 359 * Normalizes the whitespaces and newlines. 360 * 361 * Similar to `wpautop()` in formatting.php. 362 * 363 * @since 4.3.0 364 * 365 * @memberof switchEditors 366 * 367 * @param {string} text The text input. 368 * @returns {string} The formatted text. 369 */ 228 370 function autop( text ) { 229 371 var preserve_linebreaks = false, 230 372 preserve_br = false, 373 374 // A list containing all block level elements. 231 375 blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre' + 232 376 '|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section' + 233 377 '|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary'; 234 378 235 // Normalize line breaks 379 // Normalize line breaks. 236 380 text = text.replace( /\r\n|\r/g, '\n' ); 237 381 382 // If there are no newlines, return the text. 238 383 if ( text.indexOf( '\n' ) === -1 ) { 239 384 return text; … … 241 386 242 387 if ( text.indexOf( '<object' ) !== -1 ) { 388 389 // If there are multiple newlines in an <object>, remove them. 243 390 text = text.replace( /<object[\s\S]+?<\/object>/g, function( a ) { 244 391 return a.replace( /\n+/g, '' ); … … 246 393 } 247 394 395 // Replace all new lines and tabs with spaces inside tags. 248 396 text = text.replace( /<[^<>]+>/g, function( a ) { 249 397 return a.replace( /[\n\t ]+/g, ' ' ); 250 398 }); 251 399 252 // Protect pre|script tags400 // Protect <pre> and <script> tags by replacing them with <wp-line-break>. 253 401 if ( text.indexOf( '<pre' ) !== -1 || text.indexOf( '<script' ) !== -1 ) { 254 402 preserve_linebreaks = true; … … 258 406 } 259 407 260 // keep <br> tags inside captions and convert line breaks408 // Keep <br> tags inside captions. 261 409 if ( text.indexOf( '[caption' ) !== -1 ) { 262 410 preserve_br = true; 411 412 // Replace all white spaces and <br> tags with <wp-temp-br>. 263 413 text = text.replace( /\[caption[\s\S]+?\[\/caption\]/g, function( a ) { 264 // keep existing <br> 414 415 // Protect <br> tags by converting them to <wp-temp-br> tags. 265 416 a = a.replace( /<br([^>]*)>/g, '<wp-temp-br$1>' ); 266 // no line breaks inside HTML tags 417 418 // Replace all new lines and tabs with spaces inside HTML tags. 267 419 a = a.replace( /<[^<>]+>/g, function( b ) { 420 421 // Replace newlines and tabs with a space. 268 422 return b.replace( /[\n\t ]+/, ' ' ); 269 423 }); 270 // convert remaining line breaks to <br> 424 425 // Convert remaining line breaks to <wp-temp-br />. 271 426 return a.replace( /\s*\n\s*/g, '<wp-temp-br />' ); 272 427 }); 273 428 } 274 429 430 // Append 2 newlines at the end of the text. 275 431 text = text + '\n\n'; 432 433 /* 434 * Replace a <br> tag followed by 1 or more spaces 435 * and another <br> tag with 2 newlines. 436 */ 276 437 text = text.replace( /<br \/>\s*<br \/>/gi, '\n\n' ); 438 439 /* 440 * Replace a block level element open tag with 2 newlines 441 * followed by the captured block level element. 442 */ 277 443 text = text.replace( new RegExp( '(<(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '\n\n$1' ); 444 445 /* 446 * Replace a block level element closing tag with the captured 447 * block level element followed by 2 newlines. 448 */ 278 449 text = text.replace( new RegExp( '(</(?:' + blocklist + ')>)', 'gi' ), '$1\n\n' ); 279 text = text.replace( /<hr( [^>]*)?>/gi, '<hr$1>\n\n' ); // hr is self closing block element 280 text = text.replace( /\s*<option/gi, '<option' ); // No <p> or <br> around <option> 450 451 // Add 2 newlines to a <hr> tag. <hr> is a self closing block element. 452 text = text.replace( /<hr( [^>]*)?>/gi, '<hr$1>\n\n' ); 453 454 // Remove the spaces before an <option> tag. 455 text = text.replace( /\s*<option/gi, '<option' ); 456 457 // Remove the spaces after an <option> closing tag. 281 458 text = text.replace( /<\/option>\s*/gi, '</option>' ); 459 460 // Remove the spaces between two newlines. 282 461 text = text.replace( /\n\s*\n+/g, '\n\n' ); 462 463 // Convert 2 newlines to a paragraph and a single newline. 283 464 text = text.replace( /([\s\S]+?)\n\n/g, '<p>$1</p>\n' ); 465 466 // Remove empty paragraphs. 284 467 text = text.replace( /<p>\s*?<\/p>/gi, ''); 468 469 // Remove spaces and <p> tags around block level elements. 285 470 text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' ); 471 472 // Remove <p> tags around li elements. 286 473 text = text.replace( /<p>(<li.+?)<\/p>/gi, '$1'); 474 475 // Remove spaces and <p> tags from blockquotes. 287 476 text = text.replace( /<p>\s*<blockquote([^>]*)>/gi, '<blockquote$1><p>'); 477 478 // Place the <blockquote> outside of the paragraph. 288 479 text = text.replace( /<\/blockquote>\s*<\/p>/gi, '</p></blockquote>'); 480 481 // Remove spaces at the start and <p> tags from block level elements. 289 482 text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '$1' ); 483 484 // Remove spaces at the end and <p> tags from block level elements. 290 485 text = text.replace( new RegExp( '(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' ); 291 486 292 // Remove redundant spaces and line breaks after existing <br /> tags487 // Remove spaces and newlines after a <br> tag. 293 488 text = text.replace( /(<br[^>]*>)\s*\n/gi, '$1' ); 294 489 295 // Create <br /> from the remaining line breaks490 // Replace spaces followed by a newline with a <br> tag followed by a new line. 296 491 text = text.replace( /\s*\n/g, '<br />\n'); 297 492 493 // Remove <br> tag that follows a block element directly, ignoring spaces. 298 494 text = text.replace( new RegExp( '(</?(?:' + blocklist + ')[^>]*>)\\s*<br />', 'gi' ), '$1' ); 495 496 /* 497 * Remove a br tag preceding white spaces followed by a 498 * <p>, <li>, <div>, <dl>, <dd>, <dt>, <th>, <pre>, <td>, <ul>, or <ol> tag. 499 */ 299 500 text = text.replace( /<br \/>(\s*<\/?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)>)/gi, '$1' ); 501 502 // Remove white spaces, <p> and <br> tags in captions. 300 503 text = text.replace( /(?:<p>|<br ?\/?>)*\s*\[caption([^\[]+)\[\/caption\]\s*(?:<\/p>|<br ?\/?>)*/gi, '[caption$1[/caption]' ); 301 504 505 /** 506 * @summary Makes sure there is a paragraph open tag for a close tag. 507 * 508 * @since 2.9.0 509 * 510 * Makes sure there is a paragraph open tag when there is a paragraph close tag 511 * in a div, th, td, form, fieldset or dd element. 512 * @param {string} a The complete match. 513 * @param {string} b The first capture group. 514 * @param {string} c The second capture group. 515 * @returns {string} The string in paragraph tags. 516 */ 302 517 text = text.replace( /(<(?:div|th|td|form|fieldset|dd)[^>]*>)(.*?)<\/p>/g, function( a, b, c ) { 518 519 /* 520 * Check if the matched group has a p open tag in it. If so, we don't need to 521 * enclose it with a paragraph. 522 */ 303 523 if ( c.match( /<p( [^>]*)?>/ ) ) { 304 524 return a; 305 525 } 306 526 527 /* 528 * If there is no p open tag in the matched string, 529 * add it and return the string including p tags. 530 */ 307 531 return b + '<p>' + c + '</p>'; 308 532 }); 309 533 310 // put back the line breaks in pre|script534 // Restore the line breaks in <pre> and <script> tags. 311 535 if ( preserve_linebreaks ) { 312 536 text = text.replace( /<wp-line-break>/g, '\n' ); 313 537 } 314 538 539 // Restore the <br> tags in captions. 315 540 if ( preserve_br ) { 316 541 text = text.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' ); … … 320 545 } 321 546 322 // Add old events 547 /** 548 * @summary Modifies the data when a switch is made from HTML to text. 549 * 550 * Modifies the data when a switch is made. 551 * Remove the <p> tags from text. 552 * Returns the modified text. 553 * Adds a trigger on beforePreWpautop and afterPreWpautop. 554 * 555 * @since 2.5.0 556 * 557 * @memberof switchEditors 558 * 559 * @param {String} html The content from the visual editor. 560 * @returns {String} the modified text. 561 */ 323 562 function pre_wpautop( html ) { 324 563 var obj = { o: exports, data: html, unfiltered: html }; … … 337 576 } 338 577 578 /** 579 * @summary Modifies the data when a switch is made from text to HTML. 580 * 581 * Modifies the data when a switch is made. Runs autop to add p tags from text. 582 * Returns the modified text. Adds a trigger on beforeWpautop and afterWpautop. 583 * 584 * @since 2.5.0 585 * 586 * @memberof switchEditors 587 * 588 * @param {String} text The content from the text editor. 589 * @returns {String} the modified text. 590 */ 339 591 function wpautop( text ) { 340 592 var obj = { o: exports, data: text, unfiltered: text }; … … 353 605 } 354 606 607 // Bind the init function to be run when the document is loaded. 355 608 if ( $ ) { 356 609 $( document ).ready( init ); 357 610 } else if ( document.addEventListener ) { 611 612 // Use the addEventListener to bind the init event on document load. 358 613 document.addEventListener( 'DOMContentLoaded', init, false ); 359 614 window.addEventListener( 'load', init, false ); 615 360 616 } else if ( window.attachEvent ) { 617 618 // Use the addEvent to bind the init event on document load. 361 619 window.attachEvent( 'onload', init ); 362 620 document.attachEvent( 'onreadystatechange', function() { … … 367 625 } 368 626 627 /* 628 * Make sure the window.wp object exists so autop and removep 629 * can be bound to it. 630 */ 369 631 window.wp = window.wp || {}; 370 632 window.wp.editor = window.wp.editor || {}; … … 383 645 } 384 646 647 /** 648 * @namespace {SwitchEditors} switchEditors 649 * Expose the switch editors to be used globally. 650 */ 385 651 window.switchEditors = new SwitchEditors(); 386 652 }( window.jQuery ));
Note: See TracChangeset
for help on using the changeset viewer.