diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css
index 8a5990e..a565f45 100644
--- a/src/wp-includes/css/media-views.css
+++ b/src/wp-includes/css/media-views.css
@@ -228,7 +228,6 @@
 .media-toolbar-secondary > .media-button,
 .media-toolbar-secondary > .media-button-group {
 	margin-right: 10px;
-	float: left;
 	margin-top: 15px;
 }
 
@@ -996,6 +995,27 @@
 	bottom: 0;
 	overflow: auto;
 	outline: none;
+	-webkit-transition: 1s ease-in-out;
+    -moz-transition: 1s ease-in-out;
+    -o-transition: 1s ease-in-out;
+    transition: 1s ease-in-out;
+}
+
+.attachments-browser .uploader-inline:not(.hidden) + .attachments {
+	-webkit-transform: translateY( 300px );
+	-ms-transform: translateY( 300px );
+	transform: translateY( 300px );
+}
+
+.attachments-browser .uploader-inline.hidden {
+	display: block;
+	-webkit-transform: translateY( -100% );
+	-ms-transform: translateY( -100% );
+	transform: translateY( -100% );
+}
+
+.attachments-browser .uploader-inline-content {
+	top: 0;
 }
 
 .inline-toolbar {
@@ -1081,7 +1101,8 @@ video#inline-media-node {
 	left: 0;
 }
 
-.attachments-browser.hide-sidebar .attachments {
+.attachments-browser.hide-sidebar .attachments,
+.attachments-browser.hide-sidebar .uploader-inline {
 	right: 0;
 	margin-right: 0;
 }
@@ -2657,6 +2678,11 @@ video#inline-media-node {
 	left: 0;
 }
 
+.edit-attachment-frame .media-frame-content {
+	border-bottom: none;
+	bottom: 0;
+}
+
 /* Hiding this for the moment instead of removing it from the template. */
 .edit-attachment-frame h3 {
 	display: none;
diff --git a/src/wp-includes/js/media-grid.js b/src/wp-includes/js/media-grid.js
index 0ebbc67..a2814ae 100644
--- a/src/wp-includes/js/media-grid.js
+++ b/src/wp-includes/js/media-grid.js
@@ -25,7 +25,6 @@
 			menu:    false,
 			router:  'edit-metadata',
 			content: 'edit-metadata',
-			toolbar: 'toolbar',
 
 			url:     ''
 		},
@@ -34,10 +33,6 @@
 			media.controller._State.prototype.initialize.apply( this, arguments );
 		},
 
-		activate: function() {
-			this.listenTo( this.frame, 'toolbar:render:edit-image', this.toolbar );
-		},
-
 		_postActivate: function() {
 			this._content();
 			this._router();
@@ -47,30 +42,6 @@
 			this.stopListening( this.frame );
 		},
 
-		toolbar: function() {
-			var frame = this.frame,
-				lastState = frame.lastState(),
-				previous = lastState && lastState.id;
-
-			frame.toolbar.set( new media.view.Toolbar({
-				controller: frame,
-				items: {
-					back: {
-						style: 'primary',
-						text:     l10n.back,
-						priority: 20,
-						click:    function() {
-							if ( previous ) {
-								frame.setState( previous );
-							} else {
-								frame.close();
-							}
-						}
-					}
-				}
-			}) );
-		},
-
 		/**
 		 * @access private
 		 */
@@ -125,12 +96,13 @@
 				modal:     false,
 				selection: [],
 				library:   {},
-				multiple:  false,
+				multiple:  'add',
 				state:     'library',
 				uploader:  true,
 				mode:      [ 'grid', 'edit' ]
 			});
 
+			$(document).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) );
 			// Ensure core and media grid view UI is enabled.
 			this.$el.addClass('wp-core-ui media-grid-view');
 
@@ -192,18 +164,26 @@
 				return;
 			}
 
