Post Edit Collision Detection from mdawaffe. fixes #6043

git-svn-id: http://svn.automattic.com/wordpress/trunk@7103 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
ryan 2008-02-29 09:51:36 +00:00
parent fcd52b23a1
commit d9aef704a1
14 changed files with 314 additions and 203 deletions

View File

@ -470,6 +470,8 @@ case 'add-user' :
break; break;
case 'autosave' : // The name of this action is hardcoded in edit_post() case 'autosave' : // The name of this action is hardcoded in edit_post()
check_ajax_referer( 'autosave', 'autosavenonce' ); check_ajax_referer( 'autosave', 'autosavenonce' );
global $current_user;
$_POST['post_content'] = $_POST['content']; $_POST['post_content'] = $_POST['content'];
$_POST['post_excerpt'] = $_POST['excerpt']; $_POST['post_excerpt'] = $_POST['excerpt'];
$_POST['post_status'] = 'draft'; $_POST['post_status'] = 'draft';
@ -478,17 +480,36 @@ case 'autosave' : // The name of this action is hardcoded in edit_post()
if($_POST['post_type'] == 'page' || empty($_POST['post_category'])) if($_POST['post_type'] == 'page' || empty($_POST['post_category']))
unset($_POST['post_category']); unset($_POST['post_category']);
$do_autosave = (bool) $_POST['autosave'];
$do_lock = true;
$data = '<div class="updated"><p>' . sprintf( __('Saved at %s.'), date( __('g:i:s a'), current_time( 'timestamp', true ) ) ) . '</p></div>';
$supplemental = array();
$id = 0;
if($_POST['post_ID'] < 0) { if($_POST['post_ID'] < 0) {
$_POST['temp_ID'] = $_POST['post_ID']; $_POST['temp_ID'] = $_POST['post_ID'];
$id = wp_write_post(); if ( $do_autosave )
if( is_wp_error($id) ) $id = wp_write_post();
die($id->get_error_message());
else
die("$id");
} else { } else {
$post_ID = (int) $_POST['post_ID']; $post_ID = (int) $_POST['post_ID'];
$_POST['ID'] = $post_ID; $_POST['ID'] = $post_ID;
$post = get_post($post_ID); $post = get_post($post_ID);
if ( $last = wp_check_post_lock( $post->ID ) ) {
$do_autosave = $do_lock = false;
$last_user = get_userdata( $last );
$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
$data = new WP_Error( 'locked', sprintf(
$_POST['post_type'] == 'page' ? __( 'Autosave disabled: %s is currently editing this page.' ) : __( 'Autosave disabled: %s is currently editing this post.' ),
wp_specialchars( $last_user_name )
) );
$supplemental['disable_autosave'] = 'disable';
}
if ( 'page' == $post->post_type ) { if ( 'page' == $post->post_type ) {
if ( !current_user_can('edit_page', $post_ID) ) if ( !current_user_can('edit_page', $post_ID) )
die(__('You are not allowed to edit this page.')); die(__('You are not allowed to edit this page.'));
@ -496,10 +517,23 @@ case 'autosave' : // The name of this action is hardcoded in edit_post()
if ( !current_user_can('edit_post', $post_ID) ) if ( !current_user_can('edit_post', $post_ID) )
die(__('You are not allowed to edit this post.')); die(__('You are not allowed to edit this post.'));
} }
wp_update_post($_POST); if ( $do_autosave )
$id = wp_update_post($_POST);
else
$id = $post->ID;
} }
die('0');
break; if ( $do_lock && $id && is_numeric($id) )
wp_set_post_lock( $id );
$x = new WP_Ajax_Response( array(
'what' => 'autosave',
'id' => $id,
'data' => $id ? $data : '',
'supplemental' => $supplemental
) );
$x->send();
break;
case 'autosave-generate-nonces' : case 'autosave-generate-nonces' :
check_ajax_referer( 'autosave', 'autosavenonce' ); check_ajax_referer( 'autosave', 'autosavenonce' );
$ID = (int) $_POST['post_ID']; $ID = (int) $_POST['post_ID'];

View File

