From e2453e94b4030f88c2f520677fe147fe53ad926c Mon Sep 17 00:00:00 2001
From: James Elliott <james.elliott@acquia.com>
Date: Wed, 13 Apr 2011 10:41:09 -0400
Subject: [PATCH 08/15] Ditch the iframe and use an AJAX call for a jQuery dialog

---
 css/media.css                |    5 --
 css/media.thumbnails.css     |    1 +
 includes/media.admin.inc     |    4 +-
 includes/media.browser.inc   |  102 +++++---------------------
 js/media.admin.js            |   36 ++++++++--
 js/media.browser.js          |    2 +-
 js/media.dialog.js           |   45 ++++++++++++
 js/plugins/media.library.css |   22 ------
 js/plugins/media.library.js  |  165 +-----------------------------------------
 media.module                 |   41 +++--------
 10 files changed, 109 insertions(+), 314 deletions(-)
 create mode 100644 js/media.dialog.js

diff --git a/css/media.css b/css/media.css
index f4816a3..96591fd 100644
--- a/css/media.css
+++ b/css/media.css
@@ -195,11 +195,6 @@ a.button {
   margin:30px;
 }
 
-#media-admin #edit-options {
-  clear: both;
-  margin: 0;
-}
-
 .media-clear {
   clear: both;
 }
diff --git a/css/media.thumbnails.css b/css/media.thumbnails.css
index d3db5cb..36ed607 100644
--- a/css/media.thumbnails.css
+++ b/css/media.thumbnails.css
@@ -92,6 +92,7 @@
 .media-list-thumbnails > li {
   float: left;
   list-style: none;
+  position: relative;
 }
 
 .media-list-thumbnails .form-type-checkbox {
diff --git a/includes/media.admin.inc b/includes/media.admin.inc
index 48c89ac..8f6488b 100644
--- a/includes/media.admin.inc
+++ b/includes/media.admin.inc
@@ -53,8 +53,8 @@ function media_admin($form, $form_state) {
   );
 
   
-  $form['browser'] = media_build_browser();
-
+  $form['browser'] = media_browser_build();
+  
   return $form;
 }
 
diff --git a/includes/media.browser.inc b/includes/media.browser.inc
index 37d2bcb..7772606 100644
--- a/includes/media.browser.inc
+++ b/includes/media.browser.inc
@@ -8,7 +8,7 @@ function media_browser($selected = NULL) {
   $output = array();
   $output['#attached']['library'][] = array('media', 'media_browser_page');
   
-  $params = drupal_get_query_parameters();
+  $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);
   
@@ -63,8 +63,8 @@ function media_browser($selected = NULL) {
   
   $tabs = array(); // List of tabs to render.
 
-  $settings = array('media' => array('browser' => array()));
-  $browser_settings =& $settings['media']['browser'];
+  $settings = array('media' => array('dialog' => array('dialogs' => array('#media-browser-tabset' => array()))));
+  $browser_settings =& $settings['media']['dialog'];
 
   //@todo: replace with Tabs module if it gets upgraded.
   foreach (element_children($plugins, TRUE) as $key) {
@@ -86,7 +86,7 @@ EOS;
     <!-- End #media-tab-$key -->
 EOS;
   }
-
+  
   drupal_add_js($settings, 'setting');
 
   $output['tabset'] = array(
@@ -98,16 +98,15 @@ EOS;
   );
 
   $output['tabset']['plugins'] = $plugins;
-  
-  return ajax_render($output);
-  
+
   return $output;
 }
 
