WordPress.org

Make WordPress Core

Ticket #23220: 23220-4.patch

File 23220-4.patch, 19.0 KB (added by azaozz, 2 years ago)
  • wp-admin/css/wp-admin.css

     
    34533453        text-decoration: none; 
    34543454} 
    34553455 
     3456#revisionsdiv h4.revisions-title { 
     3457        margin-bottom: 0.7em; 
     3458} 
     3459 
     3460#revisionsdiv ul.post-revisions, 
     3461#revisionsdiv p.no-revisions, 
     3462#localsave-items .localsave-text { 
     3463        margin: 0 10px; 
     3464} 
     3465 
     3466#localsave-items .localsave-item, 
     3467#localsave-items .localsave-preview-wrap { 
     3468        display: none; 
     3469} 
     3470 
     3471#localsave-items { 
     3472        margin-bottom: 15px; 
     3473} 
     3474 
     3475#localsave-items .localsave-item { 
     3476        margin-bottom: 6px; 
     3477} 
     3478 
     3479#localsave-items .localsave-preview-wrap { 
     3480        background-color: #eee; 
     3481        border-bottom: 1px solid #dfdfdf; 
     3482        border-top: 1px solid #dfdfdf; 
     3483        margin: 10px -12px 10px -10px; 
     3484} 
     3485 
     3486#localsave-items .localsave-preview { 
     3487        padding: 10px; 
     3488        margin: 15px 15px 10px; 
     3489        height: auto; 
     3490        min-height: 200px; 
     3491        max-height: 500px; 
     3492        overflow: auto; 
     3493        background: #fff; 
     3494        border: 1px solid #dfdfdf; 
     3495        border-radius: 3px; 
     3496} 
     3497 
     3498#localsave-items .localsave-preview > div { 
     3499        padding: 0 10px; 
     3500} 
     3501 
     3502#localsave-items .localsave-preview > textarea { 
     3503        width: 100%; 
     3504        max-width: 100%; 
     3505        height: 250px; 
     3506        border: 0 none; 
     3507        box-shadow: none; 
     3508} 
     3509 
     3510#localsave-items .localsave-preview-wrap > p { 
     3511        padding: 0 15px; 
     3512} 
     3513 
     3514#localsave-items .localsave-preview-wrap > p strong { 
     3515        color: #c00; 
     3516} 
     3517 
     3518#localsave-items .localsave-time { 
     3519        font-size: 1.2em; 
     3520} 
     3521 
    34563522/*------------------------------------------------------------------------------ 
    34573523  11.3 - Featured Images 
    34583524------------------------------------------------------------------------------*/ 
  • wp-admin/edit-form-advanced.php

     
    159159                add_meta_box('authordiv', __('Author'), 'post_author_meta_box', null, 'normal', 'core'); 
    160160} 
    161161 
    162 if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID && wp_get_post_revisions( $post_ID ) ) 
     162if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID ) 
    163163        add_meta_box('revisionsdiv', __('Revisions'), 'post_revisions_meta_box', null, 'normal', 'core'); 
    164164 
    165165do_action('add_meta_boxes', $post_type, $post); 
  • wp-admin/includes/meta-boxes.php

     
    603603 * @param object $post 
    604604 */ 
    605605function post_revisions_meta_box($post) { 
    606         wp_list_post_revisions(); 
     606        if ( wp_get_post_revisions( $post->ID ) ) { 
     607                wp_list_post_revisions(); 
     608        } else { 
     609                ?> 
     610                <h4 class="revisions-title"><?php _e('Post revisions'); ?></h4> 
     611                <p class="no-revisions"><?php _e('(no revisions yet)'); ?></p> 
     612                <?php 
     613        } 
     614 
     615        ?> 
     616        <h4 class="revisions-title"><?php _e('Local backups'); ?></h4> 
     617        <div id="localsave-items"> 
     618                <p class="no-revisions localsave-no-revisions"><?php _e('(no backups yet)'); ?></p> 
     619 
     620                <div class="localsave-item localsave-item-main"> 
     621                        <a href="#" class="localsave-text"><?php _e('Saved %s hours ago'); ?></a> 
     622                </div> 
     623 
     624                <div class="localsave-preview-wrap"> 
     625                        <div class="localsave-preview"></div> 
     626                        <p class="warning"><?php _e('<strong>Warning:</strong> restoring a backup will replace the current content in the editor.') ?></p> 
     627                        <p class="localsave-preview-actions"> 
     628                                <a href="#" class="button localsave-do-close"><?php _e('Close'); ?></a> 
     629                                <a href="#" class="alignright button button-primary localsave-do-restore"><?php _e('Restore'); ?></a> 
     630                        </p> 
     631                </div> 
     632        </div> 
     633        <?php 
    607634} 
    608635 
    609636// -- Page related Meta Boxes 
     
    9791006function post_thumbnail_meta_box( $post ) { 
    9801007        $thumbnail_id = get_post_meta( $post->ID, '_thumbnail_id', true ); 
    9811008        echo _wp_post_thumbnail_html( $thumbnail_id, $post->ID ); 
    982 } 
    983  No newline at end of file 
     1009} 
  • wp-admin/js/common.js

     
    11var showNotice, adminMenu, columns, validateForm, screenMeta; 
     2window.wp = window.wp || {}; 
     3 
    24(function($){ 
    35// Removed in 3.3. 
    46// (perhaps) needed for back-compat 
     
    424426        return true; 
    425427}); 
    426428 
    427 })(jQuery); 
     429// Autosave in localStorage 
     430// set as simple object/mixin for now 
     431wp.autosave = wp.autosave || {}; 
     432 
     433// Returns only post ID, title, content and excerpt for local autosaves, the rest of the fields for remote 
     434wp.autosave.getPostData = function( local ) { 
     435        var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, cats = [], 
     436                data = { 
     437                        autosave: true, 
     438                        post_id: $('#post_ID').val() || 0 
     439                }; 
     440 
     441        if ( ed && !ed.isHidden() ) { 
     442                // Don't run while the tinymce spellcheck is on. It resets all found words. 
     443                if ( ed.plugins.spellchecker && ed.plugins.spellchecker.active ) { 
     444                        data.autosave = false; 
     445                        return data; 
     446                } else { 
     447                        if ( 'mce_fullscreen' == ed.id ) 
     448                                tinymce.get('content').setContent(ed.getContent({format : 'raw'}), {format : 'raw'}); 
     449 
     450                        tinymce.triggerSave(); 
     451                } 
     452        } 
     453 
     454        if ( typeof fullscreen != 'undefined' && fullscreen.settings.visible ) { 
     455                data['post_title'] = $('#wp-fullscreen-title').val() || ''; 
     456                data['content'] = $('#wp_mce_fullscreen').val() || ''; 
     457        } else { 
     458                data['post_title'] = $('#title').val() || ''; 
     459                data['content'] = $('#content').val() || ''; 
     460        } 
     461 
     462        data['excerpt'] = $('#excerpt').val() || ''; 
     463 
     464        if ( local ) 
     465                return data; 
     466 
     467        $.extend( data, { 
     468                action: 'autosave', 
     469                autosavenonce: $('#autosavenonce').val() || '', 
     470                post_type: $('#post_type').val() || '', 
     471                post_author: $('#post_author').val() || '' 
     472        }); 
     473 
     474        $('.tags-input').each( function() { 
     475                data[this.name] = this.value; 
     476        }); 
     477 
     478        $('input[id^="in-category-"]:checked').each( function() { 
     479                cats.push(this.value); 
     480        }); 
     481        data['catslist'] = cats.join(','); 
     482 
     483        if ( post_name = $('#post_name').val() ) 
     484                data['post_name'] = post_name; 
     485 
     486        if ( parent_id = $('#parent_id').val() ) 
     487                data['parent_id'] = parent_id; 
     488 
     489        if ( $('#comment_status').prop('checked') ) 
     490                data['comment_status'] = 'open'; 
     491 
     492        if ( $('#ping_status').prop('checked') ) 
     493                data['ping_status'] = 'open'; 
     494 
     495        if ( $('#auto_draft').val() == '1' ) 
     496                data['auto_draft'] = '1'; 
     497 
     498        return data; 
     499} 
     500 
     501// simple object/mixin for now 
     502wp.autosave.local = { 
     503 
     504        lastsaveddata: '', 
     505        unexpired: {}, 
     506        blog_id: 0, 
     507        hasStorage: (function() { 
     508                var test = Math.random(), result; 
     509                // Check if the browser supports localStorage and it's not disabled 
     510                try { 
     511                        localStorage.setItem('wp-test', test); 
     512                        result = localStorage.getItem('wp-test') == test; 
     513                        localStorage.removeItem('wp-test'); 
     514                        return result; 
     515                } catch(e) { 
     516                        return false; 
     517                } 
     518    }()), 
     519 
     520        /** 
     521         * Initialize the local storage 
     522         * @return mixed simple object or false if no localStorage in the browser 
     523         */ 
     524        getStorage: function() { 
     525                var storage = false; 
     526                 
     527                // separate local storage containers for each blog_id 
     528                if ( this.hasStorage && this.blog_id ) { 
     529                        storage = localStorage.getItem( 'wp_autosave_' + this.blog_id ); 
     530 
     531                        if ( storage ) 
     532                                storage = JSON.parse( storage ); 
     533                        else 
     534                                storage = {}; 
     535                } 
     536 
     537                return storage; 
     538        }, 
     539 
     540        setStorage: function( storage_obj ) { 
     541                if ( this.hasStorage ) 
     542                        return localStorage.setItem( 'wp_autosave_' + this.blog_id, JSON.stringify( storage_obj ) ); 
     543        }, 
     544         
     545        getData: function( post_id ) { 
     546                var storage = this.getStorage(); 
     547 
     548                post_id = post_id || $('#post_ID').val(); 
     549 
     550                if ( !storage || !post_id ) 
     551                        return false; 
     552 
     553                return storage[ 'post_' + post_id ] || []; 
     554        }, 
     555 
     556        setData: function( stored_data ) { 
     557                var storage = this.getStorage(), post_id = $('#post_ID').val(), result; 
     558 
     559                if ( !storage || !post_id ) 
     560                        return false; 
     561 
     562                storage[ 'post_' + post_id ] = stored_data; 
     563                result = this.setStorage(storage); 
     564 
     565                // TODO do we need this? 
     566                /* 
     567                if ( result === false && stored_data.length > 1 ) { 
     568                        // localStorage is full, pop the oldest revision and try again 
     569                        while ( result === false && stored_data.length > 1 ) { 
     570                                stored_data.pop(); 
     571                                storage[ 'post_' + post_id ] = stored_data; 
     572                                result = this.setStorage(storage); 
     573                        } 
     574                } 
     575                */ 
     576 
     577                if ( result === false ) { 
     578                        // localStorage is still full, throw error? 
     579                        return false; 
     580                } 
     581 
     582                return true; 
     583        }, 
     584 
     585        /** 
     586         * Set post data for particular post id 
     587         */ 
     588        save: function() { 
     589                var stored_data, post_data, result = false; 
     590 
     591                // Prepares data for saving in local storage. 
     592                post_data = wp.autosave.getPostData( true ); 
     593 
     594                // If the content and title are empty or did not change since the last save, don't save again 
     595                if ( ( ! post_data.post_title && ! post_data.content ) || post_data.post_title + post_data.content + post_data.excerpt == this.lastsaveddata ) 
     596                        return false; 
     597 
     598                // cannot save at this moment 
     599                if ( !post_data.autosave ) 
     600                        return false; 
     601 
     602                $.extend( post_data, { 
     603                        save_time: (new Date()).getTime(), 
     604                        storage_status: 'fresh' 
     605                }); 
     606 
     607                stored_data = this.getData(); 
     608                 
     609                if ( stored_data ) { 
     610                        stored_data.unshift( post_data ); 
     611                         
     612                        if ( stored_data.length > 5 ) { 
     613                                // Store only the 5 newest revisions 
     614                                stored_data.pop(); 
     615                        } 
     616console.log('saved at: '+post_data.save_time)                    
     617                        result = this.setData( stored_data ); 
     618                         
     619                        if ( result ) { 
     620                                this.lastsaveddata = post_data.post_title + post_data.content; 
     621                                // Update the local revisions as they are added 
     622                                this.showItems(); 
     623                        } 
     624                } 
     625 
     626                return result; 
     627        }, 
     628 
     629        /** 
     630         * Checks if all revisions have expired. Removes expired revisions from local storage after 24 hours. 
     631         */ 
     632        cleanup: function() {  
     633                var self = this, storage = this.getStorage(), current_time = (new Date()).getTime(), deleted = false, has_unexpired = false;  
     634 
     635                if ( !storage ) 
     636                        return; 
     637 
     638                $.each( storage, function( key, value ) { 
     639                        var new_arr; 
     640 
     641                        if ( !value ) 
     642                                return; 
     643 
     644                        new_arr = $.grep( value, function( post_data ) { 
     645                                if ( post_data.storage_status ) { 
     646                                        if ( !self.unexpired[key] ) 
     647                                                self.unexpired[key] = post_data; 
     648 
     649                                        has_unexpired = true; 
     650                                        return true; 
     651                                } 
     652                                // keep if less than 24 hr 
     653                                if ( ( current_time - post_data.save_time ) < 86400000 ) 
     654                                        return true; 
     655 
     656                                return false; 
     657                        }); 
     658 
     659                        if ( new_arr.length != value.length ) 
     660                                deleted = true; 
     661 
     662                        if ( new_arr.length ) 
     663                                storage[key] = new_arr; 
     664                        else 
     665                                delete storage[key]; 
     666                }); 
     667 
     668                if ( deleted ) 
     669                        this.setStorage( storage ); 
     670 
     671                if ( has_unexpired ) { 
     672                        // show warning about unexpired post data 
     673                        this.showWarning(); 
     674                } 
     675        }, 
     676 
     677        /** 
     678         * Marks post data as expired 
     679         * 
     680         * For use after remote autosave has completed 
     681         */ 
     682        expire: function() { 
     683                var stored_data = this.getData(); 
     684 
     685                $.each( stored_data, function( key, post_data ) { 
     686                        delete post_data.storage_status; 
     687                }); 
     688 
     689                return this.setData( stored_data ); 
     690        }, 
     691 
     692        showItems: function() { 
     693                var self = this, data; 
     694 
     695                function formatTime( milisec ) { 
     696                        var sec = parseInt( milisec / 1000, 10 ) || 0, 
     697                                h = Math.floor( sec / 3600 ), 
     698                                m = Math.floor( (sec % 3600) / 60 ), 
     699                                s = sec - ( (h * 3600) + (m * 60) ); 
     700 
     701                        function zeroize(n) { 
     702                                if ( !n ) 
     703                                        return '00'; 
     704 
     705                                if ( n < 10 ) 
     706                                        return '0' + n.toString(); 
     707 
     708                                return n.toString(); 
     709                        } 
     710 
     711                        return { 
     712                                h: zeroize(h), 
     713                                m: zeroize(m), 
     714                                s: zeroize(s) 
     715                        }; 
     716                } 
     717 
     718                if ( window.pagenow && window.pagenow == 'post' ) { 
     719                        data = this.getData(), current_time = (new Date()).getTime(); 
     720 
     721                        if ( data && data.length ) { 
     722                                $.each( data, function( key, post_data ) { 
     723                                        var timeSaved = formatTime( current_time - post_data.save_time ), 
     724                                                element = $('#localsave-items #localsave-item-' + key); 
     725console.log(element) 
     726                                        $('.localsave-no-revisions').remove(); 
     727 
     728                                        // can do something here with post_data.storage_status to show non-expired 
     729                                        // (not saved to the server) backups with different color 
     730 
     731                                        if ( ! element.length ) { 
     732                                                element = $('.localsave-item-main').clone().removeClass('localsave-item-main').attr( 'id', 'localsave-item-' + key ).data('key', key); 
     733 
     734                                                $('.localsave-text', element).html( $('.localsave-text', element).text().replace( /%s/, function(){ 
     735                                                        return '<span class="localsave-h">' + timeSaved.h + '</span>:' + 
     736                                                                '<span class="localsave-m">' + timeSaved.m + '</span>:' + 
     737                                                                '<span class="localsave-s">' + timeSaved.s + '</span>'; 
     738                                                } ) ); 
     739 
     740                                                $('#localsave-items').append( element.data('key', key).show() ); 
     741                                        } else { 
     742                                                element.data('key', key); 
     743                                                $('.localsave-h', element).text( timeSaved.h ); 
     744                                                $('.localsave-m', element).text( timeSaved.m ); 
     745                                                $('.localsave-s', element).text( timeSaved.s ); 
     746                                        } 
     747                                }); 
     748                        } 
     749                } 
     750        }, 
     751 
     752        preview: function( key ) { 
     753                var data = this.getData(), content, element; 
     754 
     755                if ( !data[key] ) 
     756                        return; // error message? 
     757 
     758                content = data[key].content; 
     759 
     760                if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) { 
     761                        content = '<div>' + switchEditors.wpautop( content ) + '</div>'; 
     762                } else if ( $('#wp-content-wrap').hasClass('html-active') ) 
     763                        content = '<textarea readonly>' + this.esc_html( content ) + '</textarea>'; 
     764 
     765                element = $('.localsave-preview-wrap').show(); 
     766                element.find('div.localsave-preview').html( content ); 
     767                element.find('a.localsave-do-restore').data('key', key); 
     768                $('#localsave-item-' + key).append( element ); 
     769        }, 
     770 
     771        closePreview: function() { 
     772                var element = $('.localsave-preview-wrap').css('display', ''); 
     773 
     774                element.find('div.localsave-preview').empty(); 
     775                element.find('a.localsave-do-restore').removeData('key'); 
     776                $('#localsave-items').append( element ); 
     777        }, 
     778 
     779        restore: function( key ) { 
     780                var data = this.getData(), content, editor; 
     781 
     782                if ( !data[key] ) 
     783                        return; // error message? 
     784 
     785                content = data[key].content; 
     786 
     787                if ( typeof tinymce != 'undefined' ) 
     788                        editor = tinymce.get('content'); 
     789 
     790                if ( typeof switchEditors != 'undefined' && editor && ! editor.isHidden() ) { 
     791                        editor.setContent( switchEditors.wpautop( content ) ); 
     792                } else if ( ( editor = $('textarea#content') ) && editor.length ) { 
     793                        editor.val( content ); 
     794                } 
     795 
     796                this.closePreview(); 
     797        }, 
     798 
     799        init: function() { 
     800                var self = this, post_data = wp.autosave.getPostData( true ); 
     801 
     802                this.blog_id = typeof window.autosaveL10n != 'undefined' ? window.autosaveL10n.blog_id : 0; 
     803                 
     804                $('#localsave-items').on( 'click.localsave-items', function(e) { 
     805                        var target = $(e.target); 
     806 
     807                        if ( target.hasClass('localsave-text') ) { 
     808                                self.preview( target.parent().data('key') ); 
     809                        } else if ( target.hasClass('localsave-do-close') ) { 
     810                                self.closePreview(); 
     811                        } else if ( target.hasClass('localsave-do-restore') ) { 
     812                                self.restore( target.data('key') ); 
     813                        } 
     814                        // Stop all links, including links in the preview 
     815                        e.preventDefault(); 
     816                }); 
     817                 
     818                // Set the comparison string 
     819                if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) 
     820                        this.lastsaveddata = post_data.post_title + switchEditors.pre_wpautop(post_data.content); 
     821                else 
     822                        this.lastsaveddata = post_data.post_title + post_data.content; 
     823 
     824                // Set the schedule 
     825                this.schedule = $.schedule({ 
     826                        time: 15 * 1000, 
     827                        func: function() { wp.autosave.local.save(); }, 
     828                        repeat: true, 
     829                        protect: true 
     830                }); 
     831                 
     832                $('form#post').on( 'submit.localsave-cancel', function() { 
     833                $.cancel( self.schedule ); 
     834                }); 
     835                 
     836                // Show the local revisions 
     837                this.showItems(); 
     838        }, 
     839 
     840        /** 
     841         * Escape html so we can show in div 
     842         * @param string str 
     843         * @return string 
     844         */ 
     845        esc_html: function( str ) { 
     846                return $('<div/>').text(str).html(); 
     847        }, 
     848 
     849        /** 
     850         * Show warning that one has historical saved data available for recovery in case one wants. 
     851         */ 
     852        showWarning: function() { 
     853                var self = this, current_post_id = $('#post_ID').val() || '', html = '', same_screen = false; 
     854 
     855                $.each( this.unexpired, function( key, post_data ) { 
     856                        var title = post_data.post_title || '#' + post_data.post_id; 
     857 
     858                        if ( window.pagenow && window.pagenow == 'post' && current_post_id == post_data.post_id ) { 
     859                                html += '<span class="localsave-recover"> <a class="localsave-recover-local" href="#revisionsdiv">' + self.esc_html(title) + '</a> </span> '; 
     860                                same_screen = true; 
     861                        } else { 
     862                                html += '<span class="localsave-recover"> <a href="post.php?post='+post_data.post_id+'&action=edit&localsave-recover=1#revisionsdiv">' + 
     863                                        self.esc_html(title) + '</a> </span> '; 
     864                        } 
     865                }); 
     866 
     867                if ( html ) { 
     868                        $('#wpbody .wrap h2:first').after( 
     869                                '<div class="error" id="localsave-warning">' + 
     870                                '<p><strong>Data saved in your browser</strong></p>' + 
     871                                '<p>' + html + '</p>' + 
     872                                '</div>' 
     873                        ); 
     874 
     875                        if ( same_screen ) { 
     876                                $('#localsave-warning a.localsave-recover-local').click( function(){ 
     877                                        // Make sure the Revisions postbox is open and not hidden 
     878                                        $('#revisionsdiv').removeClass('closed').show(); 
     879                                        // Hide the warning 
     880                                        $('#localsave-warning').slideUp('fast', function(){ $(this).remove(); }); 
     881                                }); 
     882                        } 
     883                } 
     884        } 
     885} 
     886 
     887$(document).ready( function() { 
     888        wp.autosave.local.cleanup(); 
     889        // run on post.php and post-new.php 
     890        if ( 'post' == window.pagenow ) 
     891                wp.autosave.local.init(); 
     892}); 
     893 
     894}(jQuery)); 
     895 
  • wp-includes/js/autosave.js

     
    177177 
    178178// called when autosaving pre-existing post 
    179179function autosave_saved(response) { 
     180 
     181        if ( window.wp && window.wp.autosave ) 
     182                window.wp.autosave.local.expire(); 
     183 
    180184        blockSave = false; 
    181185        autosave_parse_response(response); // parse the ajax response 
    182186        autosave_enable_buttons(); // re-enable disabled form buttons 
     
    186190function autosave_saved_new(response) { 
    187191        blockSave = false; 
    188192        var res = autosave_parse_response(response), postID; 
     193 
     194        if ( window.wp && window.wp.autosave ) 
     195                window.wp.autosave.local.expire(); 
     196 
    189197        if ( res && res.responses.length && !res.errors ) { 
    190198                // An ID is sent only for real auto-saves, not for autosave=0 "keepalive" saves 
    191199                postID = parseInt( res.responses[0].id, 10 ); 
  • wp-includes/post-template.php

     
    14551455 
    14561456<?php 
    14571457        else : 
     1458                echo '<h4 class="revisions-title">' . __('Post revisions') . "</h4>\n"; 
    14581459                echo "<ul class='post-revisions'>\n"; 
    14591460                echo $rows; 
    14601461                echo "</ul>"; 
  • wp-includes/script-loader.php

     
    582582        wp_localize_script( 'autosave', 'autosaveL10n', array( 
    583583                'autosaveInterval' => AUTOSAVE_INTERVAL, 
    584584                'savingText' => __('Saving Draft&#8230;'), 
    585                 'saveAlert' => __('The changes you made will be lost if you navigate away from this page.') 
     585                'saveAlert' => __('The changes you made will be lost if you navigate away from this page.'), 
     586                'blog_id' => get_current_blog_id() 
    586587        ) ); 
    587588 
    588589}