@ -55,6 +55,15 @@ $saveasdraft = '<input name="save" type="submit" id="save" class="button" tabind
<input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" /> <input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
<input type="hidden" name="post_author" value="<?php echo attribute_escape( $post->post_author ); ?>" /> <input type="hidden" name="post_author" value="<?php echo attribute_escape( $post->post_author ); ?>" />
<input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" /> <input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
<input name="referredby" type="hidden" id="referredby" value="<?php
if ( !empty($_REQUEST['popupurl']) )
echo clean_url(stripslashes($_REQUEST['popupurl']));
else if ( url_to_postid(wp_get_referer()) == $post_ID )
echo 'redo';
else
echo clean_url(stripslashes(wp_get_referer()));
?>" />
<?php echo $form_extra ?> <?php echo $form_extra ?>
<?php if ((isset($post->post_title) && '' == $post->post_title) || (isset($_GET['message']) && 2 > $_GET['message'])) : ?> <?php if ((isset($post->post_title) && '' == $post->post_title) || (isset($_GET['message']) && 2 > $_GET['message'])) : ?>
@ -189,19 +198,7 @@ endif; ?>
<?php echo $form_pingback ?> <?php echo $form_pingback ?>
<?php echo $form_prevstatus ?> <?php echo $form_prevstatus ?>
<p class="submit"> <div id="autosave"></div>
<span id="autosave"></span>
<input name="referredby" type="hidden" id="referredby" value="<?php
if ( !empty($_REQUEST['popupurl']) )
echo clean_url(stripslashes($_REQUEST['popupurl']));
else if ( url_to_postid(wp_get_referer()) == $post_ID )
echo 'redo';
else
echo clean_url(stripslashes(wp_get_referer()));
?>" /></p>
<div id="tagsdiv" class="postbox <?php echo postbox_classes('tagsdiv', 'post'); ?>"> <div id="tagsdiv" class="postbox <?php echo postbox_classes('tagsdiv', 'post'); ?>">
<h3><?php _e('Tags'); ?></h3> <h3><?php _e('Tags'); ?></h3>

View File

@ -36,6 +36,7 @@ if (isset($mode) && 'bookmarklet' == $mode)
<input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" /> <input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
<?php echo $form_extra ?> <?php echo $form_extra ?>
<input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" /> <input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
<input name="referredby" type="hidden" id="referredby" value="<?php <input name="referredby" type="hidden" id="referredby" value="<?php
if ( url_to_postid(wp_get_referer()) == $post_ID ) if ( url_to_postid(wp_get_referer()) == $post_ID )
echo 'redo'; echo 'redo';
@ -169,11 +170,7 @@ endif; ?>
<?php wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false ); ?> <?php wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false ); ?>
</div> </div>
<p class="submit"> <div id="autosave"></div>
<span id="autosave"></span>
</p>
<?php do_meta_boxes('page', 'normal', $post); ?> <?php do_meta_boxes('page', 'normal', $post); ?>

View File

@ -18,8 +18,7 @@ function edit_post() {
$post =& get_post( $post_ID ); $post =& get_post( $post_ID );
$now = time(); $now = time();
$then = strtotime($post->post_date_gmt . ' +0000'); $then = strtotime($post->post_date_gmt . ' +0000');
// Keep autosave_interval in sync with autosave-js.php. $delta = get_option( 'autosave_interval' ) / 2;
$delta = apply_filters( 'autosave_interval', 120 ) / 2;
if ( ($now - $then) < $delta ) if ( ($now - $then) < $delta )
return $post_ID; return $post_ID;
} }
@ -619,4 +618,37 @@ function get_sample_permalink_html($id, $new_slug=null) {
return $return; return $return;
} }
// false: not locked or locked by current user
// int: user ID of user with lock
function wp_check_post_lock( $post_id ) {
global $current_user;
if ( !$post = get_post( $post_id ) )
return false;
$lock = get_post_meta( $post->ID, '_edit_lock', true );
$last = get_post_meta( $post->ID, '_edit_last', true );
$time_window = apply_filters( 'wp_check_post_lock_window', get_option( 'autosave_interval' ) * 2 );
if ( $lock && $lock > time() - $time_window && $last != $current_user->ID )
return $last;
return false;
}
function wp_set_post_lock( $post_id ) {
global $current_user;
if ( !$post = get_post( $post_id ) )
return false;
if ( !$current_user || !$current_user->ID )
return false;
$now = time();
if ( !add_post_meta( $post->ID, '_edit_lock', $now, true ) )
update_post_meta( $post->ID, '_edit_lock', $now );
if ( !add_post_meta( $post->ID, '_edit_last', $current_user->ID, true ) )
update_post_meta( $post->ID, '_edit_last', $current_user->ID );
}
?> ?>

