diff --git a/browser/library.inc b/browser/library.inc
new file mode 100644
index 0000000..16422f8
--- /dev/null
+++ b/browser/library.inc
@@ -0,0 +1,13 @@
+<?php
+
+$plugin = array(
+  'title' => t('Library'),
+  'callback' => array(
+    'file' => 'media.pages.inc',
+    'path' => drupal_get_path('module', 'media') . '/includes',
+    'function' => 'media_library_form',
+  ),
+  'weight' => 10000,
+  // @TODO: Add an access callback?
+
+);
diff --git a/browser/upload.inc b/browser/upload.inc
new file mode 100644
index 0000000..3a05af5
--- /dev/null
+++ b/browser/upload.inc
@@ -0,0 +1,32 @@
+<?php
+
+$plugin = array(
+  'title' => t('Upload'),
+  'weight' => -10,
+  'callback' => array(
+    'file' => 'media.pages.inc',
+    'path' => drupal_get_path('module', 'media') . '/includes',
+    'function' => 'media_get_upload_form',
+  ),
+  'access callback' => 'media_upload_access',
+);
+
+/**
+ * Access callback for uploading media.
+ */
+function media_upload_access() {
+  return user_access('administer media') || user_access('edit media');
+}
+
+/**
+ * Form builder; returns the correct upload form.
+ */
+function media_get_upload_form($form, &$form_state) {
+  $params = $form_state['params'];
+  if (!isset($params['singleselect']) && module_exists('plupload')) {
+    return media_add_upload_multiple($form, $form_state);
+  }
+  else {
+    return media_add_upload($form, $form_state);
+  }
+}
diff --git a/css/media.css b/css/media.css
index 639354a..ca97201 100644
--- a/css/media.css
+++ b/css/media.css
@@ -8,73 +8,44 @@
 
 /* @group media item list */
 
-.item-list .media-display-switch {
+#media-display-switches {
   float: right;
-  line-height: 0;
+  margin-bottom: 10px;
 }
-.item-list .media-display-switch li {
-  float: left;
-  list-style: none;
-  margin-left: -1px;
-}
-.item-list .media-display-switch li a {
-  background: #f2f1f1;
+#media-display-switches .form-media-display {
+  background-color: #f2f1f1;
+  background-position: center center;
+  background-repeat: no-repeat;
   border: 1px solid;
   border-color: #e4e4e4 #d2d2d2 #b4b4b4 #d3d3d3;
   display: block;
-  padding: 7px 9px;
+  float: left;
+  text-indent: -2000px;
+  padding: 4px 15px;
 }
-.item-list .media-display-switch li.first a {
+#media-display-switches .form-media-display:first-child {
   -moz-border-radius-topleft: 4px;
   -moz-border-radius-bottomleft: 4px;
   -webkit-border-top-left-radius: 4px;
   -webkit-border-bottom-left-radius: 4px;
 }
-.item-list .media-display-switch li.last a {
+#media-display-switches .form-media-display:last-child {
   -moz-border-radius-topright: 4px;
   -moz-border-radius-bottomright: 4px;
   -webkit-border-top-right-radius: 4px;
   -webkit-border-bottom-right-radius: 4px;
 }
-.item-list .media-display-switch li a.active {
+#media-display-switches .form-media-display.active {
   position: relative;
-  background: #666;
+  background-color: #666;
   border: 1px solid #555;
   color: #fff;
 }
 
-/* Set the height to auto */
-#media_content_browser .media-thumbnail {
-  height: auto;
-  width: 120px;
-}
-
-
-/* Push content under the tabs */
-#media_content_browser_tabs {
-  margin-bottom: 30px;
-}
-
-/* This is some stuff to just get some basic mockup done on the
-   content navigator. Should be removed/revised soon */
-
-.result_limit {
-  float: right;
-}
-.result_limit li {
-   display: inline;
-   list-style: none;
-}
-
-.item-list .media_content_navigator li {
-  display: inline;
-  list-style: none;
-}
-
 /** This is a massive hack. There must be a better way. See media.fields.inc **/
 
 .media-widget .fid {
-  display:none;
+  display: none;
 }
 
 .media-widget a.button + a.button {
@@ -84,195 +55,6 @@
 
 /* @end */
 
-/* @group media item */
-
-.media-item {
-  background: #FFF;
-  border: 1px solid #CCCCCC;
-  margin: 10px;
-  padding: 6px 6px 2px;
-  width: 100px;
-}
-
-.media-item.selected {
-  background: #F4ECC7;
-}
-
-.media-item a {
-  display: block;
-}
-
-.media-item img {
-  border: 2px solid transparent;
-  display: inline-block;
-  margin-left: -2px;
-  height: auto;
-  width: 100%;
-}
-
-.media-item img:hover {
-  border-color: #058AC5;
-}
-
-
-.media-item-icons img{
-  height:25px;
-  width:25px;
-  float:left;
-}
-
-.media-item .label-wrapper {
-  overflow: hidden;
-  margin-left: 14px;
-}
-
-.media-item .label-wrapper:hover {
-  border-bottom: 2px solid #CCC;
-  border-right: 2px solid #CCC;
-  display: inline-block;
-  line-height: 16px;
-  margin-bottom: -1px;
-  overflow: visible;
-  position: relative;
-  z-index: 10;
-}
-
-.preview .media-item .label-wrapper {
-  margin-left: 0;
-}
-
-.preview {
-  display: inline-block;
-  vertical-align: middle;
-}
-
-
-.media-item .media-filename {
-  background: #FFF;
-  color: #058AC5;
-  font-size: 10px;
-  padding: 0 3px;
-  white-space: nowrap;
-}
-
-.media-item .label-wrapper:hover .media-filename {
-  border: 1px solid #888;
-  display: inline-block;
-  margin: 0 0 -2px -1px;
-}
-
-.media-item.selected .media-filename {
-  background: #F4ECC7;
-}
-
-.media-item .media-filename:hover {
-  text-decoration: underline;
-}
-
-.media-modal-frame {
-  overflow: hidden;
-}
-
-.media-display-thumbnails .media-list-thumbnails {
-  margin: 0 -10px;
-}
-
-.media-list-thumbnails > li {
-  float: left;
-  list-style: none;
-}
-
-.media-list-thumbnails .form-type-checkbox {
-  margin: -35px 0 0 16px;
-  position:  absolute;
-}
-
-.media-item .media-type-icon {
-  border: none;
-  margin: 0 0 -5px;
-  width: auto;
-}
-
-.ui-dialog.media-wrapper .ui-dialog-buttonpane {
-  display: none;
-}
-
-.ui-widget.ui-widget-content.media-wrapper {
-  background: none;
-  border: none;
-}
-
-/* @end */
-
-/* @group media browser */
-
-body.page-media-browser {
-  background: none;
-  overflow: hidden;
-}
-
-div#media-browser-tabs {
-  -moz-border-radius: 0;
-  -webkit-border-radius: 0;
-  border-radius: 0;
-  border: 0;
-}
-
-/* show the throbber on the page */
-div#media-browser .throbber {
-  height:100%;
-  width:100%;
-  position:absolute;
-  background: transparent url('images/loading.gif') no-repeat center center;
-}
-
-#media-browser .ui-tabs-panel {
-  /**
-   * This sucks, I don't want to hardcode this, but don't know how else
-   * to keep the scrollbar INSIDE the iframe.
-   */
-  height: 410px;
-  overflow-y: auto;
-}
-
-#media-tab-media_internet .media-provider img {
-  vertical-align: middle;
-  margin-right: 1em;
-}
-
-#media-browser-library-list .label-wrapper {
-  margin-left: 0;
-}
-
-#mediaBrowser body {
-  background: none;
-}
-
-#media-browser-tabset {
-  background: #FFF;
-}
-
-#media-browser-tabset .media-browser-tab {
-  border: 1px solid #aaa;
-}
-
-#media-browser-tabset .ui-tabs-nav {
-  border-left: 1px solid #aaa;
-  border-right: 1px solid #aaa;
-  border-top: 1px solid #aaa;
-}
-
-.fake-ok {
-  margin-right: 5px;
-}
-
-a.button {
-  display: inline-block;
-  line-height: 21px;
-}
-
-/* @end media browser */
-
 /* @group media edit page */
 
 .no-overflow {
@@ -315,58 +97,59 @@ a.button {
   margin:30px;
 }
 
-#media-admin #edit-options {
+.media-clear {
   clear: both;
-  margin: 0;
 }
 
-.media-clear {
-  clear: both;
+.form-item-format label {
+  display: inline;
 }
 
-.media-thumbnails-select {
-  float: left;
+.media-multiedit-form .media-edit-form {
+   border-bottom: 1px solid #aaa;
+   margin-bottom:1em;
+   margin-top:1.5em;
 }
 
-#edit-options .form-item-format label {
-  display: inline;
+#media-add-upload-multiple .plupload_start {
+  display:none;
 }
 
-#media-format-form .media-item {
-  float: left;
-  margin-left: 0;
-  margin-top: 0;
+a.button {
+  display: inline-block;
+  margin: 10px 5px 0 0;
 }
 
-#media-format-form .label-wrapper {
-  margin-left: 0;
+/* @end media format form */
+
+/* @group Media browser */
+
+.ui-dialog.media-browser-dialog {
+  padding: 0;
+  border: 0;
 }
 
-.media-multiedit-form .media-edit-form {
-   border-bottom: 1px solid #aaa;
-   margin-bottom:1em;
-   margin-top:1.5em;
+#media-browser-wrapper,
+#media-browser-tabset {
+  padding: 0;
 }
 
-body.page-media-format-form {
-  background: none;
+.media-provider {
+  margin-bottom: 0.5em;
 }
 
-#media-browser-page {
-  background: #FFF;
-  padding: 1px 0;
-  -moz-border-radius: 4px;
-  -webkit-border-radius: 4px;
-  border-radius: 4px;
+#media-browser-wrapper .progress-disabled {
+  float: none;
 }
 
-#media-browser-page .plupload_start {
-  display:none;
+#media-browser-wrapper .ajax-progress {
+  position: absolute;
+  right: 1.5em;
+  bottom: 2em;
 }
 
-a.button {
-  display: inline-block;
-  margin: 10px 5px 0 0;
+#media-browser-wrapper .ajax-progress .message {
+  float: left;
 }
 
-/* @end media format form */
\ No newline at end of file
+/* @end Media browser */
diff --git a/css/media.thumbnails.css b/css/media.thumbnails.css
new file mode 100644
index 0000000..ee43cec
--- /dev/null
+++ b/css/media.thumbnails.css
@@ -0,0 +1,174 @@
+@media all {
+  .media-item-wrapper {
+    width: 100%;
+  }
+}
+
+@media all and (min-width: 301px)  {
+  .media-item-wrapper {
+    width: 50%;
+  }
+}
+
+@media all and (min-width: 451px)  {
+  .media-item-wrapper {
+    width: 25%;
+  }
+}
+
+@media all and (min-width: 800px)  {
+  .media-item-wrapper {
+    width: 16%;
+  }
+}
+
+@media all and (min-width: 1200px)  {
+  .media-item-wrapper {
+    width: 12.5%;
+  }
+}
+
+@media all and (min-width: 1600px)  {
+  .media-item-wrapper {
+    width: 8.3%;
+  }
+}
+
+@media all and (min-width: 2400px)  {
+  .media-item-wrapper {
+    width: 6.25%;
+  }
+}
+
+.media-display-thumbnails .media-item {
+  background: #FFF;
+  border: 1px solid #CCCCCC;
+  padding: 6px 6px 2px;
+  margin: 10px;
+}
+
+.media-item.selected {
+  background: #F4ECC7;
+}
+
+.media-display-thumbnails .media-item img {
+  border: 2px solid transparent;
+  display: inline-block;
+  margin-left: -2px;
+  height: auto;
+  width: 100%;
+}
+
+.media-item img:hover {
+  border-color: #058AC5;
+}
+
+.media-item .label-wrapper {
+  overflow: hidden;
+}
+
+.media-item .label-wrapper:hover {
+  overflow: visible;
+}
+
+.media-item .media-filename {
+  background: #fff;
+  display: inline-block;
+  margin: -4px 0 -4px 11px;
+  padding: 4px 8px;
+  position: relative;
+  text-decoration: underline;
+  white-space: nowrap;
+}
+
+.media-item.selected .media-filename {
+  background: #F4ECC7;
+}
+
+.media-item .media-filename:hover {
+  border: 1px solid #ccc;
+  margin: -5px 0 -5px 10px;
+  z-index: 1;
+}
+
+.media-display-thumbnails .media-list-thumbnails {
+  margin: 0 -10px;
+}
+
+.media-list-thumbnails > .media-item-wrapper {
+  float: left;
+  list-style: none;
+  position: relative;
+}
+
+.media-list-thumbnails .form-type-checkbox {
+  bottom: 14px;
+  left: 16px;
+  margin: 0;
+  position:  absolute;
+}
+
+.media-item .media-type-icon {
+  border: none;
+  margin: 0 0 -5px;
+  width: auto;
+}
+
+.ui-dialog.media-wrapper .ui-dialog-buttonpane {
+  display: none;
+}
+
+.ui-widget.ui-widget-content.media-wrapper {
+  background: none;
+  border: none;
+}
+
+.media-thumbnails-select {
+  display: none;
+}
+
+html.js .media-thumbnails-select {
+  display: block;
+  float: left;
+  margin-top: 11px;
+}
+
+html.js .media-thumbnails-select ul {
+  padding: 0;
+  margin: 0 0 0 5px;
+  display: inline;
+}
+
+.media-thumbnails-select li {
+  padding: 0;
+  display: inline;
+}
+
+#select-box {
+  position: absolute;
+  border: 1px solid blue;
+  z-index: 10000;
+}
+
+#media-browser.unselectable {
+   -moz-user-select: -moz-none;
+   -khtml-user-select: none;
+   -webkit-user-select: none;
+   -o-user-select: none;
+   user-select: none;
+}
+
+.format-form .media-item {
+  float: left;
+  margin-left: 0;
+  margin-top: 0;
+  width: 100px;
+}
+
+.format-form .label-wrapper label {
+  margin-left: -8px;
+}
+
+.format-form .label-wrapper label:hover {
+  margin-left: -9px;
+}
diff --git a/includes/media.admin.inc b/includes/media.admin.inc
index b533089..b37deab 100644
--- a/includes/media.admin.inc
+++ b/includes/media.admin.inc
@@ -15,8 +15,6 @@ require_once dirname(__FILE__) . '/media.pages.inc';
  * Display the list or thumbnails media admin display.
  */
 function media_admin($form, $form_state) {
-  global $user;
-
   $path = drupal_get_path('module', 'media');
 
   $form['#attached'] = array(
@@ -29,37 +27,6 @@ function media_admin($form, $form_state) {
     return media_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['files']), 'admin/content/media', 'admin/content/media');
   }
 