+			var libraryState = new media.controller.Library({
+				library:    media.query( options.library ),
+				multiple:   options.multiple,
+				title:      options.title,
+				priority:   20,
+				toolbar:    false,
+				router:     false,
+				content:    'browse',
+				filterable: 'mime-types'
+			});
+
+			libraryState._renderTitle = function( view ) {
+				var text = this.get('title') || '';
+				view.$el.addClass( 'wrap' );
+				text += '<a class="add-new-h2">Add New</a>';
+				view.$el.html( text );
+			};
 			// Add the default states.
 			this.states.add([
-				new media.controller.Library({
-					library:    media.query( options.library ),
-					multiple:   options.multiple,
-					title:      options.title,
-					priority:   20,
-					toolbar:    false,
-					router:     false,
-					content:    'browse',
-					filterable: 'mime-types'
-				})
+				libraryState
 			]);
 		},
 
@@ -217,6 +197,10 @@
 			this.on( 'edit:attachment:previous', this.editPreviousAttachment, this );
 		},
 
+		addNewClickHandler: function() {
+			this.trigger( 'show:upload:attachment' );
+		},
+
 		editPreviousAttachment: function( currentModel ) {
 			var library = this.state().get('library'),
 				currentModelIndex = library.indexOf( currentModel );
@@ -233,26 +217,17 @@
 		 * Open the Edit Attachment modal.
 		 */
 		editAttachment: function( model ) {
-			var library = this.state().get('library'), hasPrevious, hasNext;
-			if ( library.indexOf( model ) > 0 ) {
-				hasPrevious = true;
-			}
-			else {
-				hasPrevious = false;
-			}
-			if ( library.indexOf( model ) < library.length - 1 ) {
-				hasNext = true;
-			}
-			else {
-				hasNext = false;
-			}
+			var library = this.state().get('library');
 
-			new media.view.Frame.EditAttachment({
-				hasPrevious:    hasPrevious,
-				hasNext:        hasNext,
-				model:          model,
-				gridController: this
+			// Create a new EditAttachment frame, passing along the library and the attachment model.
+			this.editAttachmentFrame = new media.view.Frame.EditAttachment({
+				library:        library,
+				model:          model
 			});
+
+			// Listen to events on the edit attachment frame for triggering pagination callback handlers.
+			this.listenTo( this.editAttachmentFrame, 'edit:attachment:next', this.editNextAttachment );
+			this.listenTo( this.editAttachmentFrame, 'edit:attachment:previous', this.editPreviousAttachment );
 		},
 
 		/**
@@ -363,6 +338,9 @@
 				this.on( 'router:render', this.browseRouter, this );
 			}
 
+			this.options.hasPrevious = ( this.options.library.indexOf( this.options.model ) > 0 ) ? true : false;
+			this.options.hasNext = ( this.options.library.indexOf( this.options.model ) < this.options.library.length - 1 ) ? true : false;
+
 			// Initialize modal container view.
 			if ( this.options.modal ) {
 				this.modal = new media.view.Modal({
@@ -471,7 +449,7 @@
 			if ( ! this.options.hasPrevious )
 				return;
 			this.modal.close();
-			this.options.gridController.trigger( 'edit:attachment:previous', this.model );
+			this.trigger( 'edit:attachment:previous', this.model );
 		},
 
 		/**
@@ -481,9 +459,8 @@
 			if ( ! this.options.hasNext )
 				return;
 			this.modal.close();
-			this.options.gridController.trigger( 'edit:attachment:next', this.model );
+			this.trigger( 'edit:attachment:next', this.model );
 		}
-
 	});
 
 	media.view.GridFieldOptions = media.View.extend({
@@ -514,4 +491,58 @@
 		}
 	});
 
+	media.view.BulkSelectionToggleButton = media.view.Button.extend({
+		initialize: function() {
+			media.view.Button.prototype.initialize.apply( this, arguments );
+			this.listenTo( this.controller, 'bulk-edit:activate bulk-edit:deactivate', _.bind( this.toggleBulkEditHandler, this ) );
+		},
+
+		click: function() {
+			var bulkEditActive = this.controller.activeModes.where( { id: 'bulk-edit' } ).length;
+			media.view.Button.prototype.click.apply( this, arguments );
+
+			if ( bulkEditActive ) {
+				this.controller.deactivateMode( 'bulk-edit' );
+				this.controller.activateMode( 'edit' );
+			} else {
+				this.controller.deactivateMode( 'edit' );
+				this.controller.activateMode( 'bulk-edit' );
+			}
+		},
+
+		toggleBulkEditHandler: function() {
+			var bulkEditActive = this.controller.activeModes.where( { id: 'bulk-edit' } ).length;
+			if ( bulkEditActive ) {
+				this.$el.addClass( 'button-primary' );
+			} else {
+				this.$el.removeClass( 'button-primary' );
+				this.controller.state().get('selection').reset();
+			}
+		}
+	});
+
+	media.view.BulkDeleteButton = media.view.Button.extend({
+		initialize: function() {
+			media.view.Button.prototype.initialize.apply( this, arguments );
+			this.$el.hide();
+			this.listenTo( this.controller, 'bulk-edit:activate bulk-edit:deactivate', _.bind( this.visibility, this ) );
+		},
+
+		click: function() {
+			media.view.Button.prototype.click.apply( this, arguments );
+			while (this.controller.state().get('selection').length > 0) {
+				this.controller.state().get('selection').at(0).destroy();
+			}
+		},
+
+		visibility: function() {
+			var bulkEditActive = this.controller.activeModes.where( { id: 'bulk-edit' } ).length;
+			if ( bulkEditActive ) {
+				this.$el.show();
+			} else {
+				this.$el.hide();
+			}
+		}
+	});
+
 }(jQuery, _, Backbone, wp));
\ No newline at end of file
diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js
index 6bf147c..328f59a 100644
--- a/src/wp-includes/js/media-views.js
+++ b/src/wp-includes/js/media-views.js
@@ -665,7 +665,7 @@
 			}
 
 			if ( ! this.get('edge') ) {
-				this.set( 'edge', 120 );
+				this.set( 'edge', 150 );
 			}
 
 			if ( ! this.get('gutter') ) {
@@ -1785,14 +1785,13 @@
 		 * @global wp.Uploader
 		 */
 		initialize: function() {
-
 			media.view.Frame.prototype.initialize.apply( this, arguments );
 
 			_.defaults( this.options, {
 				title:    '',
 				modal:    true,
 				uploader: true,
-				mode:     ['select']
+				mode:     [ 'select' ]
 			});
 
 			// Ensure core UI is enabled.
@@ -1808,6 +1807,14 @@
 				this.modal.content( this );
 			}
 
+			// Store active "modes" that the frame is in. Unrelated to region modes.
+			this.activeModes = new Backbone.Collection();
+			this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
+
+			_.each( this.options.mode, function( mode ) {
+				this.activeModes.add( new Backbone.Model( { id: mode } ) );
+			}, this );
+
 			// Force the uploader off if the upload limit has been exceeded or
 			// if the browser isn't supported.
 			if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
@@ -1972,6 +1979,42 @@
 
 			window.tb_remove = this._tb_remove;
 			delete this._tb_remove;
+		},
+
+		/**
+		 * Map activeMode collection events to the frame.
+		 */
+		triggerModeEvents: function( model, collection, options ) {
+			var collectionEvent,
+				modeEventMap = {
+					add: 'activate',
+					remove: 'deactivate'
+				},
+				eventToTrigger;
+			// Probably a better way to do this.
+			_.each( options, function( value, key ) {
+				if ( value ) {
+					collectionEvent = key;
+				}
+			} );
+
+			if ( ! _.has( modeEventMap, collectionEvent ) )
+				return;
+
+			eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
+			this.trigger( eventToTrigger );
+		},
+		activateMode: function( mode ) {
+			this.activeModes.add( [ { id: mode } ] );
+			this.trigger( mode + ':activate' );
+		},
+		deactivateMode: function( mode ) {
+			// Bail if the mode isn't active.
+			if ( ! this.activeModes.where( { id: mode } ).length ) {
+				return;
+			}
+			this.activeModes.remove( this.activeModes.where( { id: mode } ) );
+			this.trigger( mode + ':deactivate' );
 		}
 	});
 
