javascript_aggregator.module

Tracking 6.x-1.x branch
  1. drupal
    1. 5 contributions/javascript_aggregator/javascript_aggregator.module
    2. 6 contributions/javascript_aggregator/javascript_aggregator.module

Functions & methods

NameDescription
javascript_aggregator_form_alterImplementation of hook_form_alter().
javascript_aggregator_helpImplementation of hook_help().
javascript_aggregator_preprocess_pageImplementation of hook_preprocess_hook().
javascript_aggregator_theme_registry_alterImplementation of hook_theme_registry_alter().
phptemplate_closureImplementation of theme_closure().
_javascript_aggregator_minifyHelper function to minify and gzip files.

File

View source
  1. <?php
  2. /**
  3. * Implementation of hook_help().
  4. */
  5. function javascript_aggregator_help($path, $arg) {
  6. switch ($path) {
  7. case 'admin/help#javascript_aggregator':
  8. $output = '<p>'. t('Uses the <a href="@jsmin">JSMin</a> library to minify the aggregated JavaScript file when <em>JavaScript optimization</em> has been enabled in the <a href="@performance">Performance settings</a>.', array('@performance' => url('admin/settings/performance'), '@jsmin' => 'http://code.google.com/p/jsmin-php/')) .'</p>';
  9. return $output;
  10. }
  11. }
  12. /**
  13. * Implementation of hook_form_alter().
  14. */
  15. function javascript_aggregator_form_alter(&$form, $form_state, $form_id) {
  16. if ($form_id == 'system_performance_settings') {
  17. $form['bandwidth_optimizations']['preprocess_js']['#title'] = t('Optimize and Minify JavaScript files');
  18. $form['bandwidth_optimizations']['preprocess_js']['#description'] .= t(' Once the JavaScript files have been aggregated, they will be minified.');
  19. $form['bandwidth_optimizations']['preprocess_js']['#weight'] = 2;
  20. $form['bandwidth_optimizations']['javascript_aggregator_gzip'] = array(
  21. '#type' => 'checkbox',
  22. '#title' => t('GZip JavaScript'),
  23. '#description' => t('Once minified, optionally <a href="@gzip">GZip</a> the aggregated JavaScript file to dramatically decrease its size.', array('@gzip' => 'http://en.wikipedia.org/wiki/Gzip')),
  24. '#default_value' => variable_get('javascript_aggregator_gzip', FALSE),
  25. '#weight' => 3,
  26. );
  27. $form['bandwidth_optimizations']['javascript_aggregator_no_htaccess'] = array(
  28. '#type' => 'checkbox',
  29. '#title' => t('Do not auto generate .htaccess file (experts only)'),
  30. '#description' => t("If you want to use GZipping and your host doesn't like multiple .htaccess files check this option, together with the option above to bypass htaccess file generation and follow directions in the README.txt."),
  31. '#default_value' => variable_get('javascript_aggregator_no_htaccess', FALSE),
  32. '#weight' => 5,
  33. );
  34. $form['bandwidth_optimizations']['javascript_aggregator_jsminplus'] = array(
  35. '#type' => 'checkbox',
  36. '#title' => t('Use JSMin+ instead of JSMin'),
  37. '#description' => t('Check this option to use <a href="@jsminplus">JSMin+</a> instead of JSMin.', array('@jsminplus' => 'http://crisp.tweakblogs.net/blog/1665/a-new-javascript-minifier-jsmin+.html')),
  38. '#default_value' => variable_get('javascript_aggregator_jsminplus', FALSE),
  39. '#weight' => 4,
  40. );
  41. }
  42. }
  43. /**
  44. * Implementation of hook_theme_registry_alter().
  45. *
  46. * Make javascript_aggregator's page preprocess function run *after* everything
  47. * else's (even jQuery Update).
  48. */
  49. function javascript_aggregator_theme_registry_alter(&$theme_registry) {
  50. if (isset($theme_registry['page'])) {
  51. // If javascript_aggregator's preprocess function is there already, remove it.
  52. if (is_array($theme_registry['page']['preprocess functions']) && $key = array_search('javascript_aggregator_preprocess_page', $theme_registry['page']['preprocess functions'])) {
  53. unset($theme_registry['page']['preprocess functions'][$key]);
  54. }
  55. // Now tack it on at the end so it runs after everything else.
  56. $theme_registry['page']['preprocess functions'][] = 'javascript_aggregator_preprocess_page';
  57. }
  58. }
  59. /**
  60. * Implementation of hook_preprocess_hook().
  61. *
  62. * Minify the aggregated JavaScript file in the page header if JavaScript
  63. * Optimization is turned on.
  64. */
  65. function javascript_aggregator_preprocess_page(&$variables) {
  66. // Only do this for pages that have JavaScript on them.
  67. if (!empty($variables['scripts'])) {
  68. $variables['scripts'] = _javascript_aggregator_minify($variables['scripts']);
  69. }
  70. }
  71. /**
  72. * Implementation of theme_closure().
  73. *
  74. * Minify the aggregated JavaScript file in the page footer if JavaScript
  75. * Optimization is turned on.
  76. */
  77. function phptemplate_closure($main = 0) {
  78. $footer = module_invoke_all('footer', $main);
  79. $js_footer = drupal_get_js('footer');
  80. // Only do this for pages that have JavaScript on them.
  81. if (!empty($js_footer)) {
  82. $js_footer = _javascript_aggregator_minify($js_footer);
  83. }
  84. return implode("\n", $footer) . $js_footer;
  85. }
  86. /**
  87. * Helper function to minify and gzip files.
  88. */
  89. function _javascript_aggregator_minify($scripts) {
  90. // Only process it is JavaScript Optimization is enabled.
  91. if (variable_get('preprocess_js', 0)) {
  92. // Strip out the aggregated JavaScript file.
  93. $path_to_files_directory = base_path() . file_directory_path();
  94. $pattern = "!(<script type=\"text\/javascript\" src=\"(.*?)$path_to_files_directory)(.*?)(\"(.*?)><\/script>)!";
  95. if (preg_match_all($pattern, $scripts, $matches) > 0) {
  96. $aggregated_file_name = $matches[3][0];
  97. $jsmin_file_name = $aggregated_file_name .'min.js';
  98. // Construct the final JSMin file path.
  99. $jsmin_file_path = file_directory_path() . $jsmin_file_name;
  100. // Create the JSMinified file if it doesn't exist yet.
  101. if (!file_exists($jsmin_file_path)) {
  102. if (variable_get('javascript_aggregator_jsminplus', FALSE)) {
  103. // JSMin+ the contents of the aggregated file.
  104. require_once(drupal_get_path('module', 'javascript_aggregator') .'/jsminplus.php');
  105. // Strip Byte Order Marks (BOM's) from the file, JSMin+ cannot parse these.
  106. $file = str_replace(pack("CCC", 0xef, 0xbb, 0xbf), "", file_get_contents(file_directory_path() . $aggregated_file_name));
  107. $contents = JSMinPlus::minify($file);
  108. }
  109. else {
  110. // JSMin the contents of the aggregated file.
  111. require_once(drupal_get_path('module', 'javascript_aggregator') .'/jsmin.php');
  112. $contents = JSMin::minify(file_get_contents(file_directory_path() . $aggregated_file_name));
  113. }
  114. // Code comments containing copyright notices and licensing information
  115. // are stripped when the file is minified. GPL and most other open
  116. // source licenses require the license text to be included whenever the
  117. // file is distributed, so include a reference to the un-minified file.
  118. $contents = '// Minified using Javascript Aggregator - see '. $path_to_files_directory . $aggregated_file_name ." for original source including licensing information.\n". $contents;
  119. // GZip the JavaScript if required.
  120. $htaccess = file_directory_path() . '/js/.htaccess';
  121. if (variable_get('javascript_aggregator_gzip', FALSE)) {
  122. // Create the GZip file if it doesn't already exist.
  123. if (!file_exists($jsmin_file_path .'.gz')) {
  124. file_save_data(gzencode($contents, 9), $jsmin_file_path .'.gz', FILE_EXISTS_REPLACE);
  125. }
  126. // Make sure the .htaccess file is active to handle GZipped JavaScript files.
  127. if (!variable_get('javascript_aggregator_no_htaccess', FALSE) && !file_exists($htaccess)) {
  128. $rewrite_base = base_path() . file_directory_path() .'/js/';
  129. $htaccess_contents = <<<EOT
  130. <Files *.js.gz>
  131. AddEncoding x-gzip .gz
  132. ForceType text/javascript
  133. </Files>
  134. <IfModule mod_rewrite.c>
  135. RewriteEngine on
  136. RewriteBase $rewrite_base
  137. RewriteCond %{HTTP_USER_AGENT} !".*Safari.*"
  138. RewriteCond %{HTTP:Accept-encoding} gzip
  139. RewriteCond %{REQUEST_FILENAME}.gz -f
  140. RewriteRule ^(.*)\.js $1.js.gz [L,QSA]
  141. </IfModule>
  142. EOT;
  143. file_save_data($htaccess_contents, $htaccess, FILE_EXISTS_REPLACE);
  144. }
  145. }
  146. else {
  147. // Delete .htaccess file so *.gz files do not get served.
  148. if (file_exists($htaccess)) {
  149. file_delete($htaccess);
  150. }
  151. }
  152. // Save the contents to the JavaScript file.
  153. file_save_data($contents, $jsmin_file_path, FILE_EXISTS_REPLACE);
  154. }
  155. // Replace the aggregated file with the minified JavaScript file.
  156. $scripts = str_replace($aggregated_file_name, $jsmin_file_name, $scripts);
  157. }
  158. }
  159. return $scripts;
  160. }