Version Notes
It's a really light module to allow you to minify CSS/JS and Html.
No complicated configuration, it support CE1.5.0 later and EE1.8.0 later!
Download this release
Release Info
| Developer | Yongcheng CHEN |
| Extension | YccMinify |
| Version | 0.1.0 |
| Comparing to | |
| See all releases | |
Version 0.1.0
- app/code/community/Ycc/Minify/Helper/Data.php +164 -0
- app/code/community/Ycc/Minify/Model/Observer.php +29 -0
- app/code/community/Ycc/Minify/Model/System/Config/Csscompressor.php +13 -0
- app/code/community/Ycc/Minify/Model/System/Config/Jscompressor.php +14 -0
- app/code/community/Ycc/Minify/etc/config.xml +33 -0
- app/code/community/Ycc/Minify/etc/system.xml +56 -0
- lib/yccminify/HTML.php +245 -0
- lib/yccminify/closurecompiler.jar +0 -0
- lib/yccminify/yuicompressor.jar +0 -0
- package.xml +23 -0
app/code/community/Ycc/Minify/Helper/Data.php
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
class Ycc_Minify_Helper_Data extends Mage_Core_Helper_Data
|
| 4 |
+
{
|
| 5 |
+
public function mergeFiles(array $srcFiles, $targetFile = false, $mustMerge = false, $beforeMergeCallback = null, $extensionsFilter = array())
|
| 6 |
+
{
|
| 7 |
+
try {
|
| 8 |
+
// check whether merger is required
|
| 9 |
+
$shouldMerge = $mustMerge || !$targetFile;
|
| 10 |
+
if (!$shouldMerge) {
|
| 11 |
+
if (!file_exists($targetFile)) {
|
| 12 |
+
$shouldMerge = true;
|
| 13 |
+
} else {
|
| 14 |
+
$targetMtime = filemtime($targetFile);
|
| 15 |
+
foreach ($srcFiles as $file) {
|
| 16 |
+
if (filemtime($file) > $targetMtime) {
|
| 17 |
+
$shouldMerge = true;
|
| 18 |
+
break;
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
// merge contents into the file
|
| 25 |
+
if ($shouldMerge) {
|
| 26 |
+
if ($targetFile && !is_writeable(dirname($targetFile))) {
|
| 27 |
+
// no translation intentionally
|
| 28 |
+
throw new Exception(sprintf('Path %s is not writeable.', dirname($targetFile)));
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
// filter by extensions
|
| 32 |
+
if ($extensionsFilter) {
|
| 33 |
+
if (!is_array($extensionsFilter)) {
|
| 34 |
+
$extensionsFilter = array($extensionsFilter);
|
| 35 |
+
}
|
| 36 |
+
if (!empty($srcFiles)){
|
| 37 |
+
foreach ($srcFiles as $key => $file) {
|
| 38 |
+
$fileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
| 39 |
+
if (!in_array($fileExt, $extensionsFilter)) {
|
| 40 |
+
unset($srcFiles[$key]);
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
if (empty($srcFiles)) {
|
| 46 |
+
// no translation intentionally
|
| 47 |
+
throw new Exception('No files to compile.');
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
$data = '';
|
| 51 |
+
foreach ($srcFiles as $file) {
|
| 52 |
+
if (!file_exists($file)) {
|
| 53 |
+
continue;
|
| 54 |
+
}
|
| 55 |
+
$contents = file_get_contents($file) . "\n";
|
| 56 |
+
if ($beforeMergeCallback && is_callable($beforeMergeCallback)) {
|
| 57 |
+
$contents = call_user_func($beforeMergeCallback, $file, $contents);
|
| 58 |
+
}
|
| 59 |
+
$data .= $contents;
|
| 60 |
+
}
|
| 61 |
+
if (!$data) {
|
| 62 |
+
// no translation intentionally
|
| 63 |
+
throw new Exception(sprintf("No content found in files:\n%s", implode("\n", $srcFiles)));
|
| 64 |
+
}
|
| 65 |
+
if ($targetFile) {
|
| 66 |
+
$this->compile($targetFile,$data);
|
| 67 |
+
/*$extend = explode("." , $targetFile);
|
| 68 |
+
$tmpfile = "/tmp/".md5($targetFile). ".". $extend[count($extend)-1];
|
| 69 |
+
file_put_contents($tmpfile, $data, LOCK_EX);
|
| 70 |
+
exec("java -jar " . Mage::getBaseDir(). DS. "lib" .DS."yccminify". DS . "yuicompressor.jar $tmpfile > $targetFile");
|
| 71 |
+
*/
|
| 72 |
+
#exec("rm -rf $tmpfile");
|
| 73 |
+
#file_put_contents($targetFile, $data, LOCK_EX);
|
| 74 |
+
} else {
|
| 75 |
+
return $data; // no need to write to file, just return data
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
return true; // no need in merger or merged into file successfully
|
| 79 |
+
} catch (Exception $e) {
|
| 80 |
+
Mage::logException($e);
|
| 81 |
+
}
|
| 82 |
+
return false;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
const CSS_COMPILER_CONFIG = 'dev/css/minify_css_files';
|
| 86 |
+
const JS_COMPILER_CONFIG = 'dev/js/minify_js_files';
|
| 87 |
+
private function compile($targetFile, $data){
|
| 88 |
+
$extend = explode("." , $targetFile);
|
| 89 |
+
$ext = $extend[count($extend)-1];
|
| 90 |
+
$tmpfile = "/tmp/".md5($targetFile). ".". $ext;
|
| 91 |
+
if ($ext == "css"){
|
| 92 |
+
$mode = Mage::getStoreConfig(self::CSS_COMPILER_CONFIG, Mage::app()->getStore()->getStoreId());
|
| 93 |
+
} else {
|
| 94 |
+
$mode = Mage::getStoreConfig(self::JS_COMPILER_CONFIG, Mage::app()->getStore()->getStoreId());
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
if (empty($mode)){
|
| 98 |
+
file_put_contents($targetFile, $data, LOCK_EX);
|
| 99 |
+
return;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
file_put_contents($tmpfile, $data, LOCK_EX);
|
| 103 |
+
if ($mode == "1"){
|
| 104 |
+
exec($this->getYUICmd(array(), $ext, $tmpfile, $targetFile));
|
| 105 |
+
} elseif ($mode == "2"){
|
| 106 |
+
exec($this->getClosuerCmd(array(), $ext, $tmpfile, $targetFile));
|
| 107 |
+
}
|
| 108 |
+
exec("rm -rf $tmpfile");
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
private function getYUICmd($userOptions, $type, $tmpfile, $targetFile)
|
| 112 |
+
{
|
| 113 |
+
$o = array_merge(
|
| 114 |
+
array(
|
| 115 |
+
'charset' => ''
|
| 116 |
+
,'line-break' => 5000
|
| 117 |
+
,'type' => $type
|
| 118 |
+
,'nomunge' => false
|
| 119 |
+
,'preserve-semi' => false
|
| 120 |
+
,'disable-optimizations' => false
|
| 121 |
+
)
|
| 122 |
+
,$userOptions
|
| 123 |
+
);
|
| 124 |
+
|
| 125 |
+
$cmd = 'java -Xmx512m -jar ' . Mage::getBaseDir(). DS. "lib" .DS."yccminify". DS . "yuicompressor.jar"
|
| 126 |
+
. " --type {$type}"
|
| 127 |
+
. (preg_match('/^[a-zA-Z\\-]+$/', $o['charset'])
|
| 128 |
+
? " --charset {$o['charset']}"
|
| 129 |
+
: '')
|
| 130 |
+
. (is_numeric($o['line-break']) && $o['line-break'] >= 0
|
| 131 |
+
? ' --line-break ' . (int)$o['line-break']
|
| 132 |
+
: '');
|
| 133 |
+
if ($type === 'js') {
|
| 134 |
+
foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) {
|
| 135 |
+
$cmd .= $o[$opt]
|
| 136 |
+
? " --{$opt}"
|
| 137 |
+
: '';
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
return "$cmd $tmpfile > $targetFile";
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
private function getClosuerCmd($userOptions, $type, $tmpfile, $targetFile)
|
| 145 |
+
{
|
| 146 |
+
$o = array_merge(
|
| 147 |
+
array(
|
| 148 |
+
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
|
| 149 |
+
'summary_detail_level' => 0,
|
| 150 |
+
)
|
| 151 |
+
,$userOptions
|
| 152 |
+
);
|
| 153 |
+
$cmd = 'java -Xmx512m -jar '. Mage::getBaseDir(). DS. "lib" .DS."yccminify". DS . "closurecompiler.jar";
|
| 154 |
+
if ($type === 'js') {
|
| 155 |
+
foreach (array('compilation_level', 'preserve-semi', 'disable-optimizations', 'warning_level', 'summary_detail_level') as $opt) {
|
| 156 |
+
if (array_key_exists($opt, $o)) {
|
| 157 |
+
$cmd .= ' --' . $opt . ' ' . $o[$opt];
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
return $cmd . ' --third_party --js=' . $tmpfile . ' --js_output_file=' . $targetFile;
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
?>
|
app/code/community/Ycc/Minify/Model/Observer.php
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/*
|
| 3 |
+
yongcheng.ch@gmail.com
|
| 4 |
+
*/
|
| 5 |
+
|
| 6 |
+
require_once (Mage::getBaseDir().DS."lib" .DS."yccminify". DS .'HTML.php');
|
| 7 |
+
|
| 8 |
+
class Ycc_Minify_Model_Observer
|
| 9 |
+
{
|
| 10 |
+
const MINIFY_CONFIG = 'dev/minifyhtml/enabled';
|
| 11 |
+
public function MinifyResponse($observer){
|
| 12 |
+
if (Mage::app()->getStore()->isAdmin()){
|
| 13 |
+
return;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
if (Mage::app()->getRequest()->isXmlHttpRequest()) { // is Ajax request
|
| 17 |
+
return;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
if ("1" === Mage::getStoreConfig(self::MINIFY_CONFIG, Mage::app()->getStore()->getStoreId())){
|
| 21 |
+
$response = $observer->getResponse();
|
| 22 |
+
$html = $response->getBody();
|
| 23 |
+
$min = new Minify_HTML($html, $options);
|
| 24 |
+
$response->setBody( $min->process() );
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
?>
|
| 29 |
+
|
app/code/community/Ycc/Minify/Model/System/Config/Csscompressor.php
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
class Ycc_Minify_Model_System_Config_Csscompressor
|
| 4 |
+
{
|
| 5 |
+
public function toOptionArray()
|
| 6 |
+
{
|
| 7 |
+
return array(
|
| 8 |
+
array('value' => 0, 'label'=>Mage::helper('adminhtml')->__('Don\'t compress')),
|
| 9 |
+
array('value' => 1, 'label'=>Mage::helper('adminhtml')->__('YUI Compressor')),
|
| 10 |
+
);
|
| 11 |
+
}
|
| 12 |
+
}
|
| 13 |
+
?>
|
app/code/community/Ycc/Minify/Model/System/Config/Jscompressor.php
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
class Ycc_Minify_Model_System_Config_Jscompressor
|
| 4 |
+
{
|
| 5 |
+
public function toOptionArray()
|
| 6 |
+
{
|
| 7 |
+
return array(
|
| 8 |
+
array('value' => 0, 'label'=>Mage::helper('adminhtml')->__('Don\'t compress')),
|
| 9 |
+
array('value' => 1, 'label'=>Mage::helper('adminhtml')->__('YUI Compressor')),
|
| 10 |
+
array('value' => 2, 'label'=>Mage::helper('adminhtml')->__('Closure Compiler')),
|
| 11 |
+
);
|
| 12 |
+
}
|
| 13 |
+
}
|
| 14 |
+
?>
|
app/code/community/Ycc/Minify/etc/config.xml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<config>
|
| 2 |
+
<modules>
|
| 3 |
+
<Ycc_Minify>
|
| 4 |
+
<version>0.1.0</version>
|
| 5 |
+
</Ycc_Minify>
|
| 6 |
+
</modules>
|
| 7 |
+
<global>
|
| 8 |
+
<models>
|
| 9 |
+
<ycc_minify>
|
| 10 |
+
<class>Ycc_Minify_Model</class>
|
| 11 |
+
</ycc_minify>
|
| 12 |
+
</models>
|
| 13 |
+
<helpers>
|
| 14 |
+
<core>
|
| 15 |
+
<rewrite>
|
| 16 |
+
<data>Ycc_Minify_Helper_Data</data>
|
| 17 |
+
</rewrite>
|
| 18 |
+
</core>
|
| 19 |
+
</helpers>
|
| 20 |
+
<events>
|
| 21 |
+
<http_response_send_before>
|
| 22 |
+
<observers>
|
| 23 |
+
<unique_label>
|
| 24 |
+
<type>singleton</type>
|
| 25 |
+
<class>ycc_minify/observer</class>
|
| 26 |
+
<method>MinifyResponse</method>
|
| 27 |
+
</unique_label>
|
| 28 |
+
</observers>
|
| 29 |
+
</http_response_send_before>
|
| 30 |
+
</events>
|
| 31 |
+
</global>
|
| 32 |
+
|
| 33 |
+
</config>
|
app/code/community/Ycc/Minify/etc/system.xml
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<config>
|
| 2 |
+
<sections>
|
| 3 |
+
<dev>
|
| 4 |
+
<groups>
|
| 5 |
+
<js>
|
| 6 |
+
<fields>
|
| 7 |
+
<minify_js_files translate="label">
|
| 8 |
+
<label>Minify JavaScript Files</label>
|
| 9 |
+
<frontend_type>select</frontend_type>
|
| 10 |
+
<source_model>ycc_minify/system_config_jscompressor</source_model>
|
| 11 |
+
<sort_order>15</sort_order>
|
| 12 |
+
<show_in_default>1</show_in_default>
|
| 13 |
+
<show_in_website>1</show_in_website>
|
| 14 |
+
<show_in_store>1</show_in_store>
|
| 15 |
+
</minify_js_files>
|
| 16 |
+
</fields>
|
| 17 |
+
</js>
|
| 18 |
+
|
| 19 |
+
<css>
|
| 20 |
+
<fields>
|
| 21 |
+
<minify_css_files translate="label">
|
| 22 |
+
<label>Minify CSS Files</label>
|
| 23 |
+
<frontend_type>select</frontend_type>
|
| 24 |
+
<source_model>ycc_minify/system_config_csscompressor</source_model>
|
| 25 |
+
<sort_order>15</sort_order>
|
| 26 |
+
<show_in_default>1</show_in_default>
|
| 27 |
+
<show_in_website>1</show_in_website>
|
| 28 |
+
<show_in_store>1</show_in_store>
|
| 29 |
+
<comment>Experimental. Turn this feature off if there are troubles with relative urls inside css-files.</comment>
|
| 30 |
+
</minify_css_files>
|
| 31 |
+
</fields>
|
| 32 |
+
</css>
|
| 33 |
+
|
| 34 |
+
<minifyhtml>
|
| 35 |
+
<label>Minify Html</label>
|
| 36 |
+
<frontend_type>text</frontend_type>
|
| 37 |
+
<sort_order>50</sort_order>
|
| 38 |
+
<show_in_default>1</show_in_default>
|
| 39 |
+
<show_in_website>1</show_in_website>
|
| 40 |
+
<show_in_store>1</show_in_store>
|
| 41 |
+
<fields>
|
| 42 |
+
<enabled translate="label">
|
| 43 |
+
<label>Enabled</label>
|
| 44 |
+
<frontend_type>select</frontend_type>
|
| 45 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
| 46 |
+
<sort_order>1</sort_order>
|
| 47 |
+
<show_in_default>1</show_in_default>
|
| 48 |
+
<show_in_website>1</show_in_website>
|
| 49 |
+
<show_in_store>1</show_in_store>
|
| 50 |
+
</enabled>
|
| 51 |
+
</fields>
|
| 52 |
+
</minifyhtml>
|
| 53 |
+
</groups>
|
| 54 |
+
</dev>
|
| 55 |
+
</sections>
|
| 56 |
+
</config>
|
lib/yccminify/HTML.php
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* Class Minify_HTML
|
| 4 |
+
* @package Minify
|
| 5 |
+
*/
|
| 6 |
+
|
| 7 |
+
/**
|
| 8 |
+
* Compress HTML
|
| 9 |
+
*
|
| 10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
| 11 |
+
* tokens. IE conditional comments are preserved. There are also options to have
|
| 12 |
+
* STYLE and SCRIPT blocks compressed by callback functions.
|
| 13 |
+
*
|
| 14 |
+
* A test suite is available.
|
| 15 |
+
*
|
| 16 |
+
* @package Minify
|
| 17 |
+
* @author Stephen Clay <steve@mrclay.org>
|
| 18 |
+
*/
|
| 19 |
+
class Minify_HTML {
|
| 20 |
+
|
| 21 |
+
/**
|
| 22 |
+
* "Minify" an HTML page
|
| 23 |
+
*
|
| 24 |
+
* @param string $html
|
| 25 |
+
*
|
| 26 |
+
* @param array $options
|
| 27 |
+
*
|
| 28 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
| 29 |
+
* elements.
|
| 30 |
+
*
|
| 31 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
| 32 |
+
* elements. Note: the type attribute is ignored.
|
| 33 |
+
*
|
| 34 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
| 35 |
+
* unset, minify will sniff for an XHTML doctype.
|
| 36 |
+
*
|
| 37 |
+
* @return string
|
| 38 |
+
*/
|
| 39 |
+
static public function minify($html, $options = array()) {
|
| 40 |
+
$min = new Minify_HTML($html, $options);
|
| 41 |
+
return $min->process();
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
/**
|
| 46 |
+
* Create a minifier object
|
| 47 |
+
*
|
| 48 |
+
* @param string $html
|
| 49 |
+
*
|
| 50 |
+
* @param array $options
|
| 51 |
+
*
|
| 52 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
| 53 |
+
* elements.
|
| 54 |
+
*
|
| 55 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
| 56 |
+
* elements. Note: the type attribute is ignored.
|
| 57 |
+
*
|
| 58 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
| 59 |
+
* unset, minify will sniff for an XHTML doctype.
|
| 60 |
+
*
|
| 61 |
+
* @return null
|
| 62 |
+
*/
|
| 63 |
+
public function __construct($html, $options = array())
|
| 64 |
+
{
|
| 65 |
+
$this->_html = str_replace("\r\n", "\n", trim($html));
|
| 66 |
+
if (isset($options['xhtml'])) {
|
| 67 |
+
$this->_isXhtml = (bool)$options['xhtml'];
|
| 68 |
+
}
|
| 69 |
+
if (isset($options['cssMinifier'])) {
|
| 70 |
+
$this->_cssMinifier = $options['cssMinifier'];
|
| 71 |
+
}
|
| 72 |
+
if (isset($options['jsMinifier'])) {
|
| 73 |
+
$this->_jsMinifier = $options['jsMinifier'];
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
/**
|
| 79 |
+
* Minify the markeup given in the constructor
|
| 80 |
+
*
|
| 81 |
+
* @return string
|
| 82 |
+
*/
|
| 83 |
+
public function process()
|
| 84 |
+
{
|
| 85 |
+
if ($this->_isXhtml === null) {
|
| 86 |
+
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
| 90 |
+
$this->_placeholders = array();
|
| 91 |
+
|
| 92 |
+
// replace SCRIPTs (and minify) with placeholders
|
| 93 |
+
$this->_html = preg_replace_callback(
|
| 94 |
+
'/(\\s*)(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
| 95 |
+
,array($this, '_removeScriptCB')
|
| 96 |
+
,$this->_html);
|
| 97 |
+
|
| 98 |
+
// replace STYLEs (and minify) with placeholders
|
| 99 |
+
$this->_html = preg_replace_callback(
|
| 100 |
+
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
|
| 101 |
+
,array($this, '_removeStyleCB')
|
| 102 |
+
,$this->_html);
|
| 103 |
+
|
| 104 |
+
// remove HTML comments (not containing IE conditional comments).
|
| 105 |
+
$this->_html = preg_replace_callback(
|
| 106 |
+
'/<!--([\\s\\S]*?)-->/'
|
| 107 |
+
,array($this, '_commentCB')
|
| 108 |
+
,$this->_html);
|
| 109 |
+
|
| 110 |
+
// replace PREs with placeholders
|
| 111 |
+
$this->_html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
| 112 |
+
,array($this, '_removePreCB')
|
| 113 |
+
,$this->_html);
|
| 114 |
+
|
| 115 |
+
// replace TEXTAREAs with placeholders
|
| 116 |
+
$this->_html = preg_replace_callback(
|
| 117 |
+
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
| 118 |
+
,array($this, '_removeTextareaCB')
|
| 119 |
+
,$this->_html);
|
| 120 |
+
|
| 121 |
+
// trim each line.
|
| 122 |
+
// @todo take into account attribute values that span multiple lines.
|
| 123 |
+
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
| 124 |
+
|
| 125 |
+
// remove ws around block/undisplayed elements
|
| 126 |
+
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
| 127 |
+
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
| 128 |
+
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
| 129 |
+
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
| 130 |
+
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
| 131 |
+
|
| 132 |
+
// remove ws outside of all elements
|
| 133 |
+
$this->_html = preg_replace_callback(
|
| 134 |
+
'/>([^<]+)</'
|
| 135 |
+
,array($this, '_outsideTagCB')
|
| 136 |
+
,$this->_html);
|
| 137 |
+
|
| 138 |
+
// use newlines before 1st attribute in open tags (to limit line lengths)
|
| 139 |
+
$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
| 140 |
+
|
| 141 |
+
// fill placeholders
|
| 142 |
+
$this->_html = str_replace(
|
| 143 |
+
array_keys($this->_placeholders)
|
| 144 |
+
,array_values($this->_placeholders)
|
| 145 |
+
,$this->_html
|
| 146 |
+
);
|
| 147 |
+
return $this->_html;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
protected function _commentCB($m)
|
| 151 |
+
{
|
| 152 |
+
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
|
| 153 |
+
? $m[0]
|
| 154 |
+
: '';
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
protected function _reservePlace($content)
|
| 158 |
+
{
|
| 159 |
+
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
| 160 |
+
$this->_placeholders[$placeholder] = $content;
|
| 161 |
+
return $placeholder;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
protected $_isXhtml = null;
|
| 165 |
+
protected $_replacementHash = null;
|
| 166 |
+
protected $_placeholders = array();
|
| 167 |
+
protected $_cssMinifier = null;
|
| 168 |
+
protected $_jsMinifier = null;
|
| 169 |
+
|
| 170 |
+
protected function _outsideTagCB($m)
|
| 171 |
+
{
|
| 172 |
+
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
protected function _removePreCB($m)
|
| 176 |
+
{
|
| 177 |
+
return $this->_reservePlace($m[1]);
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
protected function _removeTextareaCB($m)
|
| 181 |
+
{
|
| 182 |
+
return $this->_reservePlace($m[1]);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
protected function _removeStyleCB($m)
|
| 186 |
+
{
|
| 187 |
+
$openStyle = $m[1];
|
| 188 |
+
$css = $m[2];
|
| 189 |
+
// remove HTML comments
|
| 190 |
+
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
| 191 |
+
|
| 192 |
+
// remove CDATA section markers
|
| 193 |
+
$css = $this->_removeCdata($css);
|
| 194 |
+
|
| 195 |
+
// minify
|
| 196 |
+
$minifier = $this->_cssMinifier
|
| 197 |
+
? $this->_cssMinifier
|
| 198 |
+
: 'trim';
|
| 199 |
+
$css = call_user_func($minifier, $css);
|
| 200 |
+
|
| 201 |
+
return $this->_reservePlace($this->_needsCdata($css)
|
| 202 |
+
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
| 203 |
+
: "{$openStyle}{$css}</style>"
|
| 204 |
+
);
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
protected function _removeScriptCB($m)
|
| 208 |
+
{
|
| 209 |
+
$openScript = $m[2];
|
| 210 |
+
$js = $m[3];
|
| 211 |
+
|
| 212 |
+
// whitespace surrounding? preserve at least one space
|
| 213 |
+
$ws1 = ($m[1] === '') ? '' : ' ';
|
| 214 |
+
$ws2 = ($m[4] === '') ? '' : ' ';
|
| 215 |
+
|
| 216 |
+
// remove HTML comments (and ending "//" if present)
|
| 217 |
+
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
| 218 |
+
|
| 219 |
+
// remove CDATA section markers
|
| 220 |
+
$js = $this->_removeCdata($js);
|
| 221 |
+
|
| 222 |
+
// minify
|
| 223 |
+
$minifier = $this->_jsMinifier
|
| 224 |
+
? $this->_jsMinifier
|
| 225 |
+
: 'trim';
|
| 226 |
+
$js = call_user_func($minifier, $js);
|
| 227 |
+
|
| 228 |
+
return $this->_reservePlace($this->_needsCdata($js)
|
| 229 |
+
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
| 230 |
+
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
| 231 |
+
);
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
protected function _removeCdata($str)
|
| 235 |
+
{
|
| 236 |
+
return (false !== strpos($str, '<![CDATA['))
|
| 237 |
+
? str_replace(array('<![CDATA[', ']]>'), '', $str)
|
| 238 |
+
: $str;
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
protected function _needsCdata($str)
|
| 242 |
+
{
|
| 243 |
+
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
| 244 |
+
}
|
| 245 |
+
}
|
lib/yccminify/closurecompiler.jar
ADDED
|
Binary file
|
lib/yccminify/yuicompressor.jar
ADDED
|
Binary file
|
package.xml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0"?>
|
| 2 |
+
<package>
|
| 3 |
+
<name>YccMinify</name>
|
| 4 |
+
<version>0.1.0</version>
|
| 5 |
+
<stability>stable</stability>
|
| 6 |
+
<license uri="http://opensource.org/licenses/OSL-3.0">OSL-3.0</license>
|
| 7 |
+
<channel>community</channel>
|
| 8 |
+
<extends/>
|
| 9 |
+
<summary>Minify your merged CSS,JS file and HTML page!!!
|
| 10 |
+
Improve your SEO!</summary>
|
| 11 |
+
<description>It's a really light module to allow you to minify CSS/JS and Html.
|
| 12 |
+

|
| 13 |
+
No complicated configuration, it support CE1.5.0 later and EE1.8.0 later!</description>
|
| 14 |
+
<notes>It's a really light module to allow you to minify CSS/JS and Html.
|
| 15 |
+

|
| 16 |
+
No complicated configuration, it support CE1.5.0 later and EE1.8.0 later!</notes>
|
| 17 |
+
<authors><author><name>Yongcheng CHEN</name><user>yongcheng</user><email>yongcheng.ch@gmail.com</email></author></authors>
|
| 18 |
+
<date>2014-03-20</date>
|
| 19 |
+
<time>00:59:03</time>
|
| 20 |
+
<contents><target name="magecommunity"><dir name="Ycc"><dir name="Minify"><dir name="Helper"><file name="Data.php" hash="c76552b8ca8cb6f92989ec73e979e691"/></dir><dir name="Model"><file name="Observer.php" hash="5cca0ae0a054f7d9c6cf4a036b9c3351"/><dir name="System"><dir name="Config"><file name="Csscompressor.php" hash="4d974633c8490311dd9b9de43aa6c0c4"/><file name="Jscompressor.php" hash="fe8ea761560f949c844220f04704c3ff"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="479b12a6750d7d5b4c56bd49d30724fe"/><file name="system.xml" hash="128b22e567d24a0f64caeaa737244452"/></dir></dir></dir></target><target name="magelib"><dir name="yccminify"><file name="HTML.php" hash="12c43b16cc5f1a2acf9d734a1ab8849b"/><file name="closurecompiler.jar" hash="d07b1f5a81dc12d6846ddd9b418bb080"/><file name="yuicompressor.jar" hash="a64311cb39d119805b41d547c8dd039d"/></dir></target><target name="mageetc"><dir name="."><file name="Ycc_minify.xml" hash=""/></dir></target></contents>
|
| 21 |
+
<compatible/>
|
| 22 |
+
<dependencies><required><php><min>5.0.0</min><max>5.4.10</max></php></required></dependencies>
|
| 23 |
+
</package>
|
