WordPress.org

Make WordPress Core

Ticket #6043: 6043.2.diff

File 6043.2.diff, 30.2 KB (added by mdawaffe, 10 years ago)

first pass

  • wp-includes/version.php

     
    1616 *
    1717 * @global int $wp_db_version
    1818 */
    19 $wp_db_version = 6846;
     19$wp_db_version = 7098;
    2020
    2121?>
  • wp-includes/js/autosave.js

     
    11var autosaveLast = '';
    22var autosavePeriodical;
    33
    4 function autosave_start_timer() {
    5         autosaveLast = jQuery('#post #title').val()+jQuery('#post #content').val();
    6         // Keep autosave_interval in sync with edit_post().
    7         autosavePeriodical = jQuery.schedule({time: autosaveL10n.autosaveInterval * 1000, func: autosave, repeat: true, protect: true});
     4jQuery(function($) {
     5        autosaveLast = $('#post #title').val()+$('#post #content').val();
     6        autosavePeriodical = $.schedule({time: autosaveL10n.autosaveInterval * 1000, func: function() { autosave(); }, repeat: true, protect: true});
    87
    98        //Disable autosave after the form has been submitted
    10         jQuery("#post #submit").submit(function() { jQuery.cancel(autosavePeriodical); });
    11         jQuery("#post #save").click(function() { jQuery.cancel(autosavePeriodical); });
    12         jQuery("#post #submit").click(function() { jQuery.cancel(autosavePeriodical); });
    13         jQuery("#post #publish").click(function() { jQuery.cancel(autosavePeriodical); });
    14         jQuery("#post #deletepost").click(function() { jQuery.cancel(autosavePeriodical); });
     9        $("#post").submit(function() { $.cancel(autosavePeriodical); });
    1510
    16         // Autosave early on for a new post
    17         jQuery("#content").keypress(function() {
    18                 if ( 1 === ( jQuery(this).val().length % 15 ) && 1 > parseInt(jQuery("#post_ID").val(),10) )
     11        // Autosave early on for a new post.  Why?  Should this only be run once?
     12        $("#content").keypress(function() {
     13                if ( 1 === ( $(this).val().length % 15 ) && 1 > parseInt($("#post_ID").val(),10) )
    1914                        setTimeout(autosave, 5000);
    2015        });
    21 }
    22 addLoadEvent(autosave_start_timer)
     16});
    2317
    24 function autosave_cur_time() {
    25         var now = new Date();
    26         return "" + ((now.getHours() >12) ? now.getHours() -12 : now.getHours()) +
    27         ((now.getMinutes() < 10) ? ":0" : ":") + now.getMinutes() +
    28         ((now.getSeconds() < 10) ? ":0" : ":") + now.getSeconds();
     18// called when autosaving pre-existing post
     19function autosave_saved(response) {
     20        var res = wpAjax.parseAjaxResponse(response, 'autosave'); // parse the ajax response
     21        var message = '';
     22
     23        if ( res && res.responses.length ) {
     24                message = res.responses[0].data; // The saved message or error.
     25                // someone else is editing: disable autosave, set errors
     26                if ( res.responses[0].supplemental && 'disable' == res.responses[0].supplemental['disable_autosave'] ) {
     27                        autosave = function() {};
     28                        res = { errors: true };
     29                }
     30
     31                // if no errors: add preview link and slug UI
     32                if ( !res.errors ) {
     33                        var postID = parseInt( res.responses[0].id );
     34                        if ( !isNaN(postID) && postID > 0 ) {
     35                                autosave_update_preview_link(postID);
     36                                autosave_update_slug(postID);
     37                        }
     38                }
     39        }
     40        if ( message ) { jQuery('#autosave').html(message); } // update autosave message
     41        autosave_enable_buttons(); // re-enable disabled form buttons
     42        return res;
    2943}
    3044
     45// called when autosaving new post
    3146function autosave_update_post_ID(response) {
    32         var res = parseInt(response);
    33         var message;
     47        var res = autosave_saved(response); // parse the ajax response do the above
    3448
    35         if(isNaN(res)) {
    36                 message = autosaveL10n.errorText.replace(/%response%/g, response);
    37         } else if( res > 0 ) {
    38                 message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time());
    39                 jQuery('#post_ID').attr({name: "post_ID"});
    40                 jQuery('#post_ID').val(res);
    41                 // We need new nonces
    42                 jQuery.post(autosaveL10n.requestFile, {
    43                         action: "autosave-generate-nonces",
    44                         post_ID: res,
    45                         autosavenonce: jQuery('#autosavenonce').val(),
    46                         post_type: jQuery('#post_type').val()
    47                 }, function(html) {
    48                         jQuery('#_wpnonce').val(html);
    49                 });
    50                 jQuery('#hiddenaction').val('editpost');
    51         } else {
    52                 message = autosaveL10n.failText;
     49        // if no errors: update post_ID from the temporary value, grab new save-nonce for that new ID
     50        if ( res && res.responses.length && !res.errors ) {
     51                var postID = parseInt( res.responses[0].id );
     52                if ( !isNaN(postID) && postID > 0 ) {
     53                        if ( postID == parseInt(jQuery('#post_ID').val()) ) { return; } // no need to do this more than once
     54                        jQuery('#post_ID').attr({name: "post_ID"});
     55                        jQuery('#post_ID').val(postID);
     56                        // We need new nonces
     57                        jQuery.post(autosaveL10n.requestFile, {
     58                                action: "autosave-generate-nonces",
     59                                post_ID: postID,
     60                                autosavenonce: jQuery('#autosavenonce').val(),
     61                                post_type: jQuery('#post_type').val()
     62                        }, function(html) {
     63                                jQuery('#_wpnonce').val(html);
     64                        });
     65                        jQuery('#hiddenaction').val('editpost');
     66                }
    5367        }
    54         jQuery('#autosave').html(message);
    55         autosave_update_preview_link(res);
    56         autosave_update_slug(res);
    57         autosave_enable_buttons();
    5868}
    5969
    6070function autosave_update_preview_link(post_id) {
    6171        // Add preview button if not already there
    62         if ( ! jQuery('#previewview > *').get()[0] ) {
     72        if ( !jQuery('#previewview > *').size() ) {
    6373                var post_type = jQuery('#post_type').val();
    6474                var previewText = 'page' == post_type ? autosaveL10n.previewPageText : autosaveL10n.previewPostText;
    6575                jQuery.post(autosaveL10n.requestFile, {
     
    7484
    7585function autosave_update_slug(post_id) {
    7686        // create slug area only if not already there
    77         if ( 'undefined' != typeof make_slugedit_clickable && ! jQuery('#edit-slug-box > *').get()[0] ) {
    78                 jQuery.post(slugL10n.requestFile, {
    79                         action: 'sample-permalink',
    80                         post_id: post_id,
    81                         samplepermalinknonce: jQuery('#samplepermalinknonce').val()}, function(data) {
     87        if ( jQuery.isFunction(make_slugedit_clickable) && !jQuery('#edit-slug-box > *').size() ) {
     88                jQuery.post(
     89                        slugL10n.requestFile,
     90                        {
     91                                action: 'sample-permalink',
     92                                post_id: post_id,
     93                                samplepermalinknonce: jQuery('#samplepermalinknonce').val()
     94                        },
     95                        function(data) {
    8296                                jQuery('#edit-slug-box').html(data);
    8397                                make_slugedit_clickable();
    84                         });
     98                        }
     99                );
    85100        }
    86101}
    87102
    88103function autosave_loading() {
    89         jQuery('#autosave').html(autosaveL10n.savingText);
     104        jQuery('#autosave').html('<div class="updated"><p>' + autosaveL10n.savingText + '</p></div>');
    90105}
    91106
    92 function autosave_saved(response) {
    93         var res = parseInt(response);
    94         var message;
    95 
    96         if(isNaN(res)) {
    97                 message = autosaveL10n.errorText.replace(/%response%/g, response);
    98         } else {
    99                 message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time());
    100         }
    101         jQuery('#autosave').html(message);
    102         autosave_update_preview_link(res);
    103         autosave_update_slug(res);
    104         autosave_enable_buttons();
     107function autosave_enable_buttons() {
     108        jQuery("#submitpost :button:disabled, #submitpost :submit:disabled").attr('disabled', '');
    105109}
    106110
    107111function autosave_disable_buttons() {
    108         jQuery("#post #save:enabled").attr('disabled', 'disabled');
    109         jQuery("#post #submit:enabled").attr('disabled', 'disabled');
    110         jQuery("#post #publish:enabled").attr('disabled', 'disabled');
    111         jQuery("#post #deletepost:enabled").attr('disabled', 'disabled');
    112         setTimeout('autosave_enable_buttons();', 1000); // Re-enable 1 sec later.  Just gives autosave a head start to avoid collisions.
     112        jQuery("#submitpost :button:enabled, #submitpost :submit:enabled").attr('disabled', 'disabled');
     113        setTimeout(autosave_enable_buttons, 1000); // Re-enable 1 sec later.  Just gives autosave a head start to avoid collisions.
    113114}
    114115
    115 function autosave_enable_buttons() {
    116         jQuery("#post #save:disabled").attr('disabled', '');
    117         jQuery("#post #submit:disabled").attr('disabled', '');
    118         jQuery("#post #publish:disabled").attr('disabled', '');
    119         jQuery("#post #deletepost:disabled").attr('disabled', '');
    120 }
    121 
    122 function autosave() {
    123         var rich = ( (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden() ) ? true : false;
     116var autosave = function() {
     117        // (bool) is rich editor enabled and active
     118        var rich = (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden();
    124119        var post_data = {
    125                         action: "autosave",
    126                         post_ID:  jQuery("#post_ID").val() || 0,
    127                         post_title: jQuery("#title").val() || "",
    128                         autosavenonce: jQuery('#autosavenonce').val(),
    129                         tags_input: jQuery("#tags-input").val() || "",
    130                         post_type: jQuery('#post_type').val() || ""
    131                 };
     120                action: "autosave",
     121                post_ID:  jQuery("#post_ID").val() || 0,
     122                post_title: jQuery("#title").val() || "",
     123                autosavenonce: jQuery('#autosavenonce').val(),
     124                tags_input: jQuery("#tags-input").val() || "",
     125                post_type: jQuery('#post_type').val() || "",
     126                autosave: 1
     127        };
    132128
     129        // We always send the ajax request in order to keep the post lock fresh.
     130        // This (bool) tells whether or not to write the post to the DB during the ajax request.
     131        var doAutoSave = true;
     132
    133133        /* Gotta do this up here so we can check the length when tinyMCE is in use */
    134         if ( rich ) {
    135                 // Don't run while the TinyMCE spellcheck is on.
    136                 if ( tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) return;
    137                 tinyMCE.triggerSave();
    138         }
     134        if ( rich ) { tinyMCE.triggerSave(); }
    139135       
    140136        post_data["content"] = jQuery("#content").val();
    141137        if ( jQuery('#post_name').val() )
    142138                post_data["post_name"] = jQuery('#post_name').val();
    143139
     140        // Nothing to save or no change.
    144141        if(post_data["post_title"].length==0 || post_data["content"].length==0 || post_data["post_title"] + post_data["content"] == autosaveLast) {
    145                 return;
     142                doAutoSave = false
    146143        }
    147144
    148145        autosave_disable_buttons();
    149146
     147        var origStatus = jQuery('#original_post_status').val();
     148        if ( 'draft' != origStatus ) // autosave currently only turned on for drafts
     149                doAutoSave = false;
     150
    150151        autosaveLast = jQuery("#title").val()+jQuery("#content").val();
    151152        goodcats = ([]);
    152153        jQuery("[@name='post_category[]']:checked").each( function(i) {
     
    161162        if( jQuery("#excerpt"))
    162163                post_data["excerpt"] = jQuery("#excerpt").val();
    163164
    164         if ( rich )
    165         tinyMCE.triggerSave();
    166    
    167         post_data["content"] = jQuery("#content").val();
     165        // Don't run while the TinyMCE spellcheck is on.  Why?  Who knows.
     166        if ( rich && tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) {
     167                doAutoSave = false;
     168        }
    168169
    169170        if(parseInt(post_data["post_ID"]) < 1) {
    170171                post_data["temp_ID"] = post_data["post_ID"];
    171                 jQuery.ajaxSetup({
    172                         success: function(html) { autosave_update_post_ID(html); }
    173                 });
     172                var successCallback = autosave_update_post_ID; // new post
    174173        } else {
    175                 jQuery.ajaxSetup({
    176                         success: function(html) { autosave_saved(html); }
    177                 });
     174                var successCallback = autosave_saved; // pre-existing post
    178175        }
     176
     177        if ( !doAutoSave ) {
     178                post_data['autosave'] = 0;
     179        }
     180
    179181        jQuery.ajax({
    180182                data: post_data,
    181                 beforeSend: function() { autosave_loading() },
     183                beforeSend: doAutoSave ? autosave_loading : null,
    182184                type: "POST",
    183                 url: autosaveL10n.requestFile
     185                url: autosaveL10n.requestFile,
     186                success: successCallback
    184187        });
    185188}
  • wp-includes/js/wp-lists.js

     
    22var currentFormEl = false;
    33var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'};
    44
    5 wpAjax = {
    6         unserialize: function( s ) {
    7                 var r = {}; if ( !s ) { return r; }
    8                 var q = s.split('?'); if ( q[1] ) { s = q[1]; }
    9                 var pp = s.split('&');
    10                 for ( var i in pp ) {
    11                         if ( $.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
    12                         var p = pp[i].split('=');
    13                         r[p[0]] = p[1];
    14                 }
    15                 return r;
    16         },
    17         parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
    18                 var re = $('#' + r).html('');
    19                 if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
    20                         var errs = $('wp_error', x);
    21                         if ( errs.size() ) {
    22                                 var err = '';
    23                                 errs.each( function() {
    24                                         var code = $(this).attr('code');
    25                                         if ( formField = $('wp_error_data[code="' + code + '"] form-field', x).text() )
    26                                                 code = formField;
    27                                         wpAjax.invalidateForm( $('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') );
    28                                         err += '<p>' + this.firstChild.nodeValue + '</p>';
    29                                 } );
    30                                 return !re.html( '<div class="error">' + err + '</div>' );
    31                         }
    32                         return true;
    33                 }
    34                 if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
    35                 x = parseInt(x,10);
    36                 if ( -1 == x ) { return !re.html('<div class="error"><p>You do not have permission to do that.</p></div>'); }
    37                 else if ( 0 === x ) { return !re.html('<div class="error"><p>AJAX is teh b0rked.</p></div>'); }
    38                 return true;
    39         },
    40         invalidateForm: function( jQ ) {
    41                 jQ.addClass( 'form-invalid' ).change( function() { $(this).removeClass( 'form-invalid' ); } );
    42         }
    43 };
    44 
    455var wpList = {
    466        settings: {
    477                url: wpListL10n.url, type: 'POST',
     
    12787                if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; }
    12888
    12989                s.success = function(r) {
    130                         if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { return false; }
     90                        var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
     91                        if ( !res || res.errors ) { return false; }
    13192
    132                         $(s.what + ' response_data', r).each( function() {
    133                                 var t = $(this);
    134                                 wpList.add.call( list, t.text(), $.extend( {}, s, { // this.firstChild.nodevalue
    135                                         pos: t.parent().attr( 'position' ) || 0,
    136                                         id: t.parent().attr( 'id' ) || 0,
    137                                         oldId: t.parent().attr( 'old_id' ) || null
     93                        jQuery.each( res.responses, function() {
     94                                wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
     95                                        pos: this.position || 0,
     96                                        id: this.id || 0,
     97                                        oldId: this.oldId || null
    13898                                } ) );
    13999                        } );
    140100
    141101                        if ( $.isFunction(s.addAfter) ) {
    142102                                var o = this.complete;
    143103                                this.complete = function(x,st) {
    144                                         var _s = $.extend( { xml: x, status: st }, s );
     104                                        var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    145105                                        s.addAfter( r, _s );
    146106                                        if ( $.isFunction(o) ) { o(x,st); }
    147107                                };
     
    194154                }
    195155
    196156                s.success = function(r) {
    197                         if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
     157                        var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
     158                        if ( !res || res.errors ) {
    198159                                element.stop().css( 'backgroundColor', '#FF3333' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
    199160                                return false;
    200161                        }
     
    202163                                var o = this.complete;
    203164                                this.complete = function(x,st) {
    204165                                        element.queue( function() {
    205                                                 var _s = $.extend( { xml: x, status: st }, s );
     166                                                var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    206167                                                s.delAfter( r, _s );
    207168                                                if ( $.isFunction(o) ) { o(x,st); }
    208169                                        } ).dequeue();
     
    256217                if ( !s.data._ajax_nonce ) { return true; }
    257218
    258219                s.success = function(r) {
    259                         if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
     220                        var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
     221                        if ( !res || res.errors ) {
    260222                                element.stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
    261223                                return false;
    262224                        }
     
    264226                                var o = this.complete;
    265227                                this.complete = function(x,st) {
    266228                                        element.queue( function() {
    267                                                 var _s = $.extend( { xml: x, status: st }, s );
     229                                                var _s = $.extend( { xml: x, status: st, parsed: res }, s );
    268230                                                s.dimAfter( r, _s );
    269231                                                if ( $.isFunction(o) ) { o(x,st); }
    270232                                        } ).dequeue();
  • wp-includes/js/wp-ajax-response.js

     
     1wpAjax = jQuery.extend( {
     2        unserialize: function( s ) {
     3                var r = {}; if ( !s ) { return r; }
     4                var q = s.split('?'); if ( q[1] ) { s = q[1]; }
     5                var pp = s.split('&');
     6                for ( var i in pp ) {
     7                        if ( jQuery.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
     8                        var p = pp[i].split('=');
     9                        r[p[0]] = p[1];
     10                }
     11                return r;
     12        },
     13        parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
     14                var parsed = {};
     15                var re = jQuery('#' + r).html('');
     16                if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
     17                        parsed.responses = [];
     18                        parsed.errors = false;
     19                        var err = '';
     20                        jQuery('response', x).each( function() {
     21                                var th = jQuery(this);
     22                                var child = jQuery(this.firstChild);
     23                                var response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
     24                                response.data = jQuery( 'response_data', child ).text();
     25                                response.supplemental = {};
     26                                if ( !jQuery( 'supplemental', child ).children().each( function() {
     27                                        response.supplemental[this.nodeName] = jQuery(this).text();
     28                                } ).size() ) { response.supplemental = false }
     29                                response.errors = [];
     30                                if ( !jQuery('wp_error', child).each( function() {
     31                                        var code = jQuery(this).attr('code');
     32                                        var anError = { code: code, message: this.firstChild.nodeValue, data: false };
     33                                        var errorData = jQuery('wp_error_data[code="' + code + '"]', x);
     34                                        if ( errorData ) { anError.data = errorData.get(); }
     35                                        var formField = jQuery( 'form-field', errorData ).text();
     36                                        if ( formField ) { code = formField; }
     37                                        if ( e ) { wpAjax.invalidateForm( jQuery('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') ); }
     38                                        err += '<p>' + anError.message + '</p>';
     39                                        response.errors.push( anError );
     40                                        parsed.errors = true;
     41                                } ).size() ) { response.errors = false; }
     42                                parsed.responses.push( response );
     43                        } );
     44                        if ( err.length ) { re.html( '<div class="error">' + err + '</div>' ); }
     45                        return parsed;
     46                }
     47                if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
     48                x = parseInt(x,10);
     49                if ( -1 == x ) { return !re.html('<div class="error"><p>' + this.noPerm + '</p></div>'); }
     50                else if ( 0 === x ) { return !re.html('<div class="error"><p>' + this.broken  + '</p></div>'); }
     51                return true;
     52        },
     53        invalidateForm: function( jQ ) {
     54                jQ.addClass( 'form-invalid' ).change( function() { jQuery(this).removeClass( 'form-invalid' ); } );
     55        }
     56}, wpAjax || { noPerm: 'You do not have permission to do that.', broken: 'AJAX is teh b0rked.' } );
  • wp-includes/classes.php

     
    777777                }
    778778
    779779                $s = '';
    780                 if ( (array) $supplemental )
     780                if ( (array) $supplemental ) {
    781781                        foreach ( $supplemental as $k => $v )
    782782                                $s .= "<$k><![CDATA[$v]]></$k>";
     783                        $s = "<supplemental>$s</supplemental>";
     784                }
    783785
    784786                if ( false === $action )
    785787                        $action = $_POST['action'];
  • wp-includes/script-loader.php

     
    4141               
    4242                $this->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6');
    4343
    44                 $this->add( 'autosave', '/wp-includes/js/autosave.js', array('jquery', 'schedule'), '20080221');
     44                $this->add( 'wp-ajax-response', '/wp-includes/js/wp-ajax-response.js', array('jquery'), '20080229' . mt_rand() );
     45                $this->localize( 'wp-ajax-response', 'wpAjax', array(
     46                        'noPerm' => 'You do not have permission to do that.',
     47                        'broken' => 'AJAX is teh b0rked.'
     48                ) );
     49
     50                $this->add( 'autosave', '/wp-includes/js/autosave.js', array('schedule', 'wp-ajax-response'), '20080221' . mt_rand());
    4551                $this->localize( 'autosave', 'autosaveL10n', array(
    46                         'autosaveInterval' => apply_filters('autosave_interval', '60'),
    47                         'errorText' => __('Error: %response%'),
    48                         'failText' => __('Error: Autosave Failed.'),
    49                         'previewPageText' => __('Preview this Page'),
    50                         'previewPostText' => __('Preview this Post'),
    51                         'saveText' => __('Saved at %time%.'),
     52                        'autosaveInterval' => get_option( 'autosave_interval' ),
     53                        'previewPageText' => __('View this Page'),
     54                        'previewPostText' => __('View this Post'),
    5255                        'requestFile' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php',
    53                         'savingText' => __('Saving Draft...')
     56                        'savingText' => __('Saving&#8230;')
    5457                ) );
    5558
    5659                $this->add( 'wp-ajax', '/wp-includes/js/wp-ajax.js', array('prototype'), '20070306');
     
    6164                        'whoaText' => __("Slow down, I'm still sending your data!")
    6265                ) );
    6366
    64                 $this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20080228' );
     67                $this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('wp-ajax-response'), '20080228' . mt_rand());
    6568                $this->localize( 'wp-lists', 'wpListL10n', array(
    6669                        'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php'
    6770                ) );
  • wp-admin/admin-ajax.php

     
    470470        break;
    471471case 'autosave' : // The name of this action is hardcoded in edit_post()
    472472        check_ajax_referer( 'autosave', 'autosavenonce' );
     473        global $current_user;
     474
    473475        $_POST['post_content'] = $_POST['content'];
    474476        $_POST['post_excerpt'] = $_POST['excerpt'];
    475477        $_POST['post_status'] = 'draft';
     
    478480        if($_POST['post_type'] == 'page' || empty($_POST['post_category']))
    479481                unset($_POST['post_category']);
    480482
     483        $do_autosave = (bool) $_POST['autosave'];
     484        $do_lock = true;
     485
     486        $data = '<div class="updated"><p>' . sprintf( __('Saved at %s.'), date( __('g:i:s a'), current_time( 'timestamp', true ) ) ) . '</p></div>';
     487
     488        $supplemental = array();
     489
     490        $id = 0;
    481491        if($_POST['post_ID'] < 0) {
    482492                $_POST['temp_ID'] = $_POST['post_ID'];
    483                 $id = wp_write_post();
    484                 if( is_wp_error($id) )
    485                         die($id->get_error_message());
    486                 else
    487                         die("$id");
     493                if ( $do_autosave )
     494                        $id = wp_write_post();
    488495        } else {
    489496                $post_ID = (int) $_POST['post_ID'];
    490497                $_POST['ID'] = $post_ID;
    491498                $post = get_post($post_ID);
     499
     500                if ( $last = wp_check_post_lock( $post->ID ) ) {
     501                        $do_autosave = $do_lock = false;
     502
     503                        $last_user = get_userdata( $last );
     504                        $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
     505                        $data = new WP_Error( 'locked', sprintf(
     506                                $_POST['post_type'] == 'page' ? __( 'Autosave disabled: %s is currently editing this page.' ) : __( 'Autosave disabled: %s is currently editing this post.' ),
     507                                wp_specialchars( $last_user_name )
     508                        ) );
     509
     510                        $supplemental['disable_autosave'] = 'disable';
     511                }
     512
    492513                if ( 'page' == $post->post_type ) {
    493514                        if ( !current_user_can('edit_page', $post_ID) )
    494515                                die(__('You are not allowed to edit this page.'));
     
    496517                        if ( !current_user_can('edit_post', $post_ID) )
    497518                                die(__('You are not allowed to edit this post.'));
    498519                }
    499                 wp_update_post($_POST);
     520                if ( $do_autosave )
     521                        $id = wp_update_post($_POST);
     522                else
     523                        $id = $post->ID;
    500524        }
    501         die('0');
    502 break;
     525
     526        if ( $do_lock && $id && is_numeric($id) )
     527                wp_set_post_lock( $id );
     528
     529        $x = new WP_Ajax_Response( array(
     530                'what' => 'autosave',
     531                'id' => $id,
     532                'data' => $id ? $data : '',
     533                'supplemental' => $supplemental
     534        ) );
     535        $x->send();
     536        break;
    503537case 'autosave-generate-nonces' :
    504538        check_ajax_referer( 'autosave', 'autosavenonce' );
    505539        $ID = (int) $_POST['post_ID'];
  • wp-admin/wp-admin.css

     
    10331033        margin-right: 8px;
    10341034}
    10351035
     1036#poststuff #autosave {
     1037        margin: 0;
     1038        padding: 0;
     1039}
     1040
     1041#poststuff #autosave div.updated, #poststuff #autosave div.error {
     1042        margin: 0 8px 10px 20px;
     1043}
     1044
    10361045#poststuff .inside {
    10371046        margin: 0 12px 15px;
    10381047        font-size: 11px;
  • wp-admin/includes/post.php

     
    1818                $post =& get_post( $post_ID );
    1919                $now = time();
    2020                $then = strtotime($post->post_date_gmt . ' +0000');
    21                 // Keep autosave_interval in sync with autosave-js.php.
    22                 $delta = apply_filters( 'autosave_interval', 120 ) / 2;
     21                $delta = get_option( 'autosave_interval' ) / 2;
    2322                if ( ($now - $then) < $delta )
    2423                        return $post_ID;
    2524        }
     
    619618        return $return;
    620619}
    621620
     621// false: not locked or locked by current user
     622// int: user ID of user with lock
     623function wp_check_post_lock( $post_id ) {
     624        global $current_user;
     625
     626        if ( !$post = get_post( $post_id ) )
     627                return false;
     628
     629        $lock = get_post_meta( $post->ID, '_edit_lock', true );
     630        $last = get_post_meta( $post->ID, '_edit_last', true );
     631
     632        $time_window = apply_filters( 'wp_check_post_lock_window', get_option( 'autosave_interval' ) * 2 );
     633
     634        if ( $lock && $lock > time() - $time_window && $last != $current_user->ID )
     635                return $last;
     636        return false;
     637}
     638
     639function wp_set_post_lock( $post_id ) {
     640        global $current_user;
     641        if ( !$post = get_post( $post_id ) )
     642                return false;
     643        if ( !$current_user || !$current_user->ID )
     644                return false;
     645       
     646        $now = time();
     647
     648        if ( !add_post_meta( $post->ID, '_edit_lock', $now, true ) )
     649                update_post_meta( $post->ID, '_edit_lock', $now );
     650        if ( !add_post_meta( $post->ID, '_edit_last', $current_user->ID, true ) )
     651                update_post_meta( $post->ID, '_edit_last', $current_user->ID );
     652}
     653
    622654?>
  • wp-admin/includes/upgrade.php

     
    198198        if ( $wp_current_db_version < 6124 )
    199199                upgrade_230_old_tables();
    200200
    201         if ( $wp_current_db_version < 6689 )
     201        if ( $wp_current_db_version < 7098 )
    202202                upgrade_250();
    203203
    204204        maybe_disable_automattic_widgets();
     
    725725        if ( $wp_current_db_version < 6689 ) {
    726726                populate_roles_250();
    727727        }
     728
     729        add_option('autosave_interval', 60);
    728730}
    729731
    730732// The functions we use to actually do stuff
  • wp-admin/post.php

     
    6666                wp_enqueue_script('editor');
    6767        wp_enqueue_script('thickbox');
    6868        wp_enqueue_script('media-upload');
    69 
    70         if ( 'draft' == $post->post_status )
     69        if ( $last = wp_check_post_lock( $post->ID ) ) {
     70                $last_user = get_userdata( $last );
     71                $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
     72                $message = sprintf( __( '%s is currently editing this post' ), wp_specialchars( $last_user_name ) );
     73                $message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
     74                add_action('admin_notices', create_function( '', "echo '$message';" ) );
     75        } else {
     76                wp_set_post_lock( $post->ID );
    7177                wp_enqueue_script('autosave');
     78        }
    7279
    7380        require_once('admin-header.php');
    7481
  • wp-admin/edit-page-form.php

     
    3636<input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
    3737<?php echo $form_extra ?>
    3838<input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
     39<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
    3940<input name="referredby" type="hidden" id="referredby" value="<?php
    4041if ( url_to_postid(wp_get_referer()) == $post_ID )
    4142        echo 'redo';
     
    169170<?php wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false ); ?>
    170171</div>
    171172
    172 <p class="submit">
     173<div id="autosave"></div>
    173174
    174 <span id="autosave"></span>
    175 
    176 </p>
    177 
    178175<?php do_meta_boxes('page', 'normal', $post); ?>
    179176
    180177<?php do_action('edit_page_form'); ?>
  • wp-admin/edit-form-advanced.php

     
    5555<input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
    5656<input type="hidden" name="post_author" value="<?php echo attribute_escape( $post->post_author ); ?>" />
    5757<input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
     58<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
     59<input name="referredby" type="hidden" id="referredby" value="<?php
     60if ( !empty($_REQUEST['popupurl']) )
     61        echo clean_url(stripslashes($_REQUEST['popupurl']));
     62else if ( url_to_postid(wp_get_referer()) == $post_ID )
     63        echo 'redo';
     64else
     65        echo clean_url(stripslashes(wp_get_referer()));
     66?>" />
    5867
    5968<?php echo $form_extra ?>
    6069<?php if ((isset($post->post_title) && '' == $post->post_title) || (isset($_GET['message']) && 2 > $_GET['message'])) : ?>
     
    189198<?php echo $form_pingback ?>
    190199<?php echo $form_prevstatus ?>
    191200
    192 <p class="submit">
     201<div id="autosave"></div>
    193202
    194 <span id="autosave"></span>
    195 
    196 
    197 <input name="referredby" type="hidden" id="referredby" value="<?php
    198 if ( !empty($_REQUEST['popupurl']) )
    199         echo clean_url(stripslashes($_REQUEST['popupurl']));
    200 else if ( url_to_postid(wp_get_referer()) == $post_ID )
    201         echo 'redo';
    202 else
    203         echo clean_url(stripslashes(wp_get_referer()));
    204 ?>" /></p>
    205 
    206203<div id="tagsdiv" class="postbox <?php echo postbox_classes('tagsdiv', 'post'); ?>">
    207204<h3><?php _e('Tags'); ?></h3>
    208205<div class="inside">
  • wp-admin/page.php

     
    5757                wp_enqueue_script('editor');
    5858        wp_enqueue_script('thickbox');
    5959        wp_enqueue_script('media-upload');
    60 
    61         if ( 'draft' == $post->post_status )
     60        if ( $last = wp_check_post_lock( $post->ID ) ) {
     61                $last_user = get_userdata( $last );
     62                $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
     63                $message = sprintf( __( '%s is currently editing this page' ), wp_specialchars( $last_user_name ) );
     64                $message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
     65                add_action('admin_notices', create_function( '', "echo '$message';" ) );
     66        } else {
     67                wp_set_post_lock( $post->ID );
    6268                wp_enqueue_script('autosave');
     69        }
    6370
    6471        require_once('admin-header.php');
    6572