Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.842
diff -u -p -r1.842 common.inc
--- includes/common.inc	5 Jan 2009 22:23:58 -0000	1.842
+++ includes/common.inc	7 Jan 2009 23:40:43 -0000
@@ -2526,8 +2526,6 @@ function drupal_get_js($scope = 'header'
   $no_preprocess = '';
   $files = array();
   $preprocess_js = (variable_get('preprocess_js', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update'));
-  $directory = file_directory_path();
-  $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
 
   // A dummy query-string is added to filenames, to gain control over
   // browser-caching. The string changes on every update or full cache
@@ -2558,7 +2556,7 @@ function drupal_get_js($scope = 'header'
         break;
 
       case 'file':
-        if (!$item['preprocess'] || !$is_writable || !$preprocess_js) {
+        if (!$item['preprocess'] || !drupal_js_preprocessor()->requirements() || !$preprocess_js) {
           $no_preprocess .= '<script type="text/javascript"' . ($item['defer'] ? ' defer="defer"' : '') . ' src="' . base_path() . $item['data'] . ($item['cache'] ? $query_string : '?' . REQUEST_TIME) . "\"></script>\n";
         }
         else {
@@ -2569,10 +2567,8 @@ function drupal_get_js($scope = 'header'
   }
 
   // Aggregate any remaining JS files that haven't already been output.
-  if ($is_writable && $preprocess_js && count($files) > 0) {
-    $filename = md5(serialize($files) . $query_string) . '.js';
-    $preprocess_file = drupal_build_js_cache($files, $filename);
-    $preprocessed .= '<script type="text/javascript" src="' . base_path() . $preprocess_file . '"></script>' . "\n";
+  if (drupal_js_preprocessor()->requirements() && $preprocess_js && count($files) > 0) {
+    $preprocessed .= drupal_js_preprocessor()->preprocess($files);
   }
 
   // Keep the order of JS files consistent as some are preprocessed and others are not.
@@ -2712,36 +2708,22 @@ function drupal_add_tabledrag($table_id,
 }
 
 /**
- * Aggregate JS files, putting them in the files directory.
- *
- * @param $files
- *   An array of JS files to aggregate and compress into one file.
- * @param $filename
- *   The name of the aggregate JS file.
- * @return
- *   The name of the JS file.
+ * Returns a JavaScript preprocessing object that implements JSPreprocessingInterface.
  */
-function drupal_build_js_cache($files, $filename) {
-  $contents = '';
+function drupal_js_preprocessor() {
+  static $instance;
 
-  // Create the js/ within the files folder.
-  $jspath = file_create_path('js');
-  file_check_directory($jspath, FILE_CREATE_DIRECTORY);
-
-  if (!file_exists($jspath . '/' . $filename)) {
-    // Build aggregate JS file.
-    foreach ($files as $path => $info) {
-      if ($info['preprocess']) {
-        // Append a ';' after each JS file to prevent them from running together.
-        $contents .= file_get_contents($path) . ';';
-      }
+  if (empty($instance)) {
+    $class = variable_get('preprocess_js_system', 'DrupalPreprocessJS');
+    $interfaces = class_implements($class);
+    if (isset($interfaces['JSPreprocessingInterface'])) {
+      $instance = new $class;
+    }
+    else {
+      throw new Exception(t('Class %class does not implement interface %interface', array('%class' => $class, '%interface' => 'JSPreprocessingInterface')));
     }
-
-    // Create the JS file.
-    file_unmanaged_save_data($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
   }
-
-  return $jspath . '/' . $filename;
+  return $instance;
 }
 
 /**
Index: includes/preprocess.inc
===================================================================
RCS file: includes/preprocess.inc
diff -N includes/preprocess.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/preprocess.inc	7 Jan 2009 23:40:43 -0000
@@ -0,0 +1,84 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Aggregate JavaScript files. 
+ */
+
+interface JSPreprocessingInterface {
+  /**
+   * Check preprocessing requirements.
+   *
+   * @return
+   *  TRUE if requirements met to preform preprocessing.
+   */
+  public function requirements();
+
+  /**
+   * Preprocess JavaScript files.
+   *
+   * @param $files
+   *  An array of JavaScript files.
+   * 
+   * @return
+   *  html for preprocessed JavaScript files.
+   */
+  public function preprocess($files);
+}
+
+class DrupalPreprocessJS implements JSPreprocessingInterface {
+  /**
+   * Cache if preprocessed files should be saved to the files directory. 
+   */
+  protected $is_writable = NULL;
+
+  /**
+   * Check directory to save files to and for public file downloads.
+   *
+   * @return
+   *  TRUE if files directory is writable and file downloads are public.
+   */
+  public function requirements() {
+    if (is_null($this->is_writable)) {
+       $directory = file_directory_path();
+       $this->is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC);
+    }
+    return $this->is_writable;
+  }
+
+  /**
+   * Aggregate JS files, putting them in the files directory.
+   *
+   * @param $files
+   *  An array of JavaScript files to aggregate and compress into one file.
+   * 
+   * @return
+   *  The script tag containing the path to the cached JavaScript file.
+   */
+  public function preprocess($files) {
+    $contents = '';
+
+    $query_string = '?' . substr(variable_get('css_js_query_string', '0'), 0, 1);
+    $filename = md5(serialize($files) . $query_string) . '.js';    
+
+    // Create the js/ within the files folder.
+    $jspath = file_create_path('js');
+    file_check_directory($jspath, FILE_CREATE_DIRECTORY);
+  
+    if (!file_exists($jspath . '/' . $filename)) {
+      // Build aggregate JS file.
+      foreach ($files as $path => $info) {
+        if ($info['preprocess']) {
+          // Append a ';' after each JS file to prevent them from running together.
+          $contents .= file_get_contents($path) . ';';
+        }
+      }
+  
+      // Create the JS file.
+      file_unmanaged_save_data($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
+    }
+  
+    return '<script type="text/javascript" src="' . base_path() . $jspath . '/' . $filename . '"></script>' . "\n";
+  }
+}
\ No newline at end of file
