Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.799
diff -u -r1.799 common.inc
--- includes/common.inc	20 Sep 2008 20:22:23 -0000	1.799
+++ includes/common.inc	1 Oct 2008 03:37:49 -0000
@@ -648,7 +648,7 @@
   // The first trace is the call itself.
   // It gives us the line and the file of the last call.
   $call = $backtrace[0];
-  
+
   // The second call give us the function where the call originated.
   if (isset($backtrace[1])) {
     if (isset($backtrace[1]['class'])) {
@@ -2340,6 +2340,57 @@
 }
 
 /**
+ * Returns all module defined plugins that are registered using hook_jq.
+ * This is cached, so a module is responsible for calling this function on
+ * installation.
+ * @TODO: When hook_modules_installed is patched, then call this function there.
+ * @param $plugin
+ *   (optional) The name of the plugin to load.
+ * @param $cached
+ *   (optional) Use the cached jQuery plugin registry.
+ * @param $display_errors
+ *   (optional) Send any reported errors to the user as a message.
+ * @param $log_errors
+ *   (optional) Whether or not to log any errors using the watchdog.
+ * @return
+ *   The plugin information for either the given plugin, or all the plugins.
+ */
+function drupal_get_jq($plugin = NULL, $cached = TRUE, $display_errors = FALSE, $log_errors = TRUE) {
+  static $plugins;
+  if (!isset($plugins) || !$cached) {
+    if ($cached && $cache = cache_get('drupal_get_jq')) {
+      $plugins = $cache->data;
+    }
+    else {
+      include_once(DRUPAL_ROOT .'/includes/jquery.cache.inc');
+      $plugins = _drupal_get_jq();
+      cache_set('drupal_get_jq', $plugins);
+    }
+  }
+  if (isset($plugin)) {
+    return isset($plugins[$plugin]) ? $plugins[$plugin] : NULL;
+  }
+  return $plugins;
+}
+
+/**
+ * Adds any registered jQuery Plugins to the page.
+ * 
+ * This will add a specific jQuery plugin to a page, if it hasn't already been.
+ * @param $plugin
+ *   The plugin to add to the page.
+ * @return
+ *   Whether the plugin was successfully loaded or not. It will pass
+ *   through any extra arguments.
+ */
+function drupal_add_jq($plugin) {
+  include_once(DRUPAL_ROOT .'/includes/jquery.inc');
+  $extra = func_get_args();
+  array_shift($extra);
+  return _drupal_add_jq($plugin, $extra);
+}
+
+/**
  * Return data in JSON format.
  *
  * This function should be used for JavaScript callback functions returning
Index: includes/jquery.cache.inc
===================================================================
RCS file: includes/jquery.cache.inc
diff -N includes/jquery.cache.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/jquery.cache.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,64 @@
+<?php
+// $Id$
+
+/**
+ * Build the jquery plugin array to be cached.
+ * Any module that defines hook_jquery_plugins may define new jquery plugins for the system.
+ *
+ * For a plugin to be registered with this module, a module needs to invoke hook_jq.
+ * hook_jquery_plugins($op = 'info|add', $plugin = NULL)
+ * If $op is 'add', then it is called with the plugin when invoked on a page.
+ * If $op is 'info', then it needs to return an associative array of defined plugins:
+ *   'name' => // ... Name of the plugin.
+ *   'description' => // ... Description of the plugin.
+ *   'files' => array(
+ *     'js' => array(
+ *       // ... An array of js files to be loaded on the page.
+ *     ),
+ *     'css' => array(
+ *       // ... An array of css files to be loaded on the page.
+ *     ),
+ *   ),
+ * @return
+ *   An array of all jQuery plugins.
+ */
+function _drupal_get_jq() {
+  $plugins = array();
+
+  // Scan the /plugins and /sites/example.com/plugins directories for .js and .css files.
+  // If there are multiple plugins with the same filename in the directory, the LAST file read will be used.
+  $files = drupal_system_listing('(\.js$|\.css$)', 'plugins', 'basename', 0);
+  foreach ($files as $file) {
+    $plugins[$file->name]['name'] = $file->name;
+    $plugins[$file->name]['plugin'] = $file->name;
+    if (substr($file->filename, strripos($file->filename, '.') + 1) == 'js') {
+      $plugins[$file->name]['files']['js'][] = $file->filename;
+    }
+    else {
+      $plugins[$file->name]['files']['css'][] = $file->filename;
+    }
+  }
+
+  // Any module may put its hook_jquery_plugins functions in module_name.jquery_plugins.inc,
+  // so that it may be included automatically.
+  module_load_all_includes('jquery_plugins.inc');
+  foreach (module_implements('jquery_plugins') as $module) {
+    $mod_jq = module_invoke($module, 'jquery_plugins', 'info');
+    if (is_array($mod_jq)) {
+      foreach ($mod_jq as $name => $plugin) {
+        // On conflicting plugin names, use the latest version.
+        if (isset($plugins[$name]) && isset($plugins[$name]['version'])) {
+          if (!isset($plugin['version']) || !is_numeric($plugin['version']) || $plugin['version'] < $plugins[$name]['version']) {
+            // Attempting to add an older plugin version.
+            continue;
+          }
+        }
+        $plugins[$name] = $plugin;
+        $plugins[$name]['plugin'] = $name;
+        $plugins[$name]['module'] = $module;
+      }
+    }
+  }
+  ksort($plugins);
+  return $plugins;
+}
Index: includes/jquery.inc
===================================================================
RCS file: includes/jquery.inc
diff -N includes/jquery.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/jquery.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+<?php
+// $Id$
+
+/**
+ *  Adds any registered jQuery Plugins to the page.
+ *  This will add a specific jquery plugin to a page, if it hasn't already been.
+ *  Returns whether the plugin was successfully loaded or not.
+ */
+function _drupal_add_jq($plugin, $extra = array()) {
+  static $invoked_plugins, $errors;
+  $jq = drupal_get_jq($plugin, TRUE);
+  if (!isset($invoked_plugins[$plugin])) {
+    if (isset($plugin) && isset($jq)) {
+      if (!variable_get('jq_allow_'. $plugin, TRUE)) {
+        $error = t('The %plugin jQuery plugin has been disabled.', array('%plugin' => $plugin));
+        watchdog('jq', $error, WATCHDOG_NOTICE);
+        $invoked_plugins[$plugin] = FALSE;
+      }
+      else {
+        if (isset($jq['dependencies']) && is_array($jq['dependencies'])) {
+          foreach ($jq['dependencies'] as $dependency) {
+            _drupal_add_jq($dependency);
+          }
+        }
+        if (isset($jq['files']['js']) && is_array($jq['files']['js'])) {
+          foreach ($jq['files']['js'] as $file) {
+            drupal_add_js($file);
+          }
+        }
+        if (isset($jq['files']['css']) && is_array($jq['files']['css'])) {
+          foreach ($jq['files']['css'] as $file) {
+            drupal_add_css($file);
+          }
+        }
+        $invoked_plugins[$plugin] = TRUE;
+      }
+    }
+    else {
+      // Log an error, but only if we haven't already. don't want to overwhelm with a lot of identical errors per page
+      $error = t('The %plugin jQuery plugin is not defined.', array('%plugin' => $plugin));
+      watchdog('jq', $error, WATCHDOG_ERROR);
+      $invoked_plugins[$plugin] = FALSE;
+    }
+  }
+  if ($invoked_plugins[$plugin] && module_exists($jq['module'])) {
+    module_load_include('jquery_plugins.inc', $jq['module']);
+    $args = array('add', $plugin);
+    $args = array_merge($args, (array)$extra);
+    $function = $jq['module'] .'_jquery_plugins';
+    if (function_exists($function)) {
+      call_user_func_array($function, $args);
+    }
+  }
+  return isset($invoked_plugins[$plugin]) ? $invoked_plugins[$plugin] : NULL;
+}
+
