Index: wp-admin/css/wp-admin.css
===================================================================
--- wp-admin/css/wp-admin.css	(revision 23401)
+++ wp-admin/css/wp-admin.css	(working copy)
@@ -3453,6 +3453,72 @@
 	text-decoration: none;
 }
 
+#revisionsdiv h4.revisions-title {
+	margin-bottom: 0.7em;
+}
+
+#revisionsdiv ul.post-revisions,
+#revisionsdiv p.no-revisions,
+#localsave-items .localsave-text {
+	margin: 0 10px;
+}
+
+#localsave-items .localsave-item,
+#localsave-items .localsave-preview-wrap {
+	display: none;
+}
+
+#localsave-items {
+	margin-bottom: 15px;
+}
+
+#localsave-items .localsave-item {
+	margin-bottom: 6px;
+}
+
+#localsave-items .localsave-preview-wrap {
+	background-color: #eee;
+	border-bottom: 1px solid #dfdfdf;
+	border-top: 1px solid #dfdfdf;
+	margin: 10px -12px 10px -10px;
+}
+
+#localsave-items .localsave-preview {
+	padding: 10px;
+	margin: 15px 15px 10px;
+	height: auto;
+	min-height: 200px;
+	max-height: 500px;
+	overflow: auto;
+	background: #fff;
+	border: 1px solid #dfdfdf;
+	border-radius: 3px;
+}
+
+#localsave-items .localsave-preview > div {
+	padding: 0 10px;
+}
+
+#localsave-items .localsave-preview > textarea {
+	width: 100%;
+	max-width: 100%;
+	height: 250px;
+	border: 0 none;
+	box-shadow: none;
+}
+
+#localsave-items .localsave-preview-wrap > p {
+	padding: 0 15px;
+}
+
+#localsave-items .localsave-preview-wrap > p strong {
+	color: #c00;
+}
+
+#localsave-items .localsave-time {
+	font-size: 1.2em;
+}
+
 /*------------------------------------------------------------------------------
   11.3 - Featured Images
 ------------------------------------------------------------------------------*/
Index: wp-admin/edit-form-advanced.php
===================================================================
--- wp-admin/edit-form-advanced.php	(revision 23401)
+++ wp-admin/edit-form-advanced.php	(working copy)
@@ -159,7 +159,7 @@
 		add_meta_box('authordiv', __('Author'), 'post_author_meta_box', null, 'normal', 'core');
 }
 
-if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID && wp_get_post_revisions( $post_ID ) )
+if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID )
 	add_meta_box('revisionsdiv', __('Revisions'), 'post_revisions_meta_box', null, 'normal', 'core');
 
 do_action('add_meta_boxes', $post_type, $post);
Index: wp-admin/includes/meta-boxes.php
===================================================================
--- wp-admin/includes/meta-boxes.php	(revision 23401)
+++ wp-admin/includes/meta-boxes.php	(working copy)
@@ -603,7 +603,34 @@
  * @param object $post
  */
 function post_revisions_meta_box($post) {
-	wp_list_post_revisions();
+	if ( wp_get_post_revisions( $post->ID ) ) {
+		wp_list_post_revisions();
+	} else {
+		?>
+		<h4 class="revisions-title"><?php _e('Post revisions'); ?></h4>
+		<p class="no-revisions"><?php _e('(no revisions yet)'); ?></p>
+		<?php
+	}
+
+	?>
+	<h4 class="revisions-title"><?php _e('Local backups'); ?></h4>
+	<div id="localsave-items">
+		<p class="no-revisions localsave-no-revisions"><?php _e('(no backups yet)'); ?></p>
+
+		<div class="localsave-item localsave-item-main">
+			<a href="#" class="localsave-text"><?php _e('Saved %s hours ago'); ?></a>
+		</div>
+
+		<div class="localsave-preview-wrap">
+			<div class="localsave-preview"></div>
+			<p class="warning"><?php _e('<strong>Warning:</strong> restoring a backup will replace the current content in the editor.') ?></p>
+			<p class="localsave-preview-actions">
+				<a href="#" class="button localsave-do-close"><?php _e('Close'); ?></a>
+				<a href="#" class="alignright button button-primary localsave-do-restore"><?php _e('Restore'); ?></a>
+			</p>
+		</div>
+	</div>
+	<?php
 }
 
 // -- Page related Meta Boxes
