4 var $window = $( window ), |
4 var $window = $( window ), |
5 $document = $( document ), |
5 $document = $( document ), |
6 $adminBar = $( '#wpadminbar' ), |
6 $adminBar = $( '#wpadminbar' ), |
7 $footer = $( '#wpfooter' ); |
7 $footer = $( '#wpfooter' ); |
8 |
8 |
9 /* Autoresize editor. */ |
9 /** |
|
10 * @summary Handles the resizing of the editor. |
|
11 * |
|
12 * @since 4.0.0 |
|
13 * |
|
14 * @returns {void} |
|
15 */ |
10 $( function() { |
16 $( function() { |
11 var $wrap = $( '#postdivrich' ), |
17 var $wrap = $( '#postdivrich' ), |
12 $contentWrap = $( '#wp-content-wrap' ), |
18 $contentWrap = $( '#wp-content-wrap' ), |
13 $tools = $( '#wp-content-editor-tools' ), |
19 $tools = $( '#wp-content-editor-tools' ), |
14 $visualTop = $(), |
20 $visualTop = $(), |
15 $visualEditor = $(), |
21 $visualEditor = $(), |
16 $textTop = $( '#ed_toolbar' ), |
22 $textTop = $( '#ed_toolbar' ), |
17 $textEditor = $( '#content' ), |
23 $textEditor = $( '#content' ), |
18 $textEditorClone = $( '<div id="content-textarea-clone" class="wp-exclude-emoji"></div>' ), |
24 textEditor = $textEditor[0], |
|
25 oldTextLength = 0, |
19 $bottom = $( '#post-status-info' ), |
26 $bottom = $( '#post-status-info' ), |
20 $menuBar = $(), |
27 $menuBar = $(), |
21 $statusBar = $(), |
28 $statusBar = $(), |
22 $sideSortables = $( '#side-sortables' ), |
29 $sideSortables = $( '#side-sortables' ), |
23 $postboxContainer = $( '#postbox-container-1' ), |
30 $postboxContainer = $( '#postbox-container-1' ), |
50 bottomHeight: 0, |
57 bottomHeight: 0, |
51 statusBarHeight: 0, |
58 statusBarHeight: 0, |
52 sideSortablesHeight: 0 |
59 sideSortablesHeight: 0 |
53 }; |
60 }; |
54 |
61 |
55 $textEditorClone.insertAfter( $textEditor ); |
62 /** |
56 |
63 * @summary Resizes textarea based on scroll height and width. |
57 $textEditorClone.css( { |
64 * |
58 'font-family': $textEditor.css( 'font-family' ), |
65 * Resizes textarea based on scroll height and width. Doesn't shrink the |
59 'font-size': $textEditor.css( 'font-size' ), |
66 * editor size below the 300px auto resize minimum height. |
60 'line-height': $textEditor.css( 'line-height' ), |
67 * |
61 'white-space': 'pre-wrap', |
68 * @since 4.6.1 |
62 'word-wrap': 'break-word' |
69 * |
63 } ); |
70 * @returns {void} |
64 |
71 */ |
|
72 var shrinkTextarea = window._.throttle( function() { |
|
73 var x = window.scrollX || document.documentElement.scrollLeft; |
|
74 var y = window.scrollY || document.documentElement.scrollTop; |
|
75 var height = parseInt( textEditor.style.height, 10 ); |
|
76 |
|
77 textEditor.style.height = autoresizeMinHeight + 'px'; |
|
78 |
|
79 if ( textEditor.scrollHeight > autoresizeMinHeight ) { |
|
80 textEditor.style.height = textEditor.scrollHeight + 'px'; |
|
81 } |
|
82 |
|
83 if ( typeof x !== 'undefined' ) { |
|
84 window.scrollTo( x, y ); |
|
85 } |
|
86 |
|
87 if ( textEditor.scrollHeight < height ) { |
|
88 adjust(); |
|
89 } |
|
90 }, 300 ); |
|
91 |
|
92 /** |
|
93 * @summary Resizes the text editor depending on the old text length. |
|
94 * |
|
95 * If there is an mceEditor and it is hidden, it resizes the editor depending |
|
96 * on the old text length. If the current length of the text is smaller than |
|
97 * the old text length, it shrinks the text area. Otherwise it resizes the editor to |
|
98 * the scroll height. |
|
99 * |
|
100 * @since 4.6.1 |
|
101 * |
|
102 * @returns {void} |
|
103 */ |
|
104 function textEditorResize() { |
|
105 var length = textEditor.value.length; |
|
106 |
|
107 if ( mceEditor && ! mceEditor.isHidden() ) { |
|
108 return; |
|
109 } |
|
110 |
|
111 if ( ! mceEditor && initialMode === 'tinymce' ) { |
|
112 return; |
|
113 } |
|
114 |
|
115 if ( length < oldTextLength ) { |
|
116 shrinkTextarea(); |
|
117 } else if ( parseInt( textEditor.style.height, 10 ) < textEditor.scrollHeight ) { |
|
118 textEditor.style.height = Math.ceil( textEditor.scrollHeight ) + 'px'; |
|
119 adjust(); |
|
120 } |
|
121 |
|
122 oldTextLength = length; |
|
123 } |
|
124 |
|
125 /** |
|
126 * @summary Gets the height and widths of elements. |
|
127 * |
|
128 * Gets the heights of the window, the adminbar, the tools, the menu, |
|
129 * the visualTop, the textTop, the bottom, the statusbar and sideSortables |
|
130 * and stores these in the heights object. Defaults to 0. |
|
131 * Gets the width of the window and stores this in the heights object. |
|
132 * |
|
133 * @since 4.0.0 |
|
134 * |
|
135 * @returns {void} |
|
136 */ |
65 function getHeights() { |
137 function getHeights() { |
66 var windowWidth = $window.width(); |
138 var windowWidth = $window.width(); |
67 |
139 |
68 heights = { |
140 heights = { |
69 windowHeight: $window.height(), |
141 windowHeight: $window.height(), |
76 bottomHeight: $bottom.outerHeight() || 0, |
148 bottomHeight: $bottom.outerHeight() || 0, |
77 statusBarHeight: $statusBar.outerHeight() || 0, |
149 statusBarHeight: $statusBar.outerHeight() || 0, |
78 sideSortablesHeight: $sideSortables.height() || 0 |
150 sideSortablesHeight: $sideSortables.height() || 0 |
79 }; |
151 }; |
80 |
152 |
81 // Adjust for hidden |
153 // Adjust for hidden menubar. |
82 if ( heights.menuBarHeight < 3 ) { |
154 if ( heights.menuBarHeight < 3 ) { |
83 heights.menuBarHeight = 0; |
155 heights.menuBarHeight = 0; |
84 } |
156 } |
85 } |
157 } |
86 |
158 |
87 function textEditorKeyup( event ) { |
|
88 var VK = jQuery.ui.keyCode, |
|
89 key = event.keyCode, |
|
90 range = document.createRange(), |
|
91 selStart = $textEditor[0].selectionStart, |
|
92 selEnd = $textEditor[0].selectionEnd, |
|
93 textNode = $textEditorClone[0].firstChild, |
|
94 buffer = 10, |
|
95 offset, cursorTop, cursorBottom, editorTop, editorBottom; |
|
96 |
|
97 if ( selStart && selEnd && selStart !== selEnd ) { |
|
98 return; |
|
99 } |
|
100 |
|
101 // These are not TinyMCE ranges. |
|
102 try { |
|
103 range.setStart( textNode, selStart ); |
|
104 range.setEnd( textNode, selEnd + 1 ); |
|
105 } catch ( ex ) {} |
|
106 |
|
107 offset = range.getBoundingClientRect(); |
|
108 |
|
109 if ( ! offset.height ) { |
|
110 return; |
|
111 } |
|
112 |
|
113 cursorTop = offset.top - buffer; |
|
114 cursorBottom = cursorTop + offset.height + buffer; |
|
115 editorTop = heights.adminBarHeight + heights.toolsHeight + heights.textTopHeight; |
|
116 editorBottom = heights.windowHeight - heights.bottomHeight; |
|
117 |
|
118 if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) { |
|
119 window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop ); |
|
120 } else if ( cursorBottom > editorBottom ) { |
|
121 window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); |
|
122 } |
|
123 } |
|
124 |
|
125 function textEditorResize() { |
|
126 if ( ( mceEditor && ! mceEditor.isHidden() ) || ( ! mceEditor && initialMode === 'tinymce' ) ) { |
|
127 return; |
|
128 } |
|
129 |
|
130 var textEditorHeight = $textEditor.height(), |
|
131 hiddenHeight; |
|
132 |
|
133 $textEditorClone.width( $textEditor.width() - 22 ); |
|
134 $textEditorClone.text( $textEditor.val() + ' ' ); |
|
135 |
|
136 hiddenHeight = $textEditorClone.height(); |
|
137 |
|
138 if ( hiddenHeight < autoresizeMinHeight ) { |
|
139 hiddenHeight = autoresizeMinHeight; |
|
140 } |
|
141 |
|
142 if ( hiddenHeight === textEditorHeight ) { |
|
143 return; |
|
144 } |
|
145 |
|
146 $textEditor.height( hiddenHeight ); |
|
147 |
|
148 adjust(); |
|
149 } |
|
150 |
|
151 // We need to wait for TinyMCE to initialize. |
159 // We need to wait for TinyMCE to initialize. |
|
160 /** |
|
161 * @summary Binds all necessary functions for editor expand to the editor |
|
162 * when the editor is initialized. |
|
163 * |
|
164 * @since 4.0.0 |
|
165 * |
|
166 * @param {event} event The TinyMCE editor init event. |
|
167 * @param {object} editor The editor to bind the vents on. |
|
168 * |
|
169 * @returns {void} |
|
170 */ |
152 $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) { |
171 $document.on( 'tinymce-editor-init.editor-expand', function( event, editor ) { |
|
172 // VK contains the type of key pressed. VK = virtual keyboard. |
153 var VK = window.tinymce.util.VK, |
173 var VK = window.tinymce.util.VK, |
|
174 /** |
|
175 * @summary Hides any float panel with a hover state. Additionally hides tooltips. |
|
176 * |
|
177 * @returns {void} |
|
178 */ |
154 hideFloatPanels = _.debounce( function() { |
179 hideFloatPanels = _.debounce( function() { |
155 ! $( '.mce-floatpanel:hover' ).length && window.tinymce.ui.FloatPanel.hideAll(); |
180 ! $( '.mce-floatpanel:hover' ).length && window.tinymce.ui.FloatPanel.hideAll(); |
156 $( '.mce-tooltip' ).hide(); |
181 $( '.mce-tooltip' ).hide(); |
157 }, 1000, true ); |
182 }, 1000, true ); |
158 |
183 |
171 $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); |
196 $visualTop = $contentWrap.find( '.mce-toolbar-grp' ); |
172 $visualEditor = $contentWrap.find( '.mce-edit-area' ); |
197 $visualEditor = $contentWrap.find( '.mce-edit-area' ); |
173 $statusBar = $contentWrap.find( '.mce-statusbar' ); |
198 $statusBar = $contentWrap.find( '.mce-statusbar' ); |
174 $menuBar = $contentWrap.find( '.mce-menubar' ); |
199 $menuBar = $contentWrap.find( '.mce-menubar' ); |
175 |
200 |
|
201 /** |
|
202 * @summary Gets the offset of the editor. |
|
203 * |
|
204 * @returns {Number|Boolean} Returns the offset of the editor |
|
205 * or false if there is no offset height. |
|
206 */ |
176 function mceGetCursorOffset() { |
207 function mceGetCursorOffset() { |
177 var node = editor.selection.getNode(), |
208 var node = editor.selection.getNode(), |
178 range, view, offset; |
209 range, view, offset; |
179 |
210 |
|
211 /* |
|
212 * If editor.wp.getView and the selection node from the editor selection |
|
213 * are defined, use this as a view for the offset. |
|
214 */ |
180 if ( editor.wp && editor.wp.getView && ( view = editor.wp.getView( node ) ) ) { |
215 if ( editor.wp && editor.wp.getView && ( view = editor.wp.getView( node ) ) ) { |
181 offset = view.getBoundingClientRect(); |
216 offset = view.getBoundingClientRect(); |
182 } else { |
217 } else { |
183 range = editor.selection.getRng(); |
218 range = editor.selection.getRng(); |
184 |
219 |
|
220 // Try to get the offset from a range. |
185 try { |
221 try { |
186 offset = range.getClientRects()[0]; |
222 offset = range.getClientRects()[0]; |
187 } catch( er ) {} |
223 } catch( er ) {} |
188 |
224 |
|
225 // Get the offset from the bounding client rectangle of the node. |
189 if ( ! offset ) { |
226 if ( ! offset ) { |
190 offset = node.getBoundingClientRect(); |
227 offset = node.getBoundingClientRect(); |
191 } |
228 } |
192 } |
229 } |
193 |
230 |
194 return offset.height ? offset : false; |
231 return offset.height ? offset : false; |
195 } |
232 } |
196 |
233 |
197 // Make sure the cursor is always visible. |
234 /** |
198 // This is not only necessary to keep the cursor between the toolbars, |
235 * @summary Filters the special keys that should not be used for scrolling. |
199 // but also to scroll the window when the cursor moves out of the viewport to a wpview. |
236 * |
200 // Setting a buffer > 0 will prevent the browser default. |
237 * @since 4.0.0 |
201 // Some browsers will scroll to the middle, |
238 * |
202 // others to the top/bottom of the *window* when moving the cursor out of the viewport. |
239 * @param {event} event The event to get the key code from. |
|
240 * |
|
241 * @returns {void} |
|
242 */ |
203 function mceKeyup( event ) { |
243 function mceKeyup( event ) { |
204 var key = event.keyCode; |
244 var key = event.keyCode; |
205 |
245 |
206 // Bail on special keys. |
246 // Bail on special keys. Key code 47 is a / |
207 if ( key <= 47 && ! ( key === VK.SPACEBAR || key === VK.ENTER || key === VK.DELETE || key === VK.BACKSPACE || key === VK.UP || key === VK.LEFT || key === VK.DOWN || key === VK.UP ) ) { |
247 if ( key <= 47 && ! ( key === VK.SPACEBAR || key === VK.ENTER || key === VK.DELETE || key === VK.BACKSPACE || key === VK.UP || key === VK.LEFT || key === VK.DOWN || key === VK.UP ) ) { |
208 return; |
248 return; |
209 // OS keys, function keys, num lock, scroll lock |
249 // OS keys, function keys, num lock, scroll lock. Key code 91-93 are OS keys. Key code 112-123 are F1 to F12. Key code 144 is num lock. Key code 145 is scroll lock. |
210 } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) { |
250 } else if ( ( key >= 91 && key <= 93 ) || ( key >= 112 && key <= 123 ) || key === 144 || key === 145 ) { |
211 return; |
251 return; |
212 } |
252 } |
213 |
253 |
214 mceScroll( key ); |
254 mceScroll( key ); |
215 } |
255 } |
216 |
256 |
|
257 /** |
|
258 * @summary Makes sure the cursor is always visible in the editor. |
|
259 * |
|
260 * Makes sure the cursor is kept between the toolbars of the editor and scrolls |
|
261 * the window when the cursor moves out of the viewport to a wpview. |
|
262 * Setting a buffer > 0 will prevent the browser default. |
|
263 * Some browsers will scroll to the middle, |
|
264 * others to the top/bottom of the *window* when moving the cursor out of the viewport. |
|
265 * |
|
266 * @since 4.1.0 |
|
267 * |
|
268 * @param {string} key The key code of the pressed key. |
|
269 * |
|
270 * @returns {void} |
|
271 */ |
217 function mceScroll( key ) { |
272 function mceScroll( key ) { |
218 var offset = mceGetCursorOffset(), |
273 var offset = mceGetCursorOffset(), |
219 buffer = 50, |
274 buffer = 50, |
220 cursorTop, cursorBottom, editorTop, editorBottom; |
275 cursorTop, cursorBottom, editorTop, editorBottom; |
221 |
276 |
|
277 // Don't scroll if there is no offset. |
222 if ( ! offset ) { |
278 if ( ! offset ) { |
223 return; |
279 return; |
224 } |
280 } |
225 |
281 |
|
282 // Determine the cursorTop based on the offset and the top of the editor iframe. |
226 cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top; |
283 cursorTop = offset.top + editor.iframeElement.getBoundingClientRect().top; |
|
284 |
|
285 // Determine the cursorBottom based on the cursorTop and offset height. |
227 cursorBottom = cursorTop + offset.height; |
286 cursorBottom = cursorTop + offset.height; |
|
287 |
|
288 // Subtract the buffer from the cursorTop. |
228 cursorTop = cursorTop - buffer; |
289 cursorTop = cursorTop - buffer; |
|
290 |
|
291 // Add the buffer to the cursorBottom. |
229 cursorBottom = cursorBottom + buffer; |
292 cursorBottom = cursorBottom + buffer; |
230 editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight; |
293 editorTop = heights.adminBarHeight + heights.toolsHeight + heights.menuBarHeight + heights.visualTopHeight; |
|
294 |
|
295 /* |
|
296 * Set the editorBottom based on the window Height, and add the bottomHeight and statusBarHeight if the |
|
297 * advanced editor is enabled. |
|
298 */ |
231 editorBottom = heights.windowHeight - ( advanced ? heights.bottomHeight + heights.statusBarHeight : 0 ); |
299 editorBottom = heights.windowHeight - ( advanced ? heights.bottomHeight + heights.statusBarHeight : 0 ); |
232 |
300 |
233 // Don't scroll if the node is taller than the visible part of the editor |
301 // Don't scroll if the node is taller than the visible part of the editor. |
234 if ( editorBottom - editorTop < offset.height ) { |
302 if ( editorBottom - editorTop < offset.height ) { |
235 return; |
303 return; |
236 } |
304 } |
237 |
305 |
|
306 /* |
|
307 * If the cursorTop is smaller than the editorTop and the up, left |
|
308 * or backspace key is pressed, scroll the editor to the position defined |
|
309 * by the cursorTop, pageYOffset and editorTop. |
|
310 */ |
238 if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) { |
311 if ( cursorTop < editorTop && ( key === VK.UP || key === VK.LEFT || key === VK.BACKSPACE ) ) { |
239 window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop ); |
312 window.scrollTo( window.pageXOffset, cursorTop + window.pageYOffset - editorTop ); |
|
313 |
|
314 /* |
|
315 * If any other key is pressed or the cursorTop is bigger than the editorTop, |
|
316 * scroll the editor to the position defined by the cursorBottom, |
|
317 * pageYOffset and editorBottom. |
|
318 */ |
240 } else if ( cursorBottom > editorBottom ) { |
319 } else if ( cursorBottom > editorBottom ) { |
241 window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); |
320 window.scrollTo( window.pageXOffset, cursorBottom + window.pageYOffset - editorBottom ); |
242 } |
321 } |
243 } |
322 } |
244 |
323 |
|
324 /** |
|
325 * @summary If the editor is fullscreen, calls adjust. |
|
326 * |
|
327 * @since 4.1.0 |
|
328 * |
|
329 * @param {event} event The FullscreenStateChanged event. |
|
330 * |
|
331 * @returns {void} |
|
332 */ |
245 function mceFullscreenToggled( event ) { |
333 function mceFullscreenToggled( event ) { |
|
334 // event.state is true if the editor is fullscreen. |
246 if ( ! event.state ) { |
335 if ( ! event.state ) { |
247 adjust(); |
336 adjust(); |
248 } |
337 } |
249 } |
338 } |
250 |
339 |
251 // Adjust when switching editor modes. |
340 /** |
|
341 * @summary Shows the editor when scrolled. |
|
342 * |
|
343 * Binds the hideFloatPanels function on the window scroll.mce-float-panels event. |
|
344 * Executes the wpAutoResize on the active editor. |
|
345 * |
|
346 * @since 4.0.0 |
|
347 * |
|
348 * @returns {void} |
|
349 */ |
252 function mceShow() { |
350 function mceShow() { |
253 $window.on( 'scroll.mce-float-panels', hideFloatPanels ); |
351 $window.on( 'scroll.mce-float-panels', hideFloatPanels ); |
254 |
352 |
255 setTimeout( function() { |
353 setTimeout( function() { |
256 editor.execCommand( 'wpAutoResize' ); |
354 editor.execCommand( 'wpAutoResize' ); |
257 adjust(); |
355 adjust(); |
258 }, 300 ); |
356 }, 300 ); |
259 } |
357 } |
260 |
358 |
|
359 /** |
|
360 * @summary Resizes the editor. |
|
361 * |
|
362 * Removes all functions from the window scroll.mce-float-panels event. |
|
363 * Resizes the text editor and scrolls to a position based on the pageXOffset and adminBarHeight. |
|
364 * |
|
365 * @since 4.0.0 |
|
366 * |
|
367 * @returns {void} |
|
368 */ |
261 function mceHide() { |
369 function mceHide() { |
262 $window.off( 'scroll.mce-float-panels' ); |
370 $window.off( 'scroll.mce-float-panels' ); |
263 |
371 |
264 setTimeout( function() { |
372 setTimeout( function() { |
265 var top = $contentWrap.offset().top; |
373 var top = $contentWrap.offset().top; |
273 }, 100 ); |
381 }, 100 ); |
274 |
382 |
275 adjust(); |
383 adjust(); |
276 } |
384 } |
277 |
385 |
|
386 /** |
|
387 * @summary Toggles advanced states. |
|
388 * |
|
389 * @since 4.1.0 |
|
390 * |
|
391 * @returns {void} |
|
392 */ |
278 function toggleAdvanced() { |
393 function toggleAdvanced() { |
279 advanced = ! advanced; |
394 advanced = ! advanced; |
280 } |
395 } |
281 |
396 |
|
397 /** |
|
398 * @summary Binds events of the editor and window. |
|
399 * |
|
400 * @since 4.0.0 |
|
401 * |
|
402 * @returns {void} |
|
403 */ |
282 mceBind = function() { |
404 mceBind = function() { |
283 editor.on( 'keyup', mceKeyup ); |
405 editor.on( 'keyup', mceKeyup ); |
284 editor.on( 'show', mceShow ); |
406 editor.on( 'show', mceShow ); |
285 editor.on( 'hide', mceHide ); |
407 editor.on( 'hide', mceHide ); |
286 editor.on( 'wp-toolbar-toggle', toggleAdvanced ); |
408 editor.on( 'wp-toolbar-toggle', toggleAdvanced ); |
|
409 |
287 // Adjust when the editor resizes. |
410 // Adjust when the editor resizes. |
288 editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); |
411 editor.on( 'setcontent wp-autoresize wp-toolbar-toggle', adjust ); |
|
412 |
289 // Don't hide the caret after undo/redo. |
413 // Don't hide the caret after undo/redo. |
290 editor.on( 'undo redo', mceScroll ); |
414 editor.on( 'undo redo', mceScroll ); |
|
415 |
291 // Adjust when exiting TinyMCE's fullscreen mode. |
416 // Adjust when exiting TinyMCE's fullscreen mode. |
292 editor.on( 'FullscreenStateChanged', mceFullscreenToggled ); |
417 editor.on( 'FullscreenStateChanged', mceFullscreenToggled ); |
293 |
418 |
294 $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels ); |
419 $window.off( 'scroll.mce-float-panels' ).on( 'scroll.mce-float-panels', hideFloatPanels ); |
295 }; |
420 }; |
296 |
421 |
|
422 /** |
|
423 * @summary Unbinds the events of the editor and window. |
|
424 * |
|
425 * @since 4.0.0 |
|
426 * |
|
427 * @returns {void} |
|
428 */ |
297 mceUnbind = function() { |
429 mceUnbind = function() { |
298 editor.off( 'keyup', mceKeyup ); |
430 editor.off( 'keyup', mceKeyup ); |
299 editor.off( 'show', mceShow ); |
431 editor.off( 'show', mceShow ); |
300 editor.off( 'hide', mceHide ); |
432 editor.off( 'hide', mceHide ); |
301 editor.off( 'wp-toolbar-toggle', toggleAdvanced ); |
433 editor.off( 'wp-toolbar-toggle', toggleAdvanced ); |
498 $statusBar.attr( 'style', advanced ? '' : 'visibility: hidden;' ); |
646 $statusBar.attr( 'style', advanced ? '' : 'visibility: hidden;' ); |
499 $bottom.attr( 'style', '' ); |
647 $bottom.attr( 'style', '' ); |
500 } |
648 } |
501 } |
649 } |
502 |
650 |
503 // Sidebar pinning |
651 // The postbox container is positioned with @media from CSS. Ensure it is pinned on the side. |
504 if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 && // sidebar position is changed with @media from CSS, make sure it is on the side |
652 if ( $postboxContainer.width() < 300 && heights.windowWidth > 600 && |
505 $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) && // the sidebar is not the tallest element |
653 |
506 heights.windowHeight < editorHeight ) { // the editor is taller than the viewport |
654 // Check if the sidebar is not taller than the document height. |
|
655 $document.height() > ( $sideSortables.height() + postBodyTop + 120 ) && |
|
656 |
|
657 // Check if the editor is taller than the viewport. |
|
658 heights.windowHeight < editorHeight ) { |
507 |
659 |
508 if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) { |
660 if ( ( heights.sideSortablesHeight + pinnedToolsTop + sidebarBottom ) > heights.windowHeight || fixedSideTop || fixedSideBottom ) { |
509 // Reset when scrolling to the top |
661 |
|
662 // Reset the sideSortables style when scrolling to the top. |
510 if ( windowPos + pinnedToolsTop <= postBodyTop ) { |
663 if ( windowPos + pinnedToolsTop <= postBodyTop ) { |
511 $sideSortables.attr( 'style', '' ); |
664 $sideSortables.attr( 'style', '' ); |
512 fixedSideTop = fixedSideBottom = false; |
665 fixedSideTop = fixedSideBottom = false; |
513 } else { |
666 } else { |
|
667 |
|
668 // When scrolling down. |
514 if ( windowPos > lastScrollPosition ) { |
669 if ( windowPos > lastScrollPosition ) { |
515 // Scrolling down |
|
516 if ( fixedSideTop ) { |
670 if ( fixedSideTop ) { |
517 // let it scroll |
671 |
|
672 // Let it scroll. |
518 fixedSideTop = false; |
673 fixedSideTop = false; |
519 sidebarTop = $sideSortables.offset().top - heights.adminBarHeight; |
674 sidebarTop = $sideSortables.offset().top - heights.adminBarHeight; |
520 footerTop = $footer.offset().top; |
675 footerTop = $footer.offset().top; |
521 |
676 |
522 // don't get over the footer |
677 // Don't get over the footer. |
523 if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { |
678 if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { |
524 sidebarTop = footerTop - heights.sideSortablesHeight - 12; |
679 sidebarTop = footerTop - heights.sideSortablesHeight - 12; |
525 } |
680 } |
526 |
681 |
527 $sideSortables.css({ |
682 $sideSortables.css({ |
528 position: 'absolute', |
683 position: 'absolute', |
529 top: sidebarTop, |
684 top: sidebarTop, |
530 bottom: '' |
685 bottom: '' |
531 }); |
686 }); |
532 } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) { |
687 } else if ( ! fixedSideBottom && heights.sideSortablesHeight + $sideSortables.offset().top + sidebarBottom < windowPos + heights.windowHeight ) { |
533 // pin the bottom |
688 // Pin the bottom. |
534 fixedSideBottom = true; |
689 fixedSideBottom = true; |
535 |
690 |
536 $sideSortables.css({ |
691 $sideSortables.css({ |
537 position: 'fixed', |
692 position: 'fixed', |
538 top: 'auto', |
693 top: 'auto', |
539 bottom: sidebarBottom |
694 bottom: sidebarBottom |
540 }); |
695 }); |
541 } |
696 } |
|
697 |
|
698 // When scrolling up. |
542 } else if ( windowPos < lastScrollPosition ) { |
699 } else if ( windowPos < lastScrollPosition ) { |
543 // Scrolling up |
|
544 if ( fixedSideBottom ) { |
700 if ( fixedSideBottom ) { |
545 // let it scroll |
701 // Let it scroll. |
546 fixedSideBottom = false; |
702 fixedSideBottom = false; |
547 sidebarTop = $sideSortables.offset().top - sidebarBottom; |
703 sidebarTop = $sideSortables.offset().top - sidebarBottom; |
548 footerTop = $footer.offset().top; |
704 footerTop = $footer.offset().top; |
549 |
705 |
550 // don't get over the footer |
706 // Don't get over the footer. |
551 if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { |
707 if ( footerTop < sidebarTop + heights.sideSortablesHeight + sidebarBottom ) { |
552 sidebarTop = footerTop - heights.sideSortablesHeight - 12; |
708 sidebarTop = footerTop - heights.sideSortablesHeight - 12; |
553 } |
709 } |
554 |
710 |
555 $sideSortables.css({ |
711 $sideSortables.css({ |
556 position: 'absolute', |
712 position: 'absolute', |
557 top: sidebarTop, |
713 top: sidebarTop, |
558 bottom: '' |
714 bottom: '' |
559 }); |
715 }); |
560 } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) { |
716 } else if ( ! fixedSideTop && $sideSortables.offset().top >= windowPos + pinnedToolsTop ) { |
561 // pin the top |
717 // Pin the top. |
562 fixedSideTop = true; |
718 fixedSideTop = true; |
563 |
719 |
564 $sideSortables.css({ |
720 $sideSortables.css({ |
565 position: 'fixed', |
721 position: 'fixed', |
566 top: pinnedToolsTop, |
722 top: pinnedToolsTop, |
601 } ); |
757 } ); |
602 } else { |
758 } else { |
603 $textEditor.css( { |
759 $textEditor.css( { |
604 marginTop: heights.textTopHeight |
760 marginTop: heights.textTopHeight |
605 } ); |
761 } ); |
606 |
762 } |
607 $textEditorClone.width( contentWrapWidth - 20 - ( borderWidth * 2 ) ); |
763 } |
608 } |
764 } |
609 } |
765 |
610 } |
766 /** |
611 |
767 * @summary Resizes the editor and adjusts the toolbars. |
|
768 * |
|
769 * @since 4.0.0 |
|
770 * |
|
771 * @returns {void} |
|
772 */ |
612 function fullscreenHide() { |
773 function fullscreenHide() { |
613 textEditorResize(); |
774 textEditorResize(); |
614 adjust(); |
775 adjust(); |
615 } |
776 } |
616 |
777 |
|
778 /** |
|
779 * @summary Runs the passed function with 500ms intervals. |
|
780 * |
|
781 * @since 4.0.0 |
|
782 * |
|
783 * @param {function} callback The function to run in the timeout. |
|
784 * |
|
785 * @returns {void} |
|
786 */ |
617 function initialResize( callback ) { |
787 function initialResize( callback ) { |
618 for ( var i = 1; i < 6; i++ ) { |
788 for ( var i = 1; i < 6; i++ ) { |
619 setTimeout( callback, 500 * i ); |
789 setTimeout( callback, 500 * i ); |
620 } |
790 } |
621 } |
791 } |
622 |
792 |
|
793 /** |
|
794 * @summary Runs adjust after 100ms. |
|
795 * |
|
796 * @since 4.0.0 |
|
797 * |
|
798 * @returns {void} |
|
799 */ |
623 function afterScroll() { |
800 function afterScroll() { |
624 clearTimeout( scrollTimer ); |
801 clearTimeout( scrollTimer ); |
625 scrollTimer = setTimeout( adjust, 100 ); |
802 scrollTimer = setTimeout( adjust, 100 ); |
626 } |
803 } |
627 |
804 |
|
805 /** |
|
806 * @summary Binds editor expand events on elements. |
|
807 * |
|
808 * @since 4.0.0 |
|
809 * |
|
810 * @returns {void} |
|
811 */ |
628 function on() { |
812 function on() { |
629 // Scroll to the top when triggering this from JS. |
813 /* |
630 // Ensures toolbars are pinned properly. |
814 * Scroll to the top when triggering this from JS. |
|
815 * Ensure the toolbars are pinned properly. |
|
816 */ |
631 if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { |
817 if ( window.pageYOffset && window.pageYOffset > pageYOffsetAtTop ) { |
632 window.scrollTo( window.pageXOffset, 0 ); |
818 window.scrollTo( window.pageXOffset, 0 ); |
633 } |
819 } |
634 |
820 |
635 $wrap.addClass( 'wp-editor-expand' ); |
821 $wrap.addClass( 'wp-editor-expand' ); |
872 |
1118 |
873 $document.trigger( 'dfw-off' ); |
1119 $document.trigger( 'dfw-off' ); |
874 } |
1120 } |
875 } |
1121 } |
876 |
1122 |
|
1123 /** |
|
1124 * @summary Binds or unbinds the editor expand events. |
|
1125 * |
|
1126 * @since 4.1.0 |
|
1127 * |
|
1128 * @returns {void} |
|
1129 */ |
877 function toggle() { |
1130 function toggle() { |
878 if ( _isOn ) { |
1131 if ( _isOn ) { |
879 off(); |
1132 off(); |
880 } else { |
1133 } else { |
881 on(); |
1134 on(); |
882 } |
1135 } |
883 } |
1136 } |
884 |
1137 |
|
1138 /** |
|
1139 * @summary Returns the value of _isOn. |
|
1140 * |
|
1141 * @since 4.1.0 |
|
1142 * |
|
1143 * @returns {boolean} Returns true if _isOn is true. |
|
1144 */ |
885 function isOn() { |
1145 function isOn() { |
886 return _isOn; |
1146 return _isOn; |
887 } |
1147 } |
888 |
1148 |
|
1149 /** |
|
1150 * @summary Fades out all elements except for the editor. |
|
1151 * |
|
1152 * The fading is done based on key presses and mouse movements. |
|
1153 * Also calls the fadeIn on certain key presses |
|
1154 * or if the mouse leaves the editor. |
|
1155 * |
|
1156 * @since 4.1.0 |
|
1157 * |
|
1158 * @param event The event that triggers this function. |
|
1159 * |
|
1160 * @returns {void} |
|
1161 */ |
889 function fadeOut( event ) { |
1162 function fadeOut( event ) { |
890 var key = event && event.keyCode; |
1163 var isMac, |
891 |
1164 key = event && event.keyCode; |
892 // fadeIn and return on Escape and keyboard shortcut Alt+Shift+W. |
1165 |
893 if ( key === 27 || ( key === 87 && event.altKey && event.shiftKey ) ) { |
1166 if ( window.navigator.platform ) { |
|
1167 isMac = ( window.navigator.platform.indexOf( 'Mac' ) > -1 ); |
|
1168 } |
|
1169 |
|
1170 // Fade in and returns on Escape and keyboard shortcut Alt+Shift+W and Ctrl+Opt+W. |
|
1171 if ( key === 27 || ( key === 87 && event.altKey && ( ( ! isMac && event.shiftKey ) || ( isMac && event.ctrlKey ) ) ) ) { |
894 fadeIn( event ); |
1172 fadeIn( event ); |
895 return; |
1173 return; |
896 } |
1174 } |
897 |
1175 |
|
1176 // Return if any of the following keys or combinations of keys is pressed. |
898 if ( event && ( event.metaKey || ( event.ctrlKey && ! event.altKey ) || ( event.altKey && event.shiftKey ) || ( key && ( |
1177 if ( event && ( event.metaKey || ( event.ctrlKey && ! event.altKey ) || ( event.altKey && event.shiftKey ) || ( key && ( |
899 // Special keys ( tab, ctrl, alt, esc, arrow keys... ) |
1178 // Special keys ( tab, ctrl, alt, esc, arrow keys... ) |
900 ( key <= 47 && key !== 8 && key !== 13 && key !== 32 && key !== 46 ) || |
1179 ( key <= 47 && key !== 8 && key !== 13 && key !== 32 && key !== 46 ) || |
901 // Windows keys |
1180 // Windows keys |
902 ( key >= 91 && key <= 93 ) || |
1181 ( key >= 91 && key <= 93 ) || |
1075 $adminBar.removeClass( 'focus-off' ); |
1378 $adminBar.removeClass( 'focus-off' ); |
1076 } ); |
1379 } ); |
1077 } |
1380 } |
1078 } |
1381 } |
1079 |
1382 |
|
1383 /** |
|
1384 * @summary Fades in the admin bar. |
|
1385 * |
|
1386 * @since 4.1.0 |
|
1387 * |
|
1388 * @returns {void} |
|
1389 */ |
1080 function fadeInAdminBar() { |
1390 function fadeInAdminBar() { |
1081 if ( fadedAdminBar ) { |
1391 if ( fadedAdminBar ) { |
1082 fadedAdminBar = false; |
1392 fadedAdminBar = false; |
1083 |
1393 |
1084 $adminBar.off( '.focus' ); |
1394 $adminBar.off( '.focus' ); |
1085 } |
1395 } |
1086 } |
1396 } |
1087 |
1397 |
|
1398 /** |
|
1399 * @summary Fades out the edit slug box. |
|
1400 * |
|
1401 * @since 4.1.0 |
|
1402 * |
|
1403 * @returns {void} |
|
1404 */ |
1088 function fadeOutSlug() { |
1405 function fadeOutSlug() { |
1089 if ( ! fadedSlug && faded && ! $slug.find( ':focus').length ) { |
1406 if ( ! fadedSlug && faded && ! $slug.find( ':focus').length ) { |
1090 fadedSlug = true; |
1407 fadedSlug = true; |
1091 |
1408 |
1092 $slug.stop().fadeTo( 'fast', 0.3 ).on( 'mouseenter.focus', fadeInSlug ).off( 'mouseleave.focus' ); |
1409 $slug.stop().fadeTo( 'fast', 0.3 ).on( 'mouseenter.focus', fadeInSlug ).off( 'mouseleave.focus' ); |
1093 |
1410 |
1094 $slugFocusEl.on( 'focus.focus', fadeInSlug ).off( 'blur.focus' ); |
1411 $slugFocusEl.on( 'focus.focus', fadeInSlug ).off( 'blur.focus' ); |
1095 } |
1412 } |
1096 } |
1413 } |
1097 |
1414 |
|
1415 /** |
|
1416 * @summary Fades in the edit slug box. |
|
1417 * |
|
1418 * @since 4.1.0 |
|
1419 * |
|
1420 * @returns {void} |
|
1421 */ |
1098 function fadeInSlug() { |
1422 function fadeInSlug() { |
1099 if ( fadedSlug ) { |
1423 if ( fadedSlug ) { |
1100 fadedSlug = false; |
1424 fadedSlug = false; |
1101 |
1425 |
1102 $slug.stop().fadeTo( 'fast', 1 ).on( 'mouseleave.focus', fadeOutSlug ).off( 'mouseenter.focus' ); |
1426 $slug.stop().fadeTo( 'fast', 1 ).on( 'mouseleave.focus', fadeOutSlug ).off( 'mouseenter.focus' ); |
1103 |
1427 |
1104 $slugFocusEl.on( 'blur.focus', fadeOutSlug ).off( 'focus.focus' ); |
1428 $slugFocusEl.on( 'blur.focus', fadeOutSlug ).off( 'focus.focus' ); |
1105 } |
1429 } |
1106 } |
1430 } |
1107 |
1431 |
|
1432 /** |
|
1433 * @summary Triggers the toggle on Alt + Shift + W. |
|
1434 * |
|
1435 * Keycode 87 = w. |
|
1436 * |
|
1437 * @since 4.1.0 |
|
1438 * |
|
1439 * @param {event} event The event to trigger the toggle. |
|
1440 * |
|
1441 * @returns {void} |
|
1442 */ |
1108 function toggleViaKeyboard( event ) { |
1443 function toggleViaKeyboard( event ) { |
1109 if ( event.altKey && event.shiftKey && 87 === event.keyCode ) { |
1444 if ( event.altKey && event.shiftKey && 87 === event.keyCode ) { |
1110 toggle(); |
1445 toggle(); |
1111 } |
1446 } |
1112 } |
1447 } |
1113 |
1448 |
1114 if ( $( '#postdivrich' ).hasClass( 'wp-editor-expand' ) ) { |
1449 if ( $( '#postdivrich' ).hasClass( 'wp-editor-expand' ) ) { |
1115 $content.on( 'keydown.focus-shortcut', toggleViaKeyboard ); |
1450 $content.on( 'keydown.focus-shortcut', toggleViaKeyboard ); |
1116 } |
1451 } |
1117 |
1452 |
|
1453 /** |
|
1454 * @summary Adds the distraction free writing button when setting up TinyMCE. |
|
1455 * |
|
1456 * @since 4.1.0 |
|
1457 * |
|
1458 * @param {event} event The TinyMCE editor setup event. |
|
1459 * @param {object} editor The editor to add the button to. |
|
1460 * |
|
1461 * @returns {void} |
|
1462 */ |
1118 $document.on( 'tinymce-editor-setup.focus', function( event, editor ) { |
1463 $document.on( 'tinymce-editor-setup.focus', function( event, editor ) { |
1119 editor.addButton( 'dfw', { |
1464 editor.addButton( 'dfw', { |
1120 active: _isOn, |
1465 active: _isOn, |
1121 classes: 'wp-dfw btn widget', |
1466 classes: 'wp-dfw btn widget', |
1122 disabled: ! _isActive, |
1467 disabled: ! _isActive, |