View File

@ -198,7 +198,7 @@ function upgrade_all() {
if ( $wp_current_db_version < 6124 ) if ( $wp_current_db_version < 6124 )
upgrade_230_old_tables(); upgrade_230_old_tables();
if ( $wp_current_db_version < 6689 ) if ( $wp_current_db_version < 7098 )
upgrade_250(); upgrade_250();
maybe_disable_automattic_widgets(); maybe_disable_automattic_widgets();
@ -725,6 +725,8 @@ function upgrade_250() {
if ( $wp_current_db_version < 6689 ) { if ( $wp_current_db_version < 6689 ) {
populate_roles_250(); populate_roles_250();
} }
add_option('autosave_interval', 60);
} }
// The functions we use to actually do stuff // The functions we use to actually do stuff

View File

@ -57,9 +57,16 @@ case 'edit':
wp_enqueue_script('editor'); wp_enqueue_script('editor');
wp_enqueue_script('thickbox'); wp_enqueue_script('thickbox');
wp_enqueue_script('media-upload'); wp_enqueue_script('media-upload');
if ( $last = wp_check_post_lock( $post->ID ) ) {
if ( 'draft' == $post->post_status ) $last_user = get_userdata( $last );
$last_user_name = $last_user ? $last_user->display_name : __('Somebody');
$message = sprintf( __( '%s is currently editing this page' ), wp_specialchars( $last_user_name ) );
$message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
add_action('admin_notices', create_function( '', "echo '$message';" ) );
} else {
wp_set_post_lock( $post->ID );
wp_enqueue_script('autosave'); wp_enqueue_script('autosave');
}
require_once('admin-header.php'); require_once('admin-header.php');

View File

@ -66,9 +66,16 @@ case 'edit':
wp_enqueue_script('editor'); wp_enqueue_script('editor');
wp_enqueue_script('thickbox'); wp_enqueue_script('thickbox');
wp_enqueue_script('media-upload'); wp_enqueue_script('media-upload');
if ( $last = wp_check_post_lock( $post->ID ) ) {
if ( 'draft' == $post->post_status ) $last_user = get_userdata( $last );
$last_user_name = $last_user ? $last_user->display_name : __('Somebody');
$message = sprintf( __( '%s is currently editing this post' ), wp_specialchars( $last_user_name ) );
$message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
add_action('admin_notices', create_function( '', "echo '$message';" ) );
} else {
wp_set_post_lock( $post->ID );
wp_enqueue_script('autosave'); wp_enqueue_script('autosave');
}
require_once('admin-header.php'); require_once('admin-header.php');

View File

@ -1033,6 +1033,15 @@ html, body {
margin-right: 8px; margin-right: 8px;
} }
#poststuff #autosave {
margin: 0;
padding: 0;
}
#poststuff #autosave div.updated, #poststuff #autosave div.error {
margin: 0 8px 10px 20px;
}
#poststuff .inside { #poststuff .inside {
margin: 0 12px 15px; margin: 0 12px 15px;
font-size: 11px; font-size: 11px;

View File

@ -777,9 +777,11 @@ class WP_Ajax_Response {
} }
$s = ''; $s = '';
if ( (array) $supplemental ) if ( (array) $supplemental ) {
foreach ( $supplemental as $k => $v ) foreach ( $supplemental as $k => $v )
$s .= "<$k><![CDATA[$v]]></$k>"; $s .= "<$k><![CDATA[$v]]></$k>";
$s = "<supplemental>$s</supplemental>";
}
if ( false === $action ) if ( false === $action )
$action = $_POST['action']; $action = $_POST['action'];

View File

