Index: libraries.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.api.php,v
retrieving revision 1.5
diff -u -p -r1.5 libraries.api.php
--- libraries.api.php	3 Nov 2010 22:22:42 -0000	1.5
+++ libraries.api.php	10 Dec 2010 10:25:40 -0000
@@ -365,3 +365,79 @@ function hook_libraries_paths() {
   // the test library.
   return array(drupal_get_path('module', 'libraries_test') . '/example');
 }
+
+/**
+* Declare callbacks to be applied to a library during the post_info stage.
+*
+* Callbacks registered in this stage are applied as soon as the library
+* information has been retrieved. If your module uses custom top-level
+* properties in libraries you could use a callback in this stage to apply
+* defaults to these.
+*
+* These callbacks are applied to all versions and variants of a library (in case
+* they have been declared). These callbacks should have the following parameters:
+* - $library: An array of library information. This might be the top-level
+*   array, but also an array of version- or variant-specific information.
+* - $version: If the passed $library is version-specific information, the
+*   version string.
+* - $variant: If the passed $library is variant-specific information, the
+*   variant name.
+*
+* If your callback only needs to be applied to one of the three types of
+* library information arrays (top-level, version-specific, variant-specific)
+* you need to check the $version and $variant parameters accordingly in your
+* callback.
+*/
+function hook_libraries_post_info() {
+  return array('mymodule_libraries_post_info_callback');
+}
+
+/**
+* Declare callbacks to be applied to a library during the post_detect stage.
+*
+* Callbacks registered in this stage are applied as soon as the library
+* has been detected. Version information and information about the availability
+* of variants is available in this stage.
+*
+* These callbacks are applied to all versions and variants of a library (in case
+* they have been declared). These callbacks should have the following parameters:
+* - $library: An array of library information. This might be the top-level
+*   array, but also an array of version- or variant-specific information.
+* - $version: If the passed $library is version-specific information, the
+*   version string.
+* - $variant: If the passed $library is variant-specific information, the
+*   variant name.
+*
+* If your callback only needs to be applied to one of the three types of
+* library information arrays (top-level, version-specific, variant-specific)
+* you need to check the $version and $variant parameters accordingly in your
+* callback.
+*/
+function hook_libraries_post_detect() {
+  return array('mymodule_libraries_post_detect_callback');
+}
+
+/**
+* Declare callbacks to be applied to a library during the pre_load stage.
+*
+* Callbacks registered in this stage are applied when the variant information
+* of the variant that is about to be loaded has been merged into the top-level
+* library.
+*
+* These callbacks are applied to all versions and variants of a library (in case
+* they have been declared). These callbacks should have the following parameters:
+* - $library: An array of library information. This might be the top-level
+*   array, but also an array of version- or variant-specific information.
+* - $version: If the passed $library is version-specific information, the
+*   version string.
+* - $variant: If the passed $library is variant-specific information, the
+*   variant name.
+*
+* If your callback only needs to be applied to one of the three types of
+* library information arrays (top-level, version-specific, variant-specific)
+* you need to check the $version and $variant parameters accordingly in your
+* callback.
+*/
+function hook_libraries_pre_load() {
+  return array('mymodule_libraries_pre_load_callback');
+}
Index: libraries.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v
retrieving revision 1.15
diff -u -p -r1.15 libraries.module
--- libraries.module	3 Dec 2010 23:16:38 -0000	1.15
+++ libraries.module	10 Dec 2010 10:25:40 -0000
@@ -158,6 +158,74 @@ function libraries_scan_info_files() {
 
   return $files;
 }
