protected function _add_prefixes(css_group $css_doc, $vendor_override = null, $ignore_keyframes = false, $remove_original_property = false) { $vendors_ids = array(1 => 'webkit', 0 => 'mozilla', 2 => 'opera', 3 => 'msie'); $originals = array(); $apply_vendors = array(); foreach ($vendors_ids as $id => $prop) { $originals[$prop] = $this->{$prop}; if (isset($vendor_override)) { $this->{$prop} = isset($vendor_override[$id]) ? $vendor_override[$id] : (isset($vendor_override[$prop]) ? $vendor_override[$prop] : false); } $apply_vendors[$id] = $this->{$prop}; } foreach ($css_doc->find_all('css_property') as $property) { /* @var $property css_property */ //Check if property is inside a @keyframes $keyframe = null; if (!$ignore_keyframes) { foreach ($property->parents() as $parent) { if ($parent instanceof css_group && stripos($parent->name, '@keyframes') === 0) { $keyframe = $parent; } } } if (isset($keyframe)) { //Create vendor keyframes, each one with its own vendor prefixes $this->_prefix_keyframe($keyframe, $apply_vendors); } else { if (array_key_exists($property->name, $this->_transformations)) { $applied = $this->_apply_transformation($property, $vendors_ids); if ($applied && $remove_original_property) { $property->remove(); } } else { //Replace vendor functions (gradients) $this->_prefix_gradients($property, $vendors_ids); } } } //Restore original values foreach ($originals as $prop => $value) { $this->{$prop} = $value; } }
/** * Clean a CSS file * * @param css_group $css_doc CSS file to clean * * @return css_group */ public function clean(css_group $css_doc) { //Find tokens $project_tokens = $this->_find_tokens(); //Clean selectors $removed = 0; $selector_usage = array(); foreach ($css_doc->find_all('css_group') as $group) { /* @var $group css_group */ if (!$group->name || stripos($group->name, '@') !== false) { continue; //Ignore @media, @keyframes and future especial groups } $current_selectors = $group->selectors(); $valid_selectors = array(); foreach ($current_selectors as $selector) { $include = true; //Remove pseudo-class $clean_selector = preg_replace('/\\:.*/', '', $selector); //Look for selector tokens in the token list foreach ($this->_get_tokens($clean_selector) as $token) { if (!isset($project_tokens[$token])) { //Remove current selector $include = false; } } if ($include) { $valid_selectors[] = $selector; if ($this->report_path) { $count = 0; foreach ($this->_get_tokens($clean_selector) as $token) { $count += $project_tokens[$token]; } $selector_usage[$clean_selector] = isset($selector_usage[$clean_selector]) ? $selector_usage[$clean_selector] + $count : $count; } } } //Set cleaned selectors, or remove entire group if empty if (empty($valid_selectors)) { $group->remove(); } else { $group->selectors($valid_selectors); } if ($this->verbose) { $dif = array_diff($current_selectors, $valid_selectors); if (!empty($dif)) { $removed += count($dif); $dif = implode(', ', $dif); echo "Removed {$dif}\n"; } } } //Create report if ($this->report_path) { asort($selector_usage); $lines = array('Selector usage report. Generated on ' . date('r'), ''); foreach ($selector_usage as $selector => $freq) { $lines[] = "{$selector} found {$freq} references"; } file_put_contents($this->report_path, implode(PHP_EOL, $lines)); } if ($this->verbose) { echo "\nClean done, removed {$removed} unused selectors\n"; } return $css_doc; }
/** * @see http://net.tutsplus.com/tutorials/html-css-techniques/quick-tip-how-to-target-ie6-ie7-and-ie8-uniquely-with-4-characters/ */ protected function _remove_ie_hacks(css_group $document) { foreach ($document->find_all('css_property') as $property) { $is_hack = in_array($property->name, array('filter', '-ms-filter')) || in_array($property->name[0], array('*', '_')) || stripos($property->value, 'expression') === 0 || substr($property->value, -2) === '\\9'; //IE8 Hack if ($is_hack) { $property->remove(); } } }