mirror of
https://github.com/mrclay/minify.git
synced 2025-01-17 21:28:14 +01:00
Remove JSMin+ and old, unfinished CssCompressor port
JSMin+ was a good effort but is unmaintained and has collected several reports of impractical memory usage for a project like this.
This commit is contained in:
parent
fede83cd48
commit
e2efb342a8
@ -4,6 +4,7 @@
|
||||
* New API incompatible with the 2.x versions
|
||||
* Installation requires use of Composer to install dependencies
|
||||
* Add config option for simply concatenating files
|
||||
* Removed JSMin+ (unmaintained, high memory usage)
|
||||
|
||||
## Version 2.2.1 (2014-10-30)
|
||||
* Builder styled with Bootstrap (thanks to help from acidvertigo)
|
||||
|
@ -75,16 +75,6 @@ function yuiCss($css, $options) {
|
||||
$min_serveOptions['minifiers'][Minify::TYPE_CSS] = 'yuiCss';
|
||||
```
|
||||
|
||||
## JSMin+
|
||||
|
||||
Minify 2.1.3 comes with Tino Zijdel's [JSMin+](http://crisp.tweakblogs.net/blog/1665/a-new-javascript-minifier-jsmin+.html) 1.1. This is a full parser based on a port of [Narcissus](http://en.wikipedia.org/wiki/Narcissus_(JavaScript_engine)). To try it out:
|
||||
```php
|
||||
$min_serveOptions['minifiers'][Minify::TYPE_JS] = array('JSMinPlus', 'minify');
|
||||
```
|
||||
This should yield smaller javascript files, but I've tested this only briefly. For production you may want to get the [latest version](http://crisp.tweakblogs.net/blog/cat/716) (you must rename it: `min/lib/JSMinPlus.php`).
|
||||
|
||||
Note: JSMin+ is memory intensive, so be prepared to up your memory limit. Also it does not preserve comments that begin with `/*!` like JSMin does.
|
||||
|
||||
## Legacy CSS compressor
|
||||
|
||||
In 3.x, Minify uses [CSSmin](https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port), a PHP port of the YUI CSS compressor. To use the compressor that came with Minify 2.x (not recommended), uncomment this line in your `config.php` file:
|
||||
|
@ -35,14 +35,14 @@ To change minifier, set `minifier` to a [callback](http://php.net/manual/en/lang
|
||||
```php
|
||||
$src1 = new Minify_Source(array(
|
||||
'filepath' => '//js/file1.js',
|
||||
'minifier' => ['JSMinPlus', 'minify'],
|
||||
'minifier' => 'myJsMinifier',
|
||||
));
|
||||
$src2 = new Minify_Source(array(
|
||||
'filepath' => '//js/file2.js',
|
||||
'minifier' => '', // don't compress
|
||||
));
|
||||
```
|
||||
In the above, `JSMinPlus.php` is only loaded when the contents of `$src1` is needed.
|
||||
In the above, `JmyJsMinifier()` is only called when the contents of `$src1` is needed.
|
||||
|
||||
**`*`Do _not_ use `create_function()` or anonymous functions for the minifier.** The internal names of these function tend to vary, causing endless cache misses, killing performance and filling cache storage up.
|
||||
|
||||
|
2086
lib/JSMinPlus.php
2086
lib/JSMinPlus.php
File diff suppressed because it is too large
Load Diff
@ -1,382 +0,0 @@
|
||||
/*
|
||||
* YUI Compressor
|
||||
* http://developer.yahoo.com/yui/compressor/
|
||||
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
||||
* Author: Isaac Schlueter - http://foohack.com/
|
||||
* Author: Stoyan Stefanov - http://phpied.com/
|
||||
* Copyright (c) 2011 Yahoo! Inc. All rights reserved.
|
||||
* The copyrights embodied in the content of this file are licensed
|
||||
* by Yahoo! Inc. under the BSD (revised) open source license.
|
||||
*/
|
||||
package com.yahoo.platform.yui.compressor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CssCompressor {
|
||||
|
||||
private StringBuffer srcsb = new StringBuffer();
|
||||
|
||||
public CssCompressor(Reader in) throws IOException {
|
||||
// Read the stream...
|
||||
int c;
|
||||
while ((c = in.read()) != -1) {
|
||||
srcsb.append((char) c);
|
||||
}
|
||||
}
|
||||
|
||||
// Leave data urls alone to increase parse performance.
|
||||
protected String extractDataUrls(String css, ArrayList preservedTokens) {
|
||||
|
||||
int maxIndex = css.length() - 1;
|
||||
int appendIndex = 0;
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
Pattern p = Pattern.compile("url\\(\\s*([\"']?)data\\:");
|
||||
Matcher m = p.matcher(css);
|
||||
|
||||
/*
|
||||
* Since we need to account for non-base64 data urls, we need to handle
|
||||
* ' and ) being part of the data string. Hence switching to indexOf,
|
||||
* to determine whether or not we have matching string terminators and
|
||||
* handling sb appends directly, instead of using matcher.append* methods.
|
||||
*/
|
||||
|
||||
while (m.find()) {
|
||||
|
||||
int startIndex = m.start() + 4; // "url(".length()
|
||||
String terminator = m.group(1); // ', " or empty (not quoted)
|
||||
|
||||
if (terminator.length() == 0) {
|
||||
terminator = ")";
|
||||
}
|
||||
|
||||
boolean foundTerminator = false;
|
||||
|
||||
int endIndex = m.end() - 1;
|
||||
while(foundTerminator == false && endIndex+1 <= maxIndex) {
|
||||
endIndex = css.indexOf(terminator, endIndex+1);
|
||||
|
||||
if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) {
|
||||
foundTerminator = true;
|
||||
if (!")".equals(terminator)) {
|
||||
endIndex = css.indexOf(")", endIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enough searching, start moving stuff over to the buffer
|
||||
sb.append(css.substring(appendIndex, m.start()));
|
||||
|
||||
if (foundTerminator) {
|
||||
String token = css.substring(startIndex, endIndex);
|
||||
token = token.replaceAll("\\s+", "");
|
||||
preservedTokens.add(token);
|
||||
|
||||
String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)";
|
||||
sb.append(preserver);
|
||||
|
||||
appendIndex = endIndex + 1;
|
||||
} else {
|
||||
// No end terminator found, re-add the whole match. Should we throw/warn here?
|
||||
sb.append(css.substring(m.start(), m.end()));
|
||||
appendIndex = m.end();
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(css.substring(appendIndex));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void compress(Writer out, int linebreakpos)
|
||||
throws IOException {
|
||||
|
||||
Pattern p;
|
||||
Matcher m;
|
||||
String css = srcsb.toString();
|
||||
|
||||
int startIndex = 0;
|
||||
int endIndex = 0;
|
||||
int i = 0;
|
||||
int max = 0;
|
||||
ArrayList preservedTokens = new ArrayList(0);
|
||||
ArrayList comments = new ArrayList(0);
|
||||
String token;
|
||||
int totallen = css.length();
|
||||
String placeholder;
|
||||
|
||||
css = this.extractDataUrls(css, preservedTokens);
|
||||
|
||||
StringBuffer sb = new StringBuffer(css);
|
||||
|
||||
// collect all comment blocks...
|
||||
while ((startIndex = sb.indexOf("/*", startIndex)) >= 0) {
|
||||
endIndex = sb.indexOf("*/", startIndex + 2);
|
||||
if (endIndex < 0) {
|
||||
endIndex = totallen;
|
||||
}
|
||||
|
||||
token = sb.substring(startIndex + 2, endIndex);
|
||||
comments.add(token);
|
||||
sb.replace(startIndex + 2, endIndex, "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.size() - 1) + "___");
|
||||
startIndex += 2;
|
||||
}
|
||||
css = sb.toString();
|
||||
|
||||
// preserve strings so their content doesn't get accidentally minified
|
||||
sb = new StringBuffer();
|
||||
p = Pattern.compile("(\"([^\\\\\"]|\\\\.|\\\\)*\")|(\'([^\\\\\']|\\\\.|\\\\)*\')");
|
||||
m = p.matcher(css);
|
||||
while (m.find()) {
|
||||
token = m.group();
|
||||
char quote = token.charAt(0);
|
||||
token = token.substring(1, token.length() - 1);
|
||||
|
||||
// maybe the string contains a comment-like substring?
|
||||
// one, maybe more? put'em back then
|
||||
if (token.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) {
|
||||
for (i = 0, max = comments.size(); i < max; i += 1) {
|
||||
token = token.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments.get(i).toString());
|
||||
}
|
||||
}
|
||||
|
||||
// minify alpha opacity in filter strings
|
||||
token = token.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity=");
|
||||
|
||||
preservedTokens.add(token);
|
||||
String preserver = quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___" + quote;
|
||||
m.appendReplacement(sb, preserver);
|
||||
}
|
||||
m.appendTail(sb);
|
||||
css = sb.toString();
|
||||
|
||||
|
||||
// strings are safe, now wrestle the comments
|
||||
for (i = 0, max = comments.size(); i < max; i += 1) {
|
||||
|
||||
token = comments.get(i).toString();
|
||||
placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___";
|
||||
|
||||
// ! in the first position of the comment means preserve
|
||||
// so push to the preserved tokens while stripping the !
|
||||
if (token.startsWith("!")) {
|
||||
preservedTokens.add(token);
|
||||
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___");
|
||||
continue;
|
||||
}
|
||||
|
||||
// \ in the last position looks like hack for Mac/IE5
|
||||
// shorten that to /*\*/ and the next one to /**/
|
||||
if (token.endsWith("\\")) {
|
||||
preservedTokens.add("\\");
|
||||
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___");
|
||||
i = i + 1; // attn: advancing the loop
|
||||
preservedTokens.add("");
|
||||
css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___");
|
||||
continue;
|
||||
}
|
||||
|
||||
// keep empty comments after child selectors (IE7 hack)
|
||||
// e.g. html >/**/ body
|
||||
if (token.length() == 0) {
|
||||
startIndex = css.indexOf(placeholder);
|
||||
if (startIndex > 2) {
|
||||
if (css.charAt(startIndex - 3) == '>') {
|
||||
preservedTokens.add("");
|
||||
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in all other cases kill the comment
|
||||
css = css.replace("/*" + placeholder + "*/", "");
|
||||
}
|
||||
|
||||
|
||||
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
||||
css = css.replaceAll("\\s+", " ");
|
||||
|
||||
// Remove the spaces before the things that should not have spaces before them.
|
||||
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
||||
// Swap out any pseudo-class colons with the token, and then swap back.
|
||||
sb = new StringBuffer();
|
||||
p = Pattern.compile("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)");
|
||||
m = p.matcher(css);
|
||||
while (m.find()) {
|
||||
String s = m.group();
|
||||
s = s.replaceAll(":", "___YUICSSMIN_PSEUDOCLASSCOLON___");
|
||||
s = s.replaceAll( "\\\\", "\\\\\\\\" ).replaceAll( "\\$", "\\\\\\$" );
|
||||
m.appendReplacement(sb, s);
|
||||
}
|
||||
m.appendTail(sb);
|
||||
css = sb.toString();
|
||||
// Remove spaces before the things that should not have spaces before them.
|
||||
css = css.replaceAll("\\s+([!{};:>+\\(\\)\\],])", "$1");
|
||||
// bring back the colon
|
||||
css = css.replaceAll("___YUICSSMIN_PSEUDOCLASSCOLON___", ":");
|
||||
|
||||
// retain space for special IE6 cases
|
||||
css = css.replaceAll(":first\\-(line|letter)(\\{|,)", ":first-$1 $2");
|
||||
|
||||
// no space after the end of a preserved comment
|
||||
css = css.replaceAll("\\*/ ", "*/");
|
||||
|
||||
// If there is a @charset, then only allow one, and push to the top of the file.
|
||||
css = css.replaceAll("^(.*)(@charset \"[^\"]*\";)", "$2$1");
|
||||
css = css.replaceAll("^(\\s*@charset [^;]+;\\s*)+", "$1");
|
||||
|
||||
// Put the space back in some cases, to support stuff like
|
||||
// @media screen and (-webkit-min-device-pixel-ratio:0){
|
||||
css = css.replaceAll("\\band\\(", "and (");
|
||||
|
||||
// Remove the spaces after the things that should not have spaces after them.
|
||||
css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1");
|
||||
|
||||
// remove unnecessary semicolons
|
||||
css = css.replaceAll(";+}", "}");
|
||||
|
||||
// Replace 0(px,em,%) with 0.
|
||||
css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2");
|
||||
|
||||
// Replace 0 0 0 0; with 0.
|
||||
css = css.replaceAll(":0 0 0 0(;|})", ":0$1");
|
||||
css = css.replaceAll(":0 0 0(;|})", ":0$1");
|
||||
css = css.replaceAll(":0 0(;|})", ":0$1");
|
||||
|
||||
|
||||
// Replace background-position:0; with background-position:0 0;
|
||||
// same for transform-origin
|
||||
sb = new StringBuffer();
|
||||
p = Pattern.compile("(?i)(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|})");
|
||||
m = p.matcher(css);
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, m.group(1).toLowerCase() + ":0 0" + m.group(2));
|
||||
}
|
||||
m.appendTail(sb);
|
||||
css = sb.toString();
|
||||
|
||||
// Replace 0.6 to .6, but only when preceded by : or a white-space
|
||||
css = css.replaceAll("(:|\\s)0+\\.(\\d+)", "$1.$2");
|
||||
|
||||
// Shorten colors from rgb(51,102,153) to #336699
|
||||
// This makes it more likely that it'll get further compressed in the next step.
|
||||
p = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)");
|
||||
m = p.matcher(css);
|
||||
sb = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String[] rgbcolors = m.group(1).split(",");
|
||||
StringBuffer hexcolor = new StringBuffer("#");
|
||||
for (i = 0; i < rgbcolors.length; i++) {
|
||||
int val = Integer.parseInt(rgbcolors[i]);
|
||||
if (val < 16) {
|
||||
hexcolor.append("0");
|
||||
}
|
||||
hexcolor.append(Integer.toHexString(val));
|
||||
}
|
||||
m.appendReplacement(sb, hexcolor.toString());
|
||||
}
|
||||
m.appendTail(sb);
|
||||
css = sb.toString();
|
||||
|
||||
// Shorten colors from #AABBCC to #ABC. Note that we want to make sure
|
||||
// the color is not preceded by either ", " or =. Indeed, the property
|
||||
// filter: chroma(color="#FFFFFF");
|
||||
// would become
|
||||
// filter: chroma(color="#FFF");
|
||||
// which makes the filter break in IE.
|
||||
// We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} )
|
||||
// We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD)
|
||||
p = Pattern.compile("(\\=\\s*?[\"']?)?" + "#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])" + "(:?\\}|[^0-9a-fA-F{][^{]*?\\})");
|
||||
|
||||
m = p.matcher(css);
|
||||
sb = new StringBuffer();
|
||||
int index = 0;
|
||||
|
||||
while (m.find(index)) {
|
||||
|
||||
sb.append(css.substring(index, m.start()));
|
||||
|
||||
boolean isFilter = (m.group(1) != null && !"".equals(m.group(1)));
|
||||
|
||||
if (isFilter) {
|
||||
// Restore, as is. Compression will break filters
|
||||
sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7));
|
||||
} else {
|
||||
if( m.group(2).equalsIgnoreCase(m.group(3)) &&
|
||||
m.group(4).equalsIgnoreCase(m.group(5)) &&
|
||||
m.group(6).equalsIgnoreCase(m.group(7))) {
|
||||
|
||||
// #AABBCC pattern
|
||||
sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase());
|
||||
|
||||
} else {
|
||||
|
||||
// Non-compressible color, restore, but lower case.
|
||||
sb.append("#" + (m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)).toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
index = m.end(7);
|
||||
}
|
||||
|
||||
sb.append(css.substring(index));
|
||||
css = sb.toString();
|
||||
|
||||
// border: none -> border:0
|
||||
sb = new StringBuffer();
|
||||
p = Pattern.compile("(?i)(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|})");
|
||||
m = p.matcher(css);
|
||||
while (m.find()) {
|
||||
m.appendReplacement(sb, m.group(1).toLowerCase() + ":0" + m.group(2));
|
||||
}
|
||||
m.appendTail(sb);
|
||||
css = sb.toString();
|
||||
|
||||
// shorter opacity IE filter
|
||||
css = css.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity=");
|
||||
|
||||
// Remove empty rules.
|
||||
css = css.replaceAll("[^\\}\\{/;]+\\{\\}", "");
|
||||
|
||||
// TODO: Should this be after we re-insert tokens. These could alter the break points. However then
|
||||
// we'd need to make sure we don't break in the middle of a string etc.
|
||||
if (linebreakpos >= 0) {
|
||||
// Some source control tools don't like it when files containing lines longer
|
||||
// than, say 8000 characters, are checked in. The linebreak option is used in
|
||||
// that case to split long lines after a specific column.
|
||||
i = 0;
|
||||
int linestartpos = 0;
|
||||
sb = new StringBuffer(css);
|
||||
while (i < sb.length()) {
|
||||
char c = sb.charAt(i++);
|
||||
if (c == '}' && i - linestartpos > linebreakpos) {
|
||||
sb.insert(i, '\n');
|
||||
linestartpos = i;
|
||||
}
|
||||
}
|
||||
|
||||
css = sb.toString();
|
||||
}
|
||||
|
||||
// Replace multiple semi-colons in a row by a single one
|
||||
// See SF bug #1980989
|
||||
css = css.replaceAll(";;+", ";");
|
||||
|
||||
// restore preserved comments and strings
|
||||
for(i = 0, max = preservedTokens.size(); i < max; i++) {
|
||||
css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i).toString());
|
||||
}
|
||||
|
||||
// Trim the final string (for any leading or trailing white spaces)
|
||||
css = css.trim();
|
||||
|
||||
// Write the output...
|
||||
out.write(css);
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Minify_YUI_CssCompressor
|
||||
* @package Minify
|
||||
*
|
||||
* YUI Compressor
|
||||
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
||||
* Author: Isaac Schlueter - http://foohack.com/
|
||||
* Author: Stoyan Stefanov - http://phpied.com/
|
||||
* Author: Steve Clay - http://www.mrclay.org/ (PHP port)
|
||||
* Copyright (c) 2009 Yahoo! Inc. All rights reserved.
|
||||
* The copyrights embodied in the content of this file are licensed
|
||||
* by Yahoo! Inc. under the BSD (revised) open source license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compress CSS (incomplete DO NOT USE)
|
||||
*
|
||||
* @see https://github.com/yui/yuicompressor/blob/master/src/com/yahoo/platform/yui/compressor/CssCompressor.java
|
||||
*
|
||||
* @package Minify
|
||||
*/
|
||||
class Minify_YUI_CssCompressor {
|
||||
|
||||
/**
|
||||
* Minify a CSS string
|
||||
*
|
||||
* @param string $css
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function compress($css, $linebreakpos = 0)
|
||||
{
|
||||
$css = str_replace("\r\n", "\n", $css);
|
||||
|
||||
/**
|
||||
* @todo comment removal
|
||||
* @todo re-port from newer Java version
|
||||
*/
|
||||
|
||||
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
||||
$css = preg_replace('@\s+@', ' ', $css);
|
||||
|
||||
// Make a pseudo class for the Box Model Hack
|
||||
$css = preg_replace("@\"\\\\\"}\\\\\"\"@", "___PSEUDOCLASSBMH___", $css);
|
||||
|
||||
// Remove the spaces before the things that should not have spaces before them.
|
||||
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
||||
// Swap out any pseudo-class colons with the token, and then swap back.
|
||||
$css = preg_replace_callback("@(^|\\})(([^\\{:])+:)+([^\\{]*\\{)@", array($this, '_removeSpacesCB'), $css);
|
||||
|
||||
$css = preg_replace("@\\s+([!{};:>+\\(\\)\\],])@", "$1", $css);
|
||||
$css = str_replace("___PSEUDOCLASSCOLON___", ":", $css);
|
||||
|
||||
// Remove the spaces after the things that should not have spaces after them.
|
||||
$css = preg_replace("@([!{}:;>+\\(\\[,])\\s+@", "$1", $css);
|
||||
|
||||
// Add the semicolon where it's missing.
|
||||
$css = preg_replace("@([^;\\}])}@", "$1;}", $css);
|
||||
|
||||
// Replace 0(px,em,%) with 0.
|
||||
$css = preg_replace("@([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)@", "$1$2", $css);
|
||||
|
||||
// Replace 0 0 0 0; with 0.
|
||||
$css = str_replace(":0 0 0 0;", ":0;", $css);
|
||||
$css = str_replace(":0 0 0;", ":0;", $css);
|
||||
$css = str_replace(":0 0;", ":0;", $css);
|
||||
|
||||
// Replace background-position:0; with background-position:0 0;
|
||||
$css = str_replace("background-position:0;", "background-position:0 0;", $css);
|
||||
|
||||
// Replace 0.6 to .6, but only when preceded by : or a white-space
|
||||
$css = preg_replace("@(:|\\s)0+\\.(\\d+)@", "$1.$2", $css);
|
||||
|
||||
// Shorten colors from rgb(51,102,153) to #336699
|
||||
// This makes it more likely that it'll get further compressed in the next step.
|
||||
$css = preg_replace_callback("@rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)@", array($this, '_shortenRgbCB'), $css);
|
||||
|
||||
// Shorten colors from #AABBCC to #ABC. Note that we want to make sure
|
||||
// the color is not preceded by either ", " or =. Indeed, the property
|
||||
// filter: chroma(color="#FFFFFF");
|
||||
// would become
|
||||
// filter: chroma(color="#FFF");
|
||||
// which makes the filter break in IE.
|
||||
$css = preg_replace_callback("@([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])@", array($this, '_shortenHexCB'), $css);
|
||||
|
||||
// Remove empty rules.
|
||||
$css = preg_replace("@[^\\}]+\\{;\\}@", "", $css);
|
||||
|
||||
$linebreakpos = isset($this->_options['linebreakpos'])
|
||||
? $this->_options['linebreakpos']
|
||||
: 0;
|
||||
|
||||
if ($linebreakpos > 0) {
|
||||
// Some source control tools don't like it when files containing lines longer
|
||||
// than, say 8000 characters, are checked in. The linebreak option is used in
|
||||
// that case to split long lines after a specific column.
|
||||
$i = 0;
|
||||
$linestartpos = 0;
|
||||
$sb = $css;
|
||||
|
||||
// make sure strlen returns byte count
|
||||
$mbIntEnc = null;
|
||||
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
||||
$mbIntEnc = mb_internal_encoding();
|
||||
mb_internal_encoding('8bit');
|
||||
}
|
||||
$sbLength = strlen($css);
|
||||
while ($i < $sbLength) {
|
||||
$c = $sb[$i++];
|
||||
if ($c === '}' && $i - $linestartpos > $linebreakpos) {
|
||||
$sb = substr_replace($sb, "\n", $i, 0);
|
||||
$sbLength++;
|
||||
$linestartpos = $i;
|
||||
}
|
||||
}
|
||||
$css = $sb;
|
||||
|
||||
// undo potential mb_encoding change
|
||||
if ($mbIntEnc !== null) {
|
||||
mb_internal_encoding($mbIntEnc);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the pseudo class for the Box Model Hack
|
||||
$css = str_replace("___PSEUDOCLASSBMH___", "\"\\\\\"}\\\\\"\"", $css);
|
||||
|
||||
// Replace multiple semi-colons in a row by a single one
|
||||
// See SF bug #1980989
|
||||
$css = preg_replace("@;;+@", ";", $css);
|
||||
|
||||
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
||||
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
||||
|
||||
// Trim the final string (for any leading or trailing white spaces)
|
||||
$css = trim($css);
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
protected function _removeSpacesCB($m)
|
||||
{
|
||||
return str_replace(':', '___PSEUDOCLASSCOLON___', $m[0]);
|
||||
}
|
||||
|
||||
protected function _shortenRgbCB($m)
|
||||
{
|
||||
$rgbcolors = explode(',', $m[1]);
|
||||
$hexcolor = '#';
|
||||
for ($i = 0; $i < count($rgbcolors); $i++) {
|
||||
$val = round($rgbcolors[$i]);
|
||||
if ($val < 16) {
|
||||
$hexcolor .= '0';
|
||||
}
|
||||
$hexcolor .= dechex($val);
|
||||
}
|
||||
return $hexcolor;
|
||||
}
|
||||
|
||||
protected function _shortenHexCB($m)
|
||||
{
|
||||
// Test for AABBCC pattern
|
||||
if ((strtolower($m[3])===strtolower($m[4])) &&
|
||||
(strtolower($m[5])===strtolower($m[6])) &&
|
||||
(strtolower($m[7])===strtolower($m[8]))) {
|
||||
return $m[1] . $m[2] . "#" . $m[3] . $m[5] . $m[7];
|
||||
} else {
|
||||
return $m[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@ if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') {
|
||||
}
|
||||
|
||||
$tpl = array();
|
||||
$tpl['classes'] = array('Minify_HTML', 'JSMin\\JSMin', 'Minify_CSS', 'Minify_CSS', 'JSMinPlus');
|
||||
$tpl['classes'] = array('Minify_HTML', 'JSMin\\JSMin', 'Minify_CSS', 'Minify_CSS');
|
||||
|
||||
if (isset($_POST['method']) && in_array($_POST['method'], $tpl['classes'])) {
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
require_once '_inc.php';
|
||||
|
||||
function test_JSMinPlus()
|
||||
{
|
||||
global $thisDir;
|
||||
|
||||
$src = file_get_contents($thisDir . '/_test_files/js/condcomm.js');
|
||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/condcomm.min_plus.js');
|
||||
|
||||
$minOutput = JSMinPlus::minify($src);
|
||||
|
||||
$passed = assertTrue($minExpected == $minOutput, 'JSMinPlus : Conditional Comments');
|
||||
|
||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||
echo "\n---Output: " .countBytes($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||
echo "---Expected: " .countBytes($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||
echo "---Source: " .countBytes($src). " bytes\n\n{$src}\n\n\n";
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
|
||||
$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/before.min_plus.js');
|
||||
$minOutput = JSMinPlus::minify($src);
|
||||
|
||||
$passed = assertTrue($minExpected == $minOutput, 'JSMinPlus : Overall');
|
||||
|
||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||
echo "\n---Output: " .countBytes($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||
echo "---Expected: " .countBytes($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||
echo "---Source: " .countBytes($src). " bytes\n\n{$src}\n\n\n";
|
||||
}
|
||||
|
||||
$src = file_get_contents($thisDir . '/_test_files/js/issue74.js');
|
||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/issue74.min_plus.js');
|
||||
$minOutput = JSMinPlus::minify($src);
|
||||
|
||||
$passed = assertTrue($minExpected == $minOutput, 'JSMinPlus : Quotes in RegExp literals (Issue 74)');
|
||||
|
||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||
echo "\n---Output: " .countBytes($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||
echo "---Expected: " .countBytes($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||
echo "---Source: " .countBytes($src). " bytes\n\n{$src}\n\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
test_JSMinPlus();
|
Loading…
x
Reference in New Issue
Block a user