@@ -979,4 +1006,4 @@
 function post_thumbnail_meta_box( $post ) {
 	$thumbnail_id = get_post_meta( $post->ID, '_thumbnail_id', true );
 	echo _wp_post_thumbnail_html( $thumbnail_id, $post->ID );
-}
\ No newline at end of file
+}
Index: wp-admin/js/common.js
===================================================================
--- wp-admin/js/common.js	(revision 23401)
+++ wp-admin/js/common.js	(working copy)
@@ -1,4 +1,6 @@
 var showNotice, adminMenu, columns, validateForm, screenMeta;
+window.wp = window.wp || {};
+
 (function($){
 // Removed in 3.3.
 // (perhaps) needed for back-compat
@@ -424,4 +426,470 @@
 	return true;
 });
 
-})(jQuery);
+// Autosave in localStorage
+// set as simple object/mixin for now
+wp.autosave = wp.autosave || {};
+
+// Returns only post ID, title, content and excerpt for local autosaves, the rest of the fields for remote
+wp.autosave.getPostData = function( local ) {
+	var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, cats = [],
+		data = {
+			autosave: true,
+			post_id: $('#post_ID').val() || 0
+		};
+
+	if ( ed && !ed.isHidden() ) {
+		// Don't run while the tinymce spellcheck is on. It resets all found words.
+		if ( ed.plugins.spellchecker && ed.plugins.spellchecker.active ) {
+			data.autosave = false;
+			return data;
+		} else {
+			if ( 'mce_fullscreen' == ed.id )
+				tinymce.get('content').setContent(ed.getContent({format : 'raw'}), {format : 'raw'});
+
+			tinymce.triggerSave();
+		}
+	}
+
+	if ( typeof fullscreen != 'undefined' && fullscreen.settings.visible ) {
+		data['post_title'] = $('#wp-fullscreen-title').val() || '';
+		data['content'] = $('#wp_mce_fullscreen').val() || '';
+	} else {
+		data['post_title'] = $('#title').val() || '';
+		data['content'] = $('#content').val() || '';
+	}
+
+	data['excerpt'] = $('#excerpt').val() || '';
+
+	if ( local )
+		return data;
+
+	$.extend( data, {
+		action: 'autosave',
+		autosavenonce: $('#autosavenonce').val() || '',
+		post_type: $('#post_type').val() || '',
+		post_author: $('#post_author').val() || ''
+	});
+
+	$('.tags-input').each( function() {
+		data[this.name] = this.value;
+	});
+
+	$('input[id^="in-category-"]:checked').each( function() {
+		cats.push(this.value);
+	});
+	data['catslist'] = cats.join(',');
+
+	if ( post_name = $('#post_name').val() )
+		data['post_name'] = post_name;
+
+	if ( parent_id = $('#parent_id').val() )
+		data['parent_id'] = parent_id;
+
+	if ( $('#comment_status').prop('checked') )
+		data['comment_status'] = 'open';
+
+	if ( $('#ping_status').prop('checked') )
+		data['ping_status'] = 'open';
+
+	if ( $('#auto_draft').val() == '1' )
+		data['auto_draft'] = '1';
+
+	return data;
+}
+
+// simple object/mixin for now
+wp.autosave.local = {
+
+	lastsaveddata: '',
+	unexpired: {},
+	blog_id: 0,
+	hasStorage: (function() {
+		var test = Math.random(), result;
+		// Check if the browser supports localStorage and it's not disabled
+		try {
+			localStorage.setItem('wp-test', test);
+			result = localStorage.getItem('wp-test') == test;
+			localStorage.removeItem('wp-test');
+			return result;
+		} catch(e) {
+			return false;
+		}
+    }()),
+
+	/**
+	 * Initialize the local storage
+	 * @return mixed simple object or false if no localStorage in the browser
+	 */
+	getStorage: function() {
+		var storage = false;
+		
+		// separate local storage containers for each blog_id
+		if ( this.hasStorage && this.blog_id ) {
+			storage = localStorage.getItem( 'wp_autosave_' + this.blog_id );
+
+			if ( storage )
+				storage = JSON.parse( storage );
+			else
+				storage = {};
+		}
+
+		return storage;
+	},
+
+	setStorage: function( storage_obj ) {
+		if ( this.hasStorage )
+			return localStorage.setItem( 'wp_autosave_' + this.blog_id, JSON.stringify( storage_obj ) );
+	},
+	
+	getData: function( post_id ) {
+		var storage = this.getStorage();
+
+		post_id = post_id || $('#post_ID').val();
+
+		if ( !storage || !post_id )
+			return false;
+
+		return storage[ 'post_' + post_id ] || [];
+	},
+
+	setData: function( stored_data ) {
+		var storage = this.getStorage(), post_id = $('#post_ID').val(), result;
+
+		if ( !storage || !post_id )
+			return false;
+
+		storage[ 'post_' + post_id ] = stored_data;
+		result = this.setStorage(storage);
+
+		// TODO do we need this?
+		/*
+		if ( result === false && stored_data.length > 1 ) {
+			// localStorage is full, pop the oldest revision and try again
+			while ( result === false && stored_data.length > 1 ) {
+				stored_data.pop();
+				storage[ 'post_' + post_id ] = stored_data;
+				result = this.setStorage(storage);
+			}
+		}
+		*/
+
+		if ( result === false ) {
+			// localStorage is still full, throw error?
+			return false;
+		}
+
+		return true;
+	},
+
+	/**
+	 * Set post data for particular post id
+	 */
+	save: function() {
+		var stored_data, post_data, result = false;
+
+		// Prepares data for saving in local storage.
+		post_data = wp.autosave.getPostData( true );
+
+		// If the content and title are empty or did not change since the last save, don't save again
+		if ( ( ! post_data.post_title && ! post_data.content ) || post_data.post_title + post_data.content + post_data.excerpt == this.lastsaveddata )
+			return false;
+
+		// cannot save at this moment
+		if ( !post_data.autosave )
+			return false;
+
+		$.extend( post_data, {
+			save_time: (new Date()).getTime(),
+			storage_status: 'fresh'
+		});
+
+		stored_data = this.getData();
+		
+		if ( stored_data ) {
+			stored_data.unshift( post_data );
+			
+			if ( stored_data.length > 5 ) {
+				// Store only the 5 newest revisions
+				stored_data.pop();
+			}
+console.log('saved at: '+post_data.save_time)			
+			result = this.setData( stored_data );
+			
+			if ( result ) {
+				this.lastsaveddata = post_data.post_title + post_data.content;
+				// Update the local revisions as they are added
+				this.showItems();
+			}
+		}
+
+		return result;
+	},
+
+	/**
+	 * Checks if all revisions have expired. Removes expired revisions from local storage after 24 hours.
+	 */
+	cleanup: function() { 
+		var self = this, storage = this.getStorage(), current_time = (new Date()).getTime(), deleted = false, has_unexpired = false; 
+
+		if ( !storage )
+			return;
+
+		$.each( storage, function( key, value ) {
+			var new_arr;
+
+			if ( !value )
+				return;
+
+			new_arr = $.grep( value, function( post_data ) {
+				if ( post_data.storage_status ) {
+					if ( !self.unexpired[key] )
+						self.unexpired[key] = post_data;
+
+					has_unexpired = true;
+					return true;
+				}
+				// keep if less than 24 hr
+				if ( ( current_time - post_data.save_time ) < 86400000 )
+					return true;
+
+				return false;
+			});
+
+			if ( new_arr.length != value.length )
+				deleted = true;
+
+			if ( new_arr.length )
+				storage[key] = new_arr;
+			else
+				delete storage[key];
+		});
+
+		if ( deleted )
+			this.setStorage( storage );
+
+		if ( has_unexpired ) {
+			// show warning about unexpired post data
+			this.showWarning();
+		}
+	},
+
+	/**
+	 * Marks post data as expired
+	 *
+	 * For use after remote autosave has completed
+	 */
+	expire: function() {
+		var stored_data = this.getData();
+
+		$.each( stored_data, function( key, post_data ) {
+			delete post_data.storage_status;
+		});
+
+		return this.setData( stored_data );
+	},
+
+	showItems: function() {
+		var self = this, data;
+
+		function formatTime( milisec ) {
+			var sec = parseInt( milisec / 1000, 10 ) || 0,
+				h = Math.floor( sec / 3600 ),
+				m = Math.floor( (sec % 3600) / 60 ),
+				s = sec - ( (h * 3600) + (m * 60) );
+
+			function zeroize(n) {
+				if ( !n )
+					return '00';
+
+				if ( n < 10 )
+					return '0' + n.toString();
+
+				return n.toString();
+			}
+
+			return {
+				h: zeroize(h),
+				m: zeroize(m),
+				s: zeroize(s)
+			};
+		}
+
+		if ( window.pagenow && window.pagenow == 'post' ) {
+			data = this.getData(), current_time = (new Date()).getTime();
+
+			if ( data && data.length ) {
+				$.each( data, function( key, post_data ) {
+					var timeSaved = formatTime( current_time - post_data.save_time ),
+						element = $('#localsave-items #localsave-item-' + key);
+console.log(element)
+					$('.localsave-no-revisions').remove();
+
+					// can do something here with post_data.storage_status to show non-expired
+					// (not saved to the server) backups with different color
+
+					if ( ! element.length ) {
+						element = $('.localsave-item-main').clone().removeClass('localsave-item-main').attr( 'id', 'localsave-item-' + key ).data('key', key);
+
+						$('.localsave-text', element).html( $('.localsave-text', element).text().replace( /%s/, function(){
+							return '<span class="localsave-h">' + timeSaved.h + '</span>:' +
+								'<span class="localsave-m">' + timeSaved.m + '</span>:' +
+								'<span class="localsave-s">' + timeSaved.s + '</span>';
+						} ) );
+
+						$('#localsave-items').append( element.data('key', key).show() );
+					} else {
+						element.data('key', key);
+						$('.localsave-h', element).text( timeSaved.h );
+						$('.localsave-m', element).text( timeSaved.m );
+						$('.localsave-s', element).text( timeSaved.s );
+					}
+				});
+			}
+		}
+	},
+
+	preview: function( key ) {
+		var data = this.getData(), content, element;
+
+		if ( !data[key] )
+			return; // error message?
+
+		content = data[key].content;
+
+		if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) {
+			content = '<div>' + switchEditors.wpautop( content ) + '</div>';
+		} else if ( $('#wp-content-wrap').hasClass('html-active') )
+			content = '<textarea readonly>' + this.esc_html( content ) + '</textarea>';
+
+		element = $('.localsave-preview-wrap').show();
+		element.find('div.localsave-preview').html( content );
+		element.find('a.localsave-do-restore').data('key', key);
+		$('#localsave-item-' + key).append( element );
+	},
+
+	closePreview: function() {
+		var element = $('.localsave-preview-wrap').css('display', '');
+
+		element.find('div.localsave-preview').empty();
+		element.find('a.localsave-do-restore').removeData('key');
+		$('#localsave-items').append( element );
+	},
+
+	restore: function( key ) {
+		var data = this.getData(), content, editor;
+
+		if ( !data[key] )
+			return; // error message?
+
+		content = data[key].content;
+
+		if ( typeof tinymce != 'undefined' )
+			editor = tinymce.get('content');
+
+		if ( typeof switchEditors != 'undefined' && editor && ! editor.isHidden() ) {
+			editor.setContent( switchEditors.wpautop( content ) );
+		} else if ( ( editor = $('textarea#content') ) && editor.length ) {
+			editor.val( content );
+		}
+
+		this.closePreview();
+	},
+
+	init: function() {
+		var self = this, post_data = wp.autosave.getPostData( true );
+
+		this.blog_id = typeof window.autosaveL10n != 'undefined' ? window.autosaveL10n.blog_id : 0;
+		
+		$('#localsave-items').on( 'click.localsave-items', function(e) {
+			var target = $(e.target);
+
+			if ( target.hasClass('localsave-text') ) {
+				self.preview( target.parent().data('key') );
+			} else if ( target.hasClass('localsave-do-close') ) {
+				self.closePreview();
+			} else if ( target.hasClass('localsave-do-restore') ) {
+				self.restore( target.data('key') );
+			}
+			// Stop all links, including links in the preview
+			e.preventDefault();
+		});
+		
+		// Set the comparison string
+		if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' )
+			this.lastsaveddata = post_data.post_title + switchEditors.pre_wpautop(post_data.content);
+		else
+			this.lastsaveddata = post_data.post_title + post_data.content;
+
+		// Set the schedule
+		this.schedule = $.schedule({
+			time: 15 * 1000,
+			func: function() { wp.autosave.local.save(); },
+			repeat: true,
+			protect: true
+		});
+		
+		$('form#post').on( 'submit.localsave-cancel', function() {
+        	$.cancel( self.schedule );
+		});
+		
+		// Show the local revisions
+		this.showItems();
+	},
+
+	/**
+	 * Escape html so we can show in div
+	 * @param string str
+	 * @return string
+	 */
+	esc_html: function( str ) {
+		return $('<div/>').text(str).html();
+	},
+
+	/**
+	 * Show warning that one has historical saved data available for recovery in case one wants.
+	 */
+	showWarning: function() {
+		var self = this, current_post_id = $('#post_ID').val() || '', html = '', same_screen = false;
+
+		$.each( this.unexpired, function( key, post_data ) {
+			var title = post_data.post_title || '#' + post_data.post_id;
+
+			if ( window.pagenow && window.pagenow == 'post' && current_post_id == post_data.post_id ) {
+				html += '<span class="localsave-recover"> <a class="localsave-recover-local" href="#revisionsdiv">' + self.esc_html(title) + '</a> </span> ';
+				same_screen = true;
+			} else {
+				html += '<span class="localsave-recover"> <a href="post.php?post='+post_data.post_id+'&action=edit&localsave-recover=1#revisionsdiv">' +
+					self.esc_html(title) + '</a> </span> ';
+			}
+		});
+
+		if ( html ) {
+			$('#wpbody .wrap h2:first').after(
+				'<div class="error" id="localsave-warning">' +
+				'<p><strong>Data saved in your browser</strong></p>' +
+				'<p>' + html + '</p>' +
+				'</div>'
+			);
+
+			if ( same_screen ) {
+				$('#localsave-warning a.localsave-recover-local').click( function(){
+					// Make sure the Revisions postbox is open and not hidden
+					$('#revisionsdiv').removeClass('closed').show();
+					// Hide the warning
+					$('#localsave-warning').slideUp('fast', function(){ $(this).remove(); });
+				});
+			}
+		}
+	}
+}
+
+$(document).ready( function() {
+	wp.autosave.local.cleanup();
+	// run on post.php and post-new.php
+	if ( 'post' == window.pagenow )
+		wp.autosave.local.init();
+});
+
+}(jQuery));
+
Index: wp-includes/js/autosave.js
===================================================================
--- wp-includes/js/autosave.js	(revision 23401)
+++ wp-includes/js/autosave.js	(working copy)
@@ -177,6 +177,10 @@
 
 // called when autosaving pre-existing post
 function autosave_saved(response) {
+
+	if ( window.wp && window.wp.autosave )
+		window.wp.autosave.local.expire();
+
 	blockSave = false;
 	autosave_parse_response(response); // parse the ajax response
 	autosave_enable_buttons(); // re-enable disabled form buttons
@@ -186,6 +190,10 @@
 function autosave_saved_new(response) {
 	blockSave = false;
 	var res = autosave_parse_response(response), postID;
+
+	if ( window.wp && window.wp.autosave )
+		window.wp.autosave.local.expire();
+
 	if ( res && res.responses.length && !res.errors ) {
 		// An ID is sent only for real auto-saves, not for autosave=0 "keepalive" saves
 		postID = parseInt( res.responses[0].id, 10 );
Index: wp-includes/post-template.php
===================================================================
--- wp-includes/post-template.php	(revision 23401)
+++ wp-includes/post-template.php	(working copy)
@@ -1455,6 +1455,7 @@
 
 <?php
 	else :
+		echo '<h4 class="revisions-title">' . __('Post revisions') . "</h4>\n";
 		echo "<ul class='post-revisions'>\n";
 		echo $rows;
 		echo "</ul>";
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 23401)
+++ wp-includes/script-loader.php	(working copy)
@@ -582,7 +582,8 @@
 	wp_localize_script( 'autosave', 'autosaveL10n', array(
 		'autosaveInterval' => AUTOSAVE_INTERVAL,
 		'savingText' => __('Saving Draft&#8230;'),
-		'saveAlert' => __('The changes you made will be lost if you navigate away from this page.')
+		'saveAlert' => __('The changes you made will be lost if you navigate away from this page.'),
+		'blog_id' => get_current_blog_id()
 	) );
 
 }