-function media_build_browser() {
+function media_browser_build() {
+  $build = array();
   // Attach browser JS
-  media_attach_browser_js($form);
-  
+  media_attach_browser_js($build);
+
   // Gather the display information.
   $display = media_browser_get_display();
   
@@ -117,7 +116,7 @@ function media_build_browser() {
   // Build the display.
   include_once $display['file'];
   $build['display'] = $display['callback']();
-  
+
   return $build;
 }
 
@@ -163,8 +162,9 @@ function media_browser_get_display() {
 function media_browser_table() {
   // @todo Change to media_variable_get('admin_pager_limit') for consistency
   //   with browser_pager_limit?
-  $limit = isset($_GET['limit']) ? $_GET['limit'] : variable_get('media_admin_limit', 50);
-  $types = isset($_GET['types']) ? $_GET['types'] : media_type_get_types();
+  $params = array_merge(drupal_get_query_parameters(), drupal_get_query_parameters($_POST));
+  $limit = isset($params['limit']) ? $params['limit'] : variable_get('media_admin_limit', 50);
+  $types = isset($params['types']) ? $params['types'] : media_type_get_types();
 
   // Build the sortable table header.
   $header = array(
@@ -221,8 +221,9 @@ function media_browser_table() {
 function media_browser_thumbnails() {
   // @todo Change to media_variable_get('admin_pager_limit') for consistency
   //   with browser_pager_limit?
-  $limit = isset($_GET['limit']) ? $_GET['limit'] : variable_get('media_admin_limit', 50);
-  $types = isset($_GET['types']) ? $_GET['types'] : media_type_get_types();
+  $params = array_merge(drupal_get_query_parameters(), drupal_get_query_parameters($_POST));
+  $limit = isset($params['limit']) ? $params['limit'] : variable_get('media_admin_limit', 50);
+  $types = isset($params['types']) ? $params['types'] : media_type_get_types();
 
   $query = new EntityFieldQuery();
 
@@ -366,69 +367,6 @@ function media_get_browser_params() {
 }
 
 /**
- * AJAX Callback function to return a list of media files
- */
-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');
-  
-  $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;
-
-  $start = isset($params['start']) ? $params['start'] : 0;
-  $limit = isset($params['limit']) ? $params['limit'] : media_variable_get('browser_pager_limit');
-  
-  $conditions = array();
-
-  $query = new EntityFieldQuery();
-  
-  $query->range($start, $limit);
-  $query->entityCondition('entity_type', 'media');
-  $query->entityOrderBy('entity_id', 'DESC');
-
-  if ($types) {
-    $query->entityCondition('bundle', $types, 'IN');
-  }
-
-  if ($url_include_patterns) {
-    $query->propertyCondition('uri', $v, 'CONTAINS');
-    // Insert stream related restrictions here.
-  }
-  if ($url_exclude_patterns) {
-    $query->propertyCondition('uri', "%$v%", 'NOT LIKE');
-  }
-
-  // @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_file_view().
-  if (!user_access('administer media')) {
-    $query->propertyCondition('uri', 'private://%', 'NOT LIKE');
-  }
-
-  $query->propertyCondition('status', FILE_STATUS_PERMANENT);
-
-  $result = $query->execute();
-  $ids = array_keys($result['media']);
-  if ($ids) {
-    $media_entities = entity_load('media', $ids);
-  }
-  else {
-    $media_entities = array();
-  }
-  
-  foreach ($media_entities as &$media) {
-    media_browser_build_media_item($media);
-  }
-  
-  drupal_json_output(array('media' => array_values($media_entities)));
-  exit();
-
-}
-
-/**
  * Implements hook_media_browser_plugin_info().
  */
 function media_media_browser_plugin_info() {
@@ -504,8 +442,7 @@ function media_media_browser_plugin_view($plugin_name, $params) {
         // 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>',
-        '#markup' => media_browser_thumbnails(),
+        'media' => media_browser_build(),
       );
     break;
   }
@@ -545,8 +482,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/js/media.admin.js b/js/media.admin.js
index 8140210..e32ab70 100644
--- a/js/media.admin.js
+++ b/js/media.admin.js
@@ -24,26 +24,47 @@ Drupal.behaviors.mediaAdmin = {
     }
     $('.media-display-switch a', context).bind('click', show_confirm_if_existing_selections)
 
-    $('a[href="/admin/content/media/add"]', context).bind('click', Drupal.media.admin.addMedia);
+    //$('a[href="/admin/content/media/add"]', context).bind('click', Drupal.media.admin.addMedia);
+    
+    $('a[href="/admin/content/media/add"]', context).once('media-ajax', function() {
+      var element_settings = {};
+      // Clicked links look better with the throbber than the progress bar.
+      element_settings.progress = { 'type': 'throbber' };
+      element_settings.wrapper = 'page';
+      element_settings.method = 'append';
+      // For anchor tags, these will go to the target of the anchor rather
+      // than the usual location.
+      element_settings.url = Drupal.settings.media.browserUrl;
+      element_settings.event = 'click';
+      element_settings.submit = {
+        js: true,
+        limit: 15
+      };
+      
+      var base = 'admin-media-add-media';
+      Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+    });
 
     // 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).
-    var $checkboxes = $('#media-admin :checkbox', context);
-    $checkboxes.bind('change', Drupal.media.admin.showOrHideEditOptions);
-    $checkboxes.trigger('change');
+    $('#media-admin :checkbox', context).once('media-admin', function() {
+      $(this).bind('change', Drupal.media.admin.showOrHideEditOptions).trigger('change');
+    });
+    
   }
 };
 
 Drupal.media.admin.addMedia = function (event) {
   event.preventDefault();
+  Drupal.media.dialog.launch();
+  return;
   // 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,
-    limit: 10
+    multiselect: true
   };
   Drupal.media.popups.mediaBrowser(function (mediaFiles) {
     // When the media browser succeeds, we refresh
@@ -53,7 +74,8 @@ Drupal.media.admin.addMedia = function (event) {
   }, options);
 };
 
-Drupal.media.admin.showOrHideEditOptions = function() {
+Drupal.media.admin.showOrHideEditOptions = function(event) {
+  event.stopPropagation();
   var fieldset = $('#edit-options');
   if (!$('#media-admin input[type=checkbox]:checked').length) {
     fieldset.slideUp('fast');
diff --git a/js/media.browser.js b/js/media.browser.js
index abe48ba..b9fc5fa 100644
--- a/js/media.browser.js
+++ b/js/media.browser.js
@@ -23,7 +23,7 @@ Drupal.behaviors.experimentalMediaBrowser = {
       show: Drupal.media.browser.resizeIframe
     });
 
-    $('.media-browser-tab').each( Drupal.media.browser.validateButtons );
+    //$('.media-browser-tab').each( Drupal.media.browser.validateButtons );
 
   }
   // Wait for additional params to be passed in.
diff --git a/js/media.dialog.js b/js/media.dialog.js
new file mode 100644
index 0000000..e96dd04
--- /dev/null
+++ b/js/media.dialog.js
@@ -0,0 +1,45 @@
+(function ($) {
+
+Drupal.media = Drupal.media || {};
+Drupal.media.dialog = Drupal.media.dialog || {};
+
+Drupal.behaviors.dialog = {
+  attach: function (context) {
+    if (typeof Drupal.settings.media.dialog != 'undefined') {
+      for(var dialog in Drupal.settings.media.dialog.dialogs) {
+        $(dialog).once('media-dialog', function () {
+          $(this).dialog(Drupal.media.dialog.defaults(Drupal.settings.media.dialog.dialogs[dialog].callback));
+        });
+      }
+    }
+  }
+};
+
+Drupal.media.dialog.defaults = function (callback) {
+  return {
+    modal: true,
+    width: '80%',
+    maxHeight: '80%',
+    resizable: false,
+    draggable: false,
+    autoOpen: true,
+    buttons: {
+      'ok': Drupal.media.dialog.confirm,
+      cancel: this.close
+    },
+    callback: callback,
+    close: Drupal.media.dialog.close
+  };
+};
+
+Drupal.media.dialog.close = function () {
+  Drupal.detachBehaviors(this, Drupal.settings);
+  $(this).remove();
+};
+
+Drupal.media.dialog.confirm = function () {
+  $(this).data().dialog.options.callback();
+  $(this).dialog('destory');
+};
+
+})(jQuery);
\ No newline at end of file
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 859895b..bcb1bd1 100644
--- a/js/plugins/media.library.js
+++ b/js/plugins/media.library.js
@@ -6,140 +6,7 @@ Drupal.media.browser = Drupal.media.browser || {};
 
 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');
-    }
-    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('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();
-    }
-  }
-};
-
-/**
- * Fetches the next media object and increments the cursor.
- */
-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);
   }
 };
 