+
+/**
+ * Invokes library callbacks.
+ *
+ * @param $stage
+ *   A string containing the stage in which the callbacks are applied. This
+ *   corresponds to the hook that is invoked to gather the callbacks that should
+ *   be applied. Should be either 'post_info', 'post_detect', or 'post_load'.
+ * @param $library
+ *   An array of library information, passed by reference.
+ */
+function libraries_invoke($stage, &$library) {
+  $callbacks = module_invoke_all("libraries_$stage");
+  foreach ($callbacks as $callback) {
+    libraries_traverse_library($library, $callback);
+  }
+}
+
+/**
+ * Helper function to apply a callback to all parts of a library.
+ *
+ * Because library declarations can include variants and versions, and those
+ * version declarations can in turn include variants, modifying e.g. the 'files'
+ * property everywhere it is declared can be quite cumbersome, in which case
+ * this helper function is useful.
+ *
+ * @param $library
+ *   An array of library information, passed by reference.
+ * @param $callback
+ *   A string containing the callback to apply to all parts of a library.
+ */
+function libraries_traverse_library(&$library, $callback) {
+  // Always apply the callback to the top-level library.
+  $callback($library, NULL, NULL);
+
+  // Apply callback to versions.
+  if (!empty($library['versions'])) {
+    foreach ($library['versions'] as $version_string => &$version) {
+      // Versions can include variants as well.
+      if (!empty($version['variants'])) {
+        foreach ($version['variants'] as $version_variant_name => &$version_variant) {
+          $callback($version_variant, $version, $version_variant_name);
+        }
+      }
+      $callback($version, $version_string, NULL);
+    }
+  }
+
+  // Apply callback to variants.
+  if (!empty($library['variants'])) {
+    foreach ($library['variants'] as $variant_name => &$variant) {
+      $callback($variant, NULL, $variant_name);
+    }
+  }
+}
+
+/**
+ * Implements hook_libraries_post_info().
+ */
+function libraries_libraries_post_info() {
+  $callbacks = array();
+  // Apply defaults to top-level libraries.
+  $callbacks[] = 'libraries_defaults';
+  // Make files declarations consistent.
+  $callbacks[] = 'libraries_prepare_files';
+  return $callbacks;
+}
+
 /**
  * Returns information about registered libraries.
  *
@@ -185,6 +253,7 @@ function libraries_info($name = NULL) {
     // Gather information from hook_libraries_info().
     foreach (module_implements('libraries_info') as $module) {
       foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
+        $properties['machine name'] = $machine_name;
         $properties['module'] = $module;
         $libraries[$machine_name] = $properties;
       }
@@ -193,26 +262,14 @@ function libraries_info($name = NULL) {
     // .info files override module definitions.
     foreach (libraries_scan_info_files() as $machine_name => $file) {
       $properties = drupal_parse_info_file($file->uri);
+      $properties['machine name'] = $machine_name;
       $properties['info file'] = $file->uri;
       $libraries[$machine_name] = $properties;
     }
 
-    // Provide defaults.
-    foreach ($libraries as $machine_name => &$properties) {
-      $properties += array(
-        'machine name' => $machine_name,
-        'name' => $machine_name,
-        'vendor url' => '',
-        'download url' => '',
-        'path' => '',
-        'library path' => NULL,
-        'version callback' => 'libraries_get_version',
-        'version arguments' => array(),
-        'files' => array(),
-        'variants' => array(),
-        'versions' => array(),
-        'integration files' => array(),
-      );
+    // Apply post_info callbacks.
+    foreach ($libraries as $machine_name => &$library) {
+      libraries_invoke('post_info', $library);
     }
 
     // Allow modules to alter the registered libraries.
@@ -226,6 +283,102 @@ function libraries_info($name = NULL) {
 }
 
 /**
+ * Applies defaults to library information.
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ * @param $version
+ *   If the library information belongs to a specific version, the version
+ *   string. NULL otherwise.
+ * @param $variant
+ *   If the library information belongs to a specific variant, the variant name.
+ *   NULL otherwise.
+ *
+ * @see libraries_info()
+ * @see libraries_invoke()
+ */
+function libraries_defaults(&$library, $version, $variant) {
+  // Only apply defaults to the top-level library, because version- and variant-
+  // specific code is merged into the top-level library later.
+  if (empty($version) && empty($variant)) {
+    $name = $library['machine name'];
+    $library += array(
+      'name' => $name,
+      'vendor url' => '',
+      'download url' => '',
+      'path' => '',
+      'library path' => NULL,
+      'version callback' => 'libraries_get_version',
+      'version arguments' => array(),
+      'files' => array(),
+      'variants' => array(),
+      'versions' => array(),
+      'integration files' => array(),
+    );
+  }
+}
+
+/**
+ * Helper callback to make 'files' property of libraries consistent.
+ *
+ * This turns libraries' file information declared as e.g.
+ * @code
+ * $library['files']['js'] = array('example_1.js', 'example_2.js');
+ * @endcode
+ * into
+ * @code
+ * $library['files']['js'] = array(
+ *   'example_1.js' => array(),
+ *   'example_2.js' => array(),
+ * );
+ * @endcode
+ * It does the same for the 'integration files' property.
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ * @param $version
+ *   If the library information belongs to a specific version, the version
+ *   string. NULL otherwise.
+ * @param $variant
+ *   If the library information belongs to a specific variant, the variant name.
+ *   NULL otherwise.
+ *   
+ *
+ * @see libraries_info()
+ * @see libraries_invoke()
+ */
+function libraries_prepare_files(&$library, $version, $variant) {
+  // Both the 'files' property and the 'integration files' property contain file
+  // declarations, and we want to make both consistent.
+  $file_types = array();
+  if (isset($library['files'])) {
+    $file_types[] = &$library['files'];
+  }
+  if (isset($library['integration files'])) {
+    // Integration files are additionally keyed by module.
+    foreach ($library['integration files'] as &$integration_files) {
+      $file_types[] = &$integration_files;
+    }
+  }
+  foreach ($file_types as &$files) {
+    // Go through all supported types of files.
+    foreach (array('js', 'css', 'php') as $type) {
+      if (!empty($files[$type])) {
+        foreach ($files[$type] as $key => $value) {
+          // Unset numeric keys and turn the respective values into keys.
+          if (is_numeric($key)) {
+            $files[$type][$value] = array();
+            unset($files[$type][$key]);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
  * Detect libraries and library versions.
  *
  * @todo It makes little sense to pass $libraries by reference here. We need to
@@ -348,6 +501,9 @@ function libraries_detect_library(&$libr
 
   // If we end up here, the library should be usable.
   $library['installed'] = TRUE;
+  
+  // Invoke post_detect callbacks.
+  libraries_invoke('post_detect', $library);
 }
 
 /**
@@ -375,8 +531,12 @@ function libraries_load($name, $variant 
       return FALSE;
     }
     $library = array_merge($library, $library['variants'][$variant]);
+    unset($library['variants']);
   }
 
+  // Apply pre_load callbacks.
+  libraries_invoke('pre_load', $library);
+
   return libraries_load_files($library, $variant);
 }
 
