Version Notes
This module was tested in Magento Commerce version 1.4.0.1 and 1.5.0.1, and work in this version smoothly.
Download this release
Release Info
Developer | Magento Core Team |
Extension | PSystem_OptimizationHead |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/community/PSystem/OptimizationHead/Block/Head.php +239 -0
- app/code/community/PSystem/OptimizationHead/Block/Head/Abstract.php +19 -0
- app/code/community/PSystem/OptimizationHead/Model/Observer.php +38 -0
- app/code/community/PSystem/OptimizationHead/etc/adminhtml.xml +28 -0
- app/code/community/PSystem/OptimizationHead/etc/config.xml +41 -0
- app/code/community/PSystem/OptimizationHead/etc/system.xml +119 -0
- app/code/community/PSystem/OptimizationHead/lib/JSMin.php +314 -0
- app/code/community/PSystem/OptimizationHead/lib/Minify/CSS.php +83 -0
- app/code/community/PSystem/OptimizationHead/lib/Minify/CSS/Compressor.php +250 -0
- app/code/community/PSystem/OptimizationHead/lib/Minify/CSS/UriRewriter.php +270 -0
- app/code/community/PSystem/OptimizationHead/lib/Minify/CommentPreserver.php +90 -0
- app/code/community/PSystem/OptimizationHead/lib/PSystemHtmlMinify.php +30 -0
- app/etc/modules/PSystem_OptimizationHead.xml +20 -0
- js/pascalsystem/combine.php +231 -0
- package.xml +18 -0
app/code/community/PSystem/OptimizationHead/Block/Head.php
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category PSystem
|
4 |
+
* @package PSystem_OptimizationHead
|
5 |
+
* @author Pascal System <info@pascalsystem.pl>
|
6 |
+
* @version 1.0.0
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Pascal Head combine
|
11 |
+
*
|
12 |
+
* @category PSystem
|
13 |
+
* @package PSystem_OptimizationHead
|
14 |
+
* @author Pascal System <info@pascalsystem.pl>
|
15 |
+
* @version 1.0.0
|
16 |
+
*/
|
17 |
+
class PSystem_OptimizationHead_Block_Head extends PSystem_OptimizationHead_Block_Head_Abstract {
|
18 |
+
/**
|
19 |
+
* Get HEAD HTML with CSS/JS/RSS definitions
|
20 |
+
* (actually it also renders other elements, TODO: fix it up or rename this method)
|
21 |
+
*
|
22 |
+
* @return string
|
23 |
+
*/
|
24 |
+
public function getCssJsHtml() {
|
25 |
+
if (Mage::getStoreConfig('psoptimizationhead/extension/disable')) {
|
26 |
+
return parent::getCssJsHtml();
|
27 |
+
}
|
28 |
+
|
29 |
+
// separate items by types
|
30 |
+
$lines = array();
|
31 |
+
foreach ($this->_data['items'] as $item) {
|
32 |
+
if (!is_null($item['cond']) && !$this->getData($item['cond']) || !isset($item['name'])) {
|
33 |
+
continue;
|
34 |
+
}
|
35 |
+
$if = !empty($item['if']) ? $item['if'] : '';
|
36 |
+
$params = !empty($item['params']) ? $item['params'] : '';
|
37 |
+
switch ($item['type']) {
|
38 |
+
case 'js': // js/*.js
|
39 |
+
case 'skin_js': // skin/*/*.js
|
40 |
+
case 'js_css': // js/*.css
|
41 |
+
case 'skin_css': // skin/*/*.css
|
42 |
+
$lines[$if][$item['type']][$params][$item['name']] = $item['name'];
|
43 |
+
break;
|
44 |
+
default:
|
45 |
+
$this->_separateOtherHtmlHeadElements($lines, $if, $item['type'], $params, $item['name'], $item);
|
46 |
+
break;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
//prepare HTML
|
51 |
+
$shouldMergeJs = Mage::getStoreConfigFlag('dev/js/merge_files');
|
52 |
+
$shouldMergeCss = Mage::getStoreConfigFlag('dev/css/merge_css_files');
|
53 |
+
$html = '';
|
54 |
+
|
55 |
+
$designPackage = Mage::getDesign();
|
56 |
+
foreach ($lines as $cond => $types) {
|
57 |
+
foreach ($types as $type => $params) {
|
58 |
+
foreach ($params as $param => $items) {
|
59 |
+
foreach ($items as $itemKey => $itemVal) {
|
60 |
+
if ($type == 'js') {
|
61 |
+
if (!isset($lines[$cond][$type][$param]['combine']))
|
62 |
+
$lines[$cond][$type][$param]['combine'] = '';
|
63 |
+
|
64 |
+
if ($lines[$cond][$type][$param]['combine']) {
|
65 |
+
$lines[$cond][$type][$param]['combine'].= ','.$itemVal;
|
66 |
+
} else {
|
67 |
+
$lines[$cond][$type][$param]['combine'].= 'file='.$itemVal;
|
68 |
+
}
|
69 |
+
|
70 |
+
unset($lines[$cond][$type][$param][$itemKey]);
|
71 |
+
} elseif ($type == 'skin_js') {
|
72 |
+
if (!isset($lines[$cond][$type][$param]['combineskin']))
|
73 |
+
$lines[$cond][$type][$param]['combineskin'] = '';
|
74 |
+
|
75 |
+
if ($lines[$cond][$type][$param]['combineskin']) {
|
76 |
+
$lines[$cond][$type][$param]['combineskin'].= ','.$this->getSkinFile($designPackage,$itemVal);
|
77 |
+
} else {
|
78 |
+
$lines[$cond][$type][$param]['combineskin'].= 'file='.$this->getSkinFile($designPackage,$itemVal);
|
79 |
+
}
|
80 |
+
unset($lines[$cond][$type][$param][$itemKey]);
|
81 |
+
} elseif ($type == 'js_css') {
|
82 |
+
if (!isset($lines[$cond][$type][$param]['combinecss']))
|
83 |
+
$lines[$cond][$type][$param]['combinecss'] = '';
|
84 |
+
|
85 |
+
if ($lines[$cond][$type][$param]['combinecss']) {
|
86 |
+
$lines[$cond][$type][$param]['combinecss'].= ','.$itemVal;
|
87 |
+
} else {
|
88 |
+
$lines[$cond][$type][$param]['combinecss'].= 'file='.$itemVal;
|
89 |
+
}
|
90 |
+
unset($lines[$cond][$type][$param][$itemKey]);
|
91 |
+
} elseif ($type == 'skin_css') {
|
92 |
+
if (!isset($lines[$cond][$type][$param]['combineskincss']))
|
93 |
+
$lines[$cond][$type][$param]['combineskincss'] = '';
|
94 |
+
|
95 |
+
if ($lines[$cond][$type][$param]['combineskincss']) {
|
96 |
+
$lines[$cond][$type][$param]['combineskincss'].= ','.$this->getSkinFile($designPackage,$itemVal);
|
97 |
+
} else {
|
98 |
+
$lines[$cond][$type][$param]['combineskincss'].= 'file='.$this->getSkinFile($designPackage,$itemVal);
|
99 |
+
}
|
100 |
+
unset($lines[$cond][$type][$param][$itemKey]);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
}
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
foreach ($lines as $if => $items) {
|
108 |
+
if (empty($items)) {
|
109 |
+
continue;
|
110 |
+
}
|
111 |
+
if (!empty($if)) {
|
112 |
+
$html .= '<!--[if '.$if.']>'."\n";
|
113 |
+
}
|
114 |
+
|
115 |
+
// static and skin css
|
116 |
+
$html .= $this->_prepareStaticAndSkinElements('<link rel="stylesheet" type="text/css" href="%s"%s />' . "\n",
|
117 |
+
empty($items['js_css']) ? array() : $items['js_css'],
|
118 |
+
empty($items['skin_css']) ? array() : $items['skin_css'],
|
119 |
+
$shouldMergeCss ? array(Mage::getDesign(), 'getMergedCssUrl') : null
|
120 |
+
);
|
121 |
+
|
122 |
+
// static and skin javascripts
|
123 |
+
$html .= $this->_prepareStaticAndSkinElements('<script type="text/javascript" src="%s"%s></script>' . "\n",
|
124 |
+
empty($items['js']) ? array() : $items['js'],
|
125 |
+
empty($items['skin_js']) ? array() : $items['skin_js'],
|
126 |
+
$shouldMergeJs ? array(Mage::getDesign(), 'getMergedJsUrl') : null
|
127 |
+
);
|
128 |
+
|
129 |
+
// other stuff
|
130 |
+
if (!empty($items['other'])) {
|
131 |
+
$html .= $this->_prepareOtherHtmlHeadElements($items['other']) . "\n";
|
132 |
+
}
|
133 |
+
|
134 |
+
if (!empty($if)) {
|
135 |
+
$html .= '<![endif]-->'."\n";
|
136 |
+
}
|
137 |
+
}
|
138 |
+
return $html;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Merge static and skin files of the same format into 1 set of HEAD directives or even into 1 directive
|
143 |
+
*
|
144 |
+
* Will attempt to merge into 1 directive, if merging callback is provided. In this case it will generate
|
145 |
+
* filenames, rather than render urls.
|
146 |
+
* The merger callback is responsible for checking whether files exist, merging them and giving result URL
|
147 |
+
*
|
148 |
+
* @param string $format - HTML element format for sprintf('<element src="%s"%s />', $src, $params)
|
149 |
+
* @param array $staticItems - array of relative names of static items to be grabbed from js/ folder
|
150 |
+
* @param array $skinItems - array of relative names of skin items to be found in skins according to design config
|
151 |
+
* @param callback $mergeCallback
|
152 |
+
* @return string
|
153 |
+
*/
|
154 |
+
protected function &_prepareStaticAndSkinElements($format, array $staticItems, array $skinItems, $mergeCallback = null) {
|
155 |
+
$designPackage = Mage::getDesign();
|
156 |
+
$baseJsUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS);
|
157 |
+
|
158 |
+
$additionalParams = '';
|
159 |
+
if ($timeRefreshing = intval(Mage::getStoreConfig('psoptimizationhead/compress/refresh'))) {
|
160 |
+
$additionalParams.= 'refresh='.$timeRefreshing.'&';
|
161 |
+
}
|
162 |
+
if (Mage::getStoreConfig('psoptimizationhead/compress/nocache')) {
|
163 |
+
$additionalParams.= 'nocache=1&';
|
164 |
+
}
|
165 |
+
if (Mage::getStoreConfig('psoptimizationhead/compress/gzipoff')) {
|
166 |
+
$additionalParams.= 'gzipoff=1&';
|
167 |
+
}
|
168 |
+
if (Mage::getStoreConfig('psoptimizationhead/compress/minifyoff')) {
|
169 |
+
$additionalParams.= 'minoff=1&';
|
170 |
+
}
|
171 |
+
|
172 |
+
|
173 |
+
$baseCombineUrl = $baseJsUrl.'pascalsystem/combine.php?type=js&'.$additionalParams;
|
174 |
+
$baseCombineSkinUrl = $baseJsUrl.'pascalsystem/combine.php?type=jsskin&'.$additionalParams;
|
175 |
+
$baseCombineCss = $baseJsUrl.'pascalsystem/combine.php?type=css&'.$additionalParams;
|
176 |
+
$baseCombineSkinCss = $baseJsUrl.'pascalsystem/combine.php?type=cssskin&'.$additionalParams;
|
177 |
+
$items = array();
|
178 |
+
if ($mergeCallback && !is_callable($mergeCallback)) {
|
179 |
+
$mergeCallback = null;
|
180 |
+
}
|
181 |
+
|
182 |
+
// get static files from the js folder, no need in lookups
|
183 |
+
foreach ($staticItems as $params => $rows) {
|
184 |
+
foreach ($rows as $key => $name) {
|
185 |
+
if ($key == 'combine') {
|
186 |
+
$items[$params][] = $baseCombineUrl.$name;
|
187 |
+
} elseif ($key == 'combinecss') {
|
188 |
+
$items[$params][] = $baseCombineCss.$name;
|
189 |
+
} else {
|
190 |
+
$items[$params][] = $mergeCallback ? Mage::getBaseDir() . DS . 'js' . DS . $name : $baseJsUrl . $name;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
// lookup each file basing on current theme configuration
|
196 |
+
foreach ($skinItems as $params => $rows) {
|
197 |
+
foreach ($rows as $key => $name) {
|
198 |
+
if ($key == 'combineskin') {
|
199 |
+
$items[$params][] = $baseCombineSkinUrl.$name;
|
200 |
+
} elseif ($key == 'combineskincss') {
|
201 |
+
$items[$params][] = $baseCombineSkinCss.$name;
|
202 |
+
} else {
|
203 |
+
$items[$params][] = $mergeCallback ? $designPackage->getFilename($name, array('_type' => 'skin')):$designPackage->getSkinUrl($name, array());
|
204 |
+
}
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
$html = '';
|
209 |
+
foreach ($items as $params => $rows) {
|
210 |
+
// attempt to merge
|
211 |
+
$mergedUrl = false;
|
212 |
+
if ($mergeCallback) {
|
213 |
+
$mergedUrl = call_user_func($mergeCallback, $rows);
|
214 |
+
}
|
215 |
+
// render elements
|
216 |
+
$params = trim($params);
|
217 |
+
$params = $params ? ' ' . $params : '';
|
218 |
+
if ($mergedUrl) {
|
219 |
+
$html .= sprintf($format, $mergedUrl, $params);
|
220 |
+
} else {
|
221 |
+
foreach ($rows as $src) {
|
222 |
+
$html .= sprintf($format, $src, $params);
|
223 |
+
}
|
224 |
+
}
|
225 |
+
}
|
226 |
+
return $html;
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Create skin url and cut base skin url
|
231 |
+
*
|
232 |
+
* @param Mage_Core_Model_Design_Package $designPackage
|
233 |
+
* @param string $fileName
|
234 |
+
* @return string
|
235 |
+
*/
|
236 |
+
protected function getSkinFile(Mage_Core_Model_Design_Package $designPackage, $fileName) {
|
237 |
+
return str_replace(Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN),'',$designPackage->getSkinUrl($fileName));
|
238 |
+
}
|
239 |
+
}
|
app/code/community/PSystem/OptimizationHead/Block/Head/Abstract.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category PSystem
|
4 |
+
* @package PSystem_OptimizationHead
|
5 |
+
* @author Pascal System <info@pascalsystem.pl>
|
6 |
+
* @version 1.0.0
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Pascal Head combine abstract
|
11 |
+
*
|
12 |
+
* @category PSystem
|
13 |
+
* @package PSystem_OptimizationHead
|
14 |
+
* @author Pascal System <info@pascalsystem.pl>
|
15 |
+
* @version 1.0.0
|
16 |
+
*/
|
17 |
+
$extClass = Mage::getStoreConfig('psoptimizationhead/extension/classname');
|
18 |
+
if (!$extClass) $extClass = 'Mage_Page_Block_Html_Head';
|
19 |
+
eval('abstract class PSystem_OptimizationHead_Block_Head_Abstract extends '.$extClass.' {}');
|
app/code/community/PSystem/OptimizationHead/Model/Observer.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category PSystem
|
4 |
+
* @package PSystem_OptimizationHead
|
5 |
+
* @author Pascal System <info@pascalsystem.pl>
|
6 |
+
* @version 1.0.0
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @see PSystemHtmlMinify
|
11 |
+
*/
|
12 |
+
require_once 'PSystem/OptimizationHead/lib/PSystemHtmlMinify.php';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Pascal Optimization observer
|
16 |
+
*
|
17 |
+
* @category PSystem
|
18 |
+
* @package PSystem_OptimizationHead
|
19 |
+
* @author Pascal System <info@pascalsystem.pl>
|
20 |
+
* @version 1.0.0
|
21 |
+
*/
|
22 |
+
class PSystem_OptimizationHead_Model_Observer {
|
23 |
+
/**
|
24 |
+
* Post dispatch proccess compress html file
|
25 |
+
*
|
26 |
+
* @param Varien_Event_Observer $event
|
27 |
+
*/
|
28 |
+
public function postDispatch(Varien_Event_Observer $event) {
|
29 |
+
if (Mage::getStoreConfig('psoptimizationhead/html/disable'))
|
30 |
+
return;
|
31 |
+
|
32 |
+
/* @var $controller Mage_Core_Controller_Varien_Action */
|
33 |
+
$controller = $event->getControllerAction();
|
34 |
+
$allHtml = $controller->getResponse()->getBody();
|
35 |
+
$allHtml = PSystemHtmlMinify::min($allHtml);
|
36 |
+
$controller->getResponse()->setBody($allHtml);
|
37 |
+
}
|
38 |
+
}
|
app/code/community/PSystem/OptimizationHead/etc/adminhtml.xml
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category PSystem
|
5 |
+
* @package PSystem_OptimizationHead
|
6 |
+
* @author Pascal System <info@pascalsystem.pl>
|
7 |
+
* @version 1.0.0
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<acl>
|
12 |
+
<resources>
|
13 |
+
<admin>
|
14 |
+
<children>
|
15 |
+
<system>
|
16 |
+
<children>
|
17 |
+
<config>
|
18 |
+
<children>
|
19 |
+
<psoptimizationhead />
|
20 |
+
</children>
|
21 |
+
</config>
|
22 |
+
</children>
|
23 |
+
</system>
|
24 |
+
</children>
|
25 |
+
</admin>
|
26 |
+
</resources>
|
27 |
+
</acl>
|
28 |
+
</config>
|
app/code/community/PSystem/OptimizationHead/etc/config.xml
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category PSystem
|
5 |
+
* @package PSystem_OptimizationHead
|
6 |
+
* @author Pascal System <info@pascalsystem.pl>
|
7 |
+
* @version 1.0.0
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<modules>
|
12 |
+
<PSystem_OptimizationHead>
|
13 |
+
<version>1.0.0</version>
|
14 |
+
</PSystem_OptimizationHead>
|
15 |
+
</modules>
|
16 |
+
<global>
|
17 |
+
<blocks>
|
18 |
+
<page>
|
19 |
+
<rewrite>
|
20 |
+
<html_head>PSystem_OptimizationHead_Block_Head</html_head>
|
21 |
+
</rewrite>
|
22 |
+
</page>
|
23 |
+
</blocks>
|
24 |
+
<models>
|
25 |
+
<psoptimizationhead>
|
26 |
+
<class>PSystem_OptimizationHead_Model</class>
|
27 |
+
</psoptimizationhead>
|
28 |
+
</models>
|
29 |
+
<events>
|
30 |
+
<controller_action_postdispatch>
|
31 |
+
<observers>
|
32 |
+
<psoptimizationhead_postdispatch>
|
33 |
+
<type>singleton</type>
|
34 |
+
<class>psoptimizationhead/observer</class>
|
35 |
+
<method>postDispatch</method>
|
36 |
+
</psoptimizationhead_postdispatch>
|
37 |
+
</observers>
|
38 |
+
</controller_action_postdispatch>
|
39 |
+
</events>
|
40 |
+
</global>
|
41 |
+
</config>
|
app/code/community/PSystem/OptimizationHead/etc/system.xml
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category PSystem
|
5 |
+
* @package PSystem_OptimizationHead
|
6 |
+
* @author Pascal System <info@pascalsystem.pl>
|
7 |
+
* @version 1.0.0
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<sections>
|
12 |
+
<psoptimizationhead translate="label" module="psbase">
|
13 |
+
<label>Optimization Head</label>
|
14 |
+
<tab>psystem</tab>
|
15 |
+
<frontend_type>text</frontend_type>
|
16 |
+
<sort_order>10</sort_order>
|
17 |
+
<show_in_default>1</show_in_default>
|
18 |
+
<show_in_website>0</show_in_website>
|
19 |
+
<show_in_store>0</show_in_store>
|
20 |
+
<groups>
|
21 |
+
<extension translate="label">
|
22 |
+
<label>Head extension</label>
|
23 |
+
<show_in_default>1</show_in_default>
|
24 |
+
<show_in_website>0</show_in_website>
|
25 |
+
<show_in_store>0</show_in_store>
|
26 |
+
<sort_order>5</sort_order>
|
27 |
+
<fields>
|
28 |
+
<disable translate="label,comment">
|
29 |
+
<label>Disable module</label>
|
30 |
+
<comment><![CDATA[default: No]]></comment>
|
31 |
+
<frontend_type>select</frontend_type>
|
32 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
33 |
+
<sort_order>5</sort_order>
|
34 |
+
<show_in_default>1</show_in_default>
|
35 |
+
<show_in_website>0</show_in_website>
|
36 |
+
<show_in_store>0</show_in_store>
|
37 |
+
</disable>
|
38 |
+
<classname translate="label,comment">
|
39 |
+
<label>Block extension class name</label>
|
40 |
+
<comment><![CDATA[default: Mage_Page_Block_Html_Head]]></comment>
|
41 |
+
<frontend_type>text</frontend_type>
|
42 |
+
<sort_order>10</sort_order>
|
43 |
+
<show_in_default>1</show_in_default>
|
44 |
+
<show_in_website>0</show_in_website>
|
45 |
+
<show_in_store>0</show_in_store>
|
46 |
+
</classname>
|
47 |
+
</fields>
|
48 |
+
</extension>
|
49 |
+
<compress>
|
50 |
+
<label>Compress JS/CSS</label>
|
51 |
+
<show_in_default>1</show_in_default>
|
52 |
+
<show_in_website>0</show_in_website>
|
53 |
+
<show_in_store>0</show_in_store>
|
54 |
+
<sort_order>10</sort_order>
|
55 |
+
<fields>
|
56 |
+
<refresh>
|
57 |
+
<label>Refresh time (second)</label>
|
58 |
+
<comment><![CDATA[default: 3days - 259200]]></comment>
|
59 |
+
<frontend_type>text</frontend_type>
|
60 |
+
<sort_order>5</sort_order>
|
61 |
+
<show_in_default>1</show_in_default>
|
62 |
+
<show_in_website>0</show_in_website>
|
63 |
+
<show_in_store>0</show_in_store>
|
64 |
+
</refresh>
|
65 |
+
<nocache translate="label,comment">
|
66 |
+
<label>No cache file</label>
|
67 |
+
<comment><![CDATA[default: No]]></comment>
|
68 |
+
<frontend_type>select</frontend_type>
|
69 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
70 |
+
<sort_order>10</sort_order>
|
71 |
+
<show_in_default>1</show_in_default>
|
72 |
+
<show_in_website>0</show_in_website>
|
73 |
+
<show_in_store>0</show_in_store>
|
74 |
+
</nocache>
|
75 |
+
<gzipoff translate="label,comment">
|
76 |
+
<label>GZip handler off</label>
|
77 |
+
<comment><![CDATA[default: No]]></comment>
|
78 |
+
<frontend_type>select</frontend_type>
|
79 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
80 |
+
<sort_order>15</sort_order>
|
81 |
+
<show_in_default>1</show_in_default>
|
82 |
+
<show_in_website>0</show_in_website>
|
83 |
+
<show_in_store>0</show_in_store>
|
84 |
+
</gzipoff>
|
85 |
+
<minifyoff>
|
86 |
+
<label>Minify off</label>
|
87 |
+
<comment><![CDATA[default: No]]></comment>
|
88 |
+
<frontend_type>select</frontend_type>
|
89 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
90 |
+
<sort_order>20</sort_order>
|
91 |
+
<show_in_default>1</show_in_default>
|
92 |
+
<show_in_website>0</show_in_website>
|
93 |
+
<show_in_store>0</show_in_store>
|
94 |
+
</minifyoff>
|
95 |
+
</fields>
|
96 |
+
</compress>
|
97 |
+
<html>
|
98 |
+
<label>HTML</label>
|
99 |
+
<show_in_default>1</show_in_default>
|
100 |
+
<show_in_website>0</show_in_website>
|
101 |
+
<show_in_store>0</show_in_store>
|
102 |
+
<sort_order>15</sort_order>
|
103 |
+
<fields>
|
104 |
+
<disable>
|
105 |
+
<label>Compress html off</label>
|
106 |
+
<comment><![CDATA[default: no]]></comment>
|
107 |
+
<frontend_type>select</frontend_type>
|
108 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
109 |
+
<sort_order>5</sort_order>
|
110 |
+
<show_in_default>1</show_in_default>
|
111 |
+
<show_in_website>0</show_in_website>
|
112 |
+
<show_in_store>0</show_in_store>
|
113 |
+
</disable>
|
114 |
+
</fields>
|
115 |
+
</html>
|
116 |
+
</groups>
|
117 |
+
</psoptimizationhead>
|
118 |
+
</sections>
|
119 |
+
</config>
|
app/code/community/PSystem/OptimizationHead/lib/JSMin.php
ADDED
@@ -0,0 +1,314 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
4 |
+
*
|
5 |
+
* This is a direct port of jsmin.c to PHP with a few PHP performance tweaks and
|
6 |
+
* modifications to preserve some comments (see below). Also, rather than using
|
7 |
+
* stdin/stdout, JSMin::minify() accepts a string as input and returns another
|
8 |
+
* string as output.
|
9 |
+
*
|
10 |
+
* Comments containing IE conditional compilation are preserved, as are multi-line
|
11 |
+
* comments that begin with "/*!" (for documentation purposes). In the latter case
|
12 |
+
* newlines are inserted around the comment to enhance readability.
|
13 |
+
*
|
14 |
+
* PHP 5 or higher is required.
|
15 |
+
*
|
16 |
+
* Permission is hereby granted to use this version of the library under the
|
17 |
+
* same terms as jsmin.c, which has the following license:
|
18 |
+
*
|
19 |
+
* --
|
20 |
+
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
21 |
+
*
|
22 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
23 |
+
* this software and associated documentation files (the "Software"), to deal in
|
24 |
+
* the Software without restriction, including without limitation the rights to
|
25 |
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
26 |
+
* of the Software, and to permit persons to whom the Software is furnished to do
|
27 |
+
* so, subject to the following conditions:
|
28 |
+
*
|
29 |
+
* The above copyright notice and this permission notice shall be included in all
|
30 |
+
* copies or substantial portions of the Software.
|
31 |
+
*
|
32 |
+
* The Software shall be used for Good, not Evil.
|
33 |
+
*
|
34 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
35 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
36 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
37 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
38 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
39 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
40 |
+
* SOFTWARE.
|
41 |
+
* --
|
42 |
+
*
|
43 |
+
* @package JSMin
|
44 |
+
* @author Ryan Grove <ryan@wonko.com> (PHP port)
|
45 |
+
* @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
|
46 |
+
* @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
|
47 |
+
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
48 |
+
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
49 |
+
* @license http://opensource.org/licenses/mit-license.php MIT License
|
50 |
+
* @link http://code.google.com/p/jsmin-php/
|
51 |
+
*/
|
52 |
+
|
53 |
+
class JSMin {
|
54 |
+
const ORD_LF = 10;
|
55 |
+
const ORD_SPACE = 32;
|
56 |
+
const ACTION_KEEP_A = 1;
|
57 |
+
const ACTION_DELETE_A = 2;
|
58 |
+
const ACTION_DELETE_A_B = 3;
|
59 |
+
|
60 |
+
protected $a = "\n";
|
61 |
+
protected $b = '';
|
62 |
+
protected $input = '';
|
63 |
+
protected $inputIndex = 0;
|
64 |
+
protected $inputLength = 0;
|
65 |
+
protected $lookAhead = null;
|
66 |
+
protected $output = '';
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Minify Javascript
|
70 |
+
*
|
71 |
+
* @param string $js Javascript to be minified
|
72 |
+
* @return string
|
73 |
+
*/
|
74 |
+
public static function minify($js)
|
75 |
+
{
|
76 |
+
$jsmin = new JSMin($js);
|
77 |
+
return $jsmin->min();
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Setup process
|
82 |
+
*/
|
83 |
+
public function __construct($input)
|
84 |
+
{
|
85 |
+
$this->input = str_replace("\r\n", "\n", $input);
|
86 |
+
$this->inputLength = strlen($this->input);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Perform minification, return result
|
91 |
+
*/
|
92 |
+
public function min()
|
93 |
+
{
|
94 |
+
if ($this->output !== '') { // min already run
|
95 |
+
return $this->output;
|
96 |
+
}
|
97 |
+
$this->action(self::ACTION_DELETE_A_B);
|
98 |
+
|
99 |
+
while ($this->a !== null) {
|
100 |
+
// determine next command
|
101 |
+
$command = self::ACTION_KEEP_A; // default
|
102 |
+
if ($this->a === ' ') {
|
103 |
+
if (! $this->isAlphaNum($this->b)) {
|
104 |
+
$command = self::ACTION_DELETE_A;
|
105 |
+
}
|
106 |
+
} elseif ($this->a === "\n") {
|
107 |
+
if ($this->b === ' ') {
|
108 |
+
$command = self::ACTION_DELETE_A_B;
|
109 |
+
} elseif (false === strpos('{[(+-', $this->b)
|
110 |
+
&& ! $this->isAlphaNum($this->b)) {
|
111 |
+
$command = self::ACTION_DELETE_A;
|
112 |
+
}
|
113 |
+
} elseif (! $this->isAlphaNum($this->a)) {
|
114 |
+
if ($this->b === ' '
|
115 |
+
|| ($this->b === "\n"
|
116 |
+
&& (false === strpos('}])+-"\'', $this->a)))) {
|
117 |
+
$command = self::ACTION_DELETE_A_B;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
$this->action($command);
|
121 |
+
}
|
122 |
+
$this->output = trim($this->output);
|
123 |
+
return $this->output;
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
|
128 |
+
* ACTION_DELETE_A = Copy B to A. Get the next B.
|
129 |
+
* ACTION_DELETE_A_B = Get the next B.
|
130 |
+
*/
|
131 |
+
protected function action($command)
|
132 |
+
{
|
133 |
+
switch ($command) {
|
134 |
+
case self::ACTION_KEEP_A:
|
135 |
+
$this->output .= $this->a;
|
136 |
+
// fallthrough
|
137 |
+
case self::ACTION_DELETE_A:
|
138 |
+
$this->a = $this->b;
|
139 |
+
if ($this->a === "'" || $this->a === '"') { // string literal
|
140 |
+
$str = $this->a; // in case needed for exception
|
141 |
+
while (true) {
|
142 |
+
$this->output .= $this->a;
|
143 |
+
$this->a = $this->get();
|
144 |
+
if ($this->a === $this->b) { // end quote
|
145 |
+
break;
|
146 |
+
}
|
147 |
+
if (ord($this->a) <= self::ORD_LF) {
|
148 |
+
throw new JSMin_UnterminatedStringException(
|
149 |
+
'Unterminated String: ' . var_export($str, true));
|
150 |
+
}
|
151 |
+
$str .= $this->a;
|
152 |
+
if ($this->a === '\\') {
|
153 |
+
$this->output .= $this->a;
|
154 |
+
$this->a = $this->get();
|
155 |
+
$str .= $this->a;
|
156 |
+
}
|
157 |
+
}
|
158 |
+
}
|
159 |
+
// fallthrough
|
160 |
+
case self::ACTION_DELETE_A_B:
|
161 |
+
$this->b = $this->next();
|
162 |
+
if ($this->b === '/' && $this->isRegexpLiteral()) { // RegExp literal
|
163 |
+
$this->output .= $this->a . $this->b;
|
164 |
+
$pattern = '/'; // in case needed for exception
|
165 |
+
while (true) {
|
166 |
+
$this->a = $this->get();
|
167 |
+
$pattern .= $this->a;
|
168 |
+
if ($this->a === '/') { // end pattern
|
169 |
+
break; // while (true)
|
170 |
+
} elseif ($this->a === '\\') {
|
171 |
+
$this->output .= $this->a;
|
172 |
+
$this->a = $this->get();
|
173 |
+
$pattern .= $this->a;
|
174 |
+
} elseif (ord($this->a) <= self::ORD_LF) {
|
175 |
+
throw new JSMin_UnterminatedRegExpException(
|
176 |
+
'Unterminated RegExp: '. var_export($pattern, true));
|
177 |
+
}
|
178 |
+
$this->output .= $this->a;
|
179 |
+
}
|
180 |
+
$this->b = $this->next();
|
181 |
+
}
|
182 |
+
// end case ACTION_DELETE_A_B
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
protected function isRegexpLiteral()
|
187 |
+
{
|
188 |
+
if (false !== strpos("\n{;(,=:[!&|?", $this->a)) { // we aren't dividing
|
189 |
+
return true;
|
190 |
+
}
|
191 |
+
if (' ' === $this->a) {
|
192 |
+
$length = strlen($this->output);
|
193 |
+
if ($length < 2) { // weird edge case
|
194 |
+
return true;
|
195 |
+
}
|
196 |
+
// you can't divide a keyword
|
197 |
+
if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
|
198 |
+
if ($this->output === $m[0]) { // odd but could happen
|
199 |
+
return true;
|
200 |
+
}
|
201 |
+
// make sure it's a keyword, not end of an identifier
|
202 |
+
$charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);
|
203 |
+
if (! $this->isAlphaNum($charBeforeKeyword)) {
|
204 |
+
return true;
|
205 |
+
}
|
206 |
+
}
|
207 |
+
}
|
208 |
+
return false;
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Get next char. Convert ctrl char to space.
|
213 |
+
*/
|
214 |
+
protected function get()
|
215 |
+
{
|
216 |
+
$c = $this->lookAhead;
|
217 |
+
$this->lookAhead = null;
|
218 |
+
if ($c === null) {
|
219 |
+
if ($this->inputIndex < $this->inputLength) {
|
220 |
+
$c = $this->input[$this->inputIndex];
|
221 |
+
$this->inputIndex += 1;
|
222 |
+
} else {
|
223 |
+
return null;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
if ($c === "\r" || $c === "\n") {
|
227 |
+
return "\n";
|
228 |
+
}
|
229 |
+
if (ord($c) < self::ORD_SPACE) { // control char
|
230 |
+
return ' ';
|
231 |
+
}
|
232 |
+
return $c;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Get next char. If is ctrl character, translate to a space or newline.
|
237 |
+
*/
|
238 |
+
protected function peek()
|
239 |
+
{
|
240 |
+
$this->lookAhead = $this->get();
|
241 |
+
return $this->lookAhead;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Is $c a letter, digit, underscore, dollar sign, escape, or non-ASCII?
|
246 |
+
*/
|
247 |
+
protected function isAlphaNum($c)
|
248 |
+
{
|
249 |
+
return (preg_match('/^[0-9a-zA-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
250 |
+
}
|
251 |
+
|
252 |
+
protected function singleLineComment()
|
253 |
+
{
|
254 |
+
$comment = '';
|
255 |
+
while (true) {
|
256 |
+
$get = $this->get();
|
257 |
+
$comment .= $get;
|
258 |
+
if (ord($get) <= self::ORD_LF) { // EOL reached
|
259 |
+
// if IE conditional comment
|
260 |
+
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
261 |
+
return "/{$comment}";
|
262 |
+
}
|
263 |
+
return $get;
|
264 |
+
}
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
protected function multipleLineComment()
|
269 |
+
{
|
270 |
+
$this->get();
|
271 |
+
$comment = '';
|
272 |
+
while (true) {
|
273 |
+
$get = $this->get();
|
274 |
+
if ($get === '*') {
|
275 |
+
if ($this->peek() === '/') { // end of comment reached
|
276 |
+
$this->get();
|
277 |
+
// if comment preserved by YUI Compressor
|
278 |
+
if (0 === strpos($comment, '!')) {
|
279 |
+
return "\n/*" . substr($comment, 1) . "*/\n";
|
280 |
+
}
|
281 |
+
// if IE conditional comment
|
282 |
+
if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
283 |
+
return "/*{$comment}*/";
|
284 |
+
}
|
285 |
+
return ' ';
|
286 |
+
}
|
287 |
+
} elseif ($get === null) {
|
288 |
+
throw new JSMin_UnterminatedCommentException('Unterminated Comment: ' . var_export('/*' . $comment, true));
|
289 |
+
}
|
290 |
+
$comment .= $get;
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Get the next character, skipping over comments.
|
296 |
+
* Some comments may be preserved.
|
297 |
+
*/
|
298 |
+
protected function next()
|
299 |
+
{
|
300 |
+
$get = $this->get();
|
301 |
+
if ($get !== '/') {
|
302 |
+
return $get;
|
303 |
+
}
|
304 |
+
switch ($this->peek()) {
|
305 |
+
case '/': return $this->singleLineComment();
|
306 |
+
case '*': return $this->multipleLineComment();
|
307 |
+
default: return $get;
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
class JSMin_UnterminatedStringException extends Exception {}
|
313 |
+
class JSMin_UnterminatedCommentException extends Exception {}
|
314 |
+
class JSMin_UnterminatedRegExpException extends Exception {}
|
app/code/community/PSystem/OptimizationHead/lib/Minify/CSS.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CSS
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Minify CSS
|
9 |
+
*
|
10 |
+
* This class uses Minify_CSS_Compressor and Minify_CSS_UriRewriter to
|
11 |
+
* minify CSS and rewrite relative URIs.
|
12 |
+
*
|
13 |
+
* @package Minify
|
14 |
+
* @author Stephen Clay <steve@mrclay.org>
|
15 |
+
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
16 |
+
*/
|
17 |
+
class Minify_CSS {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Minify a CSS string
|
21 |
+
*
|
22 |
+
* @param string $css
|
23 |
+
*
|
24 |
+
* @param array $options available options:
|
25 |
+
*
|
26 |
+
* 'preserveComments': (default true) multi-line comments that begin
|
27 |
+
* with "/*!" will be preserved with newlines before and after to
|
28 |
+
* enhance readability.
|
29 |
+
*
|
30 |
+
* 'prependRelativePath': (default null) if given, this string will be
|
31 |
+
* prepended to all relative URIs in import/url declarations
|
32 |
+
*
|
33 |
+
* 'currentDir': (default null) if given, this is assumed to be the
|
34 |
+
* directory of the current CSS file. Using this, minify will rewrite
|
35 |
+
* all relative URIs in import/url declarations to correctly point to
|
36 |
+
* the desired files. For this to work, the files *must* exist and be
|
37 |
+
* visible by the PHP process.
|
38 |
+
*
|
39 |
+
* 'symlinks': (default = array()) If the CSS file is stored in
|
40 |
+
* a symlink-ed directory, provide an array of link paths to
|
41 |
+
* target paths, where the link paths are within the document root. Because
|
42 |
+
* paths need to be normalized for this to work, use "//" to substitute
|
43 |
+
* the doc root in the link paths (the array keys). E.g.:
|
44 |
+
* <code>
|
45 |
+
* array('//symlink' => '/real/target/path') // unix
|
46 |
+
* array('//static' => 'D:\\staticStorage') // Windows
|
47 |
+
* </code>
|
48 |
+
*
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
public static function minify($css, $options = array())
|
52 |
+
{
|
53 |
+
require_once 'Minify/CSS/Compressor.php';
|
54 |
+
if (isset($options['preserveComments'])
|
55 |
+
&& !$options['preserveComments']) {
|
56 |
+
$css = Minify_CSS_Compressor::process($css, $options);
|
57 |
+
} else {
|
58 |
+
require_once 'Minify/CommentPreserver.php';
|
59 |
+
$css = Minify_CommentPreserver::process(
|
60 |
+
$css
|
61 |
+
,array('Minify_CSS_Compressor', 'process')
|
62 |
+
,array($options)
|
63 |
+
);
|
64 |
+
}
|
65 |
+
if (! isset($options['currentDir']) && ! isset($options['prependRelativePath'])) {
|
66 |
+
return $css;
|
67 |
+
}
|
68 |
+
require_once 'Minify/CSS/UriRewriter.php';
|
69 |
+
if (isset($options['currentDir'])) {
|
70 |
+
return Minify_CSS_UriRewriter::rewrite(
|
71 |
+
$css
|
72 |
+
,$options['currentDir']
|
73 |
+
,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
|
74 |
+
,isset($options['symlinks']) ? $options['symlinks'] : array()
|
75 |
+
);
|
76 |
+
} else {
|
77 |
+
return Minify_CSS_UriRewriter::prepend(
|
78 |
+
$css
|
79 |
+
,$options['prependRelativePath']
|
80 |
+
);
|
81 |
+
}
|
82 |
+
}
|
83 |
+
}
|
app/code/community/PSystem/OptimizationHead/lib/Minify/CSS/Compressor.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CSS_Compressor
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress CSS
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary
|
11 |
+
* comments and tokens, and some CSS value minimization, where practical.
|
12 |
+
* Many steps have been taken to avoid breaking comment-based hacks,
|
13 |
+
* including the ie5/mac filter (and its inversion), but expect tricky
|
14 |
+
* hacks involving comment tokens in 'content' value strings to break
|
15 |
+
* minimization badly. A test suite is available.
|
16 |
+
*
|
17 |
+
* @package Minify
|
18 |
+
* @author Stephen Clay <steve@mrclay.org>
|
19 |
+
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
20 |
+
*/
|
21 |
+
class Minify_CSS_Compressor {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Minify a CSS string
|
25 |
+
*
|
26 |
+
* @param string $css
|
27 |
+
*
|
28 |
+
* @param array $options (currently ignored)
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public static function process($css, $options = array())
|
33 |
+
{
|
34 |
+
$obj = new Minify_CSS_Compressor($options);
|
35 |
+
return $obj->_process($css);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var array options
|
40 |
+
*/
|
41 |
+
protected $_options = null;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @var bool Are we "in" a hack?
|
45 |
+
*
|
46 |
+
* I.e. are some browsers targetted until the next comment?
|
47 |
+
*/
|
48 |
+
protected $_inHack = false;
|
49 |
+
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Constructor
|
53 |
+
*
|
54 |
+
* @param array $options (currently ignored)
|
55 |
+
*
|
56 |
+
* @return null
|
57 |
+
*/
|
58 |
+
private function __construct($options) {
|
59 |
+
$this->_options = $options;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Minify a CSS string
|
64 |
+
*
|
65 |
+
* @param string $css
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
protected function _process($css)
|
70 |
+
{
|
71 |
+
$css = str_replace("\r\n", "\n", $css);
|
72 |
+
|
73 |
+
// preserve empty comment after '>'
|
74 |
+
// http://www.webdevout.net/css-hacks#in_css-selectors
|
75 |
+
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
|
76 |
+
|
77 |
+
// preserve empty comment between property and value
|
78 |
+
// http://css-discuss.incutio.com/?page=BoxModelHack
|
79 |
+
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
|
80 |
+
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
81 |
+
|
82 |
+
// apply callback to all valid comments (and strip out surrounding ws
|
83 |
+
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
84 |
+
,array($this, '_commentCB'), $css);
|
85 |
+
|
86 |
+
// remove ws around { } and last semicolon in declaration block
|
87 |
+
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
88 |
+
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
|
89 |
+
|
90 |
+
// remove ws surrounding semicolons
|
91 |
+
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
92 |
+
|
93 |
+
// remove ws around urls
|
94 |
+
$css = preg_replace('/
|
95 |
+
url\\( # url(
|
96 |
+
\\s*
|
97 |
+
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
98 |
+
\\s*
|
99 |
+
\\) # )
|
100 |
+
/x', 'url($1)', $css);
|
101 |
+
|
102 |
+
// remove ws between rules and colons
|
103 |
+
$css = preg_replace('/
|
104 |
+
\\s*
|
105 |
+
([{;]) # 1 = beginning of block or rule separator
|
106 |
+
\\s*
|
107 |
+
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
|
108 |
+
\\s*
|
109 |
+
:
|
110 |
+
\\s*
|
111 |
+
(\\b|[#\'"]) # 3 = first character of a value
|
112 |
+
/x', '$1$2:$3', $css);
|
113 |
+
|
114 |
+
// remove ws in selectors
|
115 |
+
$css = preg_replace_callback('/
|
116 |
+
(?: # non-capture
|
117 |
+
\\s*
|
118 |
+
[^~>+,\\s]+ # selector part
|
119 |
+
\\s*
|
120 |
+
[,>+~] # combinators
|
121 |
+
)+
|
122 |
+
\\s*
|
123 |
+
[^~>+,\\s]+ # selector part
|
124 |
+
{ # open declaration block
|
125 |
+
/x'
|
126 |
+
,array($this, '_selectorsCB'), $css);
|
127 |
+
|
128 |
+
// minimize hex colors
|
129 |
+
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
130 |
+
, '$1#$2$3$4$5', $css);
|
131 |
+
|
132 |
+
// remove spaces between font families
|
133 |
+
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
134 |
+
,array($this, '_fontFamilyCB'), $css);
|
135 |
+
|
136 |
+
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
137 |
+
|
138 |
+
// replace any ws involving newlines with a single newline
|
139 |
+
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
140 |
+
|
141 |
+
// separate common descendent selectors w/ newlines (to limit line lengths)
|
142 |
+
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
143 |
+
|
144 |
+
// Use newline after 1st numeric value (to limit line lengths).
|
145 |
+
$css = preg_replace('/
|
146 |
+
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
147 |
+
\\s+
|
148 |
+
/x'
|
149 |
+
,"$1\n", $css);
|
150 |
+
|
151 |
+
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
152 |
+
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
153 |
+
|
154 |
+
return trim($css);
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Replace what looks like a set of selectors
|
159 |
+
*
|
160 |
+
* @param array $m regex matches
|
161 |
+
*
|
162 |
+
* @return string
|
163 |
+
*/
|
164 |
+
protected function _selectorsCB($m)
|
165 |
+
{
|
166 |
+
// remove ws around the combinators
|
167 |
+
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Process a comment and return a replacement
|
172 |
+
*
|
173 |
+
* @param array $m regex matches
|
174 |
+
*
|
175 |
+
* @return string
|
176 |
+
*/
|
177 |
+
protected function _commentCB($m)
|
178 |
+
{
|
179 |
+
$hasSurroundingWs = (trim($m[0]) !== $m[1]);
|
180 |
+
$m = $m[1];
|
181 |
+
// $m is the comment content w/o the surrounding tokens,
|
182 |
+
// but the return value will replace the entire comment.
|
183 |
+
if ($m === 'keep') {
|
184 |
+
return '/**/';
|
185 |
+
}
|
186 |
+
if ($m === '" "') {
|
187 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
188 |
+
return '/*" "*/';
|
189 |
+
}
|
190 |
+
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
191 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
192 |
+
return '/*";}}/* */';
|
193 |
+
}
|
194 |
+
if ($this->_inHack) {
|
195 |
+
// inversion: feeding only to one browser
|
196 |
+
if (preg_match('@
|
197 |
+
^/ # comment started like /*/
|
198 |
+
\\s*
|
199 |
+
(\\S[\\s\\S]+?) # has at least some non-ws content
|
200 |
+
\\s*
|
201 |
+
/\\* # ends like /*/ or /**/
|
202 |
+
@x', $m, $n)) {
|
203 |
+
// end hack mode after this comment, but preserve the hack and comment content
|
204 |
+
$this->_inHack = false;
|
205 |
+
return "/*/{$n[1]}/**/";
|
206 |
+
}
|
207 |
+
}
|
208 |
+
if (substr($m, -1) === '\\') { // comment ends like \*/
|
209 |
+
// begin hack mode and preserve hack
|
210 |
+
$this->_inHack = true;
|
211 |
+
return '/*\\*/';
|
212 |
+
}
|
213 |
+
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
214 |
+
// begin hack mode and preserve hack
|
215 |
+
$this->_inHack = true;
|
216 |
+
return '/*/*/';
|
217 |
+
}
|
218 |
+
if ($this->_inHack) {
|
219 |
+
// a regular comment ends hack mode but should be preserved
|
220 |
+
$this->_inHack = false;
|
221 |
+
return '/**/';
|
222 |
+
}
|
223 |
+
// Issue 107: if there's any surrounding whitespace, it may be important, so
|
224 |
+
// replace the comment with a single space
|
225 |
+
return $hasSurroundingWs // remove all other comments
|
226 |
+
? ' '
|
227 |
+
: '';
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Process a font-family listing and return a replacement
|
232 |
+
*
|
233 |
+
* @param array $m regex matches
|
234 |
+
*
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function _fontFamilyCB($m)
|
238 |
+
{
|
239 |
+
$m[1] = preg_replace('/
|
240 |
+
\\s*
|
241 |
+
(
|
242 |
+
"[^"]+" # 1 = family in double qutoes
|
243 |
+
|\'[^\']+\' # or 1 = family in single quotes
|
244 |
+
|[\\w\\-]+ # or 1 = unquoted family
|
245 |
+
)
|
246 |
+
\\s*
|
247 |
+
/x', '$1', $m[1]);
|
248 |
+
return 'font-family:' . $m[1] . $m[2];
|
249 |
+
}
|
250 |
+
}
|
app/code/community/PSystem/OptimizationHead/lib/Minify/CSS/UriRewriter.php
ADDED
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CSS_UriRewriter
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Rewrite file-relative URIs as root-relative in CSS files
|
9 |
+
*
|
10 |
+
* @package Minify
|
11 |
+
* @author Stephen Clay <steve@mrclay.org>
|
12 |
+
*/
|
13 |
+
class Minify_CSS_UriRewriter {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Defines which class to call as part of callbacks, change this
|
17 |
+
* if you extend Minify_CSS_UriRewriter
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
protected static $className = 'Minify_CSS_UriRewriter';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* rewrite() and rewriteRelative() append debugging information here
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
public static $debugText = '';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Rewrite file relative URIs as root relative in CSS files
|
30 |
+
*
|
31 |
+
* @param string $css
|
32 |
+
*
|
33 |
+
* @param string $currentDir The directory of the current CSS file.
|
34 |
+
*
|
35 |
+
* @param string $docRoot The document root of the web site in which
|
36 |
+
* the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
|
37 |
+
*
|
38 |
+
* @param array $symlinks (default = array()) If the CSS file is stored in
|
39 |
+
* a symlink-ed directory, provide an array of link paths to
|
40 |
+
* target paths, where the link paths are within the document root. Because
|
41 |
+
* paths need to be normalized for this to work, use "//" to substitute
|
42 |
+
* the doc root in the link paths (the array keys). E.g.:
|
43 |
+
* <code>
|
44 |
+
* array('//symlink' => '/real/target/path') // unix
|
45 |
+
* array('//static' => 'D:\\staticStorage') // Windows
|
46 |
+
* </code>
|
47 |
+
*
|
48 |
+
* @return string
|
49 |
+
*/
|
50 |
+
public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
|
51 |
+
{
|
52 |
+
self::$_docRoot = self::_realpath(
|
53 |
+
$docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
|
54 |
+
);
|
55 |
+
self::$_currentDir = self::_realpath($currentDir);
|
56 |
+
self::$_symlinks = array();
|
57 |
+
|
58 |
+
// normalize symlinks
|
59 |
+
foreach ($symlinks as $link => $target) {
|
60 |
+
$link = ($link === '//')
|
61 |
+
? self::$_docRoot
|
62 |
+
: str_replace('//', self::$_docRoot . '/', $link);
|
63 |
+
$link = strtr($link, '/', DIRECTORY_SEPARATOR);
|
64 |
+
self::$_symlinks[$link] = self::_realpath($target);
|
65 |
+
}
|
66 |
+
|
67 |
+
self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
|
68 |
+
. "currentDir : " . self::$_currentDir . "\n";
|
69 |
+
if (self::$_symlinks) {
|
70 |
+
self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
|
71 |
+
}
|
72 |
+
self::$debugText .= "\n";
|
73 |
+
|
74 |
+
$css = self::_trimUrls($css);
|
75 |
+
|
76 |
+
// rewrite
|
77 |
+
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
78 |
+
,array(self::$className, '_processUriCB'), $css);
|
79 |
+
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
80 |
+
,array(self::$className, '_processUriCB'), $css);
|
81 |
+
|
82 |
+
return $css;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Prepend a path to relative URIs in CSS files
|
87 |
+
*
|
88 |
+
* @param string $css
|
89 |
+
*
|
90 |
+
* @param string $path The path to prepend.
|
91 |
+
*
|
92 |
+
* @return string
|
93 |
+
*/
|
94 |
+
public static function prepend($css, $path)
|
95 |
+
{
|
96 |
+
self::$_prependPath = $path;
|
97 |
+
|
98 |
+
$css = self::_trimUrls($css);
|
99 |
+
|
100 |
+
// append
|
101 |
+
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
102 |
+
,array(self::$className, '_processUriCB'), $css);
|
103 |
+
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
104 |
+
,array(self::$className, '_processUriCB'), $css);
|
105 |
+
|
106 |
+
self::$_prependPath = null;
|
107 |
+
return $css;
|
108 |
+
}
|
109 |
+
|
110 |
+
|
111 |
+
/**
|
112 |
+
* @var string directory of this stylesheet
|
113 |
+
*/
|
114 |
+
private static $_currentDir = '';
|
115 |
+
|
116 |
+
/**
|
117 |
+
* @var string DOC_ROOT
|
118 |
+
*/
|
119 |
+
private static $_docRoot = '';
|
120 |
+
|
121 |
+
/**
|
122 |
+
* @var array directory replacements to map symlink targets back to their
|
123 |
+
* source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
|
124 |
+
*/
|
125 |
+
private static $_symlinks = array();
|
126 |
+
|
127 |
+
/**
|
128 |
+
* @var string path to prepend
|
129 |
+
*/
|
130 |
+
private static $_prependPath = null;
|
131 |
+
|
132 |
+
private static function _trimUrls($css)
|
133 |
+
{
|
134 |
+
return preg_replace('/
|
135 |
+
url\\( # url(
|
136 |
+
\\s*
|
137 |
+
([^\\)]+?) # 1 = URI (assuming does not contain ")")
|
138 |
+
\\s*
|
139 |
+
\\) # )
|
140 |
+
/x', 'url($1)', $css);
|
141 |
+
}
|
142 |
+
|
143 |
+
private static function _processUriCB($m)
|
144 |
+
{
|
145 |
+
// $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
146 |
+
$isImport = ($m[0][0] === '@');
|
147 |
+
// determine URI and the quote character (if any)
|
148 |
+
if ($isImport) {
|
149 |
+
$quoteChar = $m[1];
|
150 |
+
$uri = $m[2];
|
151 |
+
} else {
|
152 |
+
// $m[1] is either quoted or not
|
153 |
+
$quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
|
154 |
+
? $m[1][0]
|
155 |
+
: '';
|
156 |
+
$uri = ($quoteChar === '')
|
157 |
+
? $m[1]
|
158 |
+
: substr($m[1], 1, strlen($m[1]) - 2);
|
159 |
+
}
|
160 |
+
// analyze URI
|
161 |
+
if ('/' !== $uri[0] // root-relative
|
162 |
+
&& false === strpos($uri, '//') // protocol (non-data)
|
163 |
+
&& 0 !== strpos($uri, 'data:') // data protocol
|
164 |
+
) {
|
165 |
+
// URI is file-relative: rewrite depending on options
|
166 |
+
$uri = (self::$_prependPath !== null)
|
167 |
+
? (self::$_prependPath . $uri)
|
168 |
+
: self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
|
169 |
+
}
|
170 |
+
return $isImport
|
171 |
+
? "@import {$quoteChar}{$uri}{$quoteChar}"
|
172 |
+
: "url({$quoteChar}{$uri}{$quoteChar})";
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Rewrite a file relative URI as root relative
|
177 |
+
*
|
178 |
+
* <code>
|
179 |
+
* Minify_CSS_UriRewriter::rewriteRelative(
|
180 |
+
* '../img/hello.gif'
|
181 |
+
* , '/home/user/www/css' // path of CSS file
|
182 |
+
* , '/home/user/www' // doc root
|
183 |
+
* );
|
184 |
+
* // returns '/img/hello.gif'
|
185 |
+
*
|
186 |
+
* // example where static files are stored in a symlinked directory
|
187 |
+
* Minify_CSS_UriRewriter::rewriteRelative(
|
188 |
+
* 'hello.gif'
|
189 |
+
* , '/var/staticFiles/theme'
|
190 |
+
* , '/home/user/www'
|
191 |
+
* , array('/home/user/www/static' => '/var/staticFiles')
|
192 |
+
* );
|
193 |
+
* // returns '/static/theme/hello.gif'
|
194 |
+
* </code>
|
195 |
+
*
|
196 |
+
* @param string $uri file relative URI
|
197 |
+
*
|
198 |
+
* @param string $realCurrentDir realpath of the current file's directory.
|
199 |
+
*
|
200 |
+
* @param string $realDocRoot realpath of the site document root.
|
201 |
+
*
|
202 |
+
* @param array $symlinks (default = array()) If the file is stored in
|
203 |
+
* a symlink-ed directory, provide an array of link paths to
|
204 |
+
* real target paths, where the link paths "appear" to be within the document
|
205 |
+
* root. E.g.:
|
206 |
+
* <code>
|
207 |
+
* array('/home/foo/www/not/real/path' => '/real/target/path') // unix
|
208 |
+
* array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
|
209 |
+
* </code>
|
210 |
+
*
|
211 |
+
* @return string
|
212 |
+
*/
|
213 |
+
public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
|
214 |
+
{
|
215 |
+
// prepend path with current dir separator (OS-independent)
|
216 |
+
$path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)
|
217 |
+
. DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
|
218 |
+
|
219 |
+
self::$debugText .= "file-relative URI : {$uri}\n"
|
220 |
+
. "path prepended : {$path}\n";
|
221 |
+
|
222 |
+
// "unresolve" a symlink back to doc root
|
223 |
+
foreach ($symlinks as $link => $target) {
|
224 |
+
if (0 === strpos($path, $target)) {
|
225 |
+
// replace $target with $link
|
226 |
+
$path = $link . substr($path, strlen($target));
|
227 |
+
|
228 |
+
self::$debugText .= "symlink unresolved : {$path}\n";
|
229 |
+
|
230 |
+
break;
|
231 |
+
}
|
232 |
+
}
|
233 |
+
// strip doc root
|
234 |
+
$path = substr($path, strlen($realDocRoot));
|
235 |
+
|
236 |
+
self::$debugText .= "docroot stripped : {$path}\n";
|
237 |
+
|
238 |
+
// fix to root-relative URI
|
239 |
+
|
240 |
+
$uri = strtr($path, '/\\', '//');
|
241 |
+
|
242 |
+
// remove /./ and /../ where possible
|
243 |
+
$uri = str_replace('/./', '/', $uri);
|
244 |
+
// inspired by patch from Oleg Cherniy
|
245 |
+
do {
|
246 |
+
$uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
|
247 |
+
} while ($changed);
|
248 |
+
|
249 |
+
self::$debugText .= "traversals removed : {$uri}\n\n";
|
250 |
+
|
251 |
+
return $uri;
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Get realpath with any trailing slash removed. If realpath() fails,
|
256 |
+
* just remove the trailing slash.
|
257 |
+
*
|
258 |
+
* @param string $path
|
259 |
+
*
|
260 |
+
* @return mixed path with no trailing slash
|
261 |
+
*/
|
262 |
+
protected static function _realpath($path)
|
263 |
+
{
|
264 |
+
$realPath = realpath($path);
|
265 |
+
if ($realPath !== false) {
|
266 |
+
$path = $realPath;
|
267 |
+
}
|
268 |
+
return rtrim($path, '/\\');
|
269 |
+
}
|
270 |
+
}
|
app/code/community/PSystem/OptimizationHead/lib/Minify/CommentPreserver.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CommentPreserver
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Process a string in pieces preserving C-style comments that begin with "/*!"
|
9 |
+
*
|
10 |
+
* @package Minify
|
11 |
+
* @author Stephen Clay <steve@mrclay.org>
|
12 |
+
*/
|
13 |
+
class Minify_CommentPreserver {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* String to be prepended to each preserved comment
|
17 |
+
*
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
public static $prepend = "\n";
|
21 |
+
|
22 |
+
/**
|
23 |
+
* String to be appended to each preserved comment
|
24 |
+
*
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
+
public static $append = "\n";
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Process a string outside of C-style comments that begin with "/*!"
|
31 |
+
*
|
32 |
+
* On each non-empty string outside these comments, the given processor
|
33 |
+
* function will be called. The first "!" will be removed from the
|
34 |
+
* preserved comments, and the comments will be surrounded by
|
35 |
+
* Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
|
36 |
+
*
|
37 |
+
* @param string $content
|
38 |
+
* @param callback $processor function
|
39 |
+
* @param array $args array of extra arguments to pass to the processor
|
40 |
+
* function (default = array())
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
public static function process($content, $processor, $args = array())
|
44 |
+
{
|
45 |
+
$ret = '';
|
46 |
+
while (true) {
|
47 |
+
list($beforeComment, $comment, $afterComment) = self::_nextComment($content);
|
48 |
+
if ('' !== $beforeComment) {
|
49 |
+
$callArgs = $args;
|
50 |
+
array_unshift($callArgs, $beforeComment);
|
51 |
+
$ret .= call_user_func_array($processor, $callArgs);
|
52 |
+
}
|
53 |
+
if (false === $comment) {
|
54 |
+
break;
|
55 |
+
}
|
56 |
+
$ret .= $comment;
|
57 |
+
$content = $afterComment;
|
58 |
+
}
|
59 |
+
return $ret;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Extract comments that YUI Compressor preserves.
|
64 |
+
*
|
65 |
+
* @param string $in input
|
66 |
+
*
|
67 |
+
* @return array 3 elements are returned. If a YUI comment is found, the
|
68 |
+
* 2nd element is the comment and the 1st and 2nd are the surrounding
|
69 |
+
* strings. If no comment is found, the entire string is returned as the
|
70 |
+
* 1st element and the other two are false.
|
71 |
+
*/
|
72 |
+
private static function _nextComment($in)
|
73 |
+
{
|
74 |
+
if (
|
75 |
+
false === ($start = strpos($in, '/*!'))
|
76 |
+
|| false === ($end = strpos($in, '*/', $start + 3))
|
77 |
+
) {
|
78 |
+
return array($in, false, false);
|
79 |
+
}
|
80 |
+
$ret = array(
|
81 |
+
substr($in, 0, $start)
|
82 |
+
,self::$prepend . '/*' . substr($in, $start + 3, $end - $start - 1) . self::$append
|
83 |
+
);
|
84 |
+
$endChars = (strlen($in) - $end - 2);
|
85 |
+
$ret[] = (0 === $endChars)
|
86 |
+
? ''
|
87 |
+
: substr($in, -$endChars);
|
88 |
+
return $ret;
|
89 |
+
}
|
90 |
+
}
|
app/code/community/PSystem/OptimizationHead/lib/PSystemHtmlMinify.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category PSystem
|
4 |
+
* @package PSystem_OptimizationHead
|
5 |
+
* @author Pascal System <info@pascalsystem.pl>
|
6 |
+
* @version 1.0.0
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Pascal Optimization observer
|
11 |
+
*
|
12 |
+
* @category PSystem
|
13 |
+
* @package PSystem_OptimizationHead
|
14 |
+
* @author Pascal System <info@pascalsystem.pl>
|
15 |
+
* @version 1.0.0
|
16 |
+
*/
|
17 |
+
class PSystemHtmlMinify {
|
18 |
+
/**
|
19 |
+
* Compress html
|
20 |
+
*
|
21 |
+
* @param string $content
|
22 |
+
* @return string
|
23 |
+
*/
|
24 |
+
public static function min($content) {
|
25 |
+
$content = str_replace("\n",'',$content);
|
26 |
+
$content = str_replace("\r",'',$content);
|
27 |
+
$content = preg_replace('/([\s]{2,})/',' ',$content);
|
28 |
+
return $content;
|
29 |
+
}
|
30 |
+
}
|
app/etc/modules/PSystem_OptimizationHead.xml
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category PSystem
|
5 |
+
* @package PSystem_OptimizationHead
|
6 |
+
* @author Pascal System <info@pascalsystem.pl>
|
7 |
+
* @version 1.0.0
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<modules>
|
12 |
+
<PSystem_OptimizationHead>
|
13 |
+
<active>true</active>
|
14 |
+
<codePool>community</codePool>
|
15 |
+
<depends>
|
16 |
+
<PSystem_Base/>
|
17 |
+
</depends>
|
18 |
+
</PSystem_OptimizationHead>
|
19 |
+
</modules>
|
20 |
+
</config>
|
js/pascalsystem/combine.php
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Pascal combine js and css
|
4 |
+
*
|
5 |
+
* @category PSystem
|
6 |
+
* @package PSystem_OptimizationHead
|
7 |
+
* @author Pascal System <info@pascalsystem.pl>
|
8 |
+
* @version 1.0.0
|
9 |
+
*/
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Return clear cache time in second
|
13 |
+
*
|
14 |
+
* @return int
|
15 |
+
*/
|
16 |
+
function getRefreshTime() {
|
17 |
+
if (!empty($_GET['refresh']) && ($time = intval($_GET['refresh'])))
|
18 |
+
return $time;
|
19 |
+
return 259200;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Set css header
|
24 |
+
*
|
25 |
+
* @return void
|
26 |
+
*/
|
27 |
+
function setCssHeader() {
|
28 |
+
if (empty($_GET['gzipoff'])) {
|
29 |
+
ob_start('ob_gzhandler');
|
30 |
+
header('Content-Encoding: gzip');
|
31 |
+
}
|
32 |
+
header('Content-type: text/css; charset:UTF-8');
|
33 |
+
header('Cache-Control: must-revalidate');
|
34 |
+
$offset = getRefreshTime();
|
35 |
+
$ExpStr = 'Expires: '.gmdate('D, d M Y H:i:s', time() + $offset) . ' GMT';
|
36 |
+
header($ExpStr);
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Set js header
|
41 |
+
*
|
42 |
+
* @return void
|
43 |
+
*/
|
44 |
+
function setJsHeader() {
|
45 |
+
if (empty($_GET['gzipoff'])) {
|
46 |
+
ob_start('ob_gzhandler');
|
47 |
+
header('Content-Encoding: gzip');
|
48 |
+
}
|
49 |
+
header('Content-type: text/javascript; charset: UTF-8');
|
50 |
+
header('Cache-Control: must-revalidate');
|
51 |
+
$offset = getRefreshTime();
|
52 |
+
$ExpStr = 'Expires: '.gmdate('D, d M Y H:i:s', time() + $offset) . ' GMT';
|
53 |
+
header($ExpStr);
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Minify css
|
58 |
+
*
|
59 |
+
* @param string $content
|
60 |
+
* @return string
|
61 |
+
*/
|
62 |
+
function minifyCss($content) {
|
63 |
+
if (!empty($_GET['minoff']))
|
64 |
+
return $content;
|
65 |
+
require_once 'Minify/CSS.php';
|
66 |
+
return Minify_CSS::minify($content);
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Minify js
|
71 |
+
*
|
72 |
+
* @param string $content
|
73 |
+
* @return string
|
74 |
+
*/
|
75 |
+
function minifyJs($content) {
|
76 |
+
if (!empty($_GET['minoff']))
|
77 |
+
return $content;
|
78 |
+
require_once 'JSMin.php';
|
79 |
+
return JSMin::minify($content);
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Get media cache dir
|
84 |
+
*
|
85 |
+
* @return string
|
86 |
+
*/
|
87 |
+
function getCacheDir() {
|
88 |
+
$dir = dirname(__FILE__).'/../../media/optimizationhead';
|
89 |
+
if (!is_dir($dir)) mkdir($dir, 0777);
|
90 |
+
return $dir.'/';
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Get base dir
|
95 |
+
*
|
96 |
+
* @param string $type
|
97 |
+
* @return string
|
98 |
+
*/
|
99 |
+
function getBaseDir($type = '') {
|
100 |
+
$path = dirname(__FILE__).'/../..';
|
101 |
+
if ($type)
|
102 |
+
$path.= '/'.$type;
|
103 |
+
return $path;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Get base url
|
108 |
+
*
|
109 |
+
* @reutrn string
|
110 |
+
*/
|
111 |
+
function getBaseUrl() {
|
112 |
+
if (isset($GLOBALS['BASE_URL']))
|
113 |
+
return $GLOBALS['BASE_URL'];
|
114 |
+
$httpUrl = '';
|
115 |
+
if (empty($_SERVER['REQUEST_URI']))
|
116 |
+
return '/';
|
117 |
+
$cutPos = strpos($_SERVER['REQUEST_URI'], 'js/pascalsystem');
|
118 |
+
if ($cutPos===false)
|
119 |
+
$httpUrl.= '/';
|
120 |
+
else
|
121 |
+
$httpUrl.= substr($_SERVER['REQUEST_URI'], 0, $cutPos);
|
122 |
+
$GLOBALS['BASE_URL'] = $httpUrl;
|
123 |
+
return $GLOBALS['BASE_URL'];
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Translate url in css file
|
128 |
+
*
|
129 |
+
* @param string $content
|
130 |
+
* @param string $file
|
131 |
+
* @param string $prefix
|
132 |
+
* @return string
|
133 |
+
*/
|
134 |
+
function translateUrlInCss($content, $file, $prefix) {
|
135 |
+
preg_match_all('/url\(([\'\"])?([^\)\'\"]+)([\'\"])?\)/', $content, $matches);
|
136 |
+
$absPath = getBaseUrl().$prefix.'/';
|
137 |
+
$absFilePart = explode('/',dirname($file));
|
138 |
+
$absFileNum = count($absFilePart);
|
139 |
+
$replaces = array();
|
140 |
+
foreach ($matches[0] as $num => $value) {
|
141 |
+
$temps = explode('/',$matches[2][$num]);
|
142 |
+
$numTemps = count($temps);
|
143 |
+
for ($i=0;$i<$numTemps;$i++) {
|
144 |
+
if ($temps[$i]=='..')
|
145 |
+
continue;
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
if ($i>$absFileNum) {
|
149 |
+
$i==$absFileNum;
|
150 |
+
}
|
151 |
+
if ($i>0) {
|
152 |
+
$temps = array_slice($temps, $i);
|
153 |
+
}
|
154 |
+
$pathSlice = array_slice($absFilePart, 0, $absFileNum-$i);
|
155 |
+
$replaces[$num] = 'url('.$matches[1][$num].$absPath.implode('/',$pathSlice).'/'.implode('/',$temps).$matches[3][$num].')';
|
156 |
+
}
|
157 |
+
return str_replace($matches[0], $replaces, $content);
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Combine files
|
162 |
+
*
|
163 |
+
* @param array $files
|
164 |
+
* @param string $prefix
|
165 |
+
* @param string $ext
|
166 |
+
* @return string
|
167 |
+
*/
|
168 |
+
function combineFiles(array $files, $prefix, $ext) {
|
169 |
+
$baseDir = getBaseDir($prefix).'/';
|
170 |
+
$cacheDir = getCacheDir();
|
171 |
+
|
172 |
+
$filesKey = md5(serialize($files)).'.'.$ext;
|
173 |
+
|
174 |
+
$noCache = empty($_GET['nocache'])?false:true;
|
175 |
+
|
176 |
+
if (!$noCache && file_exists($cacheDir.$filesKey) && (filemtime($cacheDir.$filesKey)+getRefreshTime() > time())) {
|
177 |
+
$allData = file_get_contents($cacheDir.$filesKey);
|
178 |
+
} else {
|
179 |
+
$allData = '';
|
180 |
+
foreach ($files as $file) {
|
181 |
+
if (!file_exists($baseDir.$file))
|
182 |
+
continue;
|
183 |
+
|
184 |
+
$data = file_get_contents($baseDir.$file);
|
185 |
+
if ($ext == 'css') {
|
186 |
+
$data = translateUrlInCss($data, $file, $prefix);
|
187 |
+
}
|
188 |
+
|
189 |
+
if ($allData) {
|
190 |
+
$allData.= "\n\n";
|
191 |
+
}
|
192 |
+
$allData.= $data;
|
193 |
+
}
|
194 |
+
|
195 |
+
if ($ext == 'css') {
|
196 |
+
$allData = minifyCss($allData);
|
197 |
+
} else {
|
198 |
+
$allData = minifyJs($allData);
|
199 |
+
}
|
200 |
+
|
201 |
+
if (!$noCache) {
|
202 |
+
file_put_contents($cacheDir.$filesKey, $allData);
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
echo $allData;
|
207 |
+
}
|
208 |
+
|
209 |
+
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__).'/../../app/code/community/PSystem/OptimizationHead/lib');
|
210 |
+
$type = empty($_GET['type'])?'':$_GET['type'];
|
211 |
+
$files = empty($_GET['file'])?array():explode(',',$_GET['file']);
|
212 |
+
switch ($type) {
|
213 |
+
case 'css' :
|
214 |
+
setCssHeader();
|
215 |
+
combineFiles($files, 'js', 'css');
|
216 |
+
exit;
|
217 |
+
case 'cssskin' :
|
218 |
+
setCssHeader();
|
219 |
+
combineFiles($files, 'skin', 'css');
|
220 |
+
exit;
|
221 |
+
case 'js' :
|
222 |
+
setJsHeader();
|
223 |
+
combineFiles($files, 'js', 'js');
|
224 |
+
exit;
|
225 |
+
case 'jsskin' :
|
226 |
+
setJsHeader();
|
227 |
+
combineFiles($files, 'skin', 'js');
|
228 |
+
exit;
|
229 |
+
}
|
230 |
+
header("HTTP/1.0 404 Not Found");
|
231 |
+
header("Status: 404 Not Found");
|
package.xml
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>PSystem_OptimizationHead</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license>OSL v3.0</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Optimize css, js and html for your magento shop</summary>
|
10 |
+
<description>This module combine (merge) your css and js files. Additionaly this module compress your files by gzip and minify. In addition this module compress your html.</description>
|
11 |
+
<notes>This module was tested in Magento Commerce version 1.4.0.1 and 1.5.0.1, and work in this version smoothly.</notes>
|
12 |
+
<authors><author><name>Pascal System</name><user>auto-converted</user><email>info@pascalsystem.pl</email></author></authors>
|
13 |
+
<date>2011-03-28</date>
|
14 |
+
<time>22:37:05</time>
|
15 |
+
<contents><target name="mage"><dir name="js"><dir name="pascalsystem"><file name="combine.php" hash="ac34bd3b233b17472565872470e5c8f8"/></dir></dir></target><target name="mageetc"><dir name="modules"><file name="PSystem_OptimizationHead.xml" hash="c275af0fe2e0a37029a739101d980241"/></dir></target><target name="magecommunity"><dir name="PSystem"><dir name="OptimizationHead"><dir name="Block"><file name="Head.php" hash="80fbc8fdcc33ab57bcfe9c986658e623"/><dir name="Head"><file name="Abstract.php" hash="1a4757995d9a9bdbbea1ed9b3f16f715"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="4c98ce2468f6321c3faf18740ef703f7"/><file name="config.xml" hash="5d260c92bd8136cd80022e0b0559bad0"/><file name="system.xml" hash="8af6addcbcb3f5796e2b5f26075981a5"/></dir><dir name="lib"><file name="JSMin.php" hash="5716028656e1d402c98a43ee18648dd3"/><file name="PSystemHtmlMinify.php" hash="2d841f14aa166efb568b1aeee3cef522"/><dir name="Minify"><file name="CommentPreserver.php" hash="86bab05265083b57935503bdd735ce74"/><file name="CSS.php" hash="cdeb49c0f35a6cef166c6cfee7f1dd95"/><dir name="CSS"><file name="Compressor.php" hash="b514fdc1f7c010031631994c77a18bf6"/><file name="UriRewriter.php" hash="5ab5dfdb489e28a39a4e9d6ad70117d6"/></dir></dir></dir><dir name="Model"><file name="Observer.php" hash="1f6e674fd06697a48a1f02b153d53a13"/></dir></dir></dir></target></contents>
|
16 |
+
<compatible/>
|
17 |
+
<dependencies><required><package><name>PSystem_Base</name><channel>community</channel><min></min><max></max></package></required></dependencies>
|
18 |
+
</package>
|