45 * Returns the height of the editor toolbar(s) in px. |
45 * Returns the height of the editor toolbar(s) in px. |
46 * |
46 * |
47 * @since 3.9.0 |
47 * @since 3.9.0 |
48 * |
48 * |
49 * @param {Object} editor The TinyMCE editor. |
49 * @param {Object} editor The TinyMCE editor. |
50 * @returns {number} If the height is between 10 and 200 return the height, |
50 * @return {number} If the height is between 10 and 200 return the height, |
51 * else return 30. |
51 * else return 30. |
52 */ |
52 */ |
53 function getToolbarHeight( editor ) { |
53 function getToolbarHeight( editor ) { |
54 var node = $$( '.mce-toolbar-grp', editor.getContainer() )[0], |
54 var node = $$( '.mce-toolbar-grp', editor.getContainer() )[0], |
55 height = node && node.clientHeight; |
55 height = node && node.clientHeight; |
68 * |
68 * |
69 * @memberof switchEditors |
69 * @memberof switchEditors |
70 * |
70 * |
71 * @param {string} id The id of the editor you want to change the editor mode for. Default: `content`. |
71 * @param {string} id The id of the editor you want to change the editor mode for. Default: `content`. |
72 * @param {string} mode The mode you want to switch to. Default: `toggle`. |
72 * @param {string} mode The mode you want to switch to. Default: `toggle`. |
73 * @returns {void} |
73 * @return {void} |
74 */ |
74 */ |
75 function switchEditor( id, mode ) { |
75 function switchEditor( id, mode ) { |
76 id = id || 'content'; |
76 id = id || 'content'; |
77 mode = mode || 'toggle'; |
77 mode = mode || 'toggle'; |
78 |
78 |
110 keepSelection = window.tinyMCEPreInit.mceInit[ id ] && |
110 keepSelection = window.tinyMCEPreInit.mceInit[ id ] && |
111 window.tinyMCEPreInit.mceInit[ id ].wp_keep_scroll_position; |
111 window.tinyMCEPreInit.mceInit[ id ].wp_keep_scroll_position; |
112 } |
112 } |
113 |
113 |
114 if ( keepSelection ) { |
114 if ( keepSelection ) { |
115 // Save the selection |
115 // Save the selection. |
116 addHTMLBookmarkInTextAreaContent( $textarea ); |
116 addHTMLBookmarkInTextAreaContent( $textarea ); |
117 } |
117 } |
118 |
118 |
119 if ( editor ) { |
119 if ( editor ) { |
120 editor.show(); |
120 editor.show(); |
129 editor.theme.resizeTo( null, editorHeight ); |
129 editor.theme.resizeTo( null, editorHeight ); |
130 } |
130 } |
131 } |
131 } |
132 |
132 |
133 if ( editor.getParam( 'wp_keep_scroll_position' ) ) { |
133 if ( editor.getParam( 'wp_keep_scroll_position' ) ) { |
134 // Restore the selection |
134 // Restore the selection. |
135 focusHTMLBookmarkInVisualEditor( editor ); |
135 focusHTMLBookmarkInVisualEditor( editor ); |
136 } |
136 } |
137 } else { |
137 } else { |
138 tinymce.init( window.tinyMCEPreInit.mceInit[ id ] ); |
138 tinymce.init( window.tinyMCEPreInit.mceInit[ id ] ); |
139 } |
139 } |
147 if ( editor && editor.isHidden() ) { |
147 if ( editor && editor.isHidden() ) { |
148 return false; |
148 return false; |
149 } |
149 } |
150 |
150 |
151 if ( editor ) { |
151 if ( editor ) { |
152 // Don't resize the textarea in iOS. The iframe is forced to 100% height there, we shouldn't match it. |
152 // Don't resize the textarea in iOS. |
|
153 // The iframe is forced to 100% height there, we shouldn't match it. |
153 if ( ! tinymce.Env.iOS ) { |
154 if ( ! tinymce.Env.iOS ) { |
154 iframe = editor.iframeElement; |
155 iframe = editor.iframeElement; |
155 editorHeight = iframe ? parseInt( iframe.style.height, 10 ) : 0; |
156 editorHeight = iframe ? parseInt( iframe.style.height, 10 ) : 0; |
156 |
157 |
157 if ( editorHeight ) { |
158 if ( editorHeight ) { |
175 |
176 |
176 if ( selectionRange ) { |
177 if ( selectionRange ) { |
177 selectTextInTextArea( editor, selectionRange ); |
178 selectTextInTextArea( editor, selectionRange ); |
178 } |
179 } |
179 } else { |
180 } else { |
180 // There is probably a JS error on the page. The TinyMCE editor instance doesn't exist. Show the textarea. |
181 // There is probably a JS error on the page. |
|
182 // The TinyMCE editor instance doesn't exist. Show the textarea. |
181 $textarea.css({ 'display': '', 'visibility': '' }); |
183 $textarea.css({ 'display': '', 'visibility': '' }); |
182 } |
184 } |
183 |
185 |
184 wrap.removeClass( 'tmce-active' ).addClass( 'html-active' ); |
186 wrap.removeClass( 'tmce-active' ).addClass( 'html-active' ); |
185 $textarea.attr( 'aria-hidden', false ); |
187 $textarea.attr( 'aria-hidden', false ); |
200 * e.g. `[caption]<img.../>..`. |
202 * e.g. `[caption]<img.../>..`. |
201 * |
203 * |
202 * @param {string} content The test content where the cursor is. |
204 * @param {string} content The test content where the cursor is. |
203 * @param {number} cursorPosition The cursor position inside the content. |
205 * @param {number} cursorPosition The cursor position inside the content. |
204 * |
206 * |
205 * @returns {(null|Object)} Null if cursor is not in a tag, Object if the cursor is inside a tag. |
207 * @return {(null|Object)} Null if cursor is not in a tag, Object if the cursor is inside a tag. |
206 */ |
208 */ |
207 function getContainingTagInfo( content, cursorPosition ) { |
209 function getContainingTagInfo( content, cursorPosition ) { |
208 var lastLtPos = content.lastIndexOf( '<', cursorPosition - 1 ), |
210 var lastLtPos = content.lastIndexOf( '<', cursorPosition - 1 ), |
209 lastGtPos = content.lastIndexOf( '>', cursorPosition ); |
211 lastGtPos = content.lastIndexOf( '>', cursorPosition ); |
210 |
212 |
211 if ( lastLtPos > lastGtPos || content.substr( cursorPosition, 1 ) === '>' ) { |
213 if ( lastLtPos > lastGtPos || content.substr( cursorPosition, 1 ) === '>' ) { |
212 // find what the tag is |
214 // Find what the tag is. |
213 var tagContent = content.substr( lastLtPos ), |
215 var tagContent = content.substr( lastLtPos ), |
214 tagMatch = tagContent.match( /<\s*(\/)?(\w+|\!-{2}.*-{2})/ ); |
216 tagMatch = tagContent.match( /<\s*(\/)?(\w+|\!-{2}.*-{2})/ ); |
215 |
217 |
216 if ( ! tagMatch ) { |
218 if ( ! tagMatch ) { |
217 return null; |
219 return null; |
220 var tagType = tagMatch[2], |
222 var tagType = tagMatch[2], |
221 closingGt = tagContent.indexOf( '>' ); |
223 closingGt = tagContent.indexOf( '>' ); |
222 |
224 |
223 return { |
225 return { |
224 ltPos: lastLtPos, |
226 ltPos: lastLtPos, |
225 gtPos: lastLtPos + closingGt + 1, // offset by one to get the position _after_ the character, |
227 gtPos: lastLtPos + closingGt + 1, // Offset by one to get the position _after_ the character. |
226 tagType: tagType, |
228 tagType: tagType, |
227 isClosingTag: !! tagMatch[1] |
229 isClosingTag: !! tagMatch[1] |
228 }; |
230 }; |
229 } |
231 } |
230 return null; |
232 return null; |
246 * |
248 * |
247 * @param {string} content The text content to check against. |
249 * @param {string} content The text content to check against. |
248 * @param {number} cursorPosition The cursor position to check. |
250 * @param {number} cursorPosition The cursor position to check. |
249 * |
251 * |
250 * @return {(undefined|Object)} Undefined if the cursor is not wrapped in a shortcode tag. |
252 * @return {(undefined|Object)} Undefined if the cursor is not wrapped in a shortcode tag. |
251 * Information about the wrapping shortcode tag if it's wrapped in one. |
253 * Information about the wrapping shortcode tag if it's wrapped in one. |
252 */ |
254 */ |
253 function getShortcodeWrapperInfo( content, cursorPosition ) { |
255 function getShortcodeWrapperInfo( content, cursorPosition ) { |
254 var contentShortcodes = getShortCodePositionsInText( content ); |
256 var contentShortcodes = getShortCodePositionsInText( content ); |
255 |
257 |
256 for ( var i = 0; i < contentShortcodes.length; i++ ) { |
258 for ( var i = 0; i < contentShortcodes.length; i++ ) { |
401 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' |
403 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' |
402 ]; |
404 ]; |
403 |
405 |
404 var cursorStart = cursorPositions.cursorStart, |
406 var cursorStart = cursorPositions.cursorStart, |
405 cursorEnd = cursorPositions.cursorEnd, |
407 cursorEnd = cursorPositions.cursorEnd, |
406 // check if the cursor is in a tag and if so, adjust it |
408 // Check if the cursor is in a tag and if so, adjust it. |
407 isCursorStartInTag = getContainingTagInfo( content, cursorStart ); |
409 isCursorStartInTag = getContainingTagInfo( content, cursorStart ); |
408 |
410 |
409 if ( isCursorStartInTag ) { |
411 if ( isCursorStartInTag ) { |
410 /** |
412 /** |
411 * Only move to the start of the HTML tag (to select the whole element) if the tag |
413 * Only move to the start of the HTML tag (to select the whole element) if the tag |
469 * |
471 * |
470 * Adds selection markers in the content of the editor `textarea`. |
472 * Adds selection markers in the content of the editor `textarea`. |
471 * The method directly manipulates the `textarea` content, to allow TinyMCE plugins |
473 * The method directly manipulates the `textarea` content, to allow TinyMCE plugins |
472 * to run after the markers are added. |
474 * to run after the markers are added. |
473 * |
475 * |
474 * @param {object} $textarea TinyMCE's textarea wrapped as a DomQuery object |
476 * @param {Object} $textarea TinyMCE's textarea wrapped as a DomQuery object |
475 */ |
477 */ |
476 function addHTMLBookmarkInTextAreaContent( $textarea ) { |
478 function addHTMLBookmarkInTextAreaContent( $textarea ) { |
477 if ( ! $textarea || ! $textarea.length ) { |
479 if ( ! $textarea || ! $textarea.length ) { |
478 // If no valid $textarea object is provided, there's nothing we can do. |
480 // If no valid $textarea object is provided, there's nothing we can do. |
479 return; |
481 return; |
504 bookMarkEnd[0].outerHTML |
506 bookMarkEnd[0].outerHTML |
505 ].join( '' ); |
507 ].join( '' ); |
506 } |
508 } |
507 |
509 |
508 textArea.value = [ |
510 textArea.value = [ |
509 textArea.value.slice( 0, htmlModeCursorStartPosition ), // text until the cursor/selection position |
511 textArea.value.slice( 0, htmlModeCursorStartPosition ), // Text until the cursor/selection position. |
510 cursorMarkerSkeleton.clone() // cursor/selection start marker |
512 cursorMarkerSkeleton.clone() // Cursor/selection start marker. |
511 .addClass( 'mce_SELRES_start' )[0].outerHTML, |
513 .addClass( 'mce_SELRES_start' )[0].outerHTML, |
512 selectedText, // selected text with end cursor/position marker |
514 selectedText, // Selected text with end cursor/position marker. |
513 textArea.value.slice( htmlModeCursorEndPosition ) // text from last cursor/selection position to end |
515 textArea.value.slice( htmlModeCursorEndPosition ) // Text from last cursor/selection position to end. |
514 ].join( '' ); |
516 ].join( '' ); |
515 } |
517 } |
516 |
518 |
517 /** |
519 /** |
518 * Focuses the selection markers in Visual mode. |
520 * Focuses the selection markers in Visual mode. |
557 * Removes selection marker and the parent node if it is an empty paragraph. |
559 * Removes selection marker and the parent node if it is an empty paragraph. |
558 * |
560 * |
559 * By default TinyMCE wraps loose inline tags in a `<p>`. |
561 * By default TinyMCE wraps loose inline tags in a `<p>`. |
560 * When removing selection markers an empty `<p>` may be left behind, remove it. |
562 * When removing selection markers an empty `<p>` may be left behind, remove it. |
561 * |
563 * |
562 * @param {object} $marker The marker to be removed from the editor DOM, wrapped in an instnce of `editor.$` |
564 * @param {Object} $marker The marker to be removed from the editor DOM, wrapped in an instnce of `editor.$` |
563 */ |
565 */ |
564 function removeSelectionMarker( $marker ) { |
566 function removeSelectionMarker( $marker ) { |
565 var $markerParent = $marker.parent(); |
567 var $markerParent = $marker.parent(); |
566 |
568 |
567 $marker.remove(); |
569 $marker.remove(); |
656 * Uses the standard DOM selection API to achieve that goal. |
658 * Uses the standard DOM selection API to achieve that goal. |
657 * |
659 * |
658 * Check the notes in the comments in the code below for more information on some gotchas |
660 * Check the notes in the comments in the code below for more information on some gotchas |
659 * and why this solution was chosen. |
661 * and why this solution was chosen. |
660 * |
662 * |
661 * @param {Object} editor The editor where we must find the selection |
663 * @param {Object} editor The editor where we must find the selection. |
662 * @returns {(null|Object)} The selection range position in the editor |
664 * @return {(null|Object)} The selection range position in the editor. |
663 */ |
665 */ |
664 function findBookmarkedPosition( editor ) { |
666 function findBookmarkedPosition( editor ) { |
665 // Get the TinyMCE `window` reference, since we need to access the raw selection. |
667 // Get the TinyMCE `window` reference, since we need to access the raw selection. |
666 var TinyMCEWindow = editor.getWin(), |
668 var TinyMCEWindow = editor.getWin(), |
667 selection = TinyMCEWindow.getSelection(); |
669 selection = TinyMCEWindow.getSelection(); |
824 * |
826 * |
825 * @param {Object} editor TinyMCE's editor instance. |
827 * @param {Object} editor TinyMCE's editor instance. |
826 * @param {Object} selection Selection data. |
828 * @param {Object} selection Selection data. |
827 */ |
829 */ |
828 function selectTextInTextArea( editor, selection ) { |
830 function selectTextInTextArea( editor, selection ) { |
829 // only valid in the text area mode and if we have selection |
831 // Only valid in the text area mode and if we have selection. |
830 if ( ! selection ) { |
832 if ( ! selection ) { |
831 return; |
833 return; |
832 } |
834 } |
833 |
835 |
834 var textArea = editor.getElement(), |
836 var textArea = editor.getElement(), |
835 start = selection.start, |
837 start = selection.start, |
836 end = selection.end || selection.start; |
838 end = selection.end || selection.start; |
837 |
839 |
838 if ( textArea.focus ) { |
840 if ( textArea.focus ) { |
839 // Wait for the Visual editor to be hidden, then focus and scroll to the position |
841 // Wait for the Visual editor to be hidden, then focus and scroll to the position. |
840 setTimeout( function() { |
842 setTimeout( function() { |
841 textArea.setSelectionRange( start, end ); |
843 textArea.setSelectionRange( start, end ); |
842 if ( textArea.blur ) { |
844 if ( textArea.blur ) { |
843 // defocus before focusing |
845 // Defocus before focusing. |
844 textArea.blur(); |
846 textArea.blur(); |
845 } |
847 } |
846 textArea.focus(); |
848 textArea.focus(); |
847 }, 100 ); |
849 }, 100 ); |
848 } |
850 } |
1002 * @since 2.5.0 |
1004 * @since 2.5.0 |
1003 * |
1005 * |
1004 * @memberof switchEditors |
1006 * @memberof switchEditors |
1005 * |
1007 * |
1006 * @param {string} text The text input. |
1008 * @param {string} text The text input. |
1007 * @returns {string} The formatted text. |
1009 * @return {string} The formatted text. |
1008 */ |
1010 */ |
1009 function autop( text ) { |
1011 function autop( text ) { |
1010 var preserve_linebreaks = false, |
1012 var preserve_linebreaks = false, |
1011 preserve_br = false, |
1013 preserve_br = false, |
1012 blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre' + |
1014 blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre' + |
1128 * |
1130 * |
1129 * @since 2.9.0 |
1131 * @since 2.9.0 |
1130 * |
1132 * |
1131 * @memberof switchEditors |
1133 * @memberof switchEditors |
1132 * |
1134 * |
1133 * @param {String} html The content from the visual editor. |
1135 * @param {string} html The content from the visual editor. |
1134 * @returns {String} the filtered content. |
1136 * @return {string} the filtered content. |
1135 */ |
1137 */ |
1136 function pre_wpautop( html ) { |
1138 function pre_wpautop( html ) { |
1137 var obj = { o: exports, data: html, unfiltered: html }; |
1139 var obj = { o: exports, data: html, unfiltered: html }; |
1138 |
1140 |
1139 if ( $ ) { |
1141 if ( $ ) { |
1154 * |
1156 * |
1155 * @since 2.9.0 |
1157 * @since 2.9.0 |
1156 * |
1158 * |
1157 * @memberof switchEditors |
1159 * @memberof switchEditors |
1158 * |
1160 * |
1159 * @param {String} text The content from the text editor. |
1161 * @param {string} text The content from the text editor. |
1160 * @returns {String} filtered content. |
1162 * @return {string} filtered content. |
1161 */ |
1163 */ |
1162 function wpautop( text ) { |
1164 function wpautop( text ) { |
1163 var obj = { o: exports, data: text, unfiltered: text }; |
1165 var obj = { o: exports, data: text, unfiltered: text }; |
1164 |
1166 |
1165 if ( $ ) { |
1167 if ( $ ) { |
1221 * |
1223 * |
1222 * @since 4.8.0 |
1224 * @since 4.8.0 |
1223 * |
1225 * |
1224 * @param {string} id The HTML id of the textarea that is used for the editor. |
1226 * @param {string} id The HTML id of the textarea that is used for the editor. |
1225 * Has to be jQuery compliant. No brackets, special chars, etc. |
1227 * Has to be jQuery compliant. No brackets, special chars, etc. |
1226 * @param {object} settings Example: |
1228 * @param {Object} settings Example: |
1227 * settings = { |
1229 * settings = { |
1228 * // See https://www.tinymce.com/docs/configure/integration-and-setup/. |
1230 * // See https://www.tinymce.com/docs/configure/integration-and-setup/. |
1229 * // Alternatively set to `true` to use the defaults. |
1231 * // Alternatively set to `true` to use the defaults. |
1230 * tinymce: { |
1232 * tinymce: { |
1231 * setup: function( editor ) { |
1233 * setup: function( editor ) { |