diff options
-rw-r--r-- | CHANGELOG.txt | 4 | ||||
-rw-r--r-- | includes/common.inc | 40 | ||||
-rw-r--r-- | modules/simpletest/tests/common.test | 130 |
3 files changed, 169 insertions, 5 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 62993ae5a..5e299f5cb 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,10 @@ Drupal 7.36, xxxx-xx-xx (development version) ----------------------- +- Added a 'javascript_always_use_jquery' variable which can be set to FALSE by + sites that may not need jQuery loaded on all pages, and a 'requires_jquery' + option to drupal_add_js() which modules can set to FALSE when adding + JavaScript files that have no dependency on jQuery. - Fixed incorrect foreign keys in the User module's role_permission and users_roles database tables. - Changed permission descriptions throughout Drupal core to consistently link diff --git a/includes/common.inc b/includes/common.inc index 0fac77201..0437ec1a4 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -4162,6 +4162,13 @@ function drupal_region_class($region) { * else being the same, JavaScript added by a call to drupal_add_js() that * happened later in the page request gets added to the page after one for * which drupal_add_js() happened earlier in the page request. + * - requires_jquery: Set this to FALSE if the JavaScript you are adding does + * not have a dependency on jQuery. Defaults to TRUE, except for JavaScript + * settings where it defaults to FALSE. This is used on sites that have the + * 'javascript_always_use_jquery' variable set to FALSE; on those sites, if + * all the JavaScript added to the page by drupal_add_js() does not have a + * dependency on jQuery, then for improved front-end performance Drupal + * will not add jQuery and related libraries and settings to the page. * - defer: If set to TRUE, the defer attribute is set on the <script> * tag. Defaults to FALSE. * - cache: If set to FALSE, the JavaScript file is loaded anew on every page @@ -4179,6 +4186,14 @@ function drupal_region_class($region) { */ function drupal_add_js($data = NULL, $options = NULL) { $javascript = &drupal_static(__FUNCTION__, array()); + $jquery_added = &drupal_static(__FUNCTION__ . ':jquery_added', FALSE); + + // If the $javascript variable has been reset with drupal_static_reset(), + // jQuery and related files will have been removed from the list, so set the + // variable back to FALSE to indicate they have not yet been added. + if (empty($javascript)) { + $jquery_added = FALSE; + } // Construct the options, taking the defaults into consideration. if (isset($options)) { @@ -4189,6 +4204,9 @@ function drupal_add_js($data = NULL, $options = NULL) { else { $options = array(); } + if (isset($options['type']) && $options['type'] == 'setting') { + $options += array('requires_jquery' => FALSE); + } $options += drupal_js_defaults($data); // Preprocess can only be set if caching is enabled. @@ -4199,14 +4217,18 @@ function drupal_add_js($data = NULL, $options = NULL) { $options['weight'] += count($javascript) / 1000; if (isset($data)) { - // Add jquery.js and drupal.js, as well as the basePath setting, the - // first time a JavaScript file is added. - if (empty($javascript)) { + // Add jquery.js, drupal.js, and related files and settings if they have + // not been added yet. However, if the 'javascript_always_use_jquery' + // variable is set to FALSE (indicating that the site does not want jQuery + // automatically added on all pages) then only add it if a file or setting + // that requires jQuery is being added also. + if (!$jquery_added && (variable_get('javascript_always_use_jquery', TRUE) || $options['requires_jquery'])) { + $jquery_added = TRUE; // url() generates the prefix using hook_url_outbound_alter(). Instead of // running the hook_url_outbound_alter() again here, extract the prefix // from url(). url('', array('prefix' => &$prefix)); - $javascript = array( + $default_javascript = array( 'settings' => array( 'data' => array( array('basePath' => base_path()), @@ -4225,11 +4247,13 @@ function drupal_add_js($data = NULL, $options = NULL) { 'group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -1, + 'requires_jquery' => TRUE, 'preprocess' => TRUE, 'cache' => TRUE, 'defer' => FALSE, ), ); + $javascript = drupal_array_merge_deep($javascript, $default_javascript); // Register all required libraries. drupal_add_library('system', 'jquery', TRUE); drupal_add_library('system', 'jquery.once', TRUE); @@ -4270,6 +4294,7 @@ function drupal_js_defaults($data = NULL) { 'group' => JS_DEFAULT, 'every_page' => FALSE, 'weight' => 0, + 'requires_jquery' => TRUE, 'scope' => 'header', 'cache' => TRUE, 'defer' => FALSE, @@ -4316,7 +4341,12 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS if (!isset($javascript)) { $javascript = drupal_add_js(); } - if (empty($javascript)) { + + // If no JavaScript items have been added, or if the only JavaScript items + // that have been added are JavaScript settings (which don't do anything + // without any JavaScript code to use them), then no JavaScript code should + // be added to the page. + if (empty($javascript) || (isset($javascript['settings']) && count($javascript) == 1)) { return ''; } diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index b8ad0cca5..0f0347fc4 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -1441,6 +1441,127 @@ class JavaScriptTestCase extends DrupalWebTestCase { } /** + * Test the 'javascript_always_use_jquery' variable. + */ + function testJavaScriptAlwaysUseJQuery() { + // The default front page of the site should use jQuery and other standard + // scripts and settings. + $this->drupalGet(''); + $this->assertRaw('misc/jquery.js', 'Default behavior: The front page of the site includes jquery.js.'); + $this->assertRaw('misc/drupal.js', 'Default behavior: The front page of the site includes drupal.js.'); + $this->assertRaw('Drupal.settings', 'Default behavior: The front page of the site includes Drupal settings.'); + $this->assertRaw('basePath', 'Default behavior: The front page of the site includes the basePath Drupal setting.'); + + // The default front page should not use jQuery and other standard scripts + // and settings when the 'javascript_always_use_jquery' variable is set to + // FALSE. + variable_set('javascript_always_use_jquery', FALSE); + $this->drupalGet(''); + $this->assertNoRaw('misc/jquery.js', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include jquery.js.'); + $this->assertNoRaw('misc/drupal.js', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include drupal.js.'); + $this->assertNoRaw('Drupal.settings', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include Drupal settings.'); + $this->assertNoRaw('basePath', 'When "javascript_always_use_jquery" is FALSE: The front page of the site does not include the basePath Drupal setting.'); + variable_del('javascript_always_use_jquery'); + + // When only settings have been added via drupal_add_js(), drupal_get_js() + // should still return jQuery and other standard scripts and settings. + $this->resetStaticVariables(); + drupal_add_js(array('testJavaScriptSetting' => 'test'), 'setting'); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'testJavaScriptSetting') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when only settings have been added includes the added Drupal settings.'); + + // When only settings have been added via drupal_add_js() and the + // 'javascript_always_use_jquery' variable is set to FALSE, drupal_get_js() + // should not return jQuery and other standard scripts and settings, nor + // should it return the requested settings (since they cannot actually be + // addded to the page without jQuery). + $this->resetStaticVariables(); + variable_set('javascript_always_use_jquery', FALSE); + drupal_add_js(array('testJavaScriptSetting' => 'test'), 'setting'); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'testJavaScriptSetting') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when only settings have been added does not include the added Drupal settings.'); + variable_del('javascript_always_use_jquery'); + + // When a regular file has been added via drupal_add_js(), drupal_get_js() + // should return jQuery and other standard scripts and settings. + $this->resetStaticVariables(); + drupal_add_js('misc/collapse.js'); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the custom file.'); + + // When a regular file has been added via drupal_add_js() and the + // 'javascript_always_use_jquery' variable is set to FALSE, drupal_get_js() + // should still return jQuery and other standard scripts and settings + // (since the file is assumed to require jQuery by default). + $this->resetStaticVariables(); + variable_set('javascript_always_use_jquery', FALSE); + drupal_add_js('misc/collapse.js'); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file has been added includes the custom file.'); + variable_del('javascript_always_use_jquery'); + + // When a file that does not require jQuery has been added via + // drupal_add_js(), drupal_get_js() should still return jQuery and other + // standard scripts and settings by default. + $this->resetStaticVariables(); + drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'Default behavior: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the custom file.'); + + // When a file that does not require jQuery has been added via + // drupal_add_js() and the 'javascript_always_use_jquery' variable is set + // to FALSE, drupal_get_js() should not return jQuery and other standard + // scripts and setting, but it should still return the requested file. + $this->resetStaticVariables(); + variable_set('javascript_always_use_jquery', FALSE); + drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') === FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added does not include the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when a custom JavaScript file that does not require jQuery has been added includes the custom file.'); + variable_del('javascript_always_use_jquery'); + + // When 'javascript_always_use_jquery' is set to FALSE and a file that does + // not require jQuery is added, followed by one that does, drupal_get_js() + // should return jQuery and other standard scripts and settings, in + // addition to both of the requested files. + $this->resetStaticVariables(); + variable_set('javascript_always_use_jquery', FALSE); + drupal_add_js('misc/collapse.js', array('requires_jquery' => FALSE)); + drupal_add_js('misc/ajax.js'); + $javascript = drupal_get_js(); + $this->assertTrue(strpos($javascript, 'misc/jquery.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes jquery.js.'); + $this->assertTrue(strpos($javascript, 'misc/drupal.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes drupal.js.'); + $this->assertTrue(strpos($javascript, 'Drupal.settings') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes Drupal.settings.'); + $this->assertTrue(strpos($javascript, 'basePath') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the basePath Drupal setting.'); + $this->assertTrue(strpos($javascript, 'misc/collapse.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the first custom file.'); + $this->assertTrue(strpos($javascript, 'misc/ajax.js') !== FALSE, 'When "javascript_always_use_jquery" is FALSE: The JavaScript returned by drupal_get_js() when at least one custom JavaScript file that requires jQuery has been added includes the second custom file.'); + variable_del('javascript_always_use_jquery'); + } + + /** * Test drupal_add_js() sets preproccess to false when cache is set to false. */ function testNoCache() { @@ -1668,6 +1789,15 @@ class JavaScriptTestCase extends DrupalWebTestCase { $query_string = variable_get('css_js_query_string', '0'); $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, 'Query string was appended correctly to js.'); } + + /** + * Resets static variables related to adding JavaScript to a page. + */ + function resetStaticVariables() { + drupal_static_reset('drupal_add_js'); + drupal_static_reset('drupal_add_library'); + drupal_static_reset('drupal_get_library'); + } } /** |