@@ -4673,7 +4716,7 @@
 			}
 
 			// In the grid view, bubble up an edit:attachment event to the controller.
-			if ( _.contains( this.controller.options.mode, 'grid' ) ) {
+			if ( this.controller.activeModes.where( { id: 'edit' } ).length ) {
 				this.controller.trigger( 'edit:attachment', this.model );
 				return;
 			}
@@ -5081,7 +5124,10 @@
 			if ( this.options.resize ) {
 				$(window).on( 'resize.attachments', this._resizeCss );
 			}
-			this.css();
+
+			// Call this.css() after this view has been rendered in the DOM so
+			// attachments get proper width applied.
+			_.defer( this.css, this );
 		},
 
 		dispose: function() {
@@ -5531,7 +5577,10 @@
 				AttachmentView: media.view.Attachment.Library
 			});
 
+			this.listenTo( this.controller, 'show:upload:attachment', _.bind( this.showUploader, this ) );
 			this.createToolbar();
+			this.createUploader();
+			this.createAttachments();
 			this.updateContent();
 			if ( this.options.sidebar ) {
 				this.createSidebar();
@@ -5568,7 +5617,7 @@
 			// Feels odd to bring the global media library switcher into the Attachment
 			// browser view. Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
 			// which the controller can tap into and add this view?
-			if ( _.contains( this.controller.options.mode, 'grid' ) ) {
+			if ( this.controller.activeModes.where( { id: 'grid' } ).length ) {
 				LibraryViewSwitcher = media.View.extend({
 					className: 'view-switch media-grid-view-switch',
 					template: media.template( 'media-library-view-switcher')
@@ -5578,6 +5627,18 @@
 					priority: -90
 				}).render() );
 
+				this.toolbar.set( 'bulkSelectionToggleButton', new media.view.BulkSelectionToggleButton({
+					text: 'Bulk Edit',
+					controller: this.controller,
+					priority: -70
+				}).render() );
+
+				this.toolbar.set( 'BulkDeleteButton', new media.view.BulkDeleteButton({
+					text: 'Bulk Delete',
+					controller: this.controller,
+					priority: -69
+				}).render() );
+
 				this.toolbar.set( 'gridFieldOptions', new media.view.GridFieldOptions({
 					controller: this.controller,
 					priority: -50
@@ -5635,48 +5696,38 @@
 
 		updateContent: function() {
 			var view = this;
-
-			if( ! this.attachments ) {
-				this.createAttachments();
-			}
-
 			if ( ! this.collection.length ) {
 				this.toolbar.get( 'spinner' ).show();
 				this.collection.more().done(function() {
 					if ( ! view.collection.length ) {
-						view.createUploader();
+						view.attachmentsNoResults.$el.removeClass( 'hidden' );
+					} else {
+						view.attachmentsNoResults.$el.addClass( 'hidden' );
 					}
 					view.toolbar.get( 'spinner' ).hide();
 				});
 			} else {
+				this.attachmentsNoResults.$el.addClass( 'hidden' );
 				view.toolbar.get( 'spinner' ).hide();
 			}
 		},
 
-		removeContent: function() {
-			_.each(['attachments','uploader'], function( key ) {
-				if ( this[ key ] ) {
-					this[ key ].remove();
-					delete this[ key ];
-				}
-			}, this );
-		},
-
 		createUploader: function() {
-			this.removeContent();
-
 			this.uploader = new media.view.UploaderInline({
 				controller: this.controller,
 				status:     false,
 				message:    l10n.noItemsFound
 			});
 
+			this.uploader.$el.addClass( 'hidden' );
 			this.views.add( this.uploader );
 		},
 
-		createAttachments: function() {
-			this.removeContent();
+		showUploader: function() {
+			this.uploader.$el.removeClass( 'hidden' );
+		},
 
+		createAttachments: function() {
 			this.attachments = new media.view.Attachments({
 				controller:           this.controller,
 				collection:           this.collection,
@@ -5690,6 +5741,17 @@
 			});
 
 			this.views.add( this.attachments );
+
+			this.attachmentsNoResults = new media.View({
+				controller: this.controller
+			});
+
+			this.attachmentsNoResults.$el.addClass( 'hidden' );
+			this.attachmentsNoResults.$el.html( 'No media found.' );
+
+			this.views.add( this.attachmentsNoResults );
+
+
 		},
 
 		createSidebar: function() {
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php
index 098a03a..8a72e1b 100644
--- a/src/wp-includes/media-template.php
+++ b/src/wp-includes/media-template.php
@@ -276,7 +276,6 @@ function wp_print_media_templates() {
 		</div>
 		<div class="media-frame-router"></div>
 		<div class="media-frame-content"></div>
-		<div class="media-frame-toolbar"></div>
 	</script>
 
 	<script type="text/html" id="tmpl-attachment-details-two-column">