@ -1,65 +1,75 @@
var autosaveLast = ''; var autosaveLast = '';
var autosavePeriodical; var autosavePeriodical;
function autosave_start_timer() { jQuery(function($) {
autosaveLast = jQuery('#post #title').val()+jQuery('#post #content').val(); autosaveLast = $('#post #title').val()+$('#post #content').val();
// Keep autosave_interval in sync with edit_post(). autosavePeriodical = $.schedule({time: autosaveL10n.autosaveInterval * 1000, func: function() { autosave(); }, repeat: true, protect: true});
autosavePeriodical = jQuery.schedule({time: autosaveL10n.autosaveInterval * 1000, func: autosave, repeat: true, protect: true});
//Disable autosave after the form has been submitted //Disable autosave after the form has been submitted
jQuery("#post #submit").submit(function() { jQuery.cancel(autosavePeriodical); }); $("#post").submit(function() { $.cancel(autosavePeriodical); });
jQuery("#post #save").click(function() { jQuery.cancel(autosavePeriodical); });
jQuery("#post #submit").click(function() { jQuery.cancel(autosavePeriodical); });
jQuery("#post #publish").click(function() { jQuery.cancel(autosavePeriodical); });
jQuery("#post #deletepost").click(function() { jQuery.cancel(autosavePeriodical); });
// Autosave early on for a new post // Autosave early on for a new post. Why? Should this only be run once?
jQuery("#content").keypress(function() { $("#content").keypress(function() {
if ( 1 === ( jQuery(this).val().length % 15 ) && 1 > parseInt(jQuery("#post_ID").val(),10) ) if ( 1 === ( $(this).val().length % 15 ) && 1 > parseInt($("#post_ID").val(),10) )
setTimeout(autosave, 5000); setTimeout(autosave, 5000);
}); });
} });
addLoadEvent(autosave_start_timer)
function autosave_cur_time() { // called when autosaving pre-existing post
var now = new Date(); function autosave_saved(response) {
return "" + ((now.getHours() >12) ? now.getHours() -12 : now.getHours()) + var res = wpAjax.parseAjaxResponse(response, 'autosave'); // parse the ajax response
((now.getMinutes() < 10) ? ":0" : ":") + now.getMinutes() + var message = '';
((now.getSeconds() < 10) ? ":0" : ":") + now.getSeconds();
}
function autosave_update_post_ID(response) { if ( res && res.responses.length ) {
var res = parseInt(response); message = res.responses[0].data; // The saved message or error.
var message; // someone else is editing: disable autosave, set errors
if ( res.responses[0].supplemental && 'disable' == res.responses[0].supplemental['disable_autosave'] ) {
autosave = function() {};
res = { errors: true };
}
if(isNaN(res)) { // if no errors: add preview link and slug UI
message = autosaveL10n.errorText.replace(/%response%/g, response); if ( !res.errors ) {
} else if( res > 0 ) { var postID = parseInt( res.responses[0].id );
message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time()); if ( !isNaN(postID) && postID > 0 ) {
jQuery('#post_ID').attr({name: "post_ID"}); autosave_update_preview_link(postID);
jQuery('#post_ID').val(res); autosave_update_slug(postID);
// We need new nonces }
jQuery.post(autosaveL10n.requestFile, { }
action: "autosave-generate-nonces", }
post_ID: res, if ( message ) { jQuery('#autosave').html(message); } // update autosave message
autosavenonce: jQuery('#autosavenonce').val(), autosave_enable_buttons(); // re-enable disabled form buttons
post_type: jQuery('#post_type').val() return res;
}, function(html) { }
jQuery('#_wpnonce').val(html);
}); // called when autosaving new post
jQuery('#hiddenaction').val('editpost'); function autosave_update_post_ID(response) {
} else { var res = autosave_saved(response); // parse the ajax response do the above
message = autosaveL10n.failText;
// if no errors: update post_ID from the temporary value, grab new save-nonce for that new ID
if ( res && res.responses.length && !res.errors ) {
var postID = parseInt( res.responses[0].id );
if ( !isNaN(postID) && postID > 0 ) {
if ( postID == parseInt(jQuery('#post_ID').val()) ) { return; } // no need to do this more than once
jQuery('#post_ID').attr({name: "post_ID"});
jQuery('#post_ID').val(postID);
// We need new nonces
jQuery.post(autosaveL10n.requestFile, {
action: "autosave-generate-nonces",
post_ID: postID,
autosavenonce: jQuery('#autosavenonce').val(),
post_type: jQuery('#post_type').val()
}, function(html) {
jQuery('#_wpnonce').val(html);
});
jQuery('#hiddenaction').val('editpost');
}
} }
jQuery('#autosave').html(message);
autosave_update_preview_link(res);
autosave_update_slug(res);
autosave_enable_buttons();
} }
function autosave_update_preview_link(post_id) { function autosave_update_preview_link(post_id) {
// Add preview button if not already there // Add preview button if not already there
if ( ! jQuery('#previewview > *').get()[0] ) { if ( !jQuery('#previewview > *').size() ) {
var post_type = jQuery('#post_type').val(); var post_type = jQuery('#post_type').val();
var previewText = 'page' == post_type ? autosaveL10n.previewPageText : autosaveL10n.previewPostText; var previewText = 'page' == post_type ? autosaveL10n.previewPageText : autosaveL10n.previewPostText;
jQuery.post(autosaveL10n.requestFile, { jQuery.post(autosaveL10n.requestFile, {
@ -74,79 +84,70 @@ function autosave_update_preview_link(post_id) {
function autosave_update_slug(post_id) { function autosave_update_slug(post_id) {
// create slug area only if not already there // create slug area only if not already there
if ( 'undefined' != typeof make_slugedit_clickable && ! jQuery('#edit-slug-box > *').get()[0] ) { if ( jQuery.isFunction(make_slugedit_clickable) && !jQuery('#edit-slug-box > *').size() ) {
jQuery.post(slugL10n.requestFile, { jQuery.post(
action: 'sample-permalink', slugL10n.requestFile,
post_id: post_id, {
samplepermalinknonce: jQuery('#samplepermalinknonce').val()}, function(data) { action: 'sample-permalink',
post_id: post_id,
samplepermalinknonce: jQuery('#samplepermalinknonce').val()
},
function(data) {
jQuery('#edit-slug-box').html(data); jQuery('#edit-slug-box').html(data);
make_slugedit_clickable(); make_slugedit_clickable();
}); }
);
} }
} }
function autosave_loading() { function autosave_loading() {
jQuery('#autosave').html(autosaveL10n.savingText); jQuery('#autosave').html('<div class="updated"><p>' + autosaveL10n.savingText + '</p></div>');
}
function autosave_saved(response) {
var res = parseInt(response);
var message;
if(isNaN(res)) {
message = autosaveL10n.errorText.replace(/%response%/g, response);
} else {
message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time());
}
jQuery('#autosave').html(message);
autosave_update_preview_link(res);
autosave_update_slug(res);
autosave_enable_buttons();
}
function autosave_disable_buttons() {
jQuery("#post #save:enabled").attr('disabled', 'disabled');
jQuery("#post #submit:enabled").attr('disabled', 'disabled');
jQuery("#post #publish:enabled").attr('disabled', 'disabled');
jQuery("#post #deletepost:enabled").attr('disabled', 'disabled');
setTimeout('autosave_enable_buttons();', 1000); // Re-enable 1 sec later. Just gives autosave a head start to avoid collisions.
} }
function autosave_enable_buttons() { function autosave_enable_buttons() {
jQuery("#post #save:disabled").attr('disabled', ''); jQuery("#submitpost :button:disabled, #submitpost :submit:disabled").attr('disabled', '');
jQuery("#post #submit:disabled").attr('disabled', '');
jQuery("#post #publish:disabled").attr('disabled', '');
jQuery("#post #deletepost:disabled").attr('disabled', '');
} }
function autosave() { function autosave_disable_buttons() {
var rich = ( (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden() ) ? true : false; jQuery("#submitpost :button:enabled, #submitpost :submit:enabled").attr('disabled', 'disabled');
setTimeout(autosave_enable_buttons, 1000); // Re-enable 1 sec later. Just gives autosave a head start to avoid collisions.
}
var autosave = function() {
// (bool) is rich editor enabled and active
var rich = (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden();
var post_data = { var post_data = {
action: "autosave", action: "autosave",
post_ID: jQuery("#post_ID").val() || 0, post_ID: jQuery("#post_ID").val() || 0,
post_title: jQuery("#title").val() || "", post_title: jQuery("#title").val() || "",
autosavenonce: jQuery('#autosavenonce').val(), autosavenonce: jQuery('#autosavenonce').val(),
tags_input: jQuery("#tags-input").val() || "", tags_input: jQuery("#tags-input").val() || "",
post_type: jQuery('#post_type').val() || "" post_type: jQuery('#post_type').val() || "",
}; autosave: 1
};
// We always send the ajax request in order to keep the post lock fresh.
// This (bool) tells whether or not to write the post to the DB during the ajax request.
var doAutoSave = true;
/* Gotta do this up here so we can check the length when tinyMCE is in use */ /* Gotta do this up here so we can check the length when tinyMCE is in use */
if ( rich ) { if ( rich ) { tinyMCE.triggerSave(); }
// Don't run while the TinyMCE spellcheck is on.
if ( tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) return;
tinyMCE.triggerSave();
}
post_data["content"] = jQuery("#content").val(); post_data["content"] = jQuery("#content").val();
if ( jQuery('#post_name').val() ) if ( jQuery('#post_name').val() )
post_data["post_name"] = jQuery('#post_name').val(); post_data["post_name"] = jQuery('#post_name').val();
// Nothing to save or no change.
if(post_data["post_title"].length==0 || post_data["content"].length==0 || post_data["post_title"] + post_data["content"] == autosaveLast) { if(post_data["post_title"].length==0 || post_data["content"].length==0 || post_data["post_title"] + post_data["content"] == autosaveLast) {
return; doAutoSave = false
} }
autosave_disable_buttons(); autosave_disable_buttons();
var origStatus = jQuery('#original_post_status').val();
if ( 'draft' != origStatus ) // autosave currently only turned on for drafts
doAutoSave = false;
autosaveLast = jQuery("#title").val()+jQuery("#content").val(); autosaveLast = jQuery("#title").val()+jQuery("#content").val();
goodcats = ([]); goodcats = ([]);
jQuery("[@name='post_category[]']:checked").each( function(i) { jQuery("[@name='post_category[]']:checked").each( function(i) {
@ -161,25 +162,27 @@ function autosave() {
if( jQuery("#excerpt")) if( jQuery("#excerpt"))
post_data["excerpt"] = jQuery("#excerpt").val(); post_data["excerpt"] = jQuery("#excerpt").val();
if ( rich ) // Don't run while the TinyMCE spellcheck is on. Why? Who knows.
tinyMCE.triggerSave(); if ( rich && tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) {
doAutoSave = false;
post_data["content"] = jQuery("#content").val(); }
if(parseInt(post_data["post_ID"]) < 1) { if(parseInt(post_data["post_ID"]) < 1) {
post_data["temp_ID"] = post_data["post_ID"]; post_data["temp_ID"] = post_data["post_ID"];
jQuery.ajaxSetup({ var successCallback = autosave_update_post_ID; // new post
success: function(html) { autosave_update_post_ID(html); }
});
} else { } else {
jQuery.ajaxSetup({ var successCallback = autosave_saved; // pre-existing post
success: function(html) { autosave_saved(html); }
});
} }
if ( !doAutoSave ) {
post_data['autosave'] = 0;
}
jQuery.ajax({ jQuery.ajax({
data: post_data, data: post_data,
beforeSend: function() { autosave_loading() }, beforeSend: doAutoSave ? autosave_loading : null,
type: "POST", type: "POST",
url: autosaveL10n.requestFile url: autosaveL10n.requestFile,
success: successCallback
}); });
} }

View File

@ -0,0 +1,56 @@
wpAjax = jQuery.extend( {
unserialize: function( s ) {
var r = {}; if ( !s ) { return r; }
var q = s.split('?'); if ( q[1] ) { s = q[1]; }
var pp = s.split('&');
for ( var i in pp ) {
if ( jQuery.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
var p = pp[i].split('=');
r[p[0]] = p[1];
}
return r;
},
parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
var parsed = {};
var re = jQuery('#' + r).html('');
if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
parsed.responses = [];
parsed.errors = false;
var err = '';
jQuery('response', x).each( function() {
var th = jQuery(this);
var child = jQuery(this.firstChild);
var response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
response.data = jQuery( 'response_data', child ).text();
response.supplemental = {};
if ( !jQuery( 'supplemental', child ).children().each( function() {
response.supplemental[this.nodeName] = jQuery(this).text();
} ).size() ) { response.supplemental = false }
response.errors = [];
if ( !jQuery('wp_error', child).each( function() {
var code = jQuery(this).attr('code');
var anError = { code: code, message: this.firstChild.nodeValue, data: false };
var errorData = jQuery('wp_error_data[code="' + code + '"]', x);
if ( errorData ) { anError.data = errorData.get(); }
var formField = jQuery( 'form-field', errorData ).text();
if ( formField ) { code = formField; }
if ( e ) { wpAjax.invalidateForm( jQuery('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') ); }
err += '<p>' + anError.message + '</p>';
response.errors.push( anError );
parsed.errors = true;
} ).size() ) { response.errors = false; }
parsed.responses.push( response );
} );
if ( err.length ) { re.html( '<div class="error">' + err + '</div>' ); }
return parsed;
}
if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
x = parseInt(x,10);
if ( -1 == x ) { return !re.html('<div class="error"><p>' + this.noPerm + '</p></div>'); }
else if ( 0 === x ) { return !re.html('<div class="error"><p>' + this.broken + '</p></div>'); }
return true;
},
invalidateForm: function( jQ ) {
jQ.addClass( 'form-invalid' ).change( function() { jQuery(this).removeClass( 'form-invalid' ); } );
}
}, wpAjax || { noPerm: 'You do not have permission to do that.', broken: 'AJAX is teh b0rked.' } );

View File

@ -2,46 +2,6 @@
var currentFormEl = false; var currentFormEl = false;
var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'}; var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'};
wpAjax = {
unserialize: function( s ) {
var r = {}; if ( !s ) { return r; }
var q = s.split('?'); if ( q[1] ) { s = q[1]; }
var pp = s.split('&');
for ( var i in pp ) {
if ( $.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
var p = pp[i].split('=');
r[p[0]] = p[1];
}
return r;
},
parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
var re = $('#' + r).html('');
if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
var errs = $('wp_error', x);
if ( errs.size() ) {
var err = '';
errs.each( function() {
var code = $(this).attr('code');
if ( formField = $('wp_error_data[code="' + code + '"] form-field', x).text() )
code = formField;
wpAjax.invalidateForm( $('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') );
err += '<p>' + this.firstChild.nodeValue + '</p>';
} );
return !re.html( '<div class="error">' + err + '</div>' );
}
return true;
}
if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
x = parseInt(x,10);
if ( -1 == x ) { return !re.html('<div class="error"><p>You do not have permission to do that.</p></div>'); }
else if ( 0 === x ) { return !re.html('<div class="error"><p>AJAX is teh b0rked.</p></div>'); }
return true;
},
invalidateForm: function( jQ ) {
jQ.addClass( 'form-invalid' ).change( function() { $(this).removeClass( 'form-invalid' ); } );
}
};
var wpList = { var wpList = {
settings: { settings: {
url: wpListL10n.url, type: 'POST', url: wpListL10n.url, type: 'POST',
@ -127,21 +87,21 @@ var wpList = {
if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; } if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; }
s.success = function(r) { s.success = function(r) {
if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { return false; } var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
if ( !res || res.errors ) { return false; }
$(s.what + ' response_data', r).each( function() { jQuery.each( res.responses, function() {
var t = $(this); wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
wpList.add.call( list, t.text(), $.extend( {}, s, { // this.firstChild.nodevalue pos: this.position || 0,
pos: t.parent().attr( 'position' ) || 0, id: this.id || 0,
id: t.parent().attr( 'id' ) || 0, oldId: this.oldId || null
oldId: t.parent().attr( 'old_id' ) || null
} ) ); } ) );
} ); } );
if ( $.isFunction(s.addAfter) ) { if ( $.isFunction(s.addAfter) ) {
var o = this.complete; var o = this.complete;
this.complete = function(x,st) { this.complete = function(x,st) {
var _s = $.extend( { xml: x, status: st }, s ); var _s = $.extend( { xml: x, status: st, parsed: res }, s );
s.addAfter( r, _s ); s.addAfter( r, _s );
if ( $.isFunction(o) ) { o(x,st); } if ( $.isFunction(o) ) { o(x,st); }
}; };
@ -194,7 +154,8 @@ var wpList = {
} }
s.success = function(r) { s.success = function(r) {
if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
if ( !res || res.errors ) {
element.stop().css( 'backgroundColor', '#FF3333' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } ); element.stop().css( 'backgroundColor', '#FF3333' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
return false; return false;
} }
@ -202,7 +163,7 @@ var wpList = {
var o = this.complete; var o = this.complete;
this.complete = function(x,st) { this.complete = function(x,st) {
element.queue( function() { element.queue( function() {
var _s = $.extend( { xml: x, status: st }, s ); var _s = $.extend( { xml: x, status: st, parsed: res }, s );
s.delAfter( r, _s ); s.delAfter( r, _s );
if ( $.isFunction(o) ) { o(x,st); } if ( $.isFunction(o) ) { o(x,st); }
} ).dequeue(); } ).dequeue();
@ -256,7 +217,8 @@ var wpList = {
if ( !s.data._ajax_nonce ) { return true; } if ( !s.data._ajax_nonce ) { return true; }
s.success = function(r) { s.success = function(r) {
if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
if ( !res || res.errors ) {
element.stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } ); element.stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
return false; return false;
} }
@ -264,7 +226,7 @@ var wpList = {
var o = this.complete; var o = this.complete;
this.complete = function(x,st) { this.complete = function(x,st) {
element.queue( function() { element.queue( function() {
var _s = $.extend( { xml: x, status: st }, s ); var _s = $.extend( { xml: x, status: st, parsed: res }, s );
s.dimAfter( r, _s ); s.dimAfter( r, _s );
if ( $.isFunction(o) ) { o(x,st); } if ( $.isFunction(o) ) { o(x,st); }
} ).dequeue(); } ).dequeue();

View File

@ -41,16 +41,19 @@ class WP_Scripts {
$this->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6'); $this->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6');
$this->add( 'autosave', '/wp-includes/js/autosave.js', array('jquery', 'schedule'), '20080221'); $this->add( 'wp-ajax-response', '/wp-includes/js/wp-ajax-response.js', array('jquery'), '20080229' . mt_rand() );
$this->localize( 'wp-ajax-response', 'wpAjax', array(
'noPerm' => 'You do not have permission to do that.',
'broken' => 'AJAX is teh b0rked.'
) );
$this->add( 'autosave', '/wp-includes/js/autosave.js', array('schedule', 'wp-ajax-response'), '20080221' . mt_rand());
$this->localize( 'autosave', 'autosaveL10n', array( $this->localize( 'autosave', 'autosaveL10n', array(
'autosaveInterval' => apply_filters('autosave_interval', '60'), 'autosaveInterval' => get_option( 'autosave_interval' ),
'errorText' => __('Error: %response%'), 'previewPageText' => __('View this Page'),
'failText' => __('Error: Autosave Failed.'), 'previewPostText' => __('View this Post'),
'previewPageText' => __('Preview this Page'),
'previewPostText' => __('Preview this Post'),
'saveText' => __('Saved at %time%.'),
'requestFile' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php', 'requestFile' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php',
'savingText' => __('Saving Draft...') 'savingText' => __('Saving&#8230;')
) ); ) );
$this->add( 'wp-ajax', '/wp-includes/js/wp-ajax.js', array('prototype'), '20070306'); $this->add( 'wp-ajax', '/wp-includes/js/wp-ajax.js', array('prototype'), '20070306');
@ -61,7 +64,7 @@ class WP_Scripts {
'whoaText' => __("Slow down, I'm still sending your data!") 'whoaText' => __("Slow down, I'm still sending your data!")
) ); ) );
$this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20080228' ); $this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('wp-ajax-response'), '20080228' . mt_rand());
$this->localize( 'wp-lists', 'wpListL10n', array( $this->localize( 'wp-lists', 'wpListL10n', array(
'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php' 'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php'
) ); ) );

View File

@ -16,6 +16,6 @@ $wp_version = '2.5-beta1';
* *
* @global int $wp_db_version * @global int $wp_db_version
*/ */
$wp_db_version = 6846; $wp_db_version = 7098;
?> ?>