equal
deleted
inserted
replaced
|
1 /** |
|
2 * @output wp-includes/js/autosave.js |
|
3 */ |
|
4 |
1 /* global tinymce, wpCookies, autosaveL10n, switchEditors */ |
5 /* global tinymce, wpCookies, autosaveL10n, switchEditors */ |
2 // Back-compat |
6 // Back-compat |
3 window.autosave = function() { |
7 window.autosave = function() { |
4 return true; |
8 return true; |
5 }; |
9 }; |
6 |
10 |
7 /** |
11 /** |
8 * @summary Adds autosave to the window object on dom ready. |
12 * Adds autosave to the window object on dom ready. |
9 * |
13 * |
10 * @since 3.9.0 |
14 * @since 3.9.0 |
11 * |
15 * |
12 * @param {jQuery} $ jQuery object. |
16 * @param {jQuery} $ jQuery object. |
13 * @param {window} The window object. |
17 * @param {window} The window object. |
14 * |
18 * |
15 */ |
19 */ |
16 ( function( $, window ) { |
20 ( function( $, window ) { |
17 /** |
21 /** |
18 * @summary Auto saves the post. |
22 * Auto saves the post. |
19 * |
23 * |
20 * @since 3.9.0 |
24 * @since 3.9.0 |
21 * |
25 * |
22 * @returns {Object} |
26 * @returns {Object} |
23 * {{ |
27 * {{ |
34 var initialCompareString, |
38 var initialCompareString, |
35 lastTriggerSave = 0, |
39 lastTriggerSave = 0, |
36 $document = $(document); |
40 $document = $(document); |
37 |
41 |
38 /** |
42 /** |
39 * @summary Returns the data saved in both local and remote autosave. |
43 * Returns the data saved in both local and remote autosave. |
40 * |
44 * |
41 * @since 3.9.0 |
45 * @since 3.9.0 |
42 * |
46 * |
43 * @param {string} type The type of autosave either local or remote. |
47 * @param {string} type The type of autosave either local or remote. |
44 * |
48 * |
97 |
101 |
98 return data; |
102 return data; |
99 } |
103 } |
100 |
104 |
101 /** |
105 /** |
102 * @summary Concatenates the title, content and excerpt. |
106 * Concatenates the title, content and excerpt. This is used to track changes |
103 * |
107 * when auto-saving. |
104 * This is used to track changes when auto-saving. |
|
105 * |
108 * |
106 * @since 3.9.0 |
109 * @since 3.9.0 |
107 * |
110 * |
108 * @param {Object} postData The object containing the post data. |
111 * @param {Object} postData The object containing the post data. |
109 * |
112 * |
116 |
119 |
117 return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' ); |
120 return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' ); |
118 } |
121 } |
119 |
122 |
120 /** |
123 /** |
121 * @summary Disables save buttons. |
124 * Disables save buttons. |
122 * |
125 * |
123 * @since 3.9.0 |
126 * @since 3.9.0 |
124 * |
127 * |
125 * @returns {void} |
128 * @returns {void} |
126 */ |
129 */ |
130 // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions. |
133 // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions. |
131 setTimeout( enableButtons, 5000 ); |
134 setTimeout( enableButtons, 5000 ); |
132 } |
135 } |
133 |
136 |
134 /** |
137 /** |
135 * @summary Enables save buttons. |
138 * Enables save buttons. |
136 * |
139 * |
137 * @since 3.9.0 |
140 * @since 3.9.0 |
138 * |
141 * |
139 * @returns {void} |
142 * @returns {void} |
140 */ |
143 */ |
141 function enableButtons() { |
144 function enableButtons() { |
142 $document.trigger( 'autosave-enable-buttons' ); |
145 $document.trigger( 'autosave-enable-buttons' ); |
143 } |
146 } |
144 |
147 |
145 /** |
148 /** |
146 * @summary Gets the content editor. |
149 * Gets the content editor. |
147 * |
150 * |
148 * @since 4.6.0 |
151 * @since 4.6.0 |
149 * |
152 * |
150 * @returns {boolean|*} Returns either false if the editor is undefined, |
153 * @returns {boolean|*} Returns either false if the editor is undefined, |
151 * or the instance of the content editor. |
154 * or the instance of the content editor. |
153 function getEditor() { |
156 function getEditor() { |
154 return typeof tinymce !== 'undefined' && tinymce.get('content'); |
157 return typeof tinymce !== 'undefined' && tinymce.get('content'); |
155 } |
158 } |
156 |
159 |
157 /** |
160 /** |
158 * @summary Autosave in localStorage. |
161 * Autosave in localStorage. |
159 * |
162 * |
160 * @since 3.9.0 |
163 * @since 3.9.0 |
161 * |
164 * |
162 * @returns { |
165 * @returns { |
163 * { |
166 * { |
174 var blog_id, post_id, hasStorage, intervalTimer, |
177 var blog_id, post_id, hasStorage, intervalTimer, |
175 lastCompareString, |
178 lastCompareString, |
176 isSuspended = false; |
179 isSuspended = false; |
177 |
180 |
178 /** |
181 /** |
179 * @summary Checks if the browser supports sessionStorage and it's not disabled. |
182 * Checks if the browser supports sessionStorage and it's not disabled. |
180 * |
183 * |
181 * @since 3.9.0 |
184 * @since 3.9.0 |
182 * |
185 * |
183 * @returns {boolean} True if the sessionStorage is supported and enabled. |
186 * @returns {boolean} True if the sessionStorage is supported and enabled. |
184 */ |
187 */ |
195 hasStorage = result; |
198 hasStorage = result; |
196 return result; |
199 return result; |
197 } |
200 } |
198 |
201 |
199 /** |
202 /** |
200 * @summary Initializes the local storage. |
203 * Initializes the local storage. |
201 * |
204 * |
202 * @since 3.9.0 |
205 * @since 3.9.0 |
203 * |
206 * |
204 * @returns {boolean|Object} False if no sessionStorage in the browser or an Object |
207 * @returns {boolean|Object} False if no sessionStorage in the browser or an Object |
205 * containing all postData for this blog. |
208 * containing all postData for this blog. |
219 |
222 |
220 return stored_obj; |
223 return stored_obj; |
221 } |
224 } |
222 |
225 |
223 /** |
226 /** |
224 * @summary Sets the storage for this blog. |
227 * Sets the storage for this blog. Confirms that the data was saved |
225 * |
228 * successfully. |
226 * Confirms that the data was saved successfully. |
|
227 * |
229 * |
228 * @since 3.9.0 |
230 * @since 3.9.0 |
229 * |
231 * |
230 * @returns {boolean} True if the data was saved successfully, false if it wasn't saved. |
232 * @returns {boolean} True if the data was saved successfully, false if it wasn't saved. |
231 */ |
233 */ |
240 |
242 |
241 return false; |
243 return false; |
242 } |
244 } |
243 |
245 |
244 /** |
246 /** |
245 * @summary Gets the saved post data for the current post. |
247 * Gets the saved post data for the current post. |
246 * |
248 * |
247 * @since 3.9.0 |
249 * @since 3.9.0 |
248 * |
250 * |
249 * @returns {boolean|Object} False if no storage or no data or the postData as an Object. |
251 * @returns {boolean|Object} False if no storage or no data or the postData as an Object. |
250 */ |
252 */ |
257 |
259 |
258 return stored[ 'post_' + post_id ] || false; |
260 return stored[ 'post_' + post_id ] || false; |
259 } |
261 } |
260 |
262 |
261 /** |
263 /** |
262 * @summary Sets (save or delete) post data in the storage. |
264 * Sets (save or delete) post data in the storage. |
263 * |
265 * |
264 * If stored_data evaluates to 'false' the storage key for the current post will be removed. |
266 * If stored_data evaluates to 'false' the storage key for the current post will be removed. |
265 * |
267 * |
266 * @since 3.9.0 |
268 * @since 3.9.0 |
267 * |
269 * |
286 |
288 |
287 return setStorage( stored ); |
289 return setStorage( stored ); |
288 } |
290 } |
289 |
291 |
290 /** |
292 /** |
291 * @summary Sets isSuspended to true. |
293 * Sets isSuspended to true. |
292 * |
294 * |
293 * @since 3.9.0 |
295 * @since 3.9.0 |
294 * |
296 * |
295 * @returns {void} |
297 * @returns {void} |
296 */ |
298 */ |
297 function suspend() { |
299 function suspend() { |
298 isSuspended = true; |
300 isSuspended = true; |
299 } |
301 } |
300 |
302 |
301 /** |
303 /** |
302 * @summary Sets isSuspended to false. |
304 * Sets isSuspended to false. |
303 * |
305 * |
304 * @since 3.9.0 |
306 * @since 3.9.0 |
305 * |
307 * |
306 * @returns {void} |
308 * @returns {void} |
307 */ |
309 */ |
308 function resume() { |
310 function resume() { |
309 isSuspended = false; |
311 isSuspended = false; |
310 } |
312 } |
311 |
313 |
312 /** |
314 /** |
313 * @summary Saves post data for the current post. |
315 * Saves post data for the current post. |
314 * |
316 * |
315 * Runs on a 15 sec. interval, saves when there are differences in the post title or content. |
317 * Runs on a 15 sec. interval, saves when there are differences in the post title or content. |
316 * When the optional data is provided, updates the last saved post data. |
318 * When the optional data is provided, updates the last saved post data. |
317 * |
319 * |
318 * @since 3.9.0 |
320 * @since 3.9.0 |
357 |
359 |
358 return result; |
360 return result; |
359 } |
361 } |
360 |
362 |
361 /** |
363 /** |
362 * @summary Initializes the auto save function. |
364 * Initializes the auto save function. |
363 * |
365 * |
364 * Checks whether the editor is active or not to use the editor events |
366 * Checks whether the editor is active or not to use the editor events |
365 * to autosave, or uses the values from the elements to autosave. |
367 * to autosave, or uses the values from the elements to autosave. |
366 * |
368 * |
367 * Runs on DOM ready. |
369 * Runs on DOM ready. |
417 wpCookies.set( 'wp-saving-post', post_id + '-check', 24 * 60 * 60, false, false, secure ); |
419 wpCookies.set( 'wp-saving-post', post_id + '-check', 24 * 60 * 60, false, false, secure ); |
418 }); |
420 }); |
419 } |
421 } |
420 |
422 |
421 /** |
423 /** |
422 * @summary Compares 2 strings. |
424 * Compares 2 strings. Removes whitespaces in the strings before comparing them. |
423 * |
|
424 * Removes whitespaces in the strings before comparing them. |
|
425 * |
425 * |
426 * @since 3.9.0 |
426 * @since 3.9.0 |
427 * |
427 * |
428 * @param {string} str1 The first string. |
428 * @param {string} str1 The first string. |
429 * @param {string} str2 The second string. |
429 * @param {string} str2 The second string. |
436 |
436 |
437 return ( removeSpaces( str1 || '' ) === removeSpaces( str2 || '' ) ); |
437 return ( removeSpaces( str1 || '' ) === removeSpaces( str2 || '' ) ); |
438 } |
438 } |
439 |
439 |
440 /** |
440 /** |
441 * @summary Checks if the saved data for the current post (if any) is different |
441 * Checks if the saved data for the current post (if any) is different than the |
442 * than the loaded post data on the screen. |
442 * loaded post data on the screen. |
443 * |
443 * |
444 * Shows a standard message letting the user restore the post data if different. |
444 * Shows a standard message letting the user restore the post data if different. |
445 * |
445 * |
446 * @since 3.9.0 |
446 * @since 3.9.0 |
447 * |
447 * |
505 }); |
505 }); |
506 }); |
506 }); |
507 } |
507 } |
508 |
508 |
509 /** |
509 /** |
510 * @summary Restores the current title, content and excerpt from postData. |
510 * Restores the current title, content and excerpt from postData. |
511 * |
511 * |
512 * @since 3.9.0 |
512 * @since 3.9.0 |
513 * |
513 * |
514 * @param {Object} postData The object containing all post data. |
514 * @param {Object} postData The object containing all post data. |
515 * |
515 * |
573 resume: resume |
573 resume: resume |
574 }; |
574 }; |
575 } |
575 } |
576 |
576 |
577 /** |
577 /** |
578 * @summary Auto saves the post on the server. |
578 * Auto saves the post on the server. |
579 * |
579 * |
580 * @since 3.9.0 |
580 * @since 3.9.0 |
581 * |
581 * |
582 * @returns {Object} { |
582 * @returns {Object} { |
583 * { |
583 * { |
594 nextRun = 0, |
594 nextRun = 0, |
595 isSuspended = false; |
595 isSuspended = false; |
596 |
596 |
597 |
597 |
598 /** |
598 /** |
599 * @summary Blocks saving for the next 10 seconds. |
599 * Blocks saving for the next 10 seconds. |
600 * |
600 * |
601 * @since 3.9.0 |
601 * @since 3.9.0 |
602 * |
602 * |
603 * @returns {void} |
603 * @returns {void} |
604 */ |
604 */ |
610 _blockSave = false; |
610 _blockSave = false; |
611 }, 10000 ); |
611 }, 10000 ); |
612 } |
612 } |
613 |
613 |
614 /** |
614 /** |
615 * @summary Sets isSuspended to true. |
615 * Sets isSuspended to true. |
616 * |
616 * |
617 * @since 3.9.0 |
617 * @since 3.9.0 |
618 * |
618 * |
619 * @returns {void} |
619 * @returns {void} |
620 */ |
620 */ |
621 function suspend() { |
621 function suspend() { |
622 isSuspended = true; |
622 isSuspended = true; |
623 } |
623 } |
624 |
624 |
625 /** |
625 /** |
626 * @summary Sets isSuspended to false. |
626 * Sets isSuspended to false. |
627 * |
627 * |
628 * @since 3.9.0 |
628 * @since 3.9.0 |
629 * |
629 * |
630 * @returns {void} |
630 * @returns {void} |
631 */ |
631 */ |
632 function resume() { |
632 function resume() { |
633 isSuspended = false; |
633 isSuspended = false; |
634 } |
634 } |
635 |
635 |
636 /** |
636 /** |
637 * @summary Triggers the autosave with the post data. |
637 * Triggers the autosave with the post data. |
638 * |
638 * |
639 * @since 3.9.0 |
639 * @since 3.9.0 |
640 * |
640 * |
641 * @param {Object} data The post data. |
641 * @param {Object} data The post data. |
642 * |
642 * |
656 $( '#auto_draft' ).val(''); |
656 $( '#auto_draft' ).val(''); |
657 } |
657 } |
658 } |
658 } |
659 |
659 |
660 /** |
660 /** |
661 * @summary Saves immediately. |
661 * Saves immediately. |
662 * |
662 * |
663 * Resets the timing and tells heartbeat to connect now. |
663 * Resets the timing and tells heartbeat to connect now. |
664 * |
664 * |
665 * @since 3.9.0 |
665 * @since 3.9.0 |
666 * |
666 * |
670 nextRun = 0; |
670 nextRun = 0; |
671 wp.heartbeat.connectNow(); |
671 wp.heartbeat.connectNow(); |
672 } |
672 } |
673 |
673 |
674 /** |
674 /** |
675 * @summary Checks if the post content in the textarea has changed since page load. |
675 * Checks if the post content in the textarea has changed since page load. |
676 * |
676 * |
677 * This also happens when TinyMCE is active and editor.save() is triggered by |
677 * This also happens when TinyMCE is active and editor.save() is triggered by |
678 * wp.autosave.getPostData(). |
678 * wp.autosave.getPostData(). |
679 * |
679 * |
680 * @since 3.9.0 |
680 * @since 3.9.0 |
684 function postChanged() { |
684 function postChanged() { |
685 return getCompareString() !== initialCompareString; |
685 return getCompareString() !== initialCompareString; |
686 } |
686 } |
687 |
687 |
688 /** |
688 /** |
689 * @summary Checks if the post can be saved or not. |
689 * Checks if the post can be saved or not. |
690 * |
690 * |
691 * If the post hasn't changed or it cannot be updated, |
691 * If the post hasn't changed or it cannot be updated, |
692 * because the autosave is blocked or suspended, the function returns false. |
692 * because the autosave is blocked or suspended, the function returns false. |
693 * |
693 * |
694 * @since 3.9.0 |
694 * @since 3.9.0 |
731 |
731 |
732 return postData; |
732 return postData; |
733 } |
733 } |
734 |
734 |
735 /** |
735 /** |
736 * @summary Sets the next run, based on the autosave interval. |
736 * Sets the next run, based on the autosave interval. |
737 * |
737 * |
738 * @private |
738 * @private |
739 * |
739 * |
740 * @since 3.9.0 |
740 * @since 3.9.0 |
741 * |
741 * |
744 function _schedule() { |
744 function _schedule() { |
745 nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000; |
745 nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000; |
746 } |
746 } |
747 |
747 |
748 /** |
748 /** |
749 * @summary Sets the autosaveData on the autosave heartbeat. |
749 * Sets the autosaveData on the autosave heartbeat. |
750 * |
750 * |
751 * @since 3.9.0 |
751 * @since 3.9.0 |
752 * |
752 * |
753 * @returns {void} |
753 * @returns {void} |
754 */ |
754 */ |
758 if ( autosaveData ) { |
758 if ( autosaveData ) { |
759 data.wp_autosave = autosaveData; |
759 data.wp_autosave = autosaveData; |
760 } |
760 } |
761 |
761 |
762 /** |
762 /** |
763 * @summary Triggers the autosave of the post with the autosave data |
763 * Triggers the autosave of the post with the autosave data on the autosave |
764 * on the autosave heartbeat. |
764 * heartbeat. |
765 * |
765 * |
766 * @since 3.9.0 |
766 * @since 3.9.0 |
767 * |
767 * |
768 * @returns {void} |
768 * @returns {void} |
769 */ |
769 */ |
770 }).on( 'heartbeat-tick.autosave', function( event, data ) { |
770 }).on( 'heartbeat-tick.autosave', function( event, data ) { |
771 if ( data.wp_autosave ) { |
771 if ( data.wp_autosave ) { |
772 response( data.wp_autosave ); |
772 response( data.wp_autosave ); |
773 } |
773 } |
774 /** |
774 /** |
775 * @summary Disables buttons and throws a notice when the connection is lost. |
775 * Disables buttons and throws a notice when the connection is lost. |
776 * |
776 * |
777 * @since 3.9.0 |
777 * @since 3.9.0 |
778 * |
778 * |
779 * @returns {void} |
779 * @returns {void} |
780 */ |
780 */ |
791 $notice.show(); |
791 $notice.show(); |
792 disableButtons(); |
792 disableButtons(); |
793 } |
793 } |
794 |
794 |
795 /** |
795 /** |
796 * @summary Enables buttons when the connection is restored. |
796 * Enables buttons when the connection is restored. |
797 * |
797 * |
798 * @since 3.9.0 |
798 * @since 3.9.0 |
799 * |
799 * |
800 * @returns {void} |
800 * @returns {void} |
801 */ |
801 */ |
814 resume: resume |
814 resume: resume |
815 }; |
815 }; |
816 } |
816 } |
817 |
817 |
818 /** |
818 /** |
819 * @summary Sets the autosave time out. |
819 * Sets the autosave time out. |
820 * |
820 * |
821 * Wait for TinyMCE to initialize plus 1 second. for any external css to finish loading, |
821 * Wait for TinyMCE to initialize plus 1 second. for any external css to finish loading, |
822 * then save to the textarea before setting initialCompareString. |
822 * then save to the textarea before setting initialCompareString. |
823 * This avoids any insignificant differences between the initial textarea content and the content |
823 * This avoids any insignificant differences between the initial textarea content and the content |
824 * extracted from the editor. |
824 * extracted from the editor. |