@@ -148,39 +15,11 @@ Drupal.media.browser.library.prototype.mediaSelected = function (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;
-  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;
+  
 }
 
 }(jQuery));
diff --git a/media.module b/media.module
index b441b64..f09562f 100644
--- a/media.module
+++ b/media.module
@@ -132,6 +132,9 @@ function media_menu() {
     '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(
@@ -142,8 +145,8 @@ 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' => 'media_dialog_theme',
   );
 
   // A testbed to try out the media browser with different launch commands.
@@ -258,6 +261,10 @@ function media_menu() {
   return $items;
 }
 
+function media_dialog_theme() {
+  return $_POST['ajax_page_state']['theme'];
+}
+
 /**
  * Implements hook_admin_paths().
  */
@@ -431,36 +438,6 @@ function media_styles_style_flush($style) {
 }
 
 /**
- * Implement 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) {
-  // Show a nagging message when the media installation needs to be completed.
-  if (user_access('administer media') && media_variable_get('show_file_type_rebuild_nag')
-    // Prevent form submissions from creating duplicate messages.
-    && ($_SERVER['REQUEST_METHOD'] == 'GET')
-    // Show on all the admin pages, except the batch and the rebuild form.
-    && path_is_admin(current_path()) && (arg(0) != 'batch') && (current_path() != 'admin/config/media/rebuild_types')) {
-    drupal_set_message(t('Media module install is not complete. <a href="@type_rebuild_link">Finish the install</a>.', array('@type_rebuild_link' => url('admin/config/media/rebuild_types'))), 'warning', FALSE);
-  }
-
-  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) {
@@ -754,7 +731,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),
     ),
@@ -777,6 +753,7 @@ function media_library() {
       array('system', 'ui.resizable'),
       array('system', 'ui.draggable'),
       array('system', 'ui.dialog'),
+      array('system', 'drupal.ajax'),
     ),
   );
 
-- 
1.7.4.msysgit.0