-  require_once dirname(__FILE__) . '/media.browser.inc';
-  media_attach_browser_js($form);
-
-  $types = media_display_types();
-
-  if (arg(3)) {
-    $display = arg(3);
-    if (!in_array($display, array_keys($types))) {
-      exit(drupal_not_found());
-    }
-    // Save their preference.
-    db_merge('media_list_type')
-      ->key(array('uid' => $user->uid))
-      ->fields(array(
-          'type' => $display,
-      ))
-      ->execute();
-  }
-  else {
-    $display = db_query("SELECT type FROM {media_list_type} WHERE uid = :uid", array(':uid' => $user->uid))->fetch();
-    if (!$display) {
-      $display = 'list';
-    }
-    else {
-      $display = $display->type;
-    }
-  }
-
-  // Build the display switch.
-  $form['switch'] = media_admin_display_switch(array('active display' => $display));
-
   // Build the 'Media operations' form.
   $form['options'] = array(
     '#type' => 'fieldset',
@@ -84,155 +51,27 @@ function media_admin($form, $form_state) {
     '#validate' => array('media_admin_validate'),
   );
 
-  include_once $types[$display]['file'];
-
-  $form['admin'] = $types[$display]['callback']();
-
-  return $form;
-}
-
-
-/**
- * Form builder: Builds the media list administration overview.
- */
-function media_admin_list() {
-  // @todo Change to media_variable_get('admin_pager_limit') for consistency
-  //   with browser_pager_limit?
-  $limit = variable_get('media_admin_limit', 50);
-
-  // Build the sortable table header.
-  $header = array(
-    'title' => array('data' => t('Title'), 'field' => 'f.filename'),
-    'type' => array('data' => t('Type'), 'field' => 'f.filemime'),
-    'size' => array('data' => t('Size'), 'field' => 'f.filesize'),
-    'author' => array('data' => t('Author'), 'field' => 'u.name'),
-    'timestamp' => array('data' => t('Updated'), 'field' => 'f.timestamp', 'sort' => 'asc'),
-    'operations' => array('data' => t('Operations')),
-  );
-
-  $query = db_select('file_managed', 'f')->extend('PagerDefault')->extend('TableSort');
-  $query->join('users', 'u', 'f.uid = u.uid');
-
-  $result = $query
-    ->fields('f')
-    ->fields('u', array('name'))
-    ->condition('f.status', FILE_STATUS_PERMANENT)
-    ->limit($limit)
-    ->orderByHeader($header)
-    ->execute();
-
-  $destination = drupal_get_destination();
-  $files = array();
-  $options = array();
-
-  foreach ($result as $file) {
-    $options[$file->fid] = array(
-      'title' => theme('media_link', array('file' => $file)),
-      'type' =>  check_plain($file->filemime),
-      'size' => format_size($file->filesize),
-      'author' => theme('username', array('account' => $file)),
-      'timestamp' => format_date($file->timestamp, 'short'),
-    );
-    $options[$file->fid]['operations'] = l(t('edit'), 'media/' . $file->fid . '/edit', array('query' => $destination));
-  }
-
-  $form['files'] = array(
-    '#type' => 'tableselect',
-    '#header' => $header,
-    '#options' => $options,
-    '#empty' => t('No media available.'),
-    '#attributes' => array('class' => array('media-display-table', 'media-clear')),
-  );
-  $form['pager'] = array('#markup' => theme('pager', array('tags' => NULL)));
+  module_load_include('inc', 'media', '/includes/media.browser');
 
-  return $form;
-}
-
-/**
- * Form builder: Builds the media thumbnails administration overview.
- */
-function media_admin_thumbnails() {
-  // @todo Change to media_variable_get('admin_pager_limit') for consistency
-  //   with browser_pager_limit?
-  $limit = variable_get('media_admin_limit', 50);
-
-
-  $query = new EntityFieldQuery();
-  $query->pager($limit);
-  $query->entityCondition('entity_type', 'file');
-  $query->propertyCondition('status', FILE_STATUS_PERMANENT);
-  $result = $query->execute();
-  $files = file_load_multiple(array_keys($result['file']));
-
-  $destination = drupal_get_destination();
-  $rows = array();
-  $options = array();
-  $form['files'] = array(
-    '#tree' => TRUE,
-    '#prefix' => '<div class="media-display-thumbnails media-clear clearfix"><ul class="media-list-thumbnails">',
-    '#suffix' => '</ul></div>',
+  // Enable the add media button.
+  $settings = array();
+  $settings['media']['dialog']['launchers']['.action-links a[href="' . url('admin/content/media/add') . '"]'] = array(
+    'submit' => array(
+      'disabledPlugins' => array('library'),
+      'trigger' => 'media-admin-base',
+    ),
+    'url' => url('media/browser'),
+    'base' => 'media-admin-base',
   );
 
-  foreach ($files as $file) {
-    $preview = media_get_thumbnail_preview($file, TRUE);
-    $form['files'][$file->fid] = array(
-      '#type' => 'checkbox',
-      '#title' => '',
-      '#prefix' => '<li>' . drupal_render($preview),
-      '#suffix' => '</li>',
-    );
-  }
+  drupal_add_js($settings, 'setting');
 
-  $form['pager'] = array('#markup' => theme('pager', array('tags' => NULL)));
+  $form['browser'] = media_browser_build();
 
   return $form;
 }
 
 /**
- * Build the display switch portion of the file listings form.
- */
-function media_admin_display_switch($options = array()) {
-  $options += array(
-    'form location' => 'admin/content/media',
-    'active display' => 'list',
-  );
-  $display_types = media_display_types();
-
-  // Build the item list.
-  $display_items = array();
-  foreach ($display_types as $delta => $item) {
-    $attributes = array('title' => $item['description']);
-
-    // Set a seperate icon for the active item.
-    if ($delta == $options['active display']) {
-      $icon = $item['icon_active'];
-      $attributes['class'][] = 'active';
-    }
-    else {
-      $icon = $item['icon'];
-    }
-
-    $display_items[] = array(
-      'data' => l(theme('image', array('path' => $icon, 'alt' => $item['title'])),
-        $options['form location'] . '/' . $delta,
-        array(
-          'html' => TRUE,
-          'attributes' => $attributes,
-        )),
-    );
-  }
-
-  return array(
-    '#type' => 'markup',
-    '#markup' => theme('item_list', array(
-       'items' => $display_items,
-       'attributes' => array('class' => 'media-display-switch'),
-      )
-    ),
-  );
-}
-
-/**
  * Validate media_admin_list form submissions.
  *
  * Check if any files have been selected to perform the chosen
@@ -240,6 +79,7 @@ function media_admin_display_switch($options = array()) {
  */
 function media_admin_validate($form, &$form_state) {
   $files = array_filter($form_state['values']['files']);
+
   if (count($files) == 0) {
     form_set_error('', t('No items selected.'));
   }
@@ -567,3 +407,4 @@ function media_admin_config_browser_pre_submit(&$form, &$form_state) {
     unset($form_state['values'][media_variable_name('dialog_theme')]);
   }
 }
+
diff --git a/includes/media.browser.inc b/includes/media.browser.inc
index f39097c..90e3b68 100644
--- a/includes/media.browser.inc
+++ b/includes/media.browser.inc
@@ -4,53 +4,191 @@
  * @file
  * Media Browser page callback
  */
-function media_browser($selected = NULL) {
-  $output = array();
-  $output['#attached']['library'][] = array('media', 'media_browser_page');
 
-  $params = drupal_get_query_parameters();
-  array_walk_recursive($params, '_media_recursive_check_plain');
-  media_set_browser_params($params);
+/**
+ * Implements hook_form_BASE_FORM_ID_alter()
+ *
+ * All media browser plugins are given the base for id of media_browser_form.
+ * This facilitates these form elements being added to each plugins form so that
+ * the appropriate AJAX behavior and callbacks will be used without each plugin
+ * having to implement this individually.
+ *
+ * @param type $form
+ * @param type $form_state
+ * @param type $form_id
+ */
+
+function media_form_media_browser_form_alter(&$form, &$form_state, $form_id) {
+  $form['actions'] = array(
+    $form_id . '-submit' => array(
+      '#type' => 'submit',
+      '#value' => t('Okay'),
+      '#ajax' => array(
+        'callback' => 'media_browser_select',
+        'path' => 'media/browser',
+        'event' => 'click',
+      ),
+      '#name' => 'process',
+    ),
+    $form_id . '-cancel' => array(
+      '#type' => 'button',
+      '#value' => t('Cancel'),
+      '#name' => 'cancel',
+      '#limit_validation_errors' => array(),
+      '#executes_submit_callback' => FALSE,
+      '#ajax' => array(
+        'callback' => 'media_browser_dismiss',
+        'path' => 'media/browser/cancel',
+      ),
+    ),
+    'trigger' => array(
+      '#type' => 'hidden',
+      '#value' => isset($form_state['values']['trigger']) ? $form_state['values']['trigger'] : $_POST['trigger'],
+    ),
+    '#weight' => 1000,
+  );
+}
+
+/**
+ * This is a centralized AJAX callback that handles processing and launching of
+ * the media browser dialog.  The reason that the default callback at /system/ajax
+ * could not be used was so that module_load_include() calls would be performed as
+ * needed within media_browser_get_plugins().
+ *
+ * @return A list of AJAX commands to be performed
+ */
+function media_browser() {
+  $commands = array();
+
+  if (!isset($_POST['form_id'])) {
+    $commands[] = media_browser_launch();
+  } else {
+    list($form, $form_state) = ajax_get_form();
 
-  // If one or more files have been selected, the browser interaction is now
-  // complete. Return empty page content to the dialog which now needs to close,
-  // but populate Drupal.settings with information about the selected files.
-  if (isset($params['fid'])) {
-    $fids = is_array($params['fid']) ? $params['fid'] : array($params['fid']);
+    // Load the necessary files for processing the form.
+    $plugin = media_browser_get_plugin($form_state['plugin']);
+    ctools_plugin_get_function($plugin, 'callback');
+
+    drupal_process_form($form['#form_id'], $form, $form_state);
+
+    if (!empty($form_state['triggering_element'])) {
+      $callback = $form_state['triggering_element']['#ajax']['callback'];
+    }
+    if (!empty($callback) && function_exists($callback)) {
+      $commands = $callback($form, $form_state);
+    }
+  }
+
+  return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * This creates an AJAX command dependent on the success or failure of the submitted
+ * form to validate and pass on an array of fids.  If no fids are passed or the
+ * form fails to validate the form is refreshed.  If fids are successfully passed
+ * media items are loaded for each fid and passed back to the browser.
+ *
+ * @param type $form
+ * @param type $form_state
+ *
+ * @return an AJAX command with the selected media files as data.
+ */
+function media_browser_select($form, &$form_state) {
+  $commands = array();
+  if (!form_get_errors() && isset($form_state['values']['fids']) && count($form_state['values']['fids']) > 0) {
+    $fids = $form_state['values']['fids'];
+    if (!is_array($form_state['values']['fids'])) {
+      $fids = array($form_state['values']['fids']);
+    }
     if (!is_numeric($fids[0])) {
       throw new Exception('Error selecting media, fid param is not an fid or an array of fids');
     }
     $files = file_load_multiple($fids);
-    foreach ($files as $file) {
+    foreach ($files as &$file) {
       media_browser_build_media_item($file);
     }
-    $setting = array('media' => array('selectedMedia' => array_values($files)));
-    drupal_add_js($setting, 'setting');
-    return $output;
-  }
 
-  // Normal browser operation.
-  foreach (module_implements('media_browser_plugin_info') as $module) {
-    foreach (module_invoke($module, 'media_browser_plugin_info') as $key => $plugin_data) {
-      $plugins[$key] = $plugin_data + array(
-        '#module' => $module,
-        '#weight' => 0,
-      );
-      $plugins[$key]['#weight'] += count($plugins)/1000;
-    }
-  }
+    $commands[] = array(
+      'command' => 'mediaBrowserSelected',
+      'files' => array_values($files),
+      'trigger' => $_POST['trigger'],
+    );
 
-  // Only the plugins in this array are loaded.
-  if (!empty($params['enabledPlugins'])) {
-    $plugins = array_intersect_key($plugins, array_fill_keys($params['enabledPlugins'], 1));
-  }
-  elseif (!empty($params['disabledPlugins'])) {
-    $plugins = array_diff_key($plugins, array_fill_keys($params['disabledPlugins'], 1));
+  } else {
+    $commands = media_browser_refresh($form, $form_state);
   }
+  return $commands;
+}
 
-  foreach ($plugins as $key => &$plugin) {
-    $plugin += module_invoke($plugin['#module'], 'media_browser_plugin_view', $key, $params);
-  }
+/**
+ * This is the callback used when the Cancel button is pressed in the media
+ * browser.
+ *
+ * @return an AJAX command to dismiss the media browser.
+ */
+function media_browser_dismiss() {
+  $commands = array();
+  $commands[] = array(
+    'command' => 'mediaBrowserDismiss',
+  );
+
+  return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
+ * This is the callback for when a form on the media browser needs to be
+ * refreshed.  This is most often called when the form is submitted but fails
+ * validation.
+ *
+ * @param type $form
+ * @param type $form_state
+ * @return AJAX commands to update the form and add any messages to the browser
+ */
+function media_browser_refresh($form, &$form_state) {
+  $commands[] = array(
+    'command' => 'insert',
+    'method' => 'replaceWith',
+    'data' => drupal_render($form),
+    'selector' => '#' . strtr($form_state['values']['form_id'], '_', '-'),
+  );
+
+  $messages = theme('status_messages');
+  $commands[] = array(
+    'command' => 'mediaBrowserMessages',
+    'data' => $messages,
+  );
+
+  return $commands;
+}
+
+/**
+ * This is the callback that launches the media browser with all loaded plugins.
+ *
+ * @return an AJAX command that will launch the media browser
+ */
+function media_browser_launch() {
+  return array(
+    'command' => 'mediaBrowserLaunch',
+    'data' => drupal_render(media_browser_forms()),
+  );
+}
+
+/**
+ * This function gathers the parameters for the plugins being launched in the
+ * media browser, builds the forms for each plugin, and assembles the plugins
+ * into tabs.
+ *
+ * @return a rederable array
+ */
+function media_browser_forms() {
+  $build = array();
+
+  $params = array_merge(drupal_get_query_parameters(), drupal_get_query_parameters($_POST));
+  array_walk_recursive($params, '_media_recursive_check_plain');
+  media_set_browser_params($params);
+
+  // Normal browser operation.
+  $plugins = media_browser_get_plugins($params);
 
   // Allow modules to change the tab names or whatever else they want to change
   // before we render.  Perhaps this should be an alter on the theming function
@@ -59,213 +197,449 @@ function media_browser($selected = NULL) {
 
   $tabs = array(); // List of tabs to render.
 
-  $settings = array('media' => array('browser' => array()));
-  $browser_settings =& $settings['media']['browser'];
-
-  //@todo: replace with Tabs module if it gets upgraded.
-  foreach (element_children($plugins, TRUE) as $key) {
-    $plugin =& $plugins[$key];
-
-    //Add any JS settings
-    $browser_settings[$key] = isset($plugin['#settings']) ? $plugin['#settings'] : array();
+  $browser_settings = array('media' => array('dialog' => array('params' => $params)));
+  $build['tabset'] = array(
+    '#prefix' => '<div id="media-browser-tabset">',
+    '#suffix' => '</div>',
+    '#weight' => 1,
+    '#attached' => array('js' => array(drupal_add_js($browser_settings, 'setting'))),
+  );
+  $build['tabset']['list'] = array(
+    '#items' => array(),
+    '#theme' => 'item_list',
+  );
 
+  foreach ($plugins as $key => $plugin) {
+    $access_callback = ctools_plugin_get_function($plugin, 'access callback');
+    if (isset($access_callback)) {
+      $access = $access_callback();
+      if (!$access) {
+        continue;
+      }
+    }
+    $form_id = ctools_plugin_get_function($plugin, 'callback');
+    $ajax_callback = ctools_plugin_get_function($plugin, 'ajax_callback');
     // If this is a "ajax" style tab, add the href, otherwise an id.
-    $href = isset($plugin['#callback']) ? $plugin['#callback'] : "#media-tab-$key";
-    $tabs[] = "<a href='$href'><span>{$plugin['#title']}</span></a>";
+    $href = isset($ajax_callback) ? $ajax_callback : "#media-tab-$key";
+    $build['tabset']['list']['#items'][] = "<a href='$href'><span>{$plugin['title']}</span></a>";
 
     // Create a div for each tab's content.
-    $plugin['#prefix'] = <<<EOS
+    $build['tabset']['plugins'][$key]['#prefix'] = <<<EOS
     <div class="media-browser-tab" id="media-tab-$key">
 EOS;
-    $plugin['#suffix'] = <<<EOS
+    $build['tabset']['plugins'][$key]['#suffix'] = <<<EOS
     </div>
     <!-- End #media-tab-$key -->
 EOS;
-  }
-
-  drupal_add_js($settings, 'setting');
+    $form_state = array(
+      'plugin' => $key,
+      'build_info' => array(
+        'base_form_id' => 'media_browser_form',
+        'params' => $params,
+        'args' => array(),
+      ),
+    );
 
-  $output['tabset'] = array(
-    '#prefix' => '<div id="media-browser-tabset">',
-    '#suffix' => '</div>',
-  );
-  $output['tabset']['list'] = array(
-    '#markup' => '<ul><li>' . implode('</li><li>', $tabs) . '</li></ul>'
-  );
+    $build['tabset']['plugins'][$key]['form'] = drupal_build_form($form_id, $form_state);
+  }
 
-  $output['tabset']['plugins'] = $plugins;
-  return $output;
+  return $build;
 }
 
 /**
- * Provides a singleton of the params passed to the media browser.
- *
- * This is useful in situations like form alters because callers can pass
- * id="wysiywg_form" or whatever they want, and a form alter could pick this up.
- * We may want to change the hook_media_browser_plugin_view() implementations to
- * use this function instead of being passed params for consistency.
+ * This function builds a listing of media items according to the user's
+ * display settings.
  *
- * It also offers a chance for some meddler to meddle with them.
- *
- * @param array $params
- *  An array of parameters provided when a media_browser is launched.
- *  See media_browser().
+ * @return A renderable array for the current display of the media browser
+ * listing and the display switch links.
  */
-function media_set_browser_params(&$params = NULL) {
-  static $stored_params;
+function media_browser_build() {
+  $form = array();
+  // Attach browser JS
+  media_attach_browser_js($form);
 
-  if (!$params) {
-    return $stored_params;
+  $params = array_merge(drupal_get_query_parameters(), drupal_get_query_parameters($_POST));
+  $params['limit'] = isset($params['limit']) ? $params['limit'] : variable_get('media_admin_limit', 48);
+  $params['types'] = isset($params['types']) ? $params['types'] : array_keys(media_type_get_types());
+  $params['no_ops'] = isset($params['no_ops']) ? TRUE : FALSE;
+  $params['page'] = isset($params['page']) ? $params['page'] : 0;
+  $params['singleselect'] = isset($params['singleselect']) ? $params['singleselect'] : FALSE;
+
+  // Workaround for jQuery Form plugin's inability to process multidimensional
+  // arrays for POST. See media_browser_display_switch().
+  foreach ($params as $key => $value) {
+    if (strpos($key, 'types-') === 0) {
+      $params['types'][$value] = $value;
+    }
   }
-  $stored_params = $params;
-  drupal_alter('media_browser_params', $stored_params);
+
+  // This will translate a POST page # to the pager and queries
+  $_GET['page'] = $params['page'];
+
+    #dpr($params['types']);
+
+  // Gather the display information.
+  $display = media_browser_get_display();
+
+  $form['browser'] = array(
+    '#prefix' => '<div id="media-browser">',
+    '#suffix' => '</div>',
+  );
+
+  drupal_add_js(drupal_get_path('module', 'media') . '/js/media.browser.js');
+  drupal_add_library('system', 'jquery.bbq');
+
+  // Build the display switch.
+  $form['browser']['switch'] = media_browser_display_switch($params);
+
+  // Build the display.
+  include_once $display['file'];
+  $form['browser']['display'] = $display['callback']($params);
+
+  return $form;
 }
 
 /**
- * For sanity in grammar.
+ * This function loads the display info from hook_media_display_types() for the
+ * user's display settings.
  *
- * @see media_set_browser_params()
+ * @global type $user
+ * @return An array containing information on the media browser display
  */
-function media_get_browser_params() {
-  return media_set_browser_params();
+function media_browser_get_display() {
+  global $user;
+  $types = media_display_types();
+
+  $type = isset($user->data['media_display_type']) ? $user->data['media_display_type'] : 'list';
+  $display = array();
+  foreach($types[$type] as $key => $data) {
+    $display[$key] = $data;
+  }
+  $display['name'] = $type;
+
+  return $display;
 }
 
 /**
- * AJAX Callback function to return a list of media files
+ * Sets the user's media browser display type.  If called as part of an AJAX
+ * submission it also returns the updated media browser display.
+ *
+ * @global type $user
+ * @param type $type
+ * @param type $js
+ * @return An array of AJAX commands
  */
-function media_browser_list() {
-  $params = drupal_get_query_parameters();
-  // How do we validate these?  I don't know.
-  // I think PDO should protect them, but I'm not 100% certain.
-  array_walk_recursive($params, '_media_recursive_check_plain');
+function media_browser_set_display($type, $js = FALSE) {
+  global $user;
+  $types = media_display_types();
 
-  $types = isset($params['types']) ? $params['types'] : NULL;
-  $url_include_patterns = isset($params['url_include_patterns']) ? $params['url_include_patterns'] : NULL;
-  $url_exclude_patterns = isset($params['url_exclude_patterns']) ? $params['url_exclude_patterns'] : NULL;
+  if (in_array($type, array_keys($types))) {
+    $user->data['media_display_type'] = $type;
+    user_save($user);
+  }
 
-  $start = isset($params['start']) ? $params['start'] : 0;
-  $limit = isset($params['limit']) ? $params['limit'] : media_variable_get('browser_pager_limit');
+  if ($js) {
+    // This may be called from the library plugin, we'll need to load its file
+    module_load_include('inc', 'media', 'includes/media.pages');
 
-  $query = new EntityFieldQuery();
+    list($form, $form_state) = ajax_get_form();
+    $form['browser'] = media_browser_build();
+    drupal_process_form($form['#form_id'], $form, $form_state);
 
-  $query->range($start, $limit);
-  $query->entityCondition('entity_type', 'file');
-  $query->entityOrderBy('entity_id', 'DESC');
+    $commands = array();
+
+    $container = array_slice(array_reverse($form_state['triggering_element']['#array_parents']), 3);
+    $element = $form;
+    foreach($container as $key) {
+      $element = $element[$key];
+    }
 
-  if ($types) {
-    $query->entityCondition('bundle', $types, 'IN');
+    $commands[] = array(
+      'command' => 'insert',
+      'selector' => '#media-browser',
+      'method' => 'replaceWith',
+      'data' => drupal_render($element),
+      'state' => $form_state,
+      'element' => $element,
+    );
+
+    return array('#type' => 'ajax', '#commands' => $commands);
+  } else {
+    drupal_goto(drupal_get_destination());
   }
+}
+
+/**
+ * Returns a sorted list of media browser plugins.
+ *
+ * @param type $params
+ * @return an array of plugins and their information
+ */
+function media_browser_get_plugins($params = array()) {
+  ctools_include('plugins');
+  $plugins = ctools_get_plugins('media', 'browser');
 
-  if ($url_include_patterns) {
-    $query->propertyCondition('uri', $v, 'CONTAINS');
-    // Insert stream related restrictions here.
+  // Only the plugins in this array are loaded.
+  if (!empty($params['enabledPlugins'])) {
+    $plugins = array_intersect_key($plugins, array_fill_keys($params['enabledPlugins'], 1));
   }
-  if ($url_exclude_patterns) {
-    $query->propertyCondition('uri', "%$v%", 'NOT LIKE');
+  elseif (!empty($params['disabledPlugins'])) {
+    $plugins = array_diff_key($plugins, array_fill_keys($params['disabledPlugins'], 1));
   }
 
-  // @todo Implement granular editorial access: http://drupal.org/node/696970.
-  //   In the meantime, protect information about private files from being
-  //   discovered by unprivileged users. See also media_view_page().
-  if (!user_access('administer media')) {
-    $query->propertyCondition('uri', 'private://%', 'NOT LIKE');
+  // Sort plugins by weight.
+  foreach ($plugins as $key => &$plugin) {
+    // element_sort() requires a #weight parameter.
+    $plugin['#weight'] = $plugin['weight'];
   }
+  uasort($plugins, 'element_sort');
 
-  $query->propertyCondition('status', FILE_STATUS_PERMANENT);
+  return $plugins;
+}
+
+/**
+ * Returns a specific media browser plugin.
+ */
+function media_browser_get_plugin($plugin) {
+  ctools_include('plugins');
+  return ctools_get_plugins('media', 'browser', $plugin);
+}
+
+/**
+ * Builds a tablesort listing of media based on the passed in parameters.
+ *
+ * @param type $params
+ * @return A renderable array
+ */
+function media_browser_table($params) {
+  drupal_add_js(drupal_get_path('module', 'media') . '/js/plugins/media.table.js');
+
+  // Build the sortable table header.
+  $header = array(
+   'title' => array('data' => t('Title'), 'field' => 'f.filename'),
+   'type' => array('data' => t('Type'), 'field' => 'f.filemime'),
+   'size' => array('data' => t('Size'), 'field' => 'f.filesize'),
+   'author' => array('data' => t('Author'), 'field' => 'u.name'),
+   'timestamp' => array('data' => t('Updated'), 'field' => 'f.timestamp', 'sort' => 'desc'),
+  );
+
+  if (!isset($params['no_ops'])) {
+    $header['operations'] = array('data' => t('Operations'));
+  }
+
+  $query = db_select('file_managed', 'f')->extend('PagerDefault')->extend('TableSort');
+  $query->join('users', 'u', 'f.uid = u.uid');
+
+  $query
+   ->fields('f')
+   ->fields('u', array('name'))
+   ->condition('f.status', FILE_STATUS_PERMANENT)
+   ->condition('f.type', $params['types'])
+   ->element(0)
+   ->limit($params['limit']/2)
+   ->orderByHeader($header);
 
   $result = $query->execute();
-  $files = file_load_multiple(array_keys($result['file']));
-  foreach ($files as $file) {
-    media_browser_build_media_item($file);
+
+  $destination = drupal_get_destination();
+  $files = array();
+  $options = array();
+
+  $form['files'] = array(
+   '#type' => 'tableselect',
+   '#header' => $header,
+   '#options' => $options,
+   '#empty' => t('No media available.'),
+   '#attributes' => array('class' => array('media-display-table', 'media-clear')),
+  );
+
+  foreach ($result as $file) {
+    $options[$file->fid] = array(
+      'title' => theme('media_link', array('file' => $file)),
+      'type' =>  check_plain($file->filemime),
+      'size' => format_size($file->filesize),
+      'author' => theme('username', array('account' => $file)),
+      'timestamp' => format_date($file->timestamp, 'short'),
+    );
+
+    if (!$params['no_ops']) {
+      $options[$file->fid]['operations'] = l(t('edit'), 'media/' . $file->fid . '/edit', array('query' => $destination));
+    }
+
+    // For some reason form_process_tableselect doesn't add these children on AJAX refresh
+    $form['files'][$file->fid] = array(
+      '#type' => 'checkbox',
+      '#title_display' => 'invisible',
+      '#return_value' => $file->fid,
+    );
   }
 
-  drupal_json_output(array('media' => array_values($files)));
-  exit();
+  $form['files']['#options'] = $options;
+
+  $form['pager'] = array('#markup' => theme('pager', array('tags' => NULL)));
 
+  return $form;
 }
 
 /**
- * Implements hook_media_browser_plugin_info().
+ * Builds a thumbnail grid of media based on the passed in parameters.
+ *
+ * @param type $params
+ * @return A renderable array
  */
-function media_media_browser_plugin_info() {
-  $plugins = array();
+function media_browser_thumbnails($params) {
 
-  // @TODO: Should we add a permission around this?
-  $plugins['library'] = array(
-    '#weight' => 10,
-  );
+  $query = new EntityFieldQuery();
+
+  $query->pager($params['limit'], 0);
+  $query->entityCondition('entity_type', 'file');
+  $query->propertyOrderBy('timestamp', 'desc');
+  $query->propertyCondition('status', FILE_STATUS_PERMANENT);
+  $query->propertyCondition('type', $params['types']);
+
+  $result = $query->execute();
+  $ids = key_exists('file', $result) ? array_keys($result['file']) : FALSE;
+  $media_entities = array();
+  if ($ids) {
+    $media_entities = entity_load('file', $ids);
+  }
 
-  if (user_access('administer media') || user_access('edit media')) {
-    $plugins['upload'] = array(
-      '#weight' => -10,
+  $path = drupal_get_path('module', 'media');
+  drupal_add_css($path . '/css/media.thumbnails.css');
+  drupal_add_js($path . '/js/plugins/media.thumbnails.js');
+
+  if (!isset($params['singleselect']) || $params['singleselect'] != TRUE) {
+    $form['select_all'] = array(
+      '#theme' => 'links',
+      '#links' => array(
+        'all' => array(
+          'title' => 'all,',
+          'href' => '#',
+          'attributes' => array('class' => array('select')),
+        ),
+        'none' => array(
+          'title' => 'none',
+          'href' => '#',
+          'attributes' => array('class' => array('deselect')),
+        ),
+      ),
+      '#prefix' => '<div class="media-thumbnails-select"><strong>' . t('Select') . ':</strong>',
+      '#suffix' => '</div>',
     );
   }
-  return $plugins;
+
+  $destination = drupal_get_destination();
+  $rows = array();
+  $options = array();
+  $form['files'] = array(
+   '#tree' => TRUE,
+   '#prefix' => '<div class="media-display-thumbnails media-clear clearfix"><ul class="media-list-thumbnails">',
+   '#suffix' => '</ul></div>',
+  );
+
+  if (count($media_entities)) {
+    foreach ($media_entities as $media) {
+     $preview = media_get_thumbnail_preview($media, !$params['no_ops']);
+     $form['files'][$media->fid] = array(
+       '#type' => 'checkbox',
+       '#title' => '',
+       '#prefix' => '<li class="media-item-wrapper">' . drupal_render($preview),
+       '#suffix' => '</li>',
+     );
+    }
+  }
+
+  $form['pager'] = array('#markup' => theme('pager', array('tags' => NULL)));
+
+  return $form;
 }
 
 /**
- * Implementaion of hook_media_browser_plugin_view().
+ * Build the display switch portion of the file listings form.
  */
-function media_media_browser_plugin_view($plugin_name, $params) {
-  $path = drupal_get_path('module', 'media');
+function media_browser_display_switch($params) {
+  global $user;
+  $type =  isset($user->data['media_display_type']) ?  $user->data['media_display_type'] : 'list';
+  $display_types = media_display_types();
 
-  module_load_include('inc', 'media', 'includes/media.admin');
-  module_load_include('inc', 'media', 'includes/media.pages');
+  // Build the item list.
+  $links = array();
 
-  $types = isset($params['types']) ? $params['types'] : array();
+  foreach ($display_types as $delta => $item) {
+    $attributes = array(
+      'title' => $item['description'],
+    );
+    $icon = $item['icon'];
+    if ($delta == $type) {
+      $icon = $item['icon_active'];
+      $attributes['class'][] = 'active';
+    }
+    $attributes['style'] = 'background-image: url("' . base_path() . $icon . '");';
+
+    $links[$delta] = array(
+      '#type' => 'button',
+      '#button_type' => 'media-display',
+      '#title' => $delta,
+      '#value' => $delta,
+      '#name' => $delta,
+      '#src' => $icon,
+      '#ajax' => array(
+        'path' => 'media/browser/ajax/' . $delta,
+        'submit' => array(
+          'limit' => $params['limit'],
+          'no_ops' => $params['no_ops'],
+          'page' => $params['page'],
+          'singleselect' => $params['singleselect'],
+        ),
+      ),
+      '#attributes' => $attributes,
+      '#limit_validation_errors' => array(),
+      '#executes_submit_callback' => FALSE,
+    );
 
-  // The multiselect parameter is a string.  So we check to see if it is set and
-  // adjust the local variable accordingly.
-  $multiselect = FALSE;
-  if (isset($params['multiselect']) && $params['multiselect'] != 'false') {
-    $multiselect = TRUE;
+    // The jQuery Form plugin incorrectly processes multidimensional arrays
+    // when encoding them as POST parameters. To work around this, we send
+    // $params['types'] to the client side as elements of the parent array.
+    foreach ($params['types'] as $type => $value) {
+      $links[$delta]['#ajax']['submit']["types-$type"] = $value;
+    }
   }
 
-  $redirect = array('media/browser', array('query' => array('render' => 'media-popup')));
-  switch ($plugin_name) {
-    case 'upload':
-      $attached = array();
-      if ($multiselect && module_exists('plupload')) {
-        $upload_form_id = 'media_add_upload_multiple';
-        $attached['js'] = array($path . '/js/plugins/media.upload_multiple.js');
-      }
-      else {
-        $upload_form_id = 'media_add_upload';
-      }
+  return array(
+    'links' => $links,
+    '#prefix' => '<div id="media-display-switches">',
+    '#suffix' => '</div>',
+  );
+}
 
-      $upload_form = drupal_get_form($upload_form_id, $types);
-      return array(
-        '#title' => t('Upload'),
-        'form' => array($upload_form),
-        '#attached' => $attached,
-      );
-      break;
-    case 'library':
-      return array(
-        '#title' => t('Library'),
-        '#attached' => array(
-          'js' => array(
-            $path . '/js/plugins/media.library.js',
-          ),
-          'css' => array(
-            //@todo: should move this.
-            $path . '/js/plugins/media.library.css',
-          ),
-        ),
-        '#settings' => array(
-          'viewMode' => 'thumbnails',
-          'getMediaUrl' => url('media/browser/list'),
-          'types' => $types,
-          'multiselect' => $multiselect,
-        // We should probably change this to load dynamically when requested
-        // via the JS file.
-        ),
-        '#markup' => '<div id="container"><div id="scrollbox"><ul id="media-browser-library-list" class="media-list-thumbnails"></ul><div id="status"></div></div></div>',
-      );
-    break;
+/**
+ * Provides a singleton of the params passed to the media browser.
+ *
+ * This is useful in situations like form alters because callers can pass
+ * id="wysiywg_form" or whatever they want, and a form alter could pick this up.
+ *
+ * It also offers a chance for some meddler to meddle with them.
+ *
+ * @param array $params
+ *  An array of parameters provided when a media_browser is launched.
+ *  See media_browser().
+ */
+function media_set_browser_params(&$params = NULL) {
+  static $stored_params;
+
+  if (!$params) {
+    return $stored_params;
   }
+  $stored_params = $params;
+  drupal_alter('media_browser_params', $stored_params);
+}
 
-  return array();
+/**
+ * For sanity in grammar.
+ * @see media_set_browser_params().
+ */
+function media_get_browser_params() {
+  return media_set_browser_params();
 }
 
 /**
@@ -300,8 +674,9 @@ function media_attach_browser_js(&$element) {
  */
 function media_browser_js() {
   $settings = array(
-    'browserUrl' => url('media/browser',
-      array('query' => array('render' => 'media-popup'))),
+    'browserUrl' => url('media/browser'
+      #array('query' => array('render' => 'media-popup')),
+    ),
     'styleSelectorUrl' => url('media/-media_id-/format-form',
       array('query' => array('render' => 'media-popup'))),
   );
diff --git a/includes/media.filter.inc b/includes/media.filter.inc
index 697912f..0219dac 100644
--- a/includes/media.filter.inc
+++ b/includes/media.filter.inc
@@ -227,6 +227,16 @@ function media_pre_render_text_format($element) {
   if (isset($tagmap)) {
     drupal_add_js(array('tagmap' => array_unique($tagmap)), 'setting');
   }
+
+  // Pass on some parameters for the media button attached to this element.
+  $settings = array('media' => array('wysiwyg' => array()));
+  $settings['media']['wysiwyg'][$element['#id'] . '-value'] = array(
+    'types' => array('image', 'video'),
+    'trigger' => $element['#id'] . '-value',
+    'limit' => 48,
+  );
+  drupal_add_js($settings, 'setting');
+
   return $element;
 }
 
@@ -270,6 +280,38 @@ function _media_generate_tagMap($text) {
 }
 
 /**
+ * AJAX callback that handles the media format form dialog.  Given a piece of media
+ * this callback will return a command to the AJAX handler to either display the
+ * media format form or to indicate that the form has been submitted and a format
+ * chosen for the piece of media.
+ *
+ * @param type $file
+ */
+function media_format($file) {
+  $commands = array();
+
+  if (!isset($_POST['form_id'])) {
+    $commands[] = array(
+      'command' => 'mediaBrowserLaunch',
+      'data' => drupal_render(drupal_get_form('media_format_form', $file)),
+    );
+  } else {
+    list($form, $form_state) = ajax_get_form();
+    drupal_process_form($form['#form_id'], $form, $form_state);
+
+    $commands[] = array(
+      'command' => 'mediaFormatSelected',
+      'file' => $file,
+      'viewMode' => $form_state['values']['format'],
+      'formattedMedia' => drupal_render(media_get_file_without_label($file, $form_state['values']['format'])),
+      'instanceId' => $form_state['values']['trigger'],
+    );
+  }
+
+  return array('#type' => 'ajax', '#commands' => $commands);
+}
+
+/**
  * Form callback used when embedding media.
  *
  * Allows the user to pick a format for their media file.
@@ -278,6 +320,9 @@ function _media_generate_tagMap($text) {
 function media_format_form($form, $form_state, $file) {
   $form = array();
   $form['#media'] = $file;
+  $form['#attributes'] = array(
+    'class' => array('format-form'),
+  );
 
   $entity_info = entity_get_info('file');
   $view_modes = $entity_info['view modes'];
@@ -320,8 +365,8 @@ function media_format_form($form, $form_state, $file) {
   drupal_add_library('system', 'form');
 
   $path = drupal_get_path('module', 'media');
-  $form['#attached']['js'][] = $path . '/js/media.format_form.js';
   $form['#attached']['css'][] = $path . '/css/media-format-form.css';
+  $form['#attached']['css'][] = $path . '/css/media.thumbnails.css';
 
   $form['heading'] = array(
     '#type' => 'markup',
@@ -362,6 +407,33 @@ function media_format_form($form, $form_state, $file) {
     $form['options']['#attributes'] = array('style' => 'display:none');
   }
 
+  $form['actions'] = array(
+    'submit' => array(
+      '#type' => 'submit',
+      '#value' => t('Okay'),
+      '#ajax' => array(
+        'path' => 'media/' . $file->fid . '/format-form',
+      ),
+      '#name' => 'process',
+    ),
+    'cancel' => array(
+      '#type' => 'button',
+      '#value' => t('Cancel'),
+      '#name' => 'cancel',
+      '#limit_validation_errors' => array(),
+      '#executes_submit_callback' => FALSE,
+      '#ajax' => array(
+        'callback' => 'media_browser_dismiss',
+        'path' => 'media/browser/cancel',
+      ),
+    ),
+    'trigger' => array(
+      '#type' => 'hidden',
+      '#value' => isset($form_state['values']['trigger']) ? $form_state['values']['trigger'] : $_POST['trigger'],
+    ),
+    '#weight' => 1000,
+  );
+
   return $form;
 }
 
diff --git a/includes/media.pages.inc b/includes/media.pages.inc
index ff101ff..b8fb58f 100644
--- a/includes/media.pages.inc
+++ b/includes/media.pages.inc
@@ -168,7 +168,8 @@ function media_multiple_delete_confirm_submit($form, &$form_state) {
  * Form callback for adding media via an upload form.
  * @todo: should use the AJAX uploader
  */
-function media_add_upload($form, &$form_state, $types = NULL) {
+function media_add_upload($form, &$form_state) {
+  $types = isset($form_state['build_info']['params']['types']) ? $form_state['build_info']['params']['types'] : '';
 
   $validators = array(
    'file_validate_extensions' => array(media_variable_get('file_extensions')),
@@ -202,11 +203,6 @@ function media_add_upload($form, &$form_state, $types = NULL) {
     '#upload_validators' => $validators,
   );
 
-  $form['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Submit'),
-  );
-
   return $form;
 }
 
@@ -224,47 +220,38 @@ function media_add_upload_validate($form, &$form_state) {
     form_set_error('upload', t("Failed to upload the file."));
   }
   else {
-    $form_state['values']['upload'] = $file;
-  }
-}
-
-/**
- * Upload a file.
- */
-function media_add_upload_submit($form, &$form_state) {
-  $scheme = variable_get('file_default_scheme', 'public') . '://';
-  $file = $form_state['values']['upload'];
-  _media_save_file_permenently($file);
+    $scheme = variable_get('file_default_scheme', 'public') . '://';
+    _media_save_file_permenently($file);
 
-  $destination = file_stream_wrapper_uri_normalize($scheme . $file->filename);
+    $destination = file_stream_wrapper_uri_normalize($scheme . $file->filename);
 
-  $defaults = array(
-    'display' => TRUE,
-  );
+    $defaults = array (
+      'display' => TRUE,
+    );
 
-  // Save the uploaded file.
-  $file = file_move($file, $destination, FILE_EXISTS_RENAME);
+    // Save the uploaded file.
+    $file_permanent = file_move($file, $destination, FILE_EXISTS_RENAME);
 
-  if ($file) {
-    drupal_set_message(t('The file @name was uploaded', array('@name' => $file->filename)));
-  }
-  else {
-    drupal_set_message(t('An error occurred and no file was uploaded.'), 'error');
-    return;
+    if ($file_permanent) {
+      drupal_set_message(t('The file @name was uploaded', array('@name' => $file->filename)));
+      $form_state['values']['fids'] = array($file->fid);
+    }
+    else {
+      form_set_error('upload', t('An error occurred and no file was uploaded.'));
+    }
   }
-
-  $form_state['redirect'] = array('media/browser', array('query' => array('render' => 'media-popup', 'fid' => $file->fid)));
 }
 
-function media_add_upload_multiple($form, &$form_state, $types) {
-  $form = media_add_upload($form, $form_state, $types);
+function media_add_upload_multiple($form, &$form_state) {
+  $form = media_add_upload($form, $form_state);
+  $form['#attached']['js'] = array(drupal_get_path('module', 'media') . '/js/plugins/media.upload_multiple.js');
+
   unset($form['upload']['#title']);
   // The validators will be set from plupload anyway.  This isn't pretty, but don't
   // it to show up twice.
   unset($form['upload']['#description']);
 
   $form['upload']['#type'] = 'plupload';
-  $form['submit']['#value'] = t('Start upload');
   return $form;
 }
 
@@ -294,11 +281,17 @@ function media_add_upload_multiple_submit($form, &$form_state) {
     }
   }
   // Get a list of fids to pass back.
-  $fids = array();
-  foreach ($saved_files as $file) {
-    $fids[] = $file->fid;
+  if (count($saved_files) > 0) {
+    $fids = array();
+    foreach ($saved_files as $file) {
+      $fids[] = $file->fid;
+    }
+    $form_state['values']['fids'] = $fids;
+    drupal_set_message(t('Files in the queue were successfully uploaded'));
+  } else {
+    form_set_error('upload', t('No files were selected to be uploaded'));
+    return;
   }
-  $form_state['redirect'] = array('media/browser', array('query' => array('render' => 'media-popup', 'fid' => $fids)));
 }
 
 /**
@@ -427,3 +420,26 @@ function media_add_remote($form, &$form_state) {
 
   return $form;
 }
+
+function media_library_form($form, &$form_state) {
+  $path = drupal_get_path('module', 'media');
+  drupal_add_js($path . '/js/plugins/media.library.js');
+  drupal_add_css($path . '/css/media.library.css');
+
+  // Disable operations when rendering the media listings
+  $_POST['no_ops'] = TRUE;
+
+  $form['browser'] = media_browser_build();
+  return $form;
+}
+
+function media_library_form_validate($form, &$form_state) {
+  foreach($form_state['values']['files'] as $key => $file) {
+    if ($file) {
+      $form_state['values']['fids'][] = $key;
+    }
+  }
+  if (!isset($form_state['values']['fids'])) {
+    form_set_error('files', t('No files selected'));
+  }
+}
diff --git a/includes/media.theme.inc b/includes/media.theme.inc
index 4904145..67b0f0b 100644
--- a/includes/media.theme.inc
+++ b/includes/media.theme.inc
@@ -277,9 +277,9 @@ function theme_media_thumbnail($variables) {
   $element = $variables['element'];
   $destination = drupal_get_destination();
 
-  // Wrappers to go around the thumbnail
-  $prefix = '<div class="media-item"><div class="media-thumbnail">';
-  $suffix = '</div></div>';
+  // Wrapper to go around the thumbnail
+  $prefix = '<div class="media-item media-thumbnail">';
+  $suffix = '</div>';
 
   // Arguments for the thumbnail link
   $thumb = $element['#children'];
@@ -291,10 +291,6 @@ function theme_media_thumbnail($variables) {
     $label = '<div class="label-wrapper"><label class="media-filename">' . $element['#name'] . '</label></div>';
   }
 
-  // How can I attach CSS here?
-  //$element['#attached']['css'][] = drupal_get_path('module', 'media') . '/css/media.css';
-  drupal_add_css(drupal_get_path('module', 'media') . '/css/media.css');
-
   $output = $prefix;
   if (!empty($element['#add_link'])) {
     $output .= l($thumb, $target, $options);
@@ -310,6 +306,7 @@ function template_preprocess_media_thumbnail(&$variables) {
   // Set the name for the thumbnail to be the filename.  This is done here so
   // that other modules can hijack the name displayed if it should not be the
   // filename.
+  $variables['element']['#attached']['css'][] = drupal_get_path('module', 'media') . '/css/thumbnails.css';
   $variables['element']['#name'] = isset($variables['element']['#file']->filename) ? $variables['element']['#file']->filename : NULL;
 }
 
diff --git a/js/media.admin.js b/js/media.admin.js
index 080d68e..b803047 100644
--- a/js/media.admin.js
+++ b/js/media.admin.js
@@ -9,116 +9,36 @@
 
 (function ($) {
 
+Drupal.media = Drupal.media || {};
+Drupal.media.admin = Drupal.media.admin || {};
+
 /**
  * Functionality for the thumbnail display
  */
 Drupal.behaviors.mediaAdmin = {
   attach: function (context) {
-    var show_confirm_if_existing_selections = function () {
-      if ($(':checkbox:checked', $('form#media-admin')).length != 0) {
-        return confirm(Drupal.t('If you switch views, you will lose your selection.'));
-      }
-    }
-
-    $('.media-display-switch a').bind('click', show_confirm_if_existing_selections)
-    // Configure the "Add file" link to fire the media browser popup.
-    $('ul.action-links li', context).remove();
-    if ($('form.media-list-operation', context).length != 0) {
-      return;
-    }
-    var $launcherLink = $('<a class="media-launcher" href="#"></a>').html('Add file');
-    $launcherLink.bind('click', function () {
-      // This option format needs *serious* work.
-      // Not even bothering documenting it because it needs to be thrown.
-      // See media.browser.js and media.browser.inc - media_browser()
-      // For how it gets passed.
-      var options = {
-        disabledPlugins: ['library'],
-        multiselect: true
-      };
-      Drupal.media.popups.mediaBrowser(function (mediaFiles) {
-        // When the media browser succeeds, we refresh
-        // @TODO: Should jump to the new media file and perhaps highlight it.
-        parent.window.location.reload();
-        return false;
-      }, options);
-    });
-    $('ul.action-links', context).append($('<li></li>').append($launcherLink));
-
-
-    if ($('body.page-admin-content-media-thumbnails').length != 0) {
-      // Implements 'select all/none' for thumbnail view.
-      // @TODO: Support grabbing more than one page of thumbnails.
-      var allLink = $('<a href="#">' + Drupal.t('all') + '</a>')
-        .click(function () {
-          $('.media-display-thumbnails', $(this).parents('form')).find(':checkbox').attr('checked', true).change();
-          return false;
-        });
-      var noneLink = $('<a href="#">' + Drupal.t('none') + '</a>')
-        .click(function () {
-          $('.media-display-thumbnails', $(this).parents('form')).find(':checkbox').attr('checked', false).change();
-          return false;
-        });
-      $('<div class="media-thumbnails-select" />')
-        .append('<strong>' + Drupal.t('Select') + ':</strong> ')
-        .append(allLink)
-        .append(', ')
-        .append(noneLink)
-        .prependTo('#media-admin > div')
-      // If the media item is clicked anywhere other than on the image itself
-      // check the checkbox. For the record, JS thinks this is wonky.
-      $('.media-item').bind('click', function (e) {
-        if ($(e.target).is('img, a')) {
-          return;
-        }
-        var checkbox = $(this).parent().find(':checkbox');
-        if (checkbox.is(':checked')) {
-          checkbox.attr('checked', false).change();
-        } else {
-          checkbox.attr('checked', true).change();
-        }
-      });
-
-      // Add an extra class to selected thumbnails.
-      $('.media-display-thumbnails :checkbox').each(function () {
-        var checkbox = $(this);
-        if (checkbox.is(':checked')) {
-          $(checkbox.parents('li').find('.media-item')).addClass('selected');
-        }
-
-        checkbox.bind('change.media', function () {
-          if (checkbox.is(':checked')) {
-            $(checkbox.parents('li').find('.media-item')).addClass('selected');
-          }
-          else {
-            $(checkbox.parents('li').find('.media-item')).removeClass('selected');
-          }
-        });
-      });
-    }
-
     // When any checkboxes are clicked on this form check to see if any are checked.
     // If any checkboxes are checked, show the edit options (@todo rename to edit-actions).
-    $('#media-admin :checkbox').bind('change', function () {
-      Drupal.behaviors.mediaAdmin.showOrHideEditOptions();
+    $('#media-browser :checkbox', context).once('media-admin', function() {
+      $(this).bind('change', Drupal.media.admin.showOrHideEditOptions).trigger('change');
     });
 
-    Drupal.behaviors.mediaAdmin.showOrHideEditOptions();
-  },
-
-  // Checks if any checkboxes on the form are checked, if so it will show the
-  // edit-options panel.
-  showOrHideEditOptions: function() {
-    var fieldset = $('#edit-options');
-    if (!$('#media-admin input[type=checkbox]:checked').size()) {
-      fieldset.slideUp('fast');
-    }
-    else {
-      fieldset.slideDown('fast');
-    }
+    // When the media browser closes successfully, refresh the page
+    // @todo: Turn this into an AJAX refresh of the current display
+    $('#media-admin-base').bind('mediaBrowserSelect', function() { location.reload(); });
   }
 };
 
+Drupal.media.admin.showOrHideEditOptions = function(event) {
+  event.stopPropagation();
+  var fieldset = $('#edit-options');
+  if (!$('#media-admin input[type=checkbox]:checked').length) {
+    fieldset.slideUp('fast');
+  }
+  else {
+    fieldset.slideDown('fast');
+  }
+};
 
 /**
  * JavaScript for the Media types administrative form.
@@ -143,7 +63,4 @@ Drupal.behaviors.mediaTypesAdmin = {
   }
 };
 
-
-
 })(jQuery);
-
diff --git a/js/media.browser.js b/js/media.browser.js
index 8d4ac13..e599d35 100644
--- a/js/media.browser.js
+++ b/js/media.browser.js
@@ -1,100 +1,23 @@
 
 (function ($) {
-namespace('Drupal.media.browser');
 
-Drupal.media.browser.selectedMedia = [];
-Drupal.media.browser.mediaAdded = function () {};
-Drupal.media.browser.selectionFinalized = function (selectedMedia) {
-  // This is intended to be overridden if a callee wants to be triggered
-  // when the media selection is finalized from inside the browser.
-  // This is used for the file upload form for instance.
-};
-
-Drupal.behaviors.experimentalMediaBrowser = {
-  attach: function (context) {
-    if (Drupal.settings.media.selectedMedia) {
-      Drupal.media.browser.selectMedia(Drupal.settings.media.selectedMedia);
-      // Fire a confirmation of some sort.
-      Drupal.media.browser.finalizeSelection();
-    }
-    $('#media-browser-tabset').tabs({
-      show: Drupal.media.browser.resizeIframe
+Drupal.behaviors.media_browser = {
+  attach: function (context, settings) {
+    // Bind a click behavior onto the pager links in the media browser.  The pager
+    // links aren't AJAX enabled themselves, so we add their query parameters
+    // to the submission of the active display's button and then trigger the
+    // AJAX event for that display.
+    $('.pager a', context).bind('click', function (event) {
+      event.preventDefault();
+      var display = $('#media-display-switches input.active');
+      var params = $.deparam.querystring($(this).attr('href'));
+
+      Drupal.ajax[display.attr('id')].options.data.page = params.page;
+      Drupal.ajax[display.attr('id')].element_settings.submit.page = params.page;
+
+      display.trigger(Drupal.ajax[display.attr('id')].event);
     });
-
-    $('.media-browser-tab').each( Drupal.media.browser.validateButtons );
-
-  }
-  // Wait for additional params to be passed in.
-};
-
-Drupal.media.browser.launch = function () {
-
-};
-
-Drupal.media.browser.validateButtons = function() {
-  // The media browser runs in an IFRAME. The Drupal.media.popups.mediaBrowser()
-  // function sets up the IFRAME and "OK" and "Cancel" buttons that are outside
-  // of the IFRAME, so that their click handlers can destroy the IFRAME while
-  // retaining information about what media items were selected. However,
-  // Drupal UI convention is to place all action buttons on the same "line"
-  // at the bottom of the form, so if the form within the IFRAME contains a
-  // "Submit" button or other action buttons, then the "OK" and "Cancel"
-  // buttons below the IFRAME break this convention and confuse the user.
-  // Therefore, we add "Submit" and "Cancel" buttons inside the IFRAME, and
-  // have their click action trigger the click action of the corresonding
-  // "OK" and "Cancel" buttons that are outside the IFRAME. media.css contains
-  // CSS rules that hide the outside buttons.
-  //
-  // We don't add a "Submit" button if the form already has one, since in these
-  // cases, another round-trip to the server is needed before the user's
-  // selection is finalized. For these cases, when the form's real Submit
-  // button is clicked, the server either returns another form for the user to
-  // fill out, or else a completion page that contains or sets the
-  // Drupal.media.browser.selectedMedia variable. If the latter, then
-  // Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad() auto-triggers the
-  // "OK" button action to finalize the selection and remove the IFRAME.
-  //
-  // @todo An alternate, less hacky solution would be most welcome.
-  if (!($('.form-submit', this).length > 0)) {
-    $('<a class="button fake-ok">' + Drupal.t('Submit') + '</a>').appendTo(this).bind('click', Drupal.media.browser.submit);
-    if (!($('.fake-cancel', this).length > 0)) {
-      $('<a class="button fake-cancel">' + Drupal.t('Cancel') + '</a>').appendTo(this).bind('click', Drupal.media.browser.submit);
-    }
-  } else if (!($('.fake-cancel', this).length > 0)) {
-    var parent = $('.form-actions', this);
-    if (!parent.length) {
-      parent = $('form > div', this);
-    }
-    $('<a class="button fake-cancel">' + Drupal.t('Cancel') + '</a>').appendTo(parent).bind('click', Drupal.media.browser.submit);
   }
 };
 
-Drupal.media.browser.submit = function () {
-  // @see Drupal.media.browser.validateButtons().
-  var buttons = $(parent.window.document.body).find('#mediaBrowser').parent('.ui-dialog').find('.ui-dialog-buttonpane button');
-  if ($(this).hasClass('fake-cancel')) {
-    buttons[1].click();
-  } else {
-    buttons[0].click();
-  }
-}
-
-Drupal.media.browser.selectMedia = function (selectedMedia) {
-  Drupal.media.browser.selectedMedia = selectedMedia;
-};
-
-Drupal.media.browser.finalizeSelection = function () {
-  if (!Drupal.media.browser.selectedMedia) {
-    throw new exception(Drupal.t('Cannot continue, nothing selected'));
-  }
-  else {
-    Drupal.media.browser.selectionFinalized(Drupal.media.browser.selectedMedia);
-  }
-};
-
-Drupal.media.browser.resizeIframe = function (event) {
-  var h = $('body').height();
-  $(parent.window.document).find('#mediaBrowser').height(h);
-};
-
 }(jQuery));
diff --git a/js/media.core.js b/js/media.core.js
deleted file mode 100644
index f99971c..0000000
--- a/js/media.core.js
+++ /dev/null
@@ -1,19 +0,0 @@
-
-/**
- * Creates a namespace.
- *
- * @return
- *   The created namespace object.
- */
-function namespace () {
-  var a=arguments, o=null, i, j, d;
-  for (i=0; i<a.length; i=i+1) {
-    d=a[i].split(".");
-    o=window;
-    for (j=0; j<d.length; j=j+1) {
-      o[d[j]]=o[d[j]] || {};
-      o=o[d[j]];
-    }
-  }
-  return o;
-};
diff --git a/js/media.dialog.js b/js/media.dialog.js
new file mode 100644
index 0000000..8692287
--- /dev/null
+++ b/js/media.dialog.js
@@ -0,0 +1,98 @@
+(function ($) {
+
+Drupal.media = Drupal.media || {};
+Drupal.media.dialog = Drupal.media.dialog || {};
+
+Drupal.behaviors.dialog = {
+  attach: function (context, settings) {
+    // Enable any dialog launchers
+    if (typeof settings.media.dialog != 'undefined' && typeof settings.media.dialog.launchers != 'undefined') {
+      for(var launcher in settings.media.dialog.launchers) {
+        $(launcher, context).once('media-launcher', function() {
+          var $this = $(this);
+          var element_settings = $.extend(Drupal.media.dialog.ajaxDefaults(), settings.media.dialog.launchers[launcher]);
+          var id = $this.attr('id');
+          if (!id) {
+            id = element_settings.base;
+            $this.attr('id', element_settings.base);
+          }
+          Drupal.ajax[id] = new Drupal.ajax(id, this, element_settings);
+        });
+      }
+    }
+  }
+};
+
+Drupal.media.dialog.ajaxDefaults = function () {
+  var element_settings = {};
+  element_settings.progress = {'type': 'throbber'};
+  element_settings.wrapper = 'page';
+  element_settings.method = 'append';
+  element_settings.url = Drupal.settings.media.browserUrl;
+  element_settings.event = 'click';
+  element_settings.submit = {
+    limit: 15
+  };
+  return element_settings;
+};
+
+Drupal.media.dialog.defaults = function () {
+  return {
+    modal: true,
+    width: '80%',
+    autoOpen: false,
+    resizable: false,
+    close: Drupal.media.dialog.close,
+    position: ['center', 50],
+    dialogClass: 'media-browser-dialog',
+    title: Drupal.t('Media browser')
+  };
+};
+
+Drupal.media.dialog.close = function () {
+  Drupal.detachBehaviors(this);
+  $(this).remove();
+};
+
+Drupal.media.dialog.tabs = function (wrapper, tab) {
+  $('#media-browser-tabset', wrapper).tabs({
+    show: 'yes',
+    selected: tab
+  });
+};
+
+Drupal.ajax.prototype.commands.mediaBrowserLaunch = function (ajax, response, status) {
+  // Create the dialog
+  var wrapper = $('<div id="media-browser-wrapper"></div>');
+  wrapper.dialog(Drupal.media.dialog.defaults());
+  wrapper.html(response.data);
+
+  // Add the tabs to the dialog if multiple plugins are enabled
+  Drupal.media.dialog.tabs(wrapper);
+
+  // Attach behaviors
+  Drupal.attachBehaviors(wrapper, ajax.settings);
+
+  // Open the dialog
+  wrapper.dialog('open');
+};
+
+Drupal.ajax.prototype.commands.mediaBrowserSelected = function (ajax, response, status) {
+  $('#media-browser-wrapper').dialog('close');
+  $('#' + response.trigger).trigger('mediaBrowserSelect', {files: response.files});
+};
+
+Drupal.ajax.prototype.commands.mediaBrowserMessages = function (ajax, response, status) {
+  var $messages = $('#media-browser-wrapper .messages');
+  if ($messages.length) {
+    $messages.replaceWith(response.data);
+  } else {
+    $('#media-browser-wrapper').prepend(response.data);
+  }
+};
+
+Drupal.ajax.prototype.commands.mediaBrowserDismiss = function (ajax, response, status) {
+  $('#media-browser-wrapper').dialog('close');
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/js/media.format_form.js b/js/media.format_form.js
deleted file mode 100644
index 4d892b1..0000000
--- a/js/media.format_form.js
+++ /dev/null
@@ -1,48 +0,0 @@
-
-/**
- *  @file
- *  Attach behaviors to formatter radio select when selecting a media's display
- *  formatter.
- */
-
-(function ($) {
-namespace('Drupal.media.formatForm');
-
-Drupal.media.mediaFormatSelected = {};
-
-Drupal.behaviors.mediaFormatForm = {
-  attach: function (context, settings) {
-    // Add "Submit" and "Cancel" buttons inside the IFRAME that trigger the
-    // behavior of the hidden "OK" and "Cancel" buttons that are outside the
-    // IFRAME. See Drupal.media.browser.validateButtons() for more details.
-    $('<a class="button fake-ok">Submit</a>').appendTo($('#media-format-form')).bind('click', Drupal.media.formatForm.submit);
-    $('<a class="button fake-cancel">Cancel</a>').appendTo($('#media-format-form')).bind('click', Drupal.media.formatForm.submit);
-
-    if (Drupal.settings.media_format_form.autosubmit) {
-      $('.button.fake-ok').click();
-    }
-  }
-};
-
-Drupal.media.formatForm.getOptions = function () {
-  // Get all the values
-  var ret = {}; $.each($('#media-format-form fieldset#edit-options *').serializeArray(), function (i, field) { ret[field.name] = field.value; });
-  return ret;
-};
-
-Drupal.media.formatForm.getFormattedMedia = function () {
-  var formatType = $("select#edit-format option:selected").val();
-  return { type: formatType, options: Drupal.media.formatForm.getOptions(), html: Drupal.settings.media.formatFormFormats[formatType] };
-};
-
-Drupal.media.formatForm.submit = function () {
-  // @see Drupal.behaviors.mediaFormatForm.attach().
-  var buttons = $(parent.window.document.body).find('#mediaStyleSelector').parent('.ui-dialog').find('.ui-dialog-buttonpane button');
-  if ($(this).hasClass('fake-cancel')) {
-    buttons[1].click();
-  } else {
-    buttons[0].click();
-  }
-}
-
-})(jQuery);
diff --git a/js/media.js b/js/media.js
index aa445b7..2f790c4 100644
--- a/js/media.js
+++ b/js/media.js
@@ -6,6 +6,8 @@
 
 (function ($) {
 
+Drupal.media = Drupal.media || {};
+
 /**
  * Loads media browsers and callbacks, specifically for media as a field.
  */
@@ -15,11 +17,6 @@ Drupal.behaviors.mediaElement = {
 
     // For each widget (in case of multi-entry)
     $('.media-widget', context).once('mediaBrowserLaunch', function () {
-      var options = settings.media.elements[this.id];
-      globalOptions = {};
-      if (options.global != undefined) {
-        var globalOptions = options.global;
-      }
       //options = Drupal.settings.media.fields[this.id];
       var fidField = $('.fid', this);
       var previewField = $('.preview', this);
@@ -30,27 +27,15 @@ Drupal.behaviors.mediaElement = {
         removeButton.css('display', 'inline-block');
       }
 
-      // When someone clicks the link to pick media (or clicks on an existing thumbnail)
-      $('.launcher', this).bind('click', function () {
-        // Launch the browser, providing the following callback function
-        // @TODO: This should not be an anomyous function.
-        Drupal.media.popups.mediaBrowser(function (mediaFiles) {
-          if (mediaFiles.length < 0) {
-            return;
-          }
-          var mediaFile = mediaFiles[0];
-          // Set the value of the filefield fid (hidden).
-          fidField.val(mediaFile.fid);
-          // Set the preview field HTML.
-          previewField.html(mediaFile.preview);
-          // Show the Remove button.
-          removeButton.show();
-        }, globalOptions);
-        return false;
+      // Bind the action for when media is selected
+      $(this).bind('mediaBrowserSelect', function(event, data) {
+        previewField.html(data.files[0].preview);
+        fidField.val(data.files[0].fid);
+        removeButton.css('display', 'inline-block');
       });
 
       // When someone clicks the Remove button.
-      $('.remove', this).bind('click', function () {
+      removeButton.bind('click', function () {
         // Set the value of the filefield fid (hidden).
         fidField.val(0);
         // Set the preview field HTML.
diff --git a/js/media.popups.js b/js/media.popups.js
deleted file mode 100644
index b3874f0..0000000
--- a/js/media.popups.js
+++ /dev/null
@@ -1,355 +0,0 @@
-
-/**
- * @file: Popup dialog interfaces for the media project.
- *
- * Drupal.media.popups.mediaBrowser
- *   Launches the media browser which allows users to pick a piece of media.
- *
- * Drupal.media.popups.mediaStyleSelector
- *  Launches the style selection form where the user can choose
- *  what format / style they want their media in.
- *
- */
-
-(function ($) {
-namespace('Drupal.media.popups');
-
-/**
- * Media browser popup. Creates a media browser dialog.
- *
- * @param {function}
- *          onSelect Callback for when dialog is closed, received (Array
- *          media, Object extra);
- * @param {Object}
- *          globalOptions Global options that will get passed upon initialization of the browser.
- *          @see Drupal.media.popups.mediaBrowser.getDefaults();
- *
- * @param {Object}
- *          pluginOptions Options for specific plugins. These are passed
- *          to the plugin upon initialization.  If a function is passed here as
- *          a callback, it is obviously not passed, but is accessible to the plugin
- *          in Drupal.settings.variables.
- *
- *          Example
- *          pluginOptions = {library: {url_include_patterns:'/foo/bar'}};
- *
- * @param {Object}
- *          widgetOptions Options controlling the appearance and behavior of the
- *          modal dialog.
- *          @see Drupal.media.popups.mediaBrowser.getDefaults();
- */
-Drupal.media.popups.mediaBrowser = function (onSelect, globalOptions, pluginOptions, widgetOptions) {
-  var options = Drupal.media.popups.mediaBrowser.getDefaults();
-  options.global = $.extend({}, options.global, globalOptions);
-  options.plugins = pluginOptions;
-  options.widget = $.extend({}, options.widget, widgetOptions);
-
-  // Create it as a modal window.
-  var browserSrc = options.widget.src;
-  // Params to send along to the iframe.  WIP.
-  var params = {};
-  $.extend(params, options.global);
-  params.plugins = options.plugins;
-
-  browserSrc += '&' + $.param(params);
-  var mediaIframe = Drupal.media.popups.getPopupIframe(browserSrc, 'mediaBrowser');
-  // Attach the onLoad event
-  mediaIframe.bind('load', options, options.widget.onLoad);
-  /**
-   * Setting up the modal dialog
-   */
-
-  var ok = 'OK';
-  var cancel = 'Cancel';
-  var notSelected = 'You have not selected anything!';
-
-  if (Drupal && Drupal.t) {
-    ok = Drupal.t(ok);
-    cancel = Drupal.t(cancel);
-    notSelected = Drupal.t(notSelected);
-  }
-
-  // @todo: let some options come through here. Currently can't be changed.
-  var dialogOptions = options.dialog;
-
-  dialogOptions.buttons[ok] = function () {
-    var selected = this.contentWindow.Drupal.media.browser.selectedMedia;
-    if (selected.length < 1) {
-      alert(notSelected);
-      return;
-    }
-    onSelect(selected);
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  dialogOptions.buttons[cancel] = function () {
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  Drupal.media.popups.setDialogPadding(mediaIframe.dialog(dialogOptions));
-  // Remove the title bar.
-  mediaIframe.parents(".ui-dialog").find(".ui-dialog-titlebar").remove();
-  Drupal.media.popups.overlayDisplace(mediaIframe.parents(".ui-dialog"));
-  return mediaIframe;
-};
-
-Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad = function (e) {
-  var options = e.data;
-  if (this.contentWindow.Drupal.media.browser.selectedMedia.length > 0) {
-    var ok = $(this).dialog('option', 'buttons')['OK'];
-    ok.call(this);
-    return;
-  }
-};
-
-Drupal.media.popups.mediaBrowser.getDefaults = function () {
-  return {
-    global: {
-      types: [], // Types to allow, defaults to all.
-      activePlugins: [] // If provided, a list of plugins which should be enabled.
-    },
-    widget: { // Settings for the actual iFrame which is launched.
-      src: Drupal.settings.media.browserUrl, // Src of the media browser (if you want to totally override it)
-      onLoad: Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad // Onload function when iFrame loads.
-    },
-    dialog: Drupal.media.popups.getDialogOptions()
-  };
-};
-
-Drupal.media.popups.mediaBrowser.finalizeSelection = function () {
-  var selected = this.contentWindow.Drupal.media.browser.selectedMedia;
-  if (selected.length < 1) {
-    alert(notSelected);
-    return;
-  }
-  onSelect(selected);
-  $(this).dialog("destroy");
-  $(this).remove();
-}
-
-/**
- * Style chooser Popup. Creates a dialog for a user to choose a media style.
- *
- * @param mediaFile
- *          The mediaFile you are requesting this formatting form for.
- *          @todo: should this be fid?  That's actually all we need now.
- *
- * @param Function
- *          onSubmit Function to be called when the user chooses a media
- *          style. Takes one parameter (Object formattedMedia).
- *
- * @param Object
- *          options Options for the mediaStyleChooser dialog.
- */
-Drupal.media.popups.mediaStyleSelector = function (mediaFile, onSelect, options) {
-  var defaults = Drupal.media.popups.mediaStyleSelector.getDefaults();
-  // @todo: remove this awful hack :(
-  defaults.src = defaults.src.replace('-media_id-', mediaFile.fid);
-  options = $.extend({}, defaults, options);
-  // Create it as a modal window.
-  var mediaIframe = Drupal.media.popups.getPopupIframe(options.src, 'mediaStyleSelector');
-  // Attach the onLoad event
-  mediaIframe.bind('load', options, options.onLoad);
-
-  /**
-   * Set up the button text
-   */
-  var ok = 'OK';
-  var cancel = 'Cancel';
-  var notSelected = 'Very sorry, there was an unknown error embedding media.';
-
-  if (Drupal && Drupal.t) {
-    ok = Drupal.t(ok);
-    cancel = Drupal.t(cancel);
-    notSelected = Drupal.t(notSelected);
-  }
-
-  // @todo: let some options come through here. Currently can't be changed.
-  var dialogOptions = Drupal.media.popups.getDialogOptions();
-
-  dialogOptions.buttons[ok] = function () {
-
-    var formattedMedia = this.contentWindow.Drupal.media.formatForm.getFormattedMedia();
-    if (!formattedMedia) {
-      alert(notSelected);
-      return;
-    }
-    onSelect(formattedMedia);
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  dialogOptions.buttons[cancel] = function () {
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  Drupal.media.popups.setDialogPadding(mediaIframe.dialog(dialogOptions));
-  // Remove the title bar.
-  mediaIframe.parents(".ui-dialog").find(".ui-dialog-titlebar").remove();
-  Drupal.media.popups.overlayDisplace(mediaIframe.parents(".ui-dialog"));
-  return mediaIframe;
-};
-
-Drupal.media.popups.mediaStyleSelector.mediaBrowserOnLoad = function (e) {
-};
-
-Drupal.media.popups.mediaStyleSelector.getDefaults = function () {
-  return {
-    src: Drupal.settings.media.styleSelectorUrl,
-    onLoad: Drupal.media.popups.mediaStyleSelector.mediaBrowserOnLoad
-  };
-};
-
-
-/**
- * Style chooser Popup. Creates a dialog for a user to choose a media style.
- *
- * @param mediaFile
- *          The mediaFile you are requesting this formatting form for.
- *          @todo: should this be fid?  That's actually all we need now.
- *
- * @param Function
- *          onSubmit Function to be called when the user chooses a media
- *          style. Takes one parameter (Object formattedMedia).
- *
- * @param Object
- *          options Options for the mediaStyleChooser dialog.
- */
-Drupal.media.popups.mediaFieldEditor = function (fid, onSelect, options) {
-  var defaults = Drupal.media.popups.mediaFieldEditor.getDefaults();
-  // @todo: remove this awful hack :(
-  defaults.src = defaults.src.replace('-media_id-', fid);
-  options = $.extend({}, defaults, options);
-  // Create it as a modal window.
-  var mediaIframe = Drupal.media.popups.getPopupIframe(options.src, 'mediaFieldEditor');
-  // Attach the onLoad event
-  // @TODO - This event is firing too early in IE on Windows 7,
-  // - so the height being calculated is too short for the content.
-  mediaIframe.bind('load', options, options.onLoad);
-
-  /**
-   * Set up the button text
-   */
-  var ok = 'OK';
-  var cancel = 'Cancel';
-  var notSelected = 'Very sorry, there was an unknown error embedding media.';
-
-  if (Drupal && Drupal.t) {
-    ok = Drupal.t(ok);
-    cancel = Drupal.t(cancel);
-    notSelected = Drupal.t(notSelected);
-  }
-
-  // @todo: let some options come through here. Currently can't be changed.
-  var dialogOptions = Drupal.media.popups.getDialogOptions();
-
-  dialogOptions.buttons[ok] = function () {
-    alert('hell yeah');
-    return "poo";
-
-    var formattedMedia = this.contentWindow.Drupal.media.formatForm.getFormattedMedia();
-    if (!formattedMedia) {
-      alert(notSelected);
-      return;
-    }
-    onSelect(formattedMedia);
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  dialogOptions.buttons[cancel] = function () {
-    $(this).dialog("destroy");
-    $(this).remove();
-  };
-
-  Drupal.media.popups.setDialogPadding(mediaIframe.dialog(dialogOptions));
-  // Remove the title bar.
-  mediaIframe.parents(".ui-dialog").find(".ui-dialog-titlebar").remove();
-  Drupal.media.popups.overlayDisplace(mediaIframe.parents(".ui-dialog"));
-  return mediaIframe;
-};
-
-Drupal.media.popups.mediaFieldEditor.mediaBrowserOnLoad = function (e) {
-
-};
-
-Drupal.media.popups.mediaFieldEditor.getDefaults = function () {
-  return {
-    // @todo: do this for real
-    src: '/media/-media_id-/edit?render=media-popup',
-    onLoad: Drupal.media.popups.mediaFieldEditor.mediaBrowserOnLoad
-  };
-};
-
-
-/**
- * Generic functions to both the media-browser and style selector
- */
-
-/**
- * Returns the commonly used options for the dialog.
- */
-Drupal.media.popups.getDialogOptions = function () {
-  return {
-    buttons: {},
-    dialogClass: 'media-wrapper',
-    modal: true,
-    draggable: false,
-    resizable: false,
-    minWidth: 600,
-    width: 800,
-    height: 550,
-    position: 'center',
-    overlay: {
-      backgroundColor: '#000000',
-      opacity: 0.4
-    }
-  };
-};
-
-/**
- * Created padding on a dialog
- *
- * @param jQuery dialogElement
- *  The element which has .dialog() attached to it.
- */
-Drupal.media.popups.setDialogPadding = function (dialogElement) {
-  // @TODO: Perhaps remove this hardcoded reference to height.
-  // - It's included to make IE on Windows 7 display the dialog without
-  //   collapsing. 550 is the height that displays all of the tab panes
-  //   within the Add Media overlay. This is either a bug in the jQuery
-  //   UI library, a bug in IE on Windows 7 or a bug in the way the
-  //   dialog is instantiated. Or a combo of the three.
-  //   All browsers except IE on Win7 ignore these defaults and adjust
-  //   the height of the iframe correctly to match the content in the panes
-  dialogElement.height(dialogElement.dialog('option', 'height'));
-  dialogElement.width(dialogElement.dialog('option', 'width'));
-};
-
-/**
- * Get an iframe to serve as the dialog's contents. Common to both plugins.
- */
-Drupal.media.popups.getPopupIframe = function (src, id, options) {
-  var defaults = {width: '800px', scrolling: 'no'};
-  var options = $.extend({}, defaults, options);
-
-  return $('<iframe class="media-modal-frame"/>')
-  .attr('src', src)
-  .attr('width', options.width)
-  .attr('id', id)
-  .attr('scrolling', options.scrolling);
-};
-
-Drupal.media.popups.overlayDisplace = function (dialog) {
-  if (parent.window.Drupal.overlay) {
-    var overlayDisplace = parent.window.Drupal.overlay.getDisplacement('top');
-    if (dialog.offset().top < overlayDisplace) {
-      dialog.css('top', overlayDisplace);
-    }
-  }
-}
-
-})(jQuery);
diff --git a/js/plugins/media.fromurl.js b/js/plugins/media.fromurl.js
index f618e23..372e0d9 100644
--- a/js/plugins/media.fromurl.js
+++ b/js/plugins/media.fromurl.js
@@ -1,6 +1,8 @@
 
 (function ($) {
-namespace('Drupal.media.browser.plugin');
+
+Drupal.media = Drupal.media || {};
+Drupal.media.browser = Drupal.media.browser || {};
 
 Drupal.media.browser.plugin.fromurl = function (mediaBrowser, options) {
   return {
diff --git a/js/plugins/media.library.css b/js/plugins/media.library.css
index dbd68dc..8b13789 100644
--- a/js/plugins/media.library.css
+++ b/js/plugins/media.library.css
@@ -1,23 +1 @@
 
-ul#media-browser-library-list {
-  list-style: none;
-  margin: -10px 0 0 0;
-  padding: 0px;
-  background-color: white;
-}
-
-#media-tab-library #container{
-  padding:20px 0;
-}
-
-#media-tab-library #scrollbox{
-  height: 300px;
-  overflow:auto;
-  overflow-x:hidden;
-}
-
-#scrollbox #status {
-  clear: both;
-  text-align: center;
-  margin-top: 10px;
-}
diff --git a/js/plugins/media.library.js b/js/plugins/media.library.js
index 856b4b5..4c4fa51 100644
--- a/js/plugins/media.library.js
+++ b/js/plugins/media.library.js
@@ -1,184 +1,41 @@
 
 (function ($) {
-namespace('Drupal.media.browser');
+
+Drupal.media = Drupal.media || {};
+Drupal.media.library = Drupal.media.library || {};
 
 Drupal.behaviors.mediaLibrary = {
   attach: function (context, settings) {
-    var library = new Drupal.media.browser.library(Drupal.settings.media.browser.library);
-    $('#media-browser-tabset').bind('tabsselect', function (event, ui) {
-      if (ui.tab.hash === '#media-tab-library') {
-        // Grab the parameters from the Drupal.settings object
-        var params = {};
-        for (var parameter in Drupal.settings.media.browser.library) {
-          params[parameter] = Drupal.settings.media.browser.library[parameter];
-        }
-        library.start($(ui.panel), params);
-        $('#scrollbox').bind('scroll', library, library.scrollUpdater);
-      }
-    });
-  }
-};
-
-Drupal.media.browser.library = function (settings) {
-  this.settings = Drupal.media.browser.library.getDefaults();
-  $.extend(this.settings, settings);
-
-  this.done = false; // Keeps track of if the last request for media returned 0 results.
-
-  this.cursor = 0; // keeps track of what the last requested media object was.
-  this.mediaFiles = []; // An array of loaded media files from the server.
-  this.selectedMediaFiles = [];
-};
-
-Drupal.media.browser.library.getDefaults = function () {
-  return {
-    emtpyMessage: "There is nothing in your media library.  Select the Upload tab above to add a file.",
-    limit: 15
-  };
-};
-
-Drupal.media.browser.library.prototype.start = function (renderElement, params) {
-  this.renderElement = renderElement;
-  this.params = params;
-  // Change the behavior dependent on multiselect
-  if (params.multiselect) {
-    this.clickFunction = this.multiSelect;
-  } else {
-    this.clickFunction = this.singleSelect;
-  }
-  this.loadMedia();
-};
-
-/**
- * Appends more media onto the list
- */
-Drupal.media.browser.library.prototype.loadMedia = function () {
-  var that = this;
-  $('#status').text('Loading...').show();
-  $.extend(this.params, {start: this.cursor, limit: this.settings.limit});
-
-  var gotMedia = function (data, status) {
-    $('#status').text('').hide();
-    if (data.media.length < that.params.limit) {
-      // We remove the scroll event listener, nothing more to load after this.
-      $('#scrollbox').unbind('scroll');
+    // If the parameter  to only allow single selection is passed, disable
+    // the ability to check multiple checkboxes.
+    if (settings.media.dialog.params.singleselect) {
+      $('#media-library-form input[type=checkbox]', context).once('single-select', function() {
+        $(this).bind('change', Drupal.media.library.singleSelect);
+      });
     }
-    that.mediaFiles = that.mediaFiles.concat(data.media);
-    that.render(that.renderElement);
-    // Remove the flag that prevents loading of more media
-    that.loading = false;
-  };
 
-  var errorCallback = function () {
-    alert(Drupal.t('Error getting media.'));
-  };
-
-  $.ajax({
-    url: this.settings.getMediaUrl,
-    type: 'GET',
-    dataType: 'json',
-    data: this.params,
-    error: errorCallback,
-    success: gotMedia
-  });
-};
-
-Drupal.media.browser.library.prototype.scrollUpdater = function (e){
-  if (!e.data.loading) {
-    var scrollbox = $('#scrollbox');
-    var scrolltop = scrollbox.attr('scrollTop');
-    var scrollheight = scrollbox.attr('scrollHeight');
-    var windowheight = scrollbox.attr('clientHeight');
-    var scrolloffset = 20;
-
-    if(scrolltop >= (scrollheight - (windowheight + scrolloffset))) {
-      // Set a flag so we don't make multiple concurrent AJAX calls
-      e.data.loading = true;
-      // Fetch new items
-      e.data.loadMedia();
-    }
+    // If we have the media display table, catch clicks on any row to prevent
+    // links being clicked.
+    $('.media-display-table tbody tr', context).bind('click', function(event) {
+      event.preventDefault();
+      var checkbox = $(this).find('input[type=checkbox]');
+      var value = !checkbox.attr('checked');
+      checkbox.attr('checked', value).change();
+      if(value) {
+        $(this).addClass('selected');
+      }
+    });
   }
 };
 
 /**
- * Fetches the next media object and increments the cursor.
+ * Unchecks all checkboxes that aren't the originators of the event.
  */
-Drupal.media.browser.library.prototype.getNextMedia = function () {
-  if (this.cursor >= this.mediaFiles.length) {
-    return false;
-  }
-  var ret = this.mediaFiles[this.cursor];
-  this.cursor += 1;
-  return ret;
-};
-
-Drupal.media.browser.library.prototype.render = function (renderElement) {
-
-  if (this.mediaFiles.length < 1) {
-    $('<div id="media-empty-message" class="media-empty-message"></div>').appendTo(renderElement)
-      .html(this.emptyMessage);
-    return;
-  }
-  else {
-    var mediaList = $('#media-browser-library-list', renderElement);
-    // If the list doesn't exist, bail.
-    if (mediaList.length === 0) {
-      throw('Cannot continue, list element is missing');
-    }
-  }
-
-  while (this.cursor < this.mediaFiles.length) {
-    var mediaFile = this.getNextMedia();
-
-    var data = {};
-    data.obj = this;
-    data.file = mediaFile;
-
-    var listItem = $('<li></li>').appendTo(mediaList)
-      .attr('id', 'media-item-' + mediaFile.fid)
-      .html(mediaFile.preview)
-      .bind('click', data, this.clickFunction);
-  }
-};
-
-Drupal.media.browser.library.prototype.mediaSelected = function (media) {
-  Drupal.media.browser.selectMedia(media);
-};
-
-Drupal.media.browser.library.prototype.singleSelect = function (event) {
-  var lib = event.data.obj;
-  var file = event.data.file;
-  event.preventDefault();
-  event.stopPropagation();
-
-  $('.media-item').removeClass('selected');
-  $('.media-item', $(this)).addClass('selected');
-  lib.mediaSelected([event.data.file]);
-  return false;
-}
-
-Drupal.media.browser.library.prototype.multiSelect = function (event) {
-  var lib = event.data.obj
-  var file = event.data.file;
+Drupal.media.library.singleSelect = function (event) {
   event.preventDefault();
-  event.stopPropagation();
-
-  // Turn off or on the selection of this item
-  $('.media-item', $(this)).toggleClass('selected');
-
-  // Add or remove the media file from the array
-  var index = $.inArray(file, lib.selectedMediaFiles);
-  if (index == -1) {
-    // Media file isn't selected, add it
-    lib.selectedMediaFiles.push(file);
-  } else {
-    // Media file has previously been selected, remove it
-    lib.selectedMediaFiles.splice(index, 1);
-  }
-
-  // Pass the array of selected media files to the invoker
-  lib.mediaSelected(lib.selectedMediaFiles);
-  return false;
+  var checkboxes = $('#media-library-form input[type=checkbox]:checked').not(this);
+  checkboxes.attr('checked', false);
+  $('#media-library-form .selected').removeClass('selected');
 }
 
 }(jQuery));
diff --git a/js/plugins/media.table.js b/js/plugins/media.table.js
new file mode 100644
index 0000000..c74b978
--- /dev/null
+++ b/js/plugins/media.table.js
@@ -0,0 +1,22 @@
+(function ($) {
+
+Drupal.behaviors.mediaTable = {
+  attach: function (context) {
+    // The sorting links in the table header aren't AJAX enabled so we capture
+    // their click events and pass on their query parameters to the active
+    // display's button.
+    $('.media-display-table th a', context).bind('click', function (event) {
+      event.preventDefault();
+      var display = $('#media-display-switches input.active');
+      var query = $(this).attr('href').split('?')[1];
+      var url = Drupal.ajax[display.attr('id')].options.url.split('?')[0];
+
+      Drupal.ajax[display.attr('id')].options.url = url + '?' + query;
+      Drupal.ajax[display.attr('id')].element_settings.url = url + '?' + query;
+
+      display.trigger(Drupal.ajax[display.attr('id')].event);
+    });
+  }
+}
+
+})(jQuery);
\ No newline at end of file
diff --git a/js/plugins/media.thumbnails.js b/js/plugins/media.thumbnails.js
new file mode 100644
index 0000000..8aa5925
--- /dev/null
+++ b/js/plugins/media.thumbnails.js
@@ -0,0 +1,196 @@
+(function ($) {
+
+Drupal.media = Drupal.media || {};
+Drupal.media.thumbnails = Drupal.media.thumbnails || {};
+
+Drupal.behaviors.mediaThumbnails = {
+  attach: function (context, settings) {
+    // Bind the behaviors for selecting all and none
+    $('.media-thumbnails-select').once('select-all-none', function() {
+      $('.select', this).bind('click', Drupal.media.thumbnails.selectAll);
+      $('.deselect', this).bind('click', Drupal.media.thumbnails.selectNone);
+    });
+
+    // Attach a behavior to visually change the thumbnail box when it is selected.
+    $('.media-item-wrapper :checkbox').bind('change', Drupal.media.thumbnails.itemChange).trigger('change');
+
+    // Attach select box functionality.
+    if (typeof settings.media.dialog.params == 'undefined' || !settings.media.dialog.params.singleselect) {
+      $('#media-browser').once('drag-select', function() {
+        $(this).bind('mousedown', Drupal.media.thumbnails.boxSelectStart);
+      });
+    } else {
+      $('.media-item', context).bind('click', Drupal.media.thumbnails.itemClick);
+    }
+  }
+}
+
+Drupal.media.thumbnails.selectAll = function (event) {
+  $('.media-display-thumbnails :checkbox').attr('checked', true).change();
+  return false;
+};
+
+Drupal.media.thumbnails.selectNone = function (event) {
+  $('.media-display-thumbnails :checkbox').attr('checked', false).change();
+  return false;
+};
+
+Drupal.media.thumbnails.itemClick = function (event) {
+  if ($(event.target).is('a img, a')) {
+    return;
+  }
+  var checkbox = $(this).parent().find(':checkbox');
+  checkbox.attr('checked', !checkbox.attr('checked')).trigger('change');
+};
+
+Drupal.media.thumbnails.itemChange = function (event) {
+  // Add an extra class to selected thumbnails.
+  var $target = $(event.target);
+  if ($target.attr('checked')) {
+    $target.parents('.media-item-wrapper').find('.media-item').addClass('selected');
+  } else {
+    $target.parents('.media-item-wrapper').find('.media-item').removeClass('selected');
+  }
+};
+
+/**
+ * Capture mousedown to start drawing the selection box.  However, only do this
+ * if the mousedown is not on a checkbox or link.  Those behaviors should
+ * function normally.
+ */
+Drupal.media.thumbnails.boxSelectStart = function (event) {
+  var target = $(event.target);
+  if (event.button === 0 && !target.is('input[type=checkbox]') && !target.is('a')) {
+    event.preventDefault();
+
+    var box = $('<div id="select-box"></div>');
+    box.appendTo('body');
+
+    var offset = {
+      left: event.pageX,
+      top: event.pageY
+    };
+    box.offset(offset);
+
+    var data = {
+      box: box,
+      x: offset.left,
+      y: offset.top
+    };
+
+    $('body')
+      .bind('mousemove', data, Drupal.media.thumbnails.boxSelectDrag)
+      .bind('mouseup', data, Drupal.media.thumbnails.boxSelectStop);
+  }
+};
+
+/**
+ * As the mouse is moved around the page, redraw the select box.
+ */
+Drupal.media.thumbnails.boxSelectDrag = function (event) {
+  var box = event.data.box;
+  var width = event.pageX-event.data.x;
+  var height = event.pageY-event.data.y;
+  var offset = {
+    left: event.data.x,
+    top: event.data.y
+  };
+
+  // Offset is always left to right, top to bottom so negative deltas from
+  // the origin point need to be converted so that the select box appears to
+  // draw from the origin point of the initial mousedown event.
+  if (width < 0) {
+    width = width*-1;
+    offset.left = event.pageX;
+  }
+  if (height < 0) {
+    height = height*-1;
+    offset.top = event.pageY;
+  }
+
+  box.offset(offset).width(width).height(height);
+};
+
+/**
+ * When the mouse is released the items intersected with the select box need
+ * to be checked and all other items unchecked.
+ */
+Drupal.media.thumbnails.boxSelectStop = function (event) {
+  $(this).unbind('mousemove mouseup');
+
+  // Deselect any other items unless the shift or ctrl keys are pressed
+  if (!event.shiftKey && !event.ctrlKey) {
+    $('.media-item-wrapper :checkbox:checked').attr('checked', false);
+    $('.media-item-wrapper .selected').removeClass('selected');
+  }
+
+  // Check to see if any items intersected with the select box.
+  $('.media-item').each(function() {
+    Drupal.media.thumbnails.checkIntersections($(this), event.data.box, event.ctrlKey);
+  });
+
+  // In case none were selected, trigger a change event to hide the operations.
+  if (!$('.media-item-wrapper :checkbox:checked').length) {
+    $('.media-item-wrapper:first-child :checkbox').change();
+  }
+
+  event.data.box.remove();
+};
+
+/**
+ * This function checks to see if any portion of any of the media items was
+ * within the area of the select box. If toggle is true, the items selected
+ * will toggle their checked status.
+ */
+Drupal.media.thumbnails.checkIntersections = function (item, box, toggle) {
+  var itemOffset = Drupal.media.thumbnails.getBounds(item);
+  var boxOffset = Drupal.media.thumbnails.getBounds(box);
+
+  var x = false;
+  // Check left
+  if (itemOffset.left >= boxOffset.left && itemOffset.left <= boxOffset.right) {
+    x = true;
+  }
+  // Check right
+  if (itemOffset.right >= boxOffset.left && itemOffset.right <= boxOffset.right) {
+    x = true;
+  }
+  // Check within
+  if (boxOffset.left > itemOffset.left && boxOffset.right < itemOffset.right) {
+    x = true;
+  }
+
+  var y = false;
+  // Check top
+  if (itemOffset.top >= boxOffset.top && itemOffset.top <= boxOffset.bottom) {
+    y = true;
+  }
+  // Check bottom
+  if (itemOffset.bottom >= boxOffset.top && itemOffset.bottom <= boxOffset.bottom) {
+    y = true;
+  }
+  // Check within
+  if (boxOffset.top > itemOffset.top && boxOffset.bottom < itemOffset.bottom) {
+    y = true;
+  }
+
+  if (x && y) {
+    var checkbox = item.parent().find(':checkbox');
+    var value = toggle ? !checkbox.attr('checked') : true;
+    checkbox.attr('checked', value).trigger('change');
+  }
+};
+
+/**
+ * This returns an object with the x and y values for the sides of the element
+ * passed as an argument.
+ */
+Drupal.media.thumbnails.getBounds = function (element) {
+  var elementOffset = element.offset();
+  elementOffset.right = elementOffset.left + element.width();
+  elementOffset.bottom = elementOffset.top + element.height();
+
+  return elementOffset;
+}
+
+})(jQuery);
\ No newline at end of file
diff --git a/js/plugins/media.upload.js b/js/plugins/media.upload.js
index 6f0117d..895eafd 100644
--- a/js/plugins/media.upload.js
+++ b/js/plugins/media.upload.js
@@ -1,6 +1,8 @@
 
 (function ($) {
-namespace('Drupal.media.browser.plugin');
+
+Drupal.media = Drupal.media || {};
+Drupal.media.browser = Drupal.media.browser || {};
 
 Drupal.media.browser.plugin.upload = function (mediaBrowser, options) {
   return {
diff --git a/js/plugins/media.upload_multiple.js b/js/plugins/media.upload_multiple.js
index 3c5d189..d3d24f5 100644
--- a/js/plugins/media.upload_multiple.js
+++ b/js/plugins/media.upload_multiple.js
@@ -1,17 +1,42 @@
+(function ($) {
+
 Drupal.behaviors.mediaUploadMultiple = {};
 
 Drupal.behaviors.mediaUploadMultiple.attach = function (context, settings) {
   // When the plupload element initializes, it expands the size of the elements
   // it has created, so we need to resize the browser iframe after it's done.
-  var uploader = jQuery('#edit-upload').pluploadQueue();
-  if (uploader) {
-    // Handle the case in which the uploader has already finished initializing.
-    Drupal.media.browser.resizeIframe();
-    // Handle the case in which the uploader has not yet initialized.
-    uploader.bind("PostInit", Drupal.media.browser.resizeIframe);
-
+  $('#media-add-upload-multiple').once('media-plupload', function() {
+    var uploader = $('.plupload-element').pluploadQueue();
+    var submit = $('#media-add-upload-multiple input[name=process]');
+    // Catch the upload finished event so that we can autosubmit the form.
+    uploader.bind('UploadProgress', function(up, files) {
+      if (uploader.total.uploaded == uploader.files.length) {
+        // The plupload is finished, trigger a submission.
+        submit.click();
+      }
+    });
     uploader.bind('StateChanged', Drupal.behaviors.mediaUploadMultiple.submit);
-  }
+
+    // The positioning of the file input doesn't always match the add file link
+    // so we trigger the click here.
+    $('.plupload_add').bind('click', function() {
+      $('#media-add-upload-multiple input[multiple]', context).click();
+    });
+
+      // Alter the text and behavior of the form submission button.
+    submit.val(Drupal.t('Start upload'));
+    submit.unbind('click').bind('click', function(event) {
+      event.preventDefault();
+      if (uploader.total.uploaded == uploader.files.length) {
+        // The plupload is done, fire off the AJAX submission.
+        Drupal.ajax[$(this).attr('id')].eventResponse($(this), event);
+      } else if (uploader.state == plupload.STOPPED) {
+        // The plupload hasn't been started, start it.
+        uploader.start();
+      }
+    });
+  });
+
 };
 
 Drupal.behaviors.mediaUploadMultiple.submit = function (uploader, file) {
@@ -19,3 +44,5 @@ Drupal.behaviors.mediaUploadMultiple.submit = function (uploader, file) {
     jQuery('#media-add-upload-multiple .form-submit').val(Drupal.t('Loading...'));
   }
 };
+
+}(jQuery));
diff --git a/js/wysiwyg-media.js b/js/wysiwyg-media.js
index acf3e08..c2a731d 100644
--- a/js/wysiwyg-media.js
+++ b/js/wysiwyg-media.js
@@ -8,6 +8,11 @@
 
 Drupal.media = Drupal.media || {};
 
+Drupal.ajax.prototype.commands.mediaFormatSelected = function (ajax, response, status) {
+  Drupal.wysiwyg.plugins.media.insertMediaFile(response.file, response.viewMode, response.formattedMedia, {}, response.instanceId);
+  $('#media-browser-wrapper').dialog('close');
+};
+
 // Define the behavior.
 Drupal.wysiwyg.plugins.media = {
 
@@ -25,9 +30,7 @@ Drupal.wysiwyg.plugins.media = {
    */
   invoke: function (data, settings, instanceId) {
     if (data.format == 'html') {
-      Drupal.media.popups.mediaBrowser(function (mediaFiles) {
-        Drupal.wysiwyg.plugins.media.mediaBrowserOnSelect(mediaFiles, instanceId);
-      }, settings['global']);
+      $('#' + instanceId).trigger('launchBrowser');
     }
   },
 
@@ -35,17 +38,20 @@ Drupal.wysiwyg.plugins.media = {
    * Respond to the mediaBrowser's onSelect event.
    * @TODO: Debug calls from this are never called. What's its function?
    */
-  mediaBrowserOnSelect: function (mediaFiles, instanceId) {
-    var mediaFile = mediaFiles[0];
-    var options = {};
-    Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) {
-      Drupal.wysiwyg.plugins.media.insertMediaFile(mediaFile, formattedMedia.type, formattedMedia.html, formattedMedia.options, Drupal.wysiwyg.instances[instanceId]);
-    }, options);
+  mediaBrowserOnSelect: function (event, data) {
+    var mediaFile = data.files[0];
+    // Need to figure out some way of launching the format form
+    var instanceId = $(this).attr('id');
+
+    Drupal.ajax[instanceId+'-ff'].element_settings.url = Drupal.settings.basePath + 'media/' + mediaFile.fid + '/format-form';
+    Drupal.ajax[instanceId+'-ff'].options.url = Drupal.settings.basePath + 'media/' + mediaFile.fid + '/format-form';
+
+    $(this).trigger('launchFF');
 
     return;
   },
 
-  insertMediaFile: function (mediaFile, viewMode, formattedMedia, options, wysiwygInstance) {
+  insertMediaFile: function (mediaFile, viewMode, formattedMedia, options, instanceId) {
 
     this.initializeTagMap();
     // @TODO: the folks @ ckeditor have told us that there is no way
@@ -62,7 +68,7 @@ Drupal.wysiwyg.plugins.media = {
     var inlineTag = Drupal.wysiwyg.plugins.media.createTag(imgElement);
     // Add it to the tag map in case the user switches input formats
     Drupal.settings.tagmap[inlineTag] = toInsert;
-    wysiwygInstance.insert(toInsert);
+    CKEDITOR.instances[instanceId].insertHtml(toInsert);
   },
 
   /**
@@ -158,6 +164,19 @@ Drupal.wysiwyg.plugins.media = {
         }
       }
     }
+    // Attach behaviors for dialogs
+    if (typeof Drupal.ajax[instanceId] == 'undefined') {
+      $('#' + instanceId).bind('mediaBrowserSelect', Drupal.wysiwyg.plugins.media.mediaBrowserOnSelect);
+      var element_settings = Drupal.media.dialog.ajaxDefaults();
+      element_settings.event = 'launchBrowser';
+      settings.trigger = instanceId;
+      element_settings.submit = settings;
+      Drupal.ajax[instanceId] = new Drupal.ajax(instanceId, $('#' + instanceId), element_settings);
+
+      element_settings.event = 'launchFF';
+      Drupal.ajax[instanceId+'-ff'] = new Drupal.ajax(instanceId, $('#' + instanceId), element_settings);
+    }
+
     return content;
   },
 
diff --git a/media.api.php b/media.api.php
index b802a2c..00335eb 100644
--- a/media.api.php
+++ b/media.api.php
@@ -1,76 +1,6 @@
 <?php
 
 /**
- * @file
- * Hook provided by the media module.
- */
-
-/**
- * Return an array of plugins for the media browser.
- *
- * Implementors are expected to return a renderable element.
- *
- * Each element will be a jQuery tab on the media browser.
- *
- * Some elements are special:
- *  - #title: The title that goes on the tab
- *  - #settings: Drupal.settings.media.browser.$key (where key is the array key).
- *  - #callback: If provided, will make the tab an "ajax" tab.
- *
- * Example:
- *   $plugins['library'] = array(
- *  '#title' => t('Library'),
- *  '#attached' => array(
- *    'js' => array(
- *       $path . '/js/plugins/media.library.js',
- *     ),
- *   ),
- *   '#settings' => array(
- *     'viewMode' => 'thumbnails',
- *     'getMediaUrl' => url('media/browser/list'),
- *   ),
- *   '#markup' => '<div> Library goes here</div>',
- * );
- *
- * @param $plugin_name
- *  The name of the plugin to view
- *
- * @param $params
- *  An array of parameters which came in is $_GET['params'].
- *  The expected parameters is still being defined.
- *   - types: Array of media types to support
- *   - multiselect: Boolean enabling or disabling multiselect
- *
- * @return
- *  Renderable array.
- */
-function hook_media_browser_plugin_view($plugin_name, $params) {
-
-}
-
-/**
- * Returns a list of plugins for the media browser.
- *
- * Plugins are defined in a multi-dimensional associative
- * array format with the following keys:
- *
- * - #weight (optional): Weight of the plugin in relation to other plugins
- *  when being displayed, e.g. tabs in the browser.
- *
- * @example
- * <code>
- * array(
- *  'unique_plugin_name' => array(
- *     '#weight' => 42,
- *   ),
- * );
- * </code>
- */
-function hook_media_browser_plugin_info() {
-
-}
-
-/**
  * Returns an array of operations which can be taken on media items.
  *
  * This is used on the admin/content/media page so users can select multiple
diff --git a/media.module b/media.module
index 3f1f617..a6b4b77 100644
--- a/media.module
+++ b/media.module
@@ -118,6 +118,19 @@ function media_menu() {
     'file' => 'includes/media.admin.inc',
   );
 
+  $items['admin/content/media/add'] = array(
+    'title' => 'Add media',
+    'description' => 'Import files into your media library.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('media_add_upload'),
+    'file' => 'includes/media.pages.inc',
+    'access arguments' => array('import media'),
+    'type' => MENU_LOCAL_ACTION,
+    'options' => array(
+      'attributes' => array('id' => 'add-media'),
+    ),
+  );
+
   $items['media/browser'] = array(
     'title' => 'Media browser',
     'description' => 'Media Browser for picking media and uploading new media',
@@ -126,55 +139,52 @@ function media_menu() {
     'access arguments' => array('view'),
     'type' => MENU_CALLBACK,
     'file' => 'includes/media.browser.inc',
-    'theme callback' => 'media_dialog_get_theme_name',
+    'delivery callback' => 'ajax_deliver',
+    'theme callback' => 'ajax_base_page_theme',
   );
 
-  // A testbed to try out the media browser with different launch commands.
-  $items['media/browser/testbed'] = array(
-    'title' => 'Media Browser test',
-    'description' => 'Make it easier to test media browser',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('media_browser_testbed'),
-    'access arguments' => array('administer media'),
+  $items['media/browser/cancel'] = array(
+    'title' => 'Close the media browser',
+    'page callback' => 'media_browser_dismiss',
+    'delivery callback' => 'ajax_deliver',
+    'access callback' => TRUE,
+    'theme callback' => 'ajax_base_page_theme',
     'type' => MENU_CALLBACK,
     'file' => 'includes/media.browser.inc',
   );
 
-
-  /**
-   * Browser callbacks
-   * @var unknown_type
-   */
-  $items['media/browser/list'] = array(
-    'title' => 'Media browser list',
-    'description' => 'Ajax Callback for getting media',
-    'page callback' => 'media_browser_list',
+  $items['media/browser/nojs/%'] = array(
+    'title' => 'Media browser display type',
+    'page callback' => 'media_browser_set_display',
+    'page arguments' => array(3, FALSE),
     'access callback' => 'media_access',
     'access arguments' => array('view'),
     'type' => MENU_CALLBACK,
     'file' => 'includes/media.browser.inc',
   );
 
-  $items['media/browser/library'] = array(
-    'title' => 'Media browser library',
-    'description' => 'Media Browser for picking media and uploading new media',
-    'page callback' => 'media_browser_library',
+  $items['media/browser/ajax/%'] = array(
+    'title' => 'Media browser display type',
+    'page callback' => 'media_browser_set_display',
+    'page arguments' => array(3, TRUE),
     'access callback' => 'media_access',
     'access arguments' => array('view'),
     'type' => MENU_CALLBACK,
     'file' => 'includes/media.browser.inc',
+    'delivery callback' => 'ajax_deliver',
   );
 
   $items['media/%file/format-form'] = array(
     'title' => 'Style selector',
     'description' => 'Choose a format for a piece of media',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('media_format_form', 1),
+    'page callback' => 'media_format',
+    'page arguments' => array(1),
     'access callback' => 'media_access',
     'access arguments' => array('view'),
     'weight' => 0,
     'file' => 'includes/media.filter.inc',
-    'theme callback' => 'media_dialog_get_theme_name',
+    'delivery callback' => 'ajax_deliver',
+    'theme callback' => 'ajax_base_page_theme',
   );
 
   $items['media/%file'] = array(
@@ -225,9 +235,6 @@ function media_menu() {
     'file' => 'includes/media.pages.inc',
   );
 
-  $items['admin/content/media/browser'] = $items['media/browser'];
-  $items['admin/content/media/browser']['type'] = MENU_LOCAL_ACTION;
-
   $items['media/js'] = array(
     'page callback' => 'media_preview_ajax',
     'access callback' => 'media_access',
@@ -317,13 +324,6 @@ function media_theme() {
       'file' => 'includes/media.theme.inc',
     ),
 
-    // Dialog page.
-    'media_dialog_page' => array(
-      'render element' => 'page',
-      'template' => 'templates/media-dialog-page',
-      'file' => 'includes/media.theme.inc',
-    ),
-
     //
     'media_element' => array(
       'render element' => 'element',
@@ -334,6 +334,11 @@ function media_theme() {
       'variables' => array('file' => NULL, 'attributes' => array()),
       'file' => 'includes/media.theme.inc',
     ),
+
+    'media_browser_display_switch' => array(
+      'render element' => 'element',
+      'file' => 'includes/media.theme.inc',
+    ),
   );
 }
 
@@ -407,27 +412,6 @@ function media_styles_style_flush($style) {
 }
 
 /**
- * Implements hook_page_alter().
- *
- * This is used to use our alternate template when ?render=media-popup is passed
- * in the URL.
- */
-function media_page_alter(&$page) {
-  if (isset($_GET['render']) && $_GET['render'] == 'media-popup') {
-    $page['#theme'] = 'media_dialog_page';
-    // temporary fix while awaiting fix for 914786
-    if (module_exists('admin_menu')) {
-      admin_menu_suppress();
-    }
-    foreach (element_children($page) as $key) {
-      if ($key != 'content') {
-        unset($page[$key]);
-      }
-    }
-  }
-}
-
-/**
  * Implements hook_element_info_alter().
  */
 function media_element_info_alter(&$types) {
@@ -449,8 +433,8 @@ function media_media_display_types() {
     'description' => t('Display as a list.'),
     'icon' => $path . '/images/display-list.png',
     'icon_active' => $path . '/images/display-list-active.png',
-    'callback' => 'media_admin_list',
-    'file' => drupal_get_path('module', 'media') . '/includes/media.admin.inc',
+    'callback' => 'media_browser_table',
+    'file' => drupal_get_path('module', 'media') . '/includes/media.browser.inc',
   );
 
   $display_types['thumbnails'] = array(
@@ -458,8 +442,8 @@ function media_media_display_types() {
     'description' => t('Display as thumbnails.'),
     'icon' => $path . '/images/display-thumbnails.png',
     'icon_active' => $path . '/images/display-thumbnails-active.png',
-    'callback' => 'media_admin_thumbnails',
-    'file' => drupal_get_path('module', 'media') . '/includes/media.admin.inc',
+    'callback' => 'media_browser_thumbnails',
+    'file' => drupal_get_path('module', 'media') . '/includes/media.browser.inc',
   );
 
   return $display_types;
@@ -599,7 +583,6 @@ function media_library() {
   $libraries['media_base'] = array(
     'title' => 'Media base',
     'js' => array(
-      $path . '/js/media.core.js' => array('group' => JS_LIBRARY, 'weight' => - 5),
       $path . '/js/util/json2.js' => array('group' => JS_LIBRARY),
       $path . '/js/util/ba-debug.min.js' => array('group' => JS_LIBRARY),
     ),
@@ -615,32 +598,16 @@ function media_library() {
   $libraries['media_browser'] = array(
     'title' => 'Media Browser popup libraries',
     'js' => array(
-      $path . '/js/media.popups.js' => array('group' => JS_DEFAULT),
+      $path . '/js/media.dialog.js' => array('group' => JS_DEFAULT),
     ),
     'dependencies' => array(
       array('media', 'media_base'),
       array('system', 'ui.resizable'),
       array('system', 'ui.draggable'),
       array('system', 'ui.dialog'),
-    ),
-  );
-
-  /**
-   * Resources needed in the media browser itself.
-   */
-  $libraries['media_browser_page'] = array(
-    'title' => 'Media browser',
-    'js' => array(
-      $path . '/js/media.browser.js'  => array('group' => JS_DEFAULT),
-    ),
-    'css' => array(
-      $path . '/css/media.browser.css' => array('group' => CSS_DEFAULT),
-    ),
-    'dependencies' => array(
-      array('media', 'media_base'),
       array('system', 'ui.tabs'),
-      array('system', 'ui.draggable'),
-      array('system', 'ui.dialog'),
+      array('system', 'drupal.ajax'),
+      array('system', 'jquery.form'),
     ),
   );
 
@@ -852,9 +819,38 @@ function media_element_process(&$element, &$form_state, $form) {
     '#type' => 'item',
     '#markup' => $markup,
     '#prefix' => '<div class="preview launcher">',
-    '#suffix' => '</div><a class="button launcher" href="#">' . t(media_variable_get('field_select_media_text')) . '</a><a class="button remove" href="#">' . t(media_variable_get('field_remove_media_text')) . '</a>',
+    '#suffix' => '</div>',
   );
 
+  $element['links'] = array(
+    'launcher' => array(
+      '#type' => 'link',
+      '#href' => '',
+      '#title' => t(media_variable_get('field_select_media_text')),
+      '#attributes' => array(
+        'class' => array('button'),
+      ),
+      '#ajax' => array(
+        'path' => 'media/browser',
+        'submit' => array(
+          'trigger' => $element['#id'],
+          'limit' => 48,
+          'singleselect' => TRUE,
+        ),
+      ),
+    ),
+    'remove' => array(
+      '#type' => 'link',
+      '#title' => t(media_variable_get('field_remove_media_text')),
+      '#href' => '',
+      '#attributes' => array(
+        'class' => array('button remove'),
+      ),
+    ),
+  );
+
+  $element['links']['launcher']['#ajax']['submit']['types'] = $element['#media_options']['global']['types'];
+
   /**
    * This section handles fields on media when media is added as a field.
    * It is pretty unpolished, so hiding it for now.
@@ -891,18 +887,6 @@ function media_element_process(&$element, &$form_state, $form) {
 
   // Media browser attach code.
   $element['#attached']['js'][] = drupal_get_path('module', 'media') . '/js/media.js';
-
-  $settings = array();
-  $setting['media']['elements'][$element['#id']] = $element['#media_options'];
-
-  $element['#attached']['js'][] = array(
-    'type' => 'setting',
-    'data' => $setting,
-  );
-
-  // hmm... Might need to think about this.
-  // All settings would likely apply to all media in a multi-value, but what about passing the existing fid?
-
   module_load_include('inc', 'media', 'includes/media.browser');
   media_attach_browser_js($element);
 
@@ -1045,8 +1029,34 @@ function media_ctools_plugin_api($owner, $api) {
     'file_entity' => array(
       'file_default_displays' => 1,
     ),
+    'media' => array(
+      'browser' => 1,
+    ),
   );
   if (isset($api_versions[$owner][$api])) {
     return array('version' => $api_versions[$owner][$api]);
   }
 }
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ *
+ * This function tells the media browser where to find browser plugins.
+ */
+function media_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'media' && $plugin == 'browser') {
+    return 'browser';
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_type().
+ */
+function media_ctools_plugin_type() {
+  $plugins = array(
+    'browser' => array(
+      'weight' => 0,
+    ),
+  );
+  return $plugins;
+}
diff --git a/modules/media_internet/browser/media_internet.inc b/modules/media_internet/browser/media_internet.inc
new file mode 100644
index 0000000..cfe64a0
--- /dev/null
+++ b/modules/media_internet/browser/media_internet.inc
@@ -0,0 +1,159 @@
+<?php
+$plugin = array(
+  'weight' => 0,
+  'callback' => 'media_internet_add',
+  'title' => t('Web'),
+  'access callback' => 'media_internet_browser_access',
+);
+
+/**
+ * Access callback to determine whether users should have access to the tab.
+ */
+function media_internet_browser_access() {
+  return user_access('administer media') || user_access('add media from remote sources');
+}
+
+/**
+ *  Provides a form for adding media items from 3rd party sources.
+ */
+function media_internet_add($form, &$form_state = array(), $types = NULL) {
+  $form['embed_code'] = array(
+    '#type' => 'textfield',
+    '#title' => 'URL or Embed code',
+    '#description' => 'Input a url or embed code from one of the listed providers.',
+    '#attributes' => array('class' => array('media-add-from-url')),
+    // There is no standard specifying a maximum length for a URL. Internet
+    // Explorer supports upto 2083 (http://support.microsoft.com/kb/208427), so
+    // we assume publicly available media URLs are within this limit.
+    '#maxlength' => 2083,
+  );
+
+
+  // @todo:
+  // Add live previews back (currently broken)
+
+  //$form['preview'] = array(
+  //  '#type' => 'item',
+  //  '#title' => t('Preview'),
+  //  '#markup' => '<div id="media-add-from-url-preview"></div>'
+  //);
+
+  $form['#validators'] = array();
+  if ($types) {
+    $form['#validators']['media_file_validate_types'] = array($types);
+  }
+
+  $form['providers'] = array();
+  $form['providers']['header'] = array('#markup' => '<h2> Supported Providers </h2>');
+  foreach (media_internet_get_providers() as $key => $provider) {
+    if (empty($provider['hidden']) || $provider['hidden'] != TRUE) {
+      if (isset($provider['image'])) {
+        $form['providers'][$key] = array('#markup' => theme('image', array('path' => $provider['image'], 'title' => $provider['title'])));
+      } else {
+        $form['providers'][$key] = array('#markup' => $provider['title']);
+      }
+      // Wrap the provider in a div so we can make a nice list
+      $form['providers'][$key]['#prefix'] = '<div class="media-provider">';
+      $form['providers'][$key]['#suffix'] = '</div>';
+    }
+  }
+  if (count($form['providers']) == 1) {
+    // Just the header, no actual providers
+    unset($form['providers']['header']);
+  }
+
+  return $form;
+}
+
+/**
+ *  Allow stream wrappers to have their chance at validation.
+ *
+ *  Any module that implements hook_media_parse will have an
+ *  opportunity to validate this.
+ *
+ *  @see media_parse_to_uri().
+ */
+function media_internet_add_validate($form, &$form_state) {
+  // Supporting providers can now claim this input.  It might be a URL, but it
+  // might be an embed code as well.
+  $embed_code = $form_state['values']['embed_code'];
+
+  try {
+    $provider = media_internet_get_provider($embed_code);
+    $provider->validate();
+  } catch (MediaInternetNoHandlerException $e) {
+    form_set_error('embed_code', $e->getMessage());
+    return;
+  } catch (MediaInternetValidationException $e) {
+    form_set_error('embed_code', $e->getMessage());
+    return;
+  }
+
+  $validators = $form['#validators'];
+  $file = $provider->getFileObject();
+  if ($validators) {
+    try {
+      $file = $provider->getFileObject();
+    } catch (Exception $e) {
+      form_set_error('embed_code', $e->getMessage());
+      return;
+    }
+
+    // Check for errors. @see media_add_upload_validate calls file_save_upload().
+    // this code is ripped from file_save_upload because we just want the validation part.
+    // Call the validation functions specified by this function's caller.
+    $errors = file_validate($file, $validators);
+
+    if (!empty($errors)) {
+      $message = t('%url could not be added.', array('%url' => $embed_code));
+      if (count($errors) > 1) {
+        $message .= theme('item_list', array('items' => $errors));
+      }
+      else {
+        $message .= ' ' . array_pop($errors);
+      }
+      form_set_error('embed_code', $message);
+      return FALSE;
+    }
+  }
+  // @TODO: Validate that if we have no $uri that this is a valid file to
+  // save. For instance, we may only be interested in images, and it would
+  // be helpful to let the user know they passed the HTML page containing
+  // the image accidentally. That would also save us from saving the file
+  // in the submit step.
+
+  // This is kinda a hack of the same.
+
+  // This should use the file_validate routines that the upload form users.
+  // We need to fix the media_parse_to_file routine to allow for a validation.
+}
+
+/**
+ *  Upload a file from a URL.
+ *
+ *  This will copy a file from a remote location and store it locally.
+ *  @see media_parse_to_uri().
+ *  @see media_parse_to_file().
+ */
+function media_internet_add_submit($form, &$form_state) {
+  $embed_code = $form_state['values']['embed_code'];
+  try {
+    // Save the remote file
+    $provider = media_internet_get_provider($embed_code);
+    // Providers decide if they need to save locally or somewhere else.
+    // This method returns a file object
+    $file = $provider->save();
+  }
+  catch (Exception $e) {
+    form_set_error('embed_code', $e->getMessage());
+    return;
+  }
+
+  if (!$file->fid) {
+    form_set_error('embed_code', 'Unknown error: unable to add file, please check URL / Embed code and try again ' . $embed_code);
+    return;
+  }
+
+  $form_state['values']['fids'] = array($file->fid);
+}
+
diff --git a/modules/media_internet/media_internet.module b/modules/media_internet/media_internet.module
index fa6b94b..31bdc95 100644
--- a/modules/media_internet/media_internet.module
+++ b/modules/media_internet/media_internet.module
@@ -1,21 +1,14 @@
 <?php
 
 /**
- * Implements hook_media_browser_plugin_info().
+ * Implements hook_ctools_plugin_directory().
+ *
+ * This function tells the media browser where to find browser plugins.
  */
-function media_internet_media_browser_plugin_info() {
-  $plugins = array();
-  /*
-   @todo: Coming soon.
-   'search' => array(
-   ),
-  */
-  if (user_access('administer media') || user_access('add media from remote sources')) {
-    $plugins['media_internet'] = array(
-      '#weight' => -10,
-    );
+function media_internet_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'media' && $plugin == 'browser') {
+    return 'browser';
   }
-  return $plugins;
 }
 
 /**
@@ -29,182 +22,7 @@ function media_internet_permission() {
     ),
   );
 }
-
-/**
- * Implements hook_media_browser_plugin_view().
- */
-function media_internet_media_browser_plugin_view($plugin_name, $params) {
-  $path = drupal_get_path('module', 'media');
-
-  $types = isset($params['types']) ? $params['types'] : array();
-  $multiselect = isset($params['multiselect']) ? $params['multiselect'] : FALSE;
-
-  $redirect = array('media/browser', array('query' => array('render' => 'media-popup')));
-  switch ($plugin_name) {
-    case 'media_internet':
-      // @todo: implement the multiselect argument here.
-      $from_web_form = drupal_get_form('media_internet_add',  $types, $multiselect);
-      return array(
-        '#title' => t('Web'),
-        'form' => array($from_web_form),
-        '#attached' => array(
-          //'js' => array($path . '/js/plugins/media.fromurl.js'),
-        ),
-      );
-      break;
-  }
-
-  return array();
-}
-
-/**
- * Provides a form for adding media items from 3rd party sources.
- */
-function media_internet_add($form, &$form_state = array(), $types = NULL) {
-  $form['embed_code'] = array(
-    '#type' => 'textfield',
-    '#title' => t('URL or Embed code'),
-    '#description' => t('Input a url or embed code from one of the listed providers.'),
-    '#attributes' => array('class' => array('media-add-from-url')),
-    // There is no standard specifying a maximum length for a URL. Internet
-    // Explorer supports upto 2083 (http://support.microsoft.com/kb/208427), so
-    // we assume publicly available media URLs are within this limit.
-    '#maxlength' => 2083,
-  );
-
-
-  // @todo:
-  // Add live previews back (currently broken)
-
-  //$form['preview'] = array(
-  //  '#type' => 'item',
-  //  '#title' => t('Preview'),
-  //  '#markup' => '<div id="media-add-from-url-preview"></div>'
-  //);
-
-  $form['#validators'] = array();
-  if ($types) {
-    $form['#validators']['media_file_validate_types'] = array($types);
-  }
-
-  $form['providers'] = array();
-  $form['providers']['header'] = array('#markup' => '<h2>' . t('Supported Providers') . '</h2>');
-  foreach (media_internet_get_providers() as $key => $provider) {
-    if (empty($provider['hidden']) || $provider['hidden'] != TRUE) {
-      if (isset($provider['image'])) {
-        $form['providers'][$key] = array('#markup' => theme('image', array('path' => $provider['image'], 'title' => $provider['title'])));
-      }
-      else {
-        $form['providers'][$key] = array('#markup' => $provider['title']);
-      }
-      // Wrap the provider in a div so we can make a nice list
-      $form['providers'][$key]['#prefix'] = '<div class="media-provider">';
-      $form['providers'][$key]['#suffix'] = '</div>';
-    }
-  }
-  if (count($form['providers']) == 1) {
-    // Just the header, no actual providers
-    unset($form['providers']['header']);
-  }
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
-  return $form;
-}
-
-/**
- * Allow stream wrappers to have their chance at validation.
- *
- * Any module that implements hook_media_parse will have an
- * opportunity to validate this.
- *
- * @see media_parse_to_uri()
- */
-function media_internet_add_validate($form, &$form_state) {
-  // Supporting providers can now claim this input.  It might be a URL, but it
-  // might be an embed code as well.
-  $embed_code = $form_state['values']['embed_code'];
-
-  try {
-    $provider = media_internet_get_provider($embed_code);
-    $provider->validate();
-  } catch (MediaInternetNoHandlerException $e) {
-    form_set_error('url', $e->getMessage());
-    return;
-  } catch (MediaInternetValidationException $e) {
-    form_set_error('url', $e->getMessage());
-    return;
-  }
-
-  $validators = $form['#validators'];
-  $file = $provider->getFileObject();
-  if ($validators) {
-    try {
-      $file = $provider->getFileObject();
-    } catch (Exception $e) {
-      form_set_error('url', $e->getMessage());
-      return;
-    }
-
-    // Check for errors. @see media_add_upload_validate calls file_save_upload().
-    // this code is ripped from file_save_upload because we just want the validation part.
-    // Call the validation functions specified by this function's caller.
-    $errors = file_validate($file, $validators);
-
-    if (!empty($errors)) {
-      $message = t('%url could not be added.', array('%url' => $embed_code));
-      if (count($errors) > 1) {
-        $message .= theme('item_list', array('items' => $errors));
-      }
-      else {
-        $message .= ' ' . array_pop($errors);
-      }
-      form_set_error('url', $message);
-      return FALSE;
-    }
-  }
-  // @TODO: Validate that if we have no $uri that this is a valid file to
-  // save. For instance, we may only be interested in images, and it would
-  // be helpful to let the user know they passed the HTML page containing
-  // the image accidentally. That would also save us from saving the file
-  // in the submit step.
-
-  // This is kinda a hack of the same.
-
-  // This should use the file_validate routines that the upload form users.
-  // We need to fix the media_parse_to_file routine to allow for a validation.
-}
-
-/**
- * Upload a file from a URL.
- *
- * This will copy a file from a remote location and store it locally.
- *
- * @see media_parse_to_uri()
- * @see media_parse_to_file()
- */
-function media_internet_add_submit($form, &$form_state) {
-  $embed_code = $form_state['values']['embed_code'];
-  try {
-    // Save the remote file
-    $provider = media_internet_get_provider($embed_code);
-    // Providers decide if they need to save locally or somewhere else.
-    // This method returns a file object
-    $file = $provider->save();
-  }
-  catch (Exception $e) {
-    form_set_error('url', $e->getMessage());
-    return;
-  }
-
-  if (!$file->fid) {
-    form_set_error('url', 'Unknown error: unable to add file, please check URL / Embed code and try again ' . $embed_code);
-    return;
-  }
-
-  $form_state['redirect'] = array('media/browser', array('query' => array('render' => 'media-popup', 'fid' => $file->fid)));
-}
-
+ 
 /**
  * Gets the list of providers.
  *
diff --git a/templates/media-dialog-page.tpl.php b/templates/media-dialog-page.tpl.php
deleted file mode 100644
index d426686..0000000
--- a/templates/media-dialog-page.tpl.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-
-/**
- * @file
- * Default theme implementation to display a single Drupal page.
- *
- * Available variables:
- *
- * General utility variables:
- * - $base_path: The base URL path of the Drupal installation. At the very
- *   least, this will always default to /.
- * - $directory: The directory the template is located in, e.g. modules/system
- *   or themes/garland.
- * - $is_front: TRUE if the current page is the front page.
- * - $logged_in: TRUE if the user is registered and signed in.
- * - $is_admin: TRUE if the user has permission to access administration pages.
- *
- * Site identity:
- * - $front_page: The URL of the front page. Use this instead of $base_path,
- *   when linking to the front page. This includes the language domain or
- *   prefix.
- * - $logo: The path to the logo image, as defined in theme configuration.
- * - $site_name: The name of the site, empty when display has been disabled
- *   in theme settings.
- * - $site_slogan: The slogan of the site, empty when display has been disabled
- *   in theme settings.
- *
- * Navigation:
- * - $main_menu (array): An array containing the Main menu links for the
- *   site, if they have been configured.
- * - $secondary_menu (array): An array containing the Secondary menu links for
- *   the site, if they have been configured.
- * - $breadcrumb: The breadcrumb trail for the current page.
- *
- * Page content (in order of occurrence in the default page.tpl.php):
- * - $title_prefix (array): An array containing additional output populated by
- *   modules, intended to be displayed in front of the main title tag that
- *   appears in the template.
- * - $title: The page title, for use in the actual HTML content.
- * - $title_suffix (array): An array containing additional output populated by
- *   modules, intended to be displayed after the main title tag that appears in
- *   the template.
- * - $messages: HTML for status and error messages. Should be displayed
- *   prominently.
- * - $tabs (array): Tabs linking to any sub-pages beneath the current page
- *   (e.g., the view and edit tabs when displaying a node).
- * - $action_links (array): Actions local to the page, such as 'Add menu' on the
- *   menu administration interface.
- * - $feed_icons: A string of all feed icons for the current page.
- * - $node: The node object, if there is an automatically-loaded node
- *   associated with the page, and the node ID is the second argument
- *   in the page's path (e.g. node/12345 and node/12345/revisions, but not
- *   comment/reply/12345).
- *
- * Regions:
- * - $page['help']: Dynamic help text, mostly for admin pages.
- * - $page['highlight']: Items for the highlighted content region.
- * - $page['content']: The main content of the current page.
- * - $page['sidebar_first']: Items for the first sidebar.
- * - $page['sidebar_second']: Items for the second sidebar.
- * - $page['header']: Items for the header region.
- * - $page['footer']: Items for the footer region.
- *
- * @see template_preprocess()
- * @see template_preprocess_page()
- * @see template_process()
- */
-?>
-
-<div id="media-browser-page-wrapper"><div id="media-browser-page">
-  <?php if (isset($messages)) { print $messages; } ?>
-  <?php print render($page['content']); ?>
-</div></div> <!-- /#page, /#page-wrapper -->
diff --git a/wysiwyg_plugins/media.inc b/wysiwyg_plugins/media.inc
index 8e0c862..79f3e3d 100644
--- a/wysiwyg_plugins/media.inc
+++ b/wysiwyg_plugins/media.inc
@@ -28,10 +28,9 @@ function media_media_plugin() {
     'css file' => NULL,
     'css path' => NULL,
     'settings' => array(
-      'global' => array(
-        'types' => media_variable_get('wysiwyg_allowed_types'),
-        'id' => 'media_wysiwyg',
-      ),
+      'types' => media_variable_get('wysiwyg_allowed_types'),
+      'singleselect' => TRUE,
+      'limit' => 10,
     ),
   );
 
