diff --git a/advagg_bundler/advagg_bundler.admin.inc b/advagg_bundler/advagg_bundler.admin.inc
index 97e94f3..1f9ec05 100644
--- a/advagg_bundler/advagg_bundler.admin.inc
+++ b/advagg_bundler/advagg_bundler.admin.inc
@@ -23,10 +23,10 @@ function advagg_bundler_admin_settings_form() {
$form = array();
$form['advagg_bundler_active'] = array(
- '#type' => 'checkbox',
- '#title' => t('Bundler is Active'),
- '#default_value' => variable_get('advagg_bundler_active', ADVAGG_BUNDLER_ACTIVE),
- '#description' => t('If not checked, the bundler will passively monitor your site, but it will not split up aggregates.'),
+ '#type' => 'checkbox',
+ '#title' => t('Bundler is Active'),
+ '#default_value' => variable_get('advagg_bundler_active', ADVAGG_BUNDLER_ACTIVE),
+ '#description' => t('If not checked, the bundler will passively monitor your site, but it will not split up aggregates.'),
);
$options = array(
@@ -43,25 +43,25 @@ function advagg_bundler_admin_settings_form() {
10 => 10,
);
$form['advagg_bundler_max_css'] = array(
- '#type' => 'select',
- '#title' => t('Max Number Of CSS Bundles Per Page'),
- '#default_value' => variable_get('advagg_bundler_max_css', ADVAGG_BUNDLER_MAX_CSS),
- '#options' => $options,
- '#description' => t('If 0 is selected then the bundler is disabled'),
+ '#type' => 'select',
+ '#title' => t('Max Number Of CSS Bundles Per Page'),
+ '#default_value' => variable_get('advagg_bundler_max_css', ADVAGG_BUNDLER_MAX_CSS),
+ '#options' => $options,
+ '#description' => t('If 0 is selected then the bundler is disabled'),
);
$form['advagg_bundler_max_js'] = array(
- '#type' => 'select',
- '#title' => t('Max Number Of JS Bundles Per Page'),
- '#default_value' => variable_get('advagg_bundler_max_js', ADVAGG_BUNDLER_MAX_JS),
- '#options' => $options,
- '#description' => t('If 0 is selected then the bundler is disabled'),
+ '#type' => 'select',
+ '#title' => t('Max Number Of JS Bundles Per Page'),
+ '#default_value' => variable_get('advagg_bundler_max_js', ADVAGG_BUNDLER_MAX_JS),
+ '#options' => $options,
+ '#description' => t('If 0 is selected then the bundler is disabled'),
);
$form['info'] = array(
- '#type' => 'fieldset',
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#title' => t('Raw Grouping Info'),
+ '#type' => 'fieldset',
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#title' => t('Raw Grouping Info'),
);
module_load_include('inc', 'advagg', 'advagg.admin');
$analysis = advagg_bundler_analysis('', TRUE);
@@ -74,10 +74,10 @@ function advagg_bundler_admin_settings_form() {
list($rawtext, $rows) = advagg_form_print_r($data);
$form['info']['advagg_bundler_info'] = array(
- '#type' => 'textarea',
- '#title' => t('%count different groupings', array('%count' => count($data))),
- '#default_value' => $rawtext,
- '#rows' => $rows -1,
+ '#type' => 'textarea',
+ '#title' => t('%count different groupings', array('%count' => count($data))),
+ '#default_value' => $rawtext,
+ '#rows' => $rows-1,
);
return system_settings_form($form);
diff --git a/advagg_bundler/advagg_bundler.info b/advagg_bundler/advagg_bundler.info
index 078885a..25f8292 100644
--- a/advagg_bundler/advagg_bundler.info
+++ b/advagg_bundler/advagg_bundler.info
@@ -3,3 +3,10 @@ description = Provides intelligent bundling of CSS and JS files by grouping file
package = Advanced CSS/JS Aggregation
core = 6.x
dependencies[] = advagg
+
+; Information added by drupal.org packaging script on 2011-10-26
+version = "6.x-1.6"
+core = "6.x"
+project = "advagg"
+datestamp = "1319670029"
+
diff --git a/advagg_bundler/advagg_bundler.install b/advagg_bundler/advagg_bundler.install
index ad8c182..95430c7 100644
--- a/advagg_bundler/advagg_bundler.install
+++ b/advagg_bundler/advagg_bundler.install
@@ -6,7 +6,14 @@
*/
/**
- * Implementation of hook_enable().
+ * Implements hook_install().
+ */
+function advagg_bundler_install() {
+ drupal_install_schema('advagg_bundler');
+}
+
+/**
+ * Implements hook_enable().
*/
function advagg_bundler_enable() {
// Flush advagg caches.
@@ -17,7 +24,7 @@ function advagg_bundler_enable() {
}
/**
- * Implementation of hook_disable().
+ * Implements hook_disable().
*/
function advagg_bundler_disable() {
// Flush advagg caches.
@@ -28,7 +35,7 @@ function advagg_bundler_disable() {
}
/**
- * Implementation of hook_uninstall().
+ * Implements hook_uninstall().
*/
function advagg_bundler_uninstall() {
// Remove variables.
@@ -36,17 +43,94 @@ function advagg_bundler_uninstall() {
variable_del('advagg_bundler_max_css');
variable_del('advagg_bundler_max_js');
variable_del('advagg_bundler_active');
+
+ drupal_uninstall_schema('advagg_bundler');
}
/**
- * Implementation of hook_requirements().
+ * Implements hook_requirements().
*/
function advagg_bundler_requirements($phase) {
$requirements = array();
- // Ensure translations don't break at install time
+ // Ensure translations don't break at install time.
$t = get_t();
if ($phase == 'runtime') {
}
return $requirements;
}
+
+/**
+ * Implements hook_schema().
+ */
+function advagg_bundler_schema() {
+ $schema['advagg_bundler_selector_count'] = array(
+ 'description' => 'Keep track of when ware the files modified.',
+ 'fields' => array(
+ 'filename' => array(
+ 'description' => 'Path of the file relative to Drupal webroot.',
+ 'type' => 'text',
+ 'size' => 'normal',
+ 'not null' => TRUE,
+ ),
+ 'filename_md5' => array(
+ 'description' => 'MD5 hash of filename',
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'selector_count' => array(
+ 'description' => 'CSS selector count of the file.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ ),
+ 'timestamp' => array(
+ 'description' => 'Last modified timestamp of the file.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('filename_md5'),
+ );
+
+ return $schema;
+}
+
+/**
+ * Add advagg_bundler_selector_count table.
+ */
+function advagg_bundler_update_6000() {
+ $schema['advagg_bundler_selector_count'] = array(
+ 'description' => 'Keep track of when ware the files modified.',
+ 'fields' => array(
+ 'filename' => array(
+ 'description' => 'Path of the file relative to Drupal webroot.',
+ 'type' => 'text',
+ 'size' => 'normal',
+ 'not null' => TRUE,
+ ),
+ 'filename_md5' => array(
+ 'description' => 'MD5 hash of filename',
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'selector_count' => array(
+ 'description' => 'CSS selector count of the file.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ ),
+ 'timestamp' => array(
+ 'description' => 'Last modified timestamp of the file.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('filename_md5'),
+ );
+ $ret = array();
+ db_create_table($ret, 'advagg_bundler_selector_count', $schema['advagg_bundler_selector_count']);
+ return $ret;
+}
diff --git a/advagg_bundler/advagg_bundler.module b/advagg_bundler/advagg_bundler.module
index 6d74a0b..51f4c3a 100644
--- a/advagg_bundler/advagg_bundler.module
+++ b/advagg_bundler/advagg_bundler.module
@@ -31,7 +31,12 @@ define('ADVAGG_BUNDLER_OUTDATED', 1209600);
define('ADVAGG_BUNDLER_ACTIVE', TRUE);
/**
- * Implementation of hook_menu
+ * CSS selector limit in a single stylesheet on IE9 and below.
+ */
+define('SELECTOR_SPLIT_VALUE', 4095);
+
+/**
+ * Implements hook_menu().
*/
function advagg_bundler_menu() {
$items = array();
@@ -52,13 +57,12 @@ function advagg_bundler_menu() {
}
/**
- * Implement hook_advagg_filenames_alter.
+ * Implements hook_advagg_filenames_alter().
*/
function advagg_bundler_advagg_filenames_alter(&$filenames) {
// Get max number of sub aggregates to create.
$max_css = variable_get('advagg_bundler_max_css', ADVAGG_BUNDLER_MAX_CSS);
$max_js = variable_get('advagg_bundler_max_js', ADVAGG_BUNDLER_MAX_JS);
- $schema = advagg_get_server_schema();
$output = array();
foreach ($filenames as $values) {
@@ -66,7 +70,7 @@ function advagg_bundler_advagg_filenames_alter(&$filenames) {
$filetype = $values['filetype'];
$files = $values['files'];
$bundle_md5 = $values['bundle_md5'];
- $cached_data_key = 'bundler_' . $schema . '_' . $bundle_md5;
+ $cached_data_key = 'bundler_' . $bundle_md5;
// Try cache first; cache table is cache_advagg_bundle_reuse.
$cached_data = advagg_cached_bundle_get($cached_data_key, 'advagg_bundler_filenames_alter');
@@ -131,7 +135,7 @@ function advagg_bundler_advagg_filenames_alter(&$filenames) {
// Make sure we didn't go over the max; if we did merge the smallest bundles
// together.
- advagg_bundler_merge($groupings, $max);
+ advagg_bundler_merge($groupings, $max, $filetype);
// If only one group then don't do any more processing. The merge algorithm
// could have reduce the groupings down to one.
@@ -146,7 +150,7 @@ function advagg_bundler_advagg_filenames_alter(&$filenames) {
$data = array();
foreach ($groupings as $bundle) {
$values['files'] = $bundle;
- $values['bundle_md5'] = md5($schema . implode('', $bundle));
+ $values['bundle_md5'] = md5(implode('', $bundle));
$data[] = $values;
$output[] = $values;
}
@@ -162,12 +166,13 @@ function advagg_bundler_advagg_filenames_alter(&$filenames) {
/**
* Given a filename return a bundle key.
*
- * @param $filename
+ * @param string $filename
* filename
- * @param $force
+ * @param bool $force
* bypass the cache and get a fresh version of the analysis.
- * @return
- * string to be used for the grouping key.
+ *
+ * @return string
+ * Value to be used for the grouping key.
*/
function advagg_bundler_analysis($filename = '', $force = FALSE) {
// Cache query in a static.
@@ -196,7 +201,7 @@ function advagg_bundler_analysis($filename = '', $force = FALSE) {
filename
FROM (
SELECT
- LPAD(CAST(COUNT(*) AS char(8)), 8, '0') AS count,
+ LPAD(COUNT(*), 8, '00000000') AS count,
bundle_md5,
filename_md5
FROM
@@ -247,12 +252,14 @@ function advagg_bundler_analysis($filename = '', $force = FALSE) {
*
* This preserves the order.
*
- * @param $groupings
+ * @param array $groupings
* array of requested groups
- * @param $max
+ * @param int $max
* max number of grouping
+ * @param string $filetype
+ * String with the file type: css or js
*/
-function advagg_bundler_merge(&$groupings, $max) {
+function advagg_bundler_merge(&$groupings, $max, $filetype) {
$group_count = count($groupings);
if (!empty($max)) {
@@ -304,9 +311,7 @@ function advagg_bundler_merge(&$groupings, $max) {
}
}
-// watchdog('debug', $first . "
\n" . $last . "
\n" . str_replace(' ', ' ', nl2br(htmlentities(print_r(array($groupings, $map, $counts), TRUE)))));
-
- // Create the new merged set
+ // Create the new merged set.
$a = $groupings[$first];
$b = $groupings[$last];
$new_set = array_merge($a, $b);
@@ -374,6 +379,98 @@ function advagg_bundler_merge(&$groupings, $max) {
$groupings[$merge_candidate_key] = $new_set;
}
- // Output Debugging info to watchdog.
- // watchdog('debug', str_replace(' ', ' ', nl2br(htmlentities(print_r($groupings, TRUE)))));
+ // Prevent CSS selectors exceeding 4095 due to limits with IE9 and below.
+ if ($filetype == 'css') {
+
+ // Check each group to see if it exceeds the selector limit.
+ do {
+ $groupings_edited = FALSE;
+ foreach ($groupings as $key => $group) {
+
+ // Restart the selector limit check if the grouping was edited.
+ if ($groupings_edited) {
+ break;
+ }
+
+ $group_selector_counter = 0;
+
+ $selector_counts = advagg_bundler_get_css_selector_count($group);
+
+ for ($i = 0; $i < count($group) && !$groupings_edited; $i++) {
+
+ $selector_count = isset($selector_counts[$group[$i]]) ? $selector_counts[$group[$i]] : 0;
+
+ if ($group_selector_counter + $selector_count > SELECTOR_SPLIT_VALUE) {
+ $groupings_edited = TRUE;
+
+ // Divide the group.
+ $first_group = array_splice($group, 0, $i);
+ $second_group = array_splice($group, 0);
+
+ // Rebuild the array with the new set in the correct place.
+ $new_groupings = array();
+ foreach ($groupings as $k => $files) {
+ if ($k == $key) {
+ $new_groupings[$k . '_1'] = $first_group;
+ $new_groupings[$k . '_2'] = $second_group;
+ }
+ else {
+ $new_groupings[$k] = $files;
+ }
+ }
+ $groupings = $new_groupings;
+ }
+ else {
+ $group_selector_counter += $selector_count;
+ }
+ }
+ }
+ } while ($groupings_edited);
+ }
+}
+
+/**
+ * Gets the selector count of the provided files.
+ *
+ * @param array $files
+ * Array of files to use.
+ *
+ * @return array
+ * The selector counts of each file.
+ */
+function advagg_bundler_get_css_selector_count($files) {
+ $results = array();
+ $placeholders = db_placeholders($files);
+ $result = db_query("SELECT filename, selector_count, timestamp FROM {advagg_bundler_selector_count} WHERE filename IN ($placeholders)", $files);
+
+ while ($row = db_fetch_array($result)) {
+ $modified = filemtime($row['filename']);
+ if ($modified > $row['timestamp']) {
+ $css = advagg_build_css_bundle(array($row['filename']), TRUE);
+
+ // Get the number of selectors.
+ // http://stackoverflow.com/questions/12567000/regex-matching-for-counting-css-selectors/12567381#12567381
+ $selector_count = preg_match_all('/\{.+?\}|,/s', $css, $matched);
+
+ db_query("UPDATE {advagg_bundler_selector_count} SET timestamp = %d, selector_count = %d WHERE filename LIKE '%s'", $modified, $selector_count, $row['filename']);
+
+ $results[$row['filename']] = $selector_count;
+ }
+ else {
+ $results[$row['filename']] = $row['selector_count'];
+ }
+ }
+
+ foreach ($files as $file) {
+ if (!isset($results[$file]) && file_exists($file)) {
+ $css = advagg_build_css_bundle(array($file), TRUE);
+ $selector_count = preg_match_all('/\{.+?\}|,/s', $css, $matched);
+
+ db_query("INSERT INTO {advagg_bundler_selector_count} VALUES('%s', '%s', %d, %d)", $file, md5($file), $selector_count, filemtime($file));
+
+ $results[$file] = $selector_count;
+ }
+ }
+
+ return $results;
}