Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.850
diff -u -p -r1.850 common.inc
--- includes/common.inc 19 Jan 2009 21:13:09 -0000 1.850
+++ includes/common.inc 20 Jan 2009 00:24:06 -0000
@@ -2538,8 +2538,12 @@ 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);
+ if ($preprocess_js) {
+ // Only check the preprocessor requirements if it's going to be
+ // preprocessing. If these requirements are not met, preprocessing
+ // will be disabled.
+ $preprocess_js = drupal_js_preprocessor()->requirements();
+ }
// A dummy query-string is added to filenames, to gain control over
// browser-caching. The string changes on every update or full cache
@@ -2570,7 +2574,7 @@ function drupal_get_js($scope = 'header'
break;
case 'file':
- if (!$item['preprocess'] || !$is_writable || !$preprocess_js) {
+ if (!$item['preprocess'] || !$preprocess_js) {
$no_preprocess .= '\n";
}
else {
@@ -2581,10 +2585,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 .= '' . "\n";
+ if ($preprocess_js && count($files)) {
+ $preprocessed .= drupal_js_preprocessor()->preprocess($files);
}
// Keep the order of JS files consistent as some are preprocessed and others are not.
@@ -2724,36 +2726,54 @@ 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)) {
+ // Retrieve the preprocess system.
+ $class = variable_get('preprocess_js_system', 'DrupalPreprocessJS');
+
+ // Allow for lazy loading of the class.
+ if (drupal_autoload_class($class)) {
+ $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);
+ else {
+ throw new Exception(t('Class %class was not found.', array('%class' => $class)));
+ }
}
+ return $instance;
+}
- return $jspath . '/' . $filename;
+/**
+ * The interface for preprocessing JavaScript.
+ */
+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);
}
/**
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 20 Jan 2009 00:24:06 -0000
@@ -0,0 +1,66 @@
+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';
+
+ // Ensure there is a js directory within the files directory that it is writable.
+ $jspath = file_create_path('js');
+ file_check_directory($jspath, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+ 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 '' . "\n";
+ }
+}
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.21
diff -u -p -r1.21 common.test
--- modules/simpletest/tests/common.test 11 Jan 2009 08:39:08 -0000 1.21
+++ modules/simpletest/tests/common.test 20 Jan 2009 00:24:07 -0000
@@ -197,6 +197,25 @@ class CascadingStylesheetsTestCase exten
drupal_add_css($css);
$this->assertTrue(strpos(drupal_get_css(), $css) > 0, t('Rendered CSS includes the added stylesheet.'));
}
+
+ /**
+ * Tests rendering inline stylesheets with preprocessing on.
+ */
+ function testRenderInlinePreprocess() {
+ $css = 'body { padding: 0px; }';
+ $css_preprocessed = drupal_load_stylesheet_content($css, TRUE);
+ drupal_add_css($css, 'inline');
+ $this->assertTrue(strpos(drupal_get_css(), $css_preprocessed) > 0, t('Rendering preprocessed inline CSS adds it to the page.'));
+ }
+
+ /**
+ * Tests rendering the stylesheets with preprocessing off.
+ */
+ function testRenderInlineNoPreprocess() {
+ $css = 'body { padding: 0px; }';
+ drupal_add_css($css, array('type' => 'inline', 'preprocess' => FALSE));
+ $this->assertTrue(strpos(drupal_get_css(), $css) > 0, t('Rendering non-preprocessed inline CSS adds it to the page.'));
+ }
}
/**
@@ -329,11 +348,12 @@ class DrupalSetContentTestCase extends D
/**
* Tests for the JavaScript system.
*/
-class JavaScriptTestCase extends DrupalWebTestCase {
+class JavaScriptTestCase extends DrupalWebTestCase implements JSPreprocessingInterface {
/**
- * Store configured value for JavaScript preprocessing.
+ * Store configured values for JavaScript preprocessing.
*/
var $preprocess_js = NULL;
+ var $js_preprocessor_class = 'DrupalPreprocessJS';
function getInfo() {
return array(
@@ -345,11 +365,13 @@ class JavaScriptTestCase extends DrupalW
function setUp() {
// Enable Locale and SimpleTest in the test environment.
- parent::setUp('locale', 'simpletest');
+ parent::setUp('locale', 'simpletest', 'javascript_test');
- // Disable preprocessing
+ // Disable preprocessing and use the default preprocessor system.
$this->preprocess_js = variable_get('preprocess_js', 0);
+ $this->js_preprocessor_class = variable_get('preprocess_js_system', 'DrupalPreprocessJS');
variable_set('preprocess_js', 0);
+ variable_del('preprocess_js_system');
// Reset drupal_add_js() before each test.
drupal_add_js(NULL, NULL, TRUE);
@@ -358,6 +380,7 @@ class JavaScriptTestCase extends DrupalW
function tearDown() {
// Restore configured value for JavaScript preprocessing.
variable_set('preprocess_js', $this->preprocess_js);
+ variable_set('preprocess_js_system', $this->js_preprocessor_class);
parent::tearDown();
}
@@ -470,6 +493,37 @@ class JavaScriptTestCase extends DrupalW
$javascript = drupal_get_js();
$this->assertTrue(strpos($javascript, 'simpletest.js') < strpos($javascript, 'misc/tableselect.js'), t('Altering JavaScript weight through the alter hook.'));
}
+
+ // Static variables required to test the pluggable preprocessor system.
+ static $testFiles = NULL;
+ static $testRequirements = FALSE;
+
+ /**
+ * Tests the pluggable JavaScript preprocessor system.
+ */
+ function testPluggablePreprocessor() {
+ // Switch the preprocessor.
+ variable_set('preprocess_js', TRUE);
+ variable_set('preprocess_js_system', 'JavaScriptTestCase');
+
+ // Add some JavaScript to test the preprocessor system.
+ drupal_add_js('misc/tableselect.js');
+
+ // Retrieve the JavaScript, running through the JavaScriptTestCase preprocessor.
+ $javascript = drupal_get_js();
+ $this->assertTrue(JavaScriptTestCase::$testRequirements, t('Pluggable preprocessor system requirements are checked.'));
+ $this->assertTrue(strpos($javascript, 'has been preprocessed') > 0 && !empty(JavaScriptTestCase::$testRequirements), t('Preprocessor system is pluggable.'));
+ }
+
+ public function requirements() {
+ JavaScriptTestCase::$testRequirements = TRUE;
+ return TRUE;
+ }
+
+ public function preprocess($files) {
+ JavaScriptTestCase::$testFiles = $files;
+ return 'JavaScript has been preprocessed.';
+ }
}
/**
Index: modules/simpletest/tests/javascript_test.info
===================================================================
RCS file: modules/simpletest/tests/javascript_test.info
diff -N modules/simpletest/tests/javascript_test.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/javascript_test.info 20 Jan 2009 00:24:07 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = "JavaScript tests"
+description = "Support module for JavaScript testing."
+package = Testing
+files[] = common.test
Index: modules/simpletest/tests/javascript_test.module
===================================================================
RCS file: modules/simpletest/tests/javascript_test.module
diff -N modules/simpletest/tests/javascript_test.module
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/javascript_test.module 20 Jan 2009 00:24:07 -0000
@@ -0,0 +1,8 @@
+