mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-25 07:50:23 +01:00
Updated minify, jQuery, MixItUp and Tooltipster
This commit is contained in:
parent
4c31dec50e
commit
a2cd7de2dc
@ -7,14 +7,14 @@
|
|||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* This is a modified port of jsmin.c. Improvements:
|
* This is a modified port of jsmin.c. Improvements:
|
||||||
*
|
*
|
||||||
* Does not choke on some regexp literals containing quote characters. E.g. /'/
|
* Does not choke on some regexp literals containing quote characters. E.g. /'/
|
||||||
*
|
*
|
||||||
* Spaces are preserved after some add/sub operators, so they are not mistakenly
|
* Spaces are preserved after some add/sub operators, so they are not mistakenly
|
||||||
* converted to post-inc/dec. E.g. a + ++b -> a+ ++b
|
* converted to post-inc/dec. E.g. a + ++b -> a+ ++b
|
||||||
*
|
*
|
||||||
* Preserves multi-line comments that begin with /*!
|
* Preserves multi-line comments that begin with /*!
|
||||||
*
|
*
|
||||||
* PHP 5 or higher is required.
|
* PHP 5 or higher is required.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted to use this version of the library under the
|
* Permission is hereby granted to use this version of the library under the
|
||||||
@ -69,6 +69,7 @@ class JSMin {
|
|||||||
protected $lookAhead = null;
|
protected $lookAhead = null;
|
||||||
protected $output = '';
|
protected $output = '';
|
||||||
protected $lastByteOut = '';
|
protected $lastByteOut = '';
|
||||||
|
protected $keptComment = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify Javascript.
|
* Minify Javascript.
|
||||||
@ -116,8 +117,8 @@ class JSMin {
|
|||||||
// determine next command
|
// determine next command
|
||||||
$command = self::ACTION_KEEP_A; // default
|
$command = self::ACTION_KEEP_A; // default
|
||||||
if ($this->a === ' ') {
|
if ($this->a === ' ') {
|
||||||
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
|
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
|
||||||
&& ($this->b === $this->lastByteOut)) {
|
&& ($this->b === $this->lastByteOut)) {
|
||||||
// Don't delete this space. If we do, the addition/subtraction
|
// Don't delete this space. If we do, the addition/subtraction
|
||||||
// could be parsed as a post-increment
|
// could be parsed as a post-increment
|
||||||
} elseif (! $this->isAlphaNum($this->b)) {
|
} elseif (! $this->isAlphaNum($this->b)) {
|
||||||
@ -126,16 +127,17 @@ class JSMin {
|
|||||||
} elseif ($this->a === "\n") {
|
} elseif ($this->a === "\n") {
|
||||||
if ($this->b === ' ') {
|
if ($this->b === ' ') {
|
||||||
$command = self::ACTION_DELETE_A_B;
|
$command = self::ACTION_DELETE_A_B;
|
||||||
// in case of mbstring.func_overload & 2, must check for null b,
|
|
||||||
// otherwise mb_strpos will give WARNING
|
// in case of mbstring.func_overload & 2, must check for null b,
|
||||||
|
// otherwise mb_strpos will give WARNING
|
||||||
} elseif ($this->b === null
|
} elseif ($this->b === null
|
||||||
|| (false === strpos('{[(+-', $this->b)
|
|| (false === strpos('{[(+-!~', $this->b)
|
||||||
&& ! $this->isAlphaNum($this->b))) {
|
&& ! $this->isAlphaNum($this->b))) {
|
||||||
$command = self::ACTION_DELETE_A;
|
$command = self::ACTION_DELETE_A;
|
||||||
}
|
}
|
||||||
} elseif (! $this->isAlphaNum($this->a)) {
|
} elseif (! $this->isAlphaNum($this->a)) {
|
||||||
if ($this->b === ' '
|
if ($this->b === ' '
|
||||||
|| ($this->b === "\n"
|
|| ($this->b === "\n"
|
||||||
&& (false === strpos('}])+-"\'', $this->a)))) {
|
&& (false === strpos('}])+-"\'', $this->a)))) {
|
||||||
$command = self::ACTION_DELETE_A_B;
|
$command = self::ACTION_DELETE_A_B;
|
||||||
}
|
}
|
||||||
@ -160,7 +162,8 @@ class JSMin {
|
|||||||
*/
|
*/
|
||||||
protected function action($command)
|
protected function action($command)
|
||||||
{
|
{
|
||||||
if ($command === self::ACTION_DELETE_A_B
|
// make sure we don't compress "a + ++b" to "a+++b", etc.
|
||||||
|
if ($command === self::ACTION_DELETE_A_B
|
||||||
&& $this->b === ' '
|
&& $this->b === ' '
|
||||||
&& ($this->a === '+' || $this->a === '-')) {
|
&& ($this->a === '+' || $this->a === '-')) {
|
||||||
// Note: we're at an addition/substraction operator; the inputIndex
|
// Note: we're at an addition/substraction operator; the inputIndex
|
||||||
@ -170,58 +173,88 @@ class JSMin {
|
|||||||
$command = self::ACTION_KEEP_A;
|
$command = self::ACTION_KEEP_A;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($command) {
|
switch ($command) {
|
||||||
case self::ACTION_KEEP_A:
|
case self::ACTION_KEEP_A: // 1
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
|
|
||||||
|
if ($this->keptComment) {
|
||||||
|
$this->output = rtrim($this->output, "\n");
|
||||||
|
$this->output .= $this->keptComment;
|
||||||
|
$this->keptComment = '';
|
||||||
|
}
|
||||||
|
|
||||||
$this->lastByteOut = $this->a;
|
$this->lastByteOut = $this->a;
|
||||||
|
|
||||||
// fallthrough
|
// fallthrough intentional
|
||||||
case self::ACTION_DELETE_A:
|
case self::ACTION_DELETE_A: // 2
|
||||||
$this->a = $this->b;
|
$this->a = $this->b;
|
||||||
if ($this->a === "'" || $this->a === '"') { // string literal
|
if ($this->a === "'" || $this->a === '"') { // string literal
|
||||||
$str = $this->a; // in case needed for exception
|
$str = $this->a; // in case needed for exception
|
||||||
while (true) {
|
for(;;) {
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
$this->lastByteOut = $this->a;
|
$this->lastByteOut = $this->a;
|
||||||
|
|
||||||
$this->a = $this->get();
|
$this->a = $this->get();
|
||||||
if ($this->a === $this->b) { // end quote
|
if ($this->a === $this->b) { // end quote
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ord($this->a) <= self::ORD_LF) {
|
if ($this->isEOF($this->a)) {
|
||||||
|
$byte = $this->inputIndex - 1;
|
||||||
throw new JSMin_UnterminatedStringException(
|
throw new JSMin_UnterminatedStringException(
|
||||||
"JSMin: Unterminated String at byte "
|
"JSMin: Unterminated String at byte {$byte}: {$str}");
|
||||||
. $this->inputIndex . ": {$str}");
|
|
||||||
}
|
}
|
||||||
$str .= $this->a;
|
$str .= $this->a;
|
||||||
if ($this->a === '\\') {
|
if ($this->a === '\\') {
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
$this->lastByteOut = $this->a;
|
$this->lastByteOut = $this->a;
|
||||||
|
|
||||||
$this->a = $this->get();
|
$this->a = $this->get();
|
||||||
$str .= $this->a;
|
$str .= $this->a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fallthrough
|
|
||||||
case self::ACTION_DELETE_A_B:
|
// fallthrough intentional
|
||||||
|
case self::ACTION_DELETE_A_B: // 3
|
||||||
$this->b = $this->next();
|
$this->b = $this->next();
|
||||||
if ($this->b === '/' && $this->isRegexpLiteral()) { // RegExp literal
|
if ($this->b === '/' && $this->isRegexpLiteral()) {
|
||||||
$this->output .= $this->a . $this->b;
|
$this->output .= $this->a . $this->b;
|
||||||
$pattern = '/'; // in case needed for exception
|
$pattern = '/'; // keep entire pattern in case we need to report it in the exception
|
||||||
while (true) {
|
for(;;) {
|
||||||
$this->a = $this->get();
|
$this->a = $this->get();
|
||||||
$pattern .= $this->a;
|
$pattern .= $this->a;
|
||||||
|
if ($this->a === '[') {
|
||||||
|
for(;;) {
|
||||||
|
$this->output .= $this->a;
|
||||||
|
$this->a = $this->get();
|
||||||
|
$pattern .= $this->a;
|
||||||
|
if ($this->a === ']') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($this->a === '\\') {
|
||||||
|
$this->output .= $this->a;
|
||||||
|
$this->a = $this->get();
|
||||||
|
$pattern .= $this->a;
|
||||||
|
}
|
||||||
|
if ($this->isEOF($this->a)) {
|
||||||
|
throw new JSMin_UnterminatedRegExpException(
|
||||||
|
"JSMin: Unterminated set in RegExp at byte "
|
||||||
|
. $this->inputIndex .": {$pattern}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->a === '/') { // end pattern
|
if ($this->a === '/') { // end pattern
|
||||||
break; // while (true)
|
break; // while (true)
|
||||||
} elseif ($this->a === '\\') {
|
} elseif ($this->a === '\\') {
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
$this->a = $this->get();
|
$this->a = $this->get();
|
||||||
$pattern .= $this->a;
|
$pattern .= $this->a;
|
||||||
} elseif (ord($this->a) <= self::ORD_LF) {
|
} elseif ($this->isEOF($this->a)) {
|
||||||
|
$byte = $this->inputIndex - 1;
|
||||||
throw new JSMin_UnterminatedRegExpException(
|
throw new JSMin_UnterminatedRegExpException(
|
||||||
"JSMin: Unterminated RegExp at byte "
|
"JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
|
||||||
. $this->inputIndex .": {$pattern}");
|
|
||||||
}
|
}
|
||||||
$this->output .= $this->a;
|
$this->output .= $this->a;
|
||||||
$this->lastByteOut = $this->a;
|
$this->lastByteOut = $this->a;
|
||||||
@ -237,31 +270,43 @@ class JSMin {
|
|||||||
*/
|
*/
|
||||||
protected function isRegexpLiteral()
|
protected function isRegexpLiteral()
|
||||||
{
|
{
|
||||||
if (false !== strpos("\n{;(,=:[!&|?", $this->a)) { // we aren't dividing
|
if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
|
||||||
|
// we obviously aren't dividing
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (' ' === $this->a) {
|
|
||||||
$length = strlen($this->output);
|
// we have to check for a preceding keyword, and we don't need to pattern
|
||||||
if ($length < 2) { // weird edge case
|
// match over the whole output.
|
||||||
return true;
|
$recentOutput = substr($this->output, -10);
|
||||||
|
|
||||||
|
// check if return/typeof directly precede a pattern without a space
|
||||||
|
foreach (array('return', 'typeof') as $keyword) {
|
||||||
|
if ($this->a !== substr($keyword, -1)) {
|
||||||
|
// certainly wasn't keyword
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
// you can't divide a keyword
|
if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) {
|
||||||
if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
|
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
||||||
if ($this->output === $m[0]) { // odd but could happen
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// make sure it's a keyword, not end of an identifier
|
|
||||||
$charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1);
|
|
||||||
if (! $this->isAlphaNum($charBeforeKeyword)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check all keywords
|
||||||
|
if ($this->a === ' ' || $this->a === "\n") {
|
||||||
|
if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) {
|
||||||
|
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get next char. Convert ctrl char to space.
|
* Return the next character from stdin. Watch out for lookahead. If the character is a control character,
|
||||||
|
* translate it to a space or linefeed.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -270,24 +315,36 @@ class JSMin {
|
|||||||
$c = $this->lookAhead;
|
$c = $this->lookAhead;
|
||||||
$this->lookAhead = null;
|
$this->lookAhead = null;
|
||||||
if ($c === null) {
|
if ($c === null) {
|
||||||
|
// getc(stdin)
|
||||||
if ($this->inputIndex < $this->inputLength) {
|
if ($this->inputIndex < $this->inputLength) {
|
||||||
$c = $this->input[$this->inputIndex];
|
$c = $this->input[$this->inputIndex];
|
||||||
$this->inputIndex += 1;
|
$this->inputIndex += 1;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
$c = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($c === "\r" || $c === "\n") {
|
if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
if ($c === "\r") {
|
||||||
return "\n";
|
return "\n";
|
||||||
}
|
}
|
||||||
if (ord($c) < self::ORD_SPACE) { // control char
|
return ' ';
|
||||||
return ' ';
|
|
||||||
}
|
|
||||||
return $c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get next char. If is ctrl character, translate to a space or newline.
|
* Does $a indicate end of input?
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isEOF($a)
|
||||||
|
{
|
||||||
|
return ord($a) <= self::ORD_LF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next char (without getting it). If is ctrl character, translate to a space or newline.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -298,7 +355,7 @@ class JSMin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is $c a letter, digit, underscore, dollar sign, escape, or non-ASCII?
|
* Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
|
||||||
*
|
*
|
||||||
* @param string $c
|
* @param string $c
|
||||||
*
|
*
|
||||||
@ -306,77 +363,84 @@ class JSMin {
|
|||||||
*/
|
*/
|
||||||
protected function isAlphaNum($c)
|
protected function isAlphaNum($c)
|
||||||
{
|
{
|
||||||
return (preg_match('/^[0-9a-zA-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* Consume a single line comment from input (possibly retaining it)
|
||||||
*/
|
*/
|
||||||
protected function singleLineComment()
|
protected function consumeSingleLineComment()
|
||||||
{
|
{
|
||||||
$comment = '';
|
$comment = '';
|
||||||
while (true) {
|
while (true) {
|
||||||
$get = $this->get();
|
$get = $this->get();
|
||||||
$comment .= $get;
|
$comment .= $get;
|
||||||
if (ord($get) <= self::ORD_LF) { // EOL reached
|
if (ord($get) <= self::ORD_LF) { // end of line reached
|
||||||
// if IE conditional comment
|
// if IE conditional comment
|
||||||
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
||||||
return "/{$comment}";
|
$this->keptComment .= "/{$comment}";
|
||||||
}
|
}
|
||||||
return $get;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* Consume a multiple line comment from input (possibly retaining it)
|
||||||
|
*
|
||||||
* @throws JSMin_UnterminatedCommentException
|
* @throws JSMin_UnterminatedCommentException
|
||||||
*/
|
*/
|
||||||
protected function multipleLineComment()
|
protected function consumeMultipleLineComment()
|
||||||
{
|
{
|
||||||
$this->get();
|
$this->get();
|
||||||
$comment = '';
|
$comment = '';
|
||||||
while (true) {
|
for(;;) {
|
||||||
$get = $this->get();
|
$get = $this->get();
|
||||||
if ($get === '*') {
|
if ($get === '*') {
|
||||||
if ($this->peek() === '/') { // end of comment reached
|
if ($this->peek() === '/') { // end of comment reached
|
||||||
$this->get();
|
$this->get();
|
||||||
// if comment preserved by YUI Compressor
|
|
||||||
if (0 === strpos($comment, '!')) {
|
if (0 === strpos($comment, '!')) {
|
||||||
return "\n/*!" . substr($comment, 1) . "*/\n";
|
// preserved by YUI Compressor
|
||||||
|
if (!$this->keptComment) {
|
||||||
|
// don't prepend a newline if two comments right after one another
|
||||||
|
$this->keptComment = "\n";
|
||||||
|
}
|
||||||
|
$this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
|
||||||
|
} else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
||||||
|
// IE conditional
|
||||||
|
$this->keptComment .= "/*{$comment}*/";
|
||||||
}
|
}
|
||||||
// if IE conditional comment
|
return;
|
||||||
if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
|
||||||
return "/*{$comment}*/";
|
|
||||||
}
|
|
||||||
return ' ';
|
|
||||||
}
|
}
|
||||||
} elseif ($get === null) {
|
} elseif ($get === null) {
|
||||||
throw new JSMin_UnterminatedCommentException(
|
throw new JSMin_UnterminatedCommentException(
|
||||||
"JSMin: Unterminated comment at byte "
|
"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
|
||||||
. $this->inputIndex . ": /*{$comment}");
|
|
||||||
}
|
}
|
||||||
$comment .= $get;
|
$comment .= $get;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next character, skipping over comments.
|
* Get the next character, skipping over comments. Some comments may be preserved.
|
||||||
* Some comments may be preserved.
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function next()
|
protected function next()
|
||||||
{
|
{
|
||||||
$get = $this->get();
|
$get = $this->get();
|
||||||
if ($get !== '/') {
|
if ($get === '/') {
|
||||||
return $get;
|
switch ($this->peek()) {
|
||||||
}
|
case '/':
|
||||||
switch ($this->peek()) {
|
$this->consumeSingleLineComment();
|
||||||
case '/': return $this->singleLineComment();
|
$get = "\n";
|
||||||
case '*': return $this->multipleLineComment();
|
break;
|
||||||
default: return $get;
|
case '*':
|
||||||
|
$this->consumeMultipleLineComment();
|
||||||
|
$get = ' ';
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return $get;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,6 @@
|
|||||||
* Class Minify
|
* Class Minify
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Minify_Source
|
|
||||||
*/
|
|
||||||
require_once 'Minify/Source.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify - Combines, minifies, and caches JavaScript and CSS files on demand.
|
* Minify - Combines, minifies, and caches JavaScript and CSS files on demand.
|
||||||
@ -29,7 +24,7 @@ require_once 'Minify/Source.php';
|
|||||||
*/
|
*/
|
||||||
class Minify {
|
class Minify {
|
||||||
|
|
||||||
const VERSION = '2.1.5';
|
const VERSION = '2.2.0';
|
||||||
const TYPE_CSS = 'text/css';
|
const TYPE_CSS = 'text/css';
|
||||||
const TYPE_HTML = 'text/html';
|
const TYPE_HTML = 'text/html';
|
||||||
// there is some debate over the ideal JS Content-Type, but this is the
|
// there is some debate over the ideal JS Content-Type, but this is the
|
||||||
@ -85,7 +80,6 @@ class Minify {
|
|||||||
public static function setCache($cache = '', $fileLocking = true)
|
public static function setCache($cache = '', $fileLocking = true)
|
||||||
{
|
{
|
||||||
if (is_string($cache)) {
|
if (is_string($cache)) {
|
||||||
require_once 'Minify/Cache/File.php';
|
|
||||||
self::$_cache = new Minify_Cache_File($cache, $fileLocking);
|
self::$_cache = new Minify_Cache_File($cache, $fileLocking);
|
||||||
} else {
|
} else {
|
||||||
self::$_cache = $cache;
|
self::$_cache = $cache;
|
||||||
@ -161,9 +155,11 @@ class Minify {
|
|||||||
*
|
*
|
||||||
* @param array $options controller/serve options
|
* @param array $options controller/serve options
|
||||||
*
|
*
|
||||||
* @return mixed null, or, if the 'quiet' option is set to true, an array
|
* @return null|array if the 'quiet' option is set to true, an array
|
||||||
* with keys "success" (bool), "statusCode" (int), "content" (string), and
|
* with keys "success" (bool), "statusCode" (int), "content" (string), and
|
||||||
* "headers" (array).
|
* "headers" (array).
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function serve($controller, $options = array())
|
public static function serve($controller, $options = array())
|
||||||
{
|
{
|
||||||
@ -174,10 +170,6 @@ class Minify {
|
|||||||
if (is_string($controller)) {
|
if (is_string($controller)) {
|
||||||
// make $controller into object
|
// make $controller into object
|
||||||
$class = 'Minify_Controller_' . $controller;
|
$class = 'Minify_Controller_' . $controller;
|
||||||
if (! class_exists($class, false)) {
|
|
||||||
require_once "Minify/Controller/"
|
|
||||||
. str_replace('_', '/', $controller) . ".php";
|
|
||||||
}
|
|
||||||
$controller = new $class();
|
$controller = new $class();
|
||||||
/* @var Minify_Controller_Base $controller */
|
/* @var Minify_Controller_Base $controller */
|
||||||
}
|
}
|
||||||
@ -219,8 +211,7 @@ class Minify {
|
|||||||
$contentEncoding = self::$_options['encodeMethod'];
|
$contentEncoding = self::$_options['encodeMethod'];
|
||||||
} else {
|
} else {
|
||||||
// sniff request header
|
// sniff request header
|
||||||
require_once 'HTTP/Encoder.php';
|
// depending on what the client accepts, $contentEncoding may be
|
||||||
// depending on what the client accepts, $contentEncoding may be
|
|
||||||
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
// 'x-gzip' while our internal encodeMethod is 'gzip'. Calling
|
||||||
// getAcceptedEncoding(false, false) leaves out compress and deflate as options.
|
// getAcceptedEncoding(false, false) leaves out compress and deflate as options.
|
||||||
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false, false);
|
list(self::$_options['encodeMethod'], $contentEncoding) = HTTP_Encoder::getAcceptedEncoding(false, false);
|
||||||
@ -231,7 +222,6 @@ class Minify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check client cache
|
// check client cache
|
||||||
require_once 'HTTP/ConditionalGet.php';
|
|
||||||
$cgOptions = array(
|
$cgOptions = array(
|
||||||
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
||||||
,'isPublic' => self::$_options['isPublic']
|
,'isPublic' => self::$_options['isPublic']
|
||||||
@ -300,7 +290,7 @@ class Minify {
|
|||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
self::$_cache->store($cacheId, $content);
|
self::$_cache->store($cacheId, $content);
|
||||||
if (function_exists('gzencode')) {
|
if (function_exists('gzencode') && self::$_options['encodeMethod']) {
|
||||||
self::$_cache->store($cacheId . '.gz', gzencode($content, self::$_options['encodeLevel']));
|
self::$_cache->store($cacheId . '.gz', gzencode($content, self::$_options['encodeLevel']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +441,7 @@ class Minify {
|
|||||||
/**
|
/**
|
||||||
* Set up sources to use Minify_Lines
|
* Set up sources to use Minify_Lines
|
||||||
*
|
*
|
||||||
* @param array $sources Minify_Source instances
|
* @param Minify_Source[] $sources Minify_Source instances
|
||||||
*/
|
*/
|
||||||
protected static function _setupDebug($sources)
|
protected static function _setupDebug($sources)
|
||||||
{
|
{
|
||||||
@ -468,6 +458,8 @@ class Minify {
|
|||||||
* Combines sources and minifies the result.
|
* Combines sources and minifies the result.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected static function _combineMinify()
|
protected static function _combineMinify()
|
||||||
{
|
{
|
||||||
@ -526,7 +518,6 @@ class Minify {
|
|||||||
$imploded = implode($implodeSeparator, $groupToProcessTogether);
|
$imploded = implode($implodeSeparator, $groupToProcessTogether);
|
||||||
$groupToProcessTogether = array();
|
$groupToProcessTogether = array();
|
||||||
if ($lastMinifier) {
|
if ($lastMinifier) {
|
||||||
self::$_controller->loadMinifier($lastMinifier);
|
|
||||||
try {
|
try {
|
||||||
$content[] = call_user_func($lastMinifier, $imploded, $lastOptions);
|
$content[] = call_user_func($lastMinifier, $imploded, $lastOptions);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -574,7 +565,7 @@ class Minify {
|
|||||||
{
|
{
|
||||||
$name = preg_replace('/[^a-zA-Z0-9\\.=_,]/', '', self::$_controller->selectionId);
|
$name = preg_replace('/[^a-zA-Z0-9\\.=_,]/', '', self::$_controller->selectionId);
|
||||||
$name = preg_replace('/\\.+/', '.', $name);
|
$name = preg_replace('/\\.+/', '.', $name);
|
||||||
$name = substr($name, 0, 200 - 34 - strlen($prefix));
|
$name = substr($name, 0, 100 - 34 - strlen($prefix));
|
||||||
$md5 = md5(serialize(array(
|
$md5 = md5(serialize(array(
|
||||||
Minify_Source::getDigest(self::$_controller->sources)
|
Minify_Source::getDigest(self::$_controller->sources)
|
||||||
,self::$_options['minifiers']
|
,self::$_options['minifiers']
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Source.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain a single last modification time for a group of Minify sources to
|
* Maintain a single last modification time for a group of Minify sources to
|
||||||
* allow use of far off Expires headers in Minify.
|
* allow use of far off Expires headers in Minify.
|
||||||
|
@ -56,6 +56,7 @@ class Minify_CSS {
|
|||||||
public static function minify($css, $options = array())
|
public static function minify($css, $options = array())
|
||||||
{
|
{
|
||||||
$options = array_merge(array(
|
$options = array_merge(array(
|
||||||
|
'compress' => true,
|
||||||
'removeCharsets' => true,
|
'removeCharsets' => true,
|
||||||
'preserveComments' => true,
|
'preserveComments' => true,
|
||||||
'currentDir' => null,
|
'currentDir' => null,
|
||||||
@ -67,21 +68,20 @@ class Minify_CSS {
|
|||||||
if ($options['removeCharsets']) {
|
if ($options['removeCharsets']) {
|
||||||
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
|
$css = preg_replace('/@charset[^;]+;\\s*/', '', $css);
|
||||||
}
|
}
|
||||||
require_once 'Minify/CSS/Compressor.php';
|
if ($options['compress']) {
|
||||||
if (! $options['preserveComments']) {
|
if (! $options['preserveComments']) {
|
||||||
$css = Minify_CSS_Compressor::process($css, $options);
|
$css = Minify_CSS_Compressor::process($css, $options);
|
||||||
} else {
|
} else {
|
||||||
require_once 'Minify/CommentPreserver.php';
|
$css = Minify_CommentPreserver::process(
|
||||||
$css = Minify_CommentPreserver::process(
|
$css
|
||||||
$css
|
,array('Minify_CSS_Compressor', 'process')
|
||||||
,array('Minify_CSS_Compressor', 'process')
|
,array($options)
|
||||||
,array($options)
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
|
if (! $options['currentDir'] && ! $options['prependRelativePath']) {
|
||||||
return $css;
|
return $css;
|
||||||
}
|
}
|
||||||
require_once 'Minify/CSS/UriRewriter.php';
|
|
||||||
if ($options['currentDir']) {
|
if ($options['currentDir']) {
|
||||||
return Minify_CSS_UriRewriter::rewrite(
|
return Minify_CSS_UriRewriter::rewrite(
|
||||||
$css
|
$css
|
||||||
|
@ -70,7 +70,7 @@ class Minify_CSS_UriRewriter {
|
|||||||
// rewrite
|
// rewrite
|
||||||
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
||||||
,array(self::$className, '_processUriCB'), $css);
|
,array(self::$className, '_processUriCB'), $css);
|
||||||
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
$css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/'
|
||||||
,array(self::$className, '_processUriCB'), $css);
|
,array(self::$className, '_processUriCB'), $css);
|
||||||
|
|
||||||
return $css;
|
return $css;
|
||||||
@ -94,7 +94,7 @@ class Minify_CSS_UriRewriter {
|
|||||||
// append
|
// append
|
||||||
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
||||||
,array(self::$className, '_processUriCB'), $css);
|
,array(self::$className, '_processUriCB'), $css);
|
||||||
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
$css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/'
|
||||||
,array(self::$className, '_processUriCB'), $css);
|
,array(self::$className, '_processUriCB'), $css);
|
||||||
|
|
||||||
self::$_prependPath = null;
|
self::$_prependPath = null;
|
||||||
@ -282,11 +282,8 @@ class Minify_CSS_UriRewriter {
|
|||||||
? $m[1]
|
? $m[1]
|
||||||
: substr($m[1], 1, strlen($m[1]) - 2);
|
: substr($m[1], 1, strlen($m[1]) - 2);
|
||||||
}
|
}
|
||||||
// analyze URI
|
// if not root/scheme relative and not starts with scheme
|
||||||
if ('/' !== $uri[0] // root-relative
|
if (!preg_match('~^(/|[a-z]+\:)~', $uri)) {
|
||||||
&& false === strpos($uri, '//') // protocol (non-data)
|
|
||||||
&& 0 !== strpos($uri, 'data:') // data protocol
|
|
||||||
) {
|
|
||||||
// URI is file-relative: rewrite depending on options
|
// URI is file-relative: rewrite depending on options
|
||||||
if (self::$_prependPath === null) {
|
if (self::$_prependPath === null) {
|
||||||
$uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
|
$uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
|
||||||
|
@ -98,6 +98,9 @@ class Minify_Cache_File {
|
|||||||
{
|
{
|
||||||
if ($this->_locking) {
|
if ($this->_locking) {
|
||||||
$fp = fopen($this->_path . '/' . $id, 'rb');
|
$fp = fopen($this->_path . '/' . $id, 'rb');
|
||||||
|
if (!$fp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
flock($fp, LOCK_SH);
|
flock($fp, LOCK_SH);
|
||||||
$ret = stream_get_contents($fp);
|
$ret = stream_get_contents($fp);
|
||||||
flock($fp, LOCK_UN);
|
flock($fp, LOCK_UN);
|
||||||
@ -186,7 +189,6 @@ class Minify_Cache_File {
|
|||||||
*/
|
*/
|
||||||
protected function _log($msg)
|
protected function _log($msg)
|
||||||
{
|
{
|
||||||
require_once 'Minify/Logger.php';
|
|
||||||
Minify_Logger::log($msg);
|
Minify_Logger::log($msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,33 +78,6 @@ abstract class Minify_Controller_Base {
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load any code necessary to execute the given minifier callback.
|
|
||||||
*
|
|
||||||
* The controller is responsible for loading minification code on demand
|
|
||||||
* via this method. This built-in function will only load classes for
|
|
||||||
* static method callbacks where the class isn't already defined. It uses
|
|
||||||
* the PEAR convention, so, given array('Jimmy_Minifier', 'minCss'), this
|
|
||||||
* function will include 'Jimmy/Minifier.php'.
|
|
||||||
*
|
|
||||||
* If you need code loaded on demand and this doesn't suit you, you'll need
|
|
||||||
* to override this function in your subclass.
|
|
||||||
* @see Minify_Controller_Page::loadMinifier()
|
|
||||||
*
|
|
||||||
* @param callback $minifierCallback callback of minifier function
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
public function loadMinifier($minifierCallback)
|
|
||||||
{
|
|
||||||
if (is_array($minifierCallback)
|
|
||||||
&& is_string($minifierCallback[0])
|
|
||||||
&& !class_exists($minifierCallback[0], false)) {
|
|
||||||
|
|
||||||
require str_replace('_', '/', $minifierCallback[0]) . '.php';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is a user-given file within an allowable directory, existing,
|
* Is a user-given file within an allowable directory, existing,
|
||||||
* and having an extension js/css/html/txt ?
|
* and having an extension js/css/html/txt ?
|
||||||
@ -244,7 +217,6 @@ abstract class Minify_Controller_Base {
|
|||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function log($msg) {
|
public function log($msg) {
|
||||||
require_once 'Minify/Logger.php';
|
|
||||||
Minify_Logger::log($msg);
|
Minify_Logger::log($msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for minifying a set of files
|
* Controller class for minifying a set of files
|
||||||
*
|
*
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for serving predetermined groups of minimized sets, selected
|
* Controller class for serving predetermined groups of minimized sets, selected
|
||||||
* by PATH_INFO
|
* by PATH_INFO
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for requests to /min/index.php
|
* Controller class for requests to /min/index.php
|
||||||
*
|
*
|
||||||
@ -22,6 +20,13 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
* @return array Minify options
|
* @return array Minify options
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
|
// PHP insecure by default: realpath() and other FS functions can't handle null bytes.
|
||||||
|
foreach (array('g', 'b', 'f') as $key) {
|
||||||
|
if (isset($_GET[$key])) {
|
||||||
|
$_GET[$key] = str_replace("\x00", '', (string)$_GET[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// filter controller options
|
// filter controller options
|
||||||
$cOptions = array_merge(
|
$cOptions = array_merge(
|
||||||
array(
|
array(
|
||||||
@ -36,7 +41,6 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
$sources = array();
|
$sources = array();
|
||||||
$this->selectionId = '';
|
$this->selectionId = '';
|
||||||
$firstMissingResource = null;
|
$firstMissingResource = null;
|
||||||
|
|
||||||
if (isset($_GET['g'])) {
|
if (isset($_GET['g'])) {
|
||||||
// add group(s)
|
// add group(s)
|
||||||
$this->selectionId .= 'g=' . $_GET['g'];
|
$this->selectionId .= 'g=' . $_GET['g'];
|
||||||
@ -195,9 +199,12 @@ class Minify_Controller_MinApp extends Minify_Controller_Base {
|
|||||||
protected function _getFileSource($file, $cOptions)
|
protected function _getFileSource($file, $cOptions)
|
||||||
{
|
{
|
||||||
$spec['filepath'] = $file;
|
$spec['filepath'] = $file;
|
||||||
if ($cOptions['noMinPattern']
|
if ($cOptions['noMinPattern'] && preg_match($cOptions['noMinPattern'], basename($file))) {
|
||||||
&& preg_match($cOptions['noMinPattern'], basename($file))) {
|
if (preg_match('~\.css$~i', $file)) {
|
||||||
$spec['minifier'] = '';
|
$spec['minifyOptions']['compress'] = false;
|
||||||
|
} else {
|
||||||
|
$spec['minifier'] = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new Minify_Source($spec);
|
return new Minify_Source($spec);
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for serving a single HTML page
|
* Controller class for serving a single HTML page
|
||||||
*
|
*
|
||||||
@ -59,7 +57,6 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
|||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
,'jsMinifier' => array('JSMin', 'minify')
|
,'jsMinifier' => array('JSMin', 'minify')
|
||||||
);
|
);
|
||||||
$this->_loadCssJsMinifiers = true;
|
|
||||||
unset($options['minifyAll']);
|
unset($options['minifyAll']);
|
||||||
}
|
}
|
||||||
$this->sources[] = new Minify_Source($sourceSpec);
|
$this->sources[] = new Minify_Source($sourceSpec);
|
||||||
@ -67,21 +64,5 @@ class Minify_Controller_Page extends Minify_Controller_Base {
|
|||||||
$options['contentType'] = Minify::TYPE_HTML;
|
$options['contentType'] = Minify::TYPE_HTML;
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $_loadCssJsMinifiers = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Minify_Controller_Base::loadMinifier()
|
|
||||||
*/
|
|
||||||
public function loadMinifier($minifierCallback)
|
|
||||||
{
|
|
||||||
if ($this->_loadCssJsMinifiers) {
|
|
||||||
// Minify will not call for these so we must manually load
|
|
||||||
// them when Minify/HTML.php is called for.
|
|
||||||
require_once 'Minify/CSS.php';
|
|
||||||
require_once 'JSMin.php';
|
|
||||||
}
|
|
||||||
parent::loadMinifier($minifierCallback); // load Minify/HTML.php
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once 'Minify/Controller/Base.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for emulating version 1 of minify.php (mostly a proof-of-concept)
|
* Controller class for emulating version 1 of minify.php (mostly a proof-of-concept)
|
||||||
*
|
*
|
||||||
@ -26,6 +24,11 @@ class Minify_Controller_Version1 extends Minify_Controller_Base {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setupSources($options) {
|
public function setupSources($options) {
|
||||||
|
// PHP insecure by default: realpath() and other FS functions can't handle null bytes.
|
||||||
|
if (isset($_GET['files'])) {
|
||||||
|
$_GET['files'] = str_replace("\x00", '', (string)$_GET['files']);
|
||||||
|
}
|
||||||
|
|
||||||
self::_setupDefines();
|
self::_setupDefines();
|
||||||
if (MINIFY_USE_CACHE) {
|
if (MINIFY_USE_CACHE) {
|
||||||
$cacheDir = defined('MINIFY_CACHE_DIR')
|
$cacheDir = defined('MINIFY_CACHE_DIR')
|
||||||
@ -51,8 +54,7 @@ class Minify_Controller_Version1 extends Minify_Controller_Base {
|
|||||||
) {
|
) {
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
$extension = $m[1];
|
|
||||||
|
|
||||||
$files = explode(',', $_GET['files']);
|
$files = explode(',', $_GET['files']);
|
||||||
if (count($files) > MINIFY_MAX_FILES) {
|
if (count($files) > MINIFY_MAX_FILES) {
|
||||||
return $options;
|
return $options;
|
||||||
@ -63,7 +65,6 @@ class Minify_Controller_Version1 extends Minify_Controller_Base {
|
|||||||
. DIRECTORY_SEPARATOR;
|
. DIRECTORY_SEPARATOR;
|
||||||
$prependAbsPaths = $_SERVER['DOCUMENT_ROOT'];
|
$prependAbsPaths = $_SERVER['DOCUMENT_ROOT'];
|
||||||
|
|
||||||
$sources = array();
|
|
||||||
$goodFiles = array();
|
$goodFiles = array();
|
||||||
$hasBadSource = false;
|
$hasBadSource = false;
|
||||||
|
|
||||||
|
@ -1,22 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Class Minify_HTML
|
* Class Minify_HTML
|
||||||
* @package Minify
|
* @package Minify
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress HTML
|
* Compress HTML
|
||||||
*
|
*
|
||||||
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
||||||
* tokens. IE conditional comments are preserved. There are also options to have
|
* tokens. IE conditional comments are preserved. There are also options to have
|
||||||
* STYLE and SCRIPT blocks compressed by callback functions.
|
* STYLE and SCRIPT blocks compressed by callback functions.
|
||||||
*
|
*
|
||||||
* A test suite is available.
|
* A test suite is available.
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
* @author Stephen Clay <steve@mrclay.org>
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
*/
|
*/
|
||||||
class Minify_HTML {
|
class Minify_HTML {
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $_jsCleanComments = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Minify" an HTML page
|
* "Minify" an HTML page
|
||||||
@ -27,21 +31,21 @@ class Minify_HTML {
|
|||||||
*
|
*
|
||||||
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
||||||
* elements.
|
* elements.
|
||||||
*
|
*
|
||||||
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
||||||
* elements. Note: the type attribute is ignored.
|
* elements. Note: the type attribute is ignored.
|
||||||
*
|
*
|
||||||
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
||||||
* unset, minify will sniff for an XHTML doctype.
|
* unset, minify will sniff for an XHTML doctype.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function minify($html, $options = array()) {
|
public static function minify($html, $options = array()) {
|
||||||
$min = new Minify_HTML($html, $options);
|
$min = new self($html, $options);
|
||||||
return $min->process();
|
return $min->process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a minifier object
|
* Create a minifier object
|
||||||
*
|
*
|
||||||
@ -51,14 +55,14 @@ class Minify_HTML {
|
|||||||
*
|
*
|
||||||
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
||||||
* elements.
|
* elements.
|
||||||
*
|
*
|
||||||
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
||||||
* elements. Note: the type attribute is ignored.
|
* elements. Note: the type attribute is ignored.
|
||||||
*
|
*
|
||||||
|
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
|
||||||
|
*
|
||||||
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
||||||
* unset, minify will sniff for an XHTML doctype.
|
* unset, minify will sniff for an XHTML doctype.
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
*/
|
||||||
public function __construct($html, $options = array())
|
public function __construct($html, $options = array())
|
||||||
{
|
{
|
||||||
@ -72,9 +76,12 @@ class Minify_HTML {
|
|||||||
if (isset($options['jsMinifier'])) {
|
if (isset($options['jsMinifier'])) {
|
||||||
$this->_jsMinifier = $options['jsMinifier'];
|
$this->_jsMinifier = $options['jsMinifier'];
|
||||||
}
|
}
|
||||||
|
if (isset($options['jsCleanComments'])) {
|
||||||
|
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify the markeup given in the constructor
|
* Minify the markeup given in the constructor
|
||||||
*
|
*
|
||||||
@ -124,7 +131,7 @@ class Minify_HTML {
|
|||||||
|
|
||||||
// remove ws around block/undisplayed elements
|
// remove ws around block/undisplayed elements
|
||||||
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
||||||
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
.'|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
||||||
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
||||||
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
||||||
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
||||||
@ -213,17 +220,19 @@ class Minify_HTML {
|
|||||||
// whitespace surrounding? preserve at least one space
|
// whitespace surrounding? preserve at least one space
|
||||||
$ws1 = ($m[1] === '') ? '' : ' ';
|
$ws1 = ($m[1] === '') ? '' : ' ';
|
||||||
$ws2 = ($m[4] === '') ? '' : ' ';
|
$ws2 = ($m[4] === '') ? '' : ' ';
|
||||||
|
|
||||||
// remove HTML comments (and ending "//" if present)
|
// remove HTML comments (and ending "//" if present)
|
||||||
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
if ($this->_jsCleanComments) {
|
||||||
|
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
||||||
|
}
|
||||||
|
|
||||||
// remove CDATA section markers
|
// remove CDATA section markers
|
||||||
$js = $this->_removeCdata($js);
|
$js = $this->_removeCdata($js);
|
||||||
|
|
||||||
// minify
|
// minify
|
||||||
$minifier = $this->_jsMinifier
|
$minifier = $this->_jsMinifier
|
||||||
? $this->_jsMinifier
|
? $this->_jsMinifier
|
||||||
: 'trim';
|
: 'trim';
|
||||||
$js = call_user_func($minifier, $js);
|
$js = call_user_func($minifier, $js);
|
||||||
|
|
||||||
return $this->_reservePlace($this->_needsCdata($js)
|
return $this->_reservePlace($this->_needsCdata($js)
|
||||||
|
@ -15,10 +15,10 @@ class Minify_HTML_Helper {
|
|||||||
public $minAppUri = '/min';
|
public $minAppUri = '/min';
|
||||||
public $groupsConfigFile = '';
|
public $groupsConfigFile = '';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Get an HTML-escaped Minify URI for a group or set of files
|
* Get an HTML-escaped Minify URI for a group or set of files
|
||||||
*
|
*
|
||||||
* @param mixed $keyOrFiles a group key or array of filepaths/URIs
|
* @param string|array $keyOrFiles a group key or array of filepaths/URIs
|
||||||
* @param array $opts options:
|
* @param array $opts options:
|
||||||
* 'farExpires' : (default true) append a modified timestamp for cache revving
|
* 'farExpires' : (default true) append a modified timestamp for cache revving
|
||||||
* 'debug' : (default false) append debug flag
|
* 'debug' : (default false) append debug flag
|
||||||
@ -51,8 +51,12 @@ class Minify_HTML_Helper {
|
|||||||
return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']);
|
return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Get non-HTML-escaped URI to minify the specified files
|
* Get non-HTML-escaped URI to minify the specified files
|
||||||
|
*
|
||||||
|
* @param bool $farExpires
|
||||||
|
* @param bool $debug
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getRawUri($farExpires = true, $debug = false)
|
public function getRawUri($farExpires = true, $debug = false)
|
||||||
{
|
{
|
||||||
@ -74,6 +78,12 @@ class Minify_HTML_Helper {
|
|||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the files that will comprise the URI we're building
|
||||||
|
*
|
||||||
|
* @param array $files
|
||||||
|
* @param bool $checkLastModified
|
||||||
|
*/
|
||||||
public function setFiles($files, $checkLastModified = true)
|
public function setFiles($files, $checkLastModified = true)
|
||||||
{
|
{
|
||||||
$this->_groupKey = null;
|
$this->_groupKey = null;
|
||||||
@ -94,6 +104,12 @@ class Minify_HTML_Helper {
|
|||||||
$this->_filePaths = $files;
|
$this->_filePaths = $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the group of files that will comprise the URI we're building
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param bool $checkLastModified
|
||||||
|
*/
|
||||||
public function setGroup($key, $checkLastModified = true)
|
public function setGroup($key, $checkLastModified = true)
|
||||||
{
|
{
|
||||||
$this->_groupKey = $key;
|
$this->_groupKey = $key;
|
||||||
@ -103,13 +119,23 @@ class Minify_HTML_Helper {
|
|||||||
}
|
}
|
||||||
if (is_file($this->groupsConfigFile)) {
|
if (is_file($this->groupsConfigFile)) {
|
||||||
$gc = (require $this->groupsConfigFile);
|
$gc = (require $this->groupsConfigFile);
|
||||||
if (isset($gc[$key])) {
|
$keys = explode(',', $key);
|
||||||
$this->_lastModified = self::getLastModified($gc[$key]);
|
foreach ($keys as $key) {
|
||||||
|
if (isset($gc[$key])) {
|
||||||
|
$this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the max(lastModified) of all files
|
||||||
|
*
|
||||||
|
* @param array|string $sources
|
||||||
|
* @param int $lastModified
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public static function getLastModified($sources, $lastModified = 0)
|
public static function getLastModified($sources, $lastModified = 0)
|
||||||
{
|
{
|
||||||
$max = $lastModified;
|
$max = $lastModified;
|
||||||
@ -142,13 +168,19 @@ class Minify_HTML_Helper {
|
|||||||
* @return mixed a common char or '' if any do not match
|
* @return mixed a common char or '' if any do not match
|
||||||
*/
|
*/
|
||||||
protected static function _getCommonCharAtPos($arr, $pos) {
|
protected static function _getCommonCharAtPos($arr, $pos) {
|
||||||
$l = count($arr);
|
if (!isset($arr[0][$pos])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
$c = $arr[0][$pos];
|
$c = $arr[0][$pos];
|
||||||
if ($c === '' || $l === 1)
|
$l = count($arr);
|
||||||
|
if ($l === 1) {
|
||||||
return $c;
|
return $c;
|
||||||
for ($i = 1; $i < $l; ++$i)
|
}
|
||||||
if ($arr[$i][$pos] !== $c)
|
for ($i = 1; $i < $l; ++$i) {
|
||||||
|
if ($arr[$i][$pos] !== $c) {
|
||||||
return '';
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,11 +189,11 @@ class Minify_HTML_Helper {
|
|||||||
*
|
*
|
||||||
* @param array $paths root-relative URIs of files
|
* @param array $paths root-relative URIs of files
|
||||||
* @param string $minRoot root-relative URI of the "min" application
|
* @param string $minRoot root-relative URI of the "min" application
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function _getShortestUri($paths, $minRoot = '/min/') {
|
protected static function _getShortestUri($paths, $minRoot = '/min/') {
|
||||||
$pos = 0;
|
$pos = 0;
|
||||||
$base = '';
|
$base = '';
|
||||||
$c;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$c = self::_getCommonCharAtPos($paths, $pos);
|
$c = self::_getCommonCharAtPos($paths, $pos);
|
||||||
if ($c === '') {
|
if ($c === '') {
|
||||||
|
@ -14,13 +14,68 @@
|
|||||||
* @todo can use a stream wrapper to unit test this?
|
* @todo can use a stream wrapper to unit test this?
|
||||||
*/
|
*/
|
||||||
class Minify_JS_ClosureCompiler {
|
class Minify_JS_ClosureCompiler {
|
||||||
const URL = 'http://closure-compiler.appspot.com/compile';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minify Javascript code via HTTP request to the Closure Compiler API
|
* @var string The option key for the maximum POST byte size
|
||||||
|
*/
|
||||||
|
const OPTION_MAX_BYTES = 'maxBytes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The option key for additional params. @see __construct
|
||||||
|
*/
|
||||||
|
const OPTION_ADDITIONAL_OPTIONS = 'additionalParams';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The option key for the fallback Minifier
|
||||||
|
*/
|
||||||
|
const OPTION_FALLBACK_FUNCTION = 'fallbackFunc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The option key for the service URL
|
||||||
|
*/
|
||||||
|
const OPTION_COMPILER_URL = 'compilerUrl';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref
|
||||||
|
*/
|
||||||
|
const DEFAULT_MAX_BYTES = 200000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service
|
||||||
|
*
|
||||||
|
* @note This would be a constant if PHP allowed it
|
||||||
|
*/
|
||||||
|
private static $DEFAULT_OPTIONS = array(
|
||||||
|
'output_format' => 'text',
|
||||||
|
'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $url URL of compiler server. defaults to Google's
|
||||||
|
*/
|
||||||
|
protected $serviceUrl = 'http://closure-compiler.appspot.com/compile';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes
|
||||||
|
*/
|
||||||
|
protected $maxBytes = self::DEFAULT_MAX_BYTES;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[] $additionalOptions Additional options to pass to the compiler service
|
||||||
|
*/
|
||||||
|
protected $additionalOptions = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var callable Function to minify JS if service fails. Default is JSMin
|
||||||
|
*/
|
||||||
|
protected $fallbackMinifier = array('JSMin', 'minify');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify JavaScript code via HTTP request to a Closure Compiler API
|
||||||
*
|
*
|
||||||
* @param string $js input code
|
* @param string $js input code
|
||||||
* @param array $options unused at this point
|
* @param array $options Options passed to __construct(). @see __construct
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function minify($js, array $options = array())
|
public static function minify($js, array $options = array())
|
||||||
@ -30,63 +85,101 @@ class Minify_JS_ClosureCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param array $options Options with keys available below:
|
||||||
*
|
*
|
||||||
* @param array $options
|
* fallbackFunc : (callable) function to minify if service unavailable. Default is JSMin.
|
||||||
*
|
*
|
||||||
* fallbackFunc : default array($this, 'fallback');
|
* compilerUrl : (string) URL to closure compiler server
|
||||||
|
*
|
||||||
|
* maxBytes : (int) The maximum amount of bytes to be sent as js_code in the POST request.
|
||||||
|
* Defaults to 200000.
|
||||||
|
*
|
||||||
|
* additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named
|
||||||
|
* in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and
|
||||||
|
* output_info
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = array())
|
public function __construct(array $options = array())
|
||||||
{
|
{
|
||||||
$this->_fallbackFunc = isset($options['fallbackMinifier'])
|
if (isset($options[self::OPTION_FALLBACK_FUNCTION])) {
|
||||||
? $options['fallbackMinifier']
|
$this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION];
|
||||||
: array($this, '_fallback');
|
}
|
||||||
|
if (isset($options[self::OPTION_COMPILER_URL])) {
|
||||||
|
$this->serviceUrl = $options[self::OPTION_COMPILER_URL];
|
||||||
|
}
|
||||||
|
if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) {
|
||||||
|
$this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS];
|
||||||
|
}
|
||||||
|
if (isset($options[self::OPTION_MAX_BYTES])) {
|
||||||
|
$this->maxBytes = (int) $options[self::OPTION_MAX_BYTES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the service to perform the minification
|
||||||
|
*
|
||||||
|
* @param string $js JavaScript code
|
||||||
|
* @return string
|
||||||
|
* @throws Minify_JS_ClosureCompiler_Exception
|
||||||
|
*/
|
||||||
public function min($js)
|
public function min($js)
|
||||||
{
|
{
|
||||||
$postBody = $this->_buildPostBody($js);
|
$postBody = $this->buildPostBody($js);
|
||||||
$bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
|
|
||||||
? mb_strlen($postBody, '8bit')
|
if ($this->maxBytes > 0) {
|
||||||
: strlen($postBody);
|
$bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2))
|
||||||
if ($bytes > 200000) {
|
? mb_strlen($postBody, '8bit')
|
||||||
throw new Minify_JS_ClosureCompiler_Exception(
|
: strlen($postBody);
|
||||||
'POST content larger than 200000 bytes'
|
if ($bytes > $this->maxBytes) {
|
||||||
);
|
throw new Minify_JS_ClosureCompiler_Exception(
|
||||||
|
'POST content larger than ' . $this->maxBytes . ' bytes'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$response = $this->_getResponse($postBody);
|
|
||||||
|
$response = $this->getResponse($postBody);
|
||||||
|
|
||||||
if (preg_match('/^Error\(\d\d?\):/', $response)) {
|
if (preg_match('/^Error\(\d\d?\):/', $response)) {
|
||||||
if (is_callable($this->_fallbackFunc)) {
|
if (is_callable($this->fallbackMinifier)) {
|
||||||
|
// use fallback
|
||||||
$response = "/* Received errors from Closure Compiler API:\n$response"
|
$response = "/* Received errors from Closure Compiler API:\n$response"
|
||||||
. "\n(Using fallback minifier)\n*/\n";
|
. "\n(Using fallback minifier)\n*/\n";
|
||||||
$response .= call_user_func($this->_fallbackFunc, $js);
|
$response .= call_user_func($this->fallbackMinifier, $js);
|
||||||
} else {
|
} else {
|
||||||
throw new Minify_JS_ClosureCompiler_Exception($response);
|
throw new Minify_JS_ClosureCompiler_Exception($response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response === '') {
|
if ($response === '') {
|
||||||
$errors = $this->_getResponse($this->_buildPostBody($js, true));
|
$errors = $this->getResponse($this->buildPostBody($js, true));
|
||||||
throw new Minify_JS_ClosureCompiler_Exception($errors);
|
throw new Minify_JS_ClosureCompiler_Exception($errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $_fallbackFunc = null;
|
|
||||||
|
|
||||||
protected function _getResponse($postBody)
|
/**
|
||||||
|
* Get the response for a given POST body
|
||||||
|
*
|
||||||
|
* @param string $postBody
|
||||||
|
* @return string
|
||||||
|
* @throws Minify_JS_ClosureCompiler_Exception
|
||||||
|
*/
|
||||||
|
protected function getResponse($postBody)
|
||||||
{
|
{
|
||||||
$allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
|
$allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
|
||||||
|
|
||||||
if ($allowUrlFopen) {
|
if ($allowUrlFopen) {
|
||||||
$contents = file_get_contents(self::URL, false, stream_context_create(array(
|
$contents = file_get_contents($this->serviceUrl, false, stream_context_create(array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'header' => 'Content-type: application/x-www-form-urlencoded',
|
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n",
|
||||||
'content' => $postBody,
|
'content' => $postBody,
|
||||||
'max_redirects' => 0,
|
'max_redirects' => 0,
|
||||||
'timeout' => 15,
|
'timeout' => 15,
|
||||||
)
|
)
|
||||||
)));
|
)));
|
||||||
} elseif (defined('CURLOPT_POST')) {
|
} elseif (defined('CURLOPT_POST')) {
|
||||||
$ch = curl_init(self::URL);
|
$ch = curl_init($this->serviceUrl);
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded'));
|
||||||
@ -100,33 +193,37 @@ class Minify_JS_ClosureCompiler {
|
|||||||
"Could not make HTTP request: allow_url_open is false and cURL not available"
|
"Could not make HTTP request: allow_url_open is false and cURL not available"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $contents) {
|
if (false === $contents) {
|
||||||
throw new Minify_JS_ClosureCompiler_Exception(
|
throw new Minify_JS_ClosureCompiler_Exception(
|
||||||
"No HTTP response from server"
|
"No HTTP response from server"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return trim($contents);
|
return trim($contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _buildPostBody($js, $returnErrors = false)
|
|
||||||
{
|
|
||||||
return http_build_query(array(
|
|
||||||
'js_code' => $js,
|
|
||||||
'output_info' => ($returnErrors ? 'errors' : 'compiled_code'),
|
|
||||||
'output_format' => 'text',
|
|
||||||
'compilation_level' => 'SIMPLE_OPTIMIZATIONS'
|
|
||||||
), null, '&');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default fallback function if CC API fails
|
* Build a POST request body
|
||||||
* @param string $js
|
*
|
||||||
|
* @param string $js JavaScript code
|
||||||
|
* @param bool $returnErrors
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function _fallback($js)
|
protected function buildPostBody($js, $returnErrors = false)
|
||||||
{
|
{
|
||||||
require_once 'JSMin.php';
|
return http_build_query(
|
||||||
return JSMin::minify($js);
|
array_merge(
|
||||||
|
self::$DEFAULT_OPTIONS,
|
||||||
|
$this->additionalOptions,
|
||||||
|
array(
|
||||||
|
'js_code' => $js,
|
||||||
|
'output_info' => ($returnErrors ? 'errors' : 'compiled_code')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
'&'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,11 @@ class Minify_Lines {
|
|||||||
$newLines = array();
|
$newLines = array();
|
||||||
while (null !== ($line = array_shift($lines))) {
|
while (null !== ($line = array_shift($lines))) {
|
||||||
if (('' !== $id) && (0 == $i % 50)) {
|
if (('' !== $id) && (0 == $i % 50)) {
|
||||||
array_push($newLines, '', "/* {$id} */", '');
|
if ($inComment) {
|
||||||
|
array_push($newLines, '', "/* {$id} *|", '');
|
||||||
|
} else {
|
||||||
|
array_push($newLines, '', "/* {$id} */", '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++$i;
|
++$i;
|
||||||
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
|
$newLines[] = self::_addNote($line, $i, $inComment, $padTo);
|
||||||
@ -65,7 +69,6 @@ class Minify_Lines {
|
|||||||
|
|
||||||
// check for desired URI rewriting
|
// check for desired URI rewriting
|
||||||
if (isset($options['currentDir'])) {
|
if (isset($options['currentDir'])) {
|
||||||
require_once 'Minify/CSS/UriRewriter.php';
|
|
||||||
Minify_CSS_UriRewriter::$debugText = '';
|
Minify_CSS_UriRewriter::$debugText = '';
|
||||||
$content = Minify_CSS_UriRewriter::rewrite(
|
$content = Minify_CSS_UriRewriter::rewrite(
|
||||||
$content
|
$content
|
||||||
@ -93,6 +96,9 @@ class Minify_Lines {
|
|||||||
*/
|
*/
|
||||||
private static function _eolInComment($line, $inComment)
|
private static function _eolInComment($line, $inComment)
|
||||||
{
|
{
|
||||||
|
// crude way to avoid things like // */
|
||||||
|
$line = preg_replace('~//.*?(\\*/|/\\*).*~', '', $line);
|
||||||
|
|
||||||
while (strlen($line)) {
|
while (strlen($line)) {
|
||||||
$search = $inComment
|
$search = $inComment
|
||||||
? '*/'
|
? '*/'
|
||||||
|
@ -13,14 +13,17 @@
|
|||||||
* Java environment.
|
* Java environment.
|
||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.3.5.jar';
|
* Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.4.6.jar';
|
||||||
* Minify_YUICompressor::$tempDir = '/tmp';
|
* Minify_YUICompressor::$tempDir = '/tmp';
|
||||||
* $code = Minify_YUICompressor::minifyJs(
|
* $code = Minify_YUICompressor::minifyJs(
|
||||||
* $code
|
* $code
|
||||||
* ,array('nomunge' => true, 'line-break' => 1000)
|
* ,array('nomunge' => true, 'line-break' => 1000)
|
||||||
* );
|
* );
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
|
* Note: In case you run out stack (default is 512k), you may increase stack size in $options:
|
||||||
|
* array('stack-size' => '2048k')
|
||||||
|
*
|
||||||
* @todo unit tests, $options docs
|
* @todo unit tests, $options docs
|
||||||
*
|
*
|
||||||
* @package Minify
|
* @package Minify
|
||||||
@ -87,7 +90,7 @@ class Minify_YUICompressor {
|
|||||||
{
|
{
|
||||||
self::_prepare();
|
self::_prepare();
|
||||||
if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) {
|
if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) {
|
||||||
throw new Exception('Minify_YUICompressor : could not create temp file.');
|
throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".');
|
||||||
}
|
}
|
||||||
file_put_contents($tmpFile, $content);
|
file_put_contents($tmpFile, $content);
|
||||||
exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code);
|
exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code);
|
||||||
@ -108,10 +111,15 @@ class Minify_YUICompressor {
|
|||||||
,'nomunge' => false
|
,'nomunge' => false
|
||||||
,'preserve-semi' => false
|
,'preserve-semi' => false
|
||||||
,'disable-optimizations' => false
|
,'disable-optimizations' => false
|
||||||
|
,'stack-size' => ''
|
||||||
)
|
)
|
||||||
,$userOptions
|
,$userOptions
|
||||||
);
|
);
|
||||||
$cmd = self::$javaExecutable . ' -jar ' . escapeshellarg(self::$jarFile)
|
$cmd = self::$javaExecutable
|
||||||
|
. (!empty($o['stack-size'])
|
||||||
|
? ' -Xss' . $o['stack-size']
|
||||||
|
: '')
|
||||||
|
. ' -jar ' . escapeshellarg(self::$jarFile)
|
||||||
. " --type {$type}"
|
. " --type {$type}"
|
||||||
. (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset'])
|
. (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset'])
|
||||||
? " --charset {$o['charset']}"
|
? " --charset {$o['charset']}"
|
||||||
@ -134,8 +142,8 @@ class Minify_YUICompressor {
|
|||||||
if (! is_file(self::$jarFile)) {
|
if (! is_file(self::$jarFile)) {
|
||||||
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
|
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
|
||||||
}
|
}
|
||||||
if (! is_executable(self::$jarFile)) {
|
if (! is_readable(self::$jarFile)) {
|
||||||
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not executable.');
|
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not readable.');
|
||||||
}
|
}
|
||||||
if (! is_dir(self::$tempDir)) {
|
if (! is_dir(self::$tempDir)) {
|
||||||
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
|
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace MrClay;
|
namespace MrClay;
|
||||||
|
|
||||||
|
use MrClay\Cli\Arg;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forms a front controller for a console app, handling and validating arguments (options)
|
* Forms a front controller for a console app, handling and validating arguments (options)
|
||||||
*
|
*
|
||||||
@ -51,7 +54,7 @@ class Cli {
|
|||||||
public $isHelpRequest = false;
|
public $isHelpRequest = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array of Cli\Arg
|
* @var Arg[]
|
||||||
*/
|
*/
|
||||||
protected $_args = array();
|
protected $_args = array();
|
||||||
|
|
||||||
@ -80,8 +83,8 @@ class Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Cli\Arg|string $letter
|
* @param Arg|string $letter
|
||||||
* @return Cli\Arg
|
* @return Arg
|
||||||
*/
|
*/
|
||||||
public function addOptionalArg($letter)
|
public function addOptionalArg($letter)
|
||||||
{
|
{
|
||||||
@ -89,8 +92,8 @@ class Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Cli\Arg|string $letter
|
* @param Arg|string $letter
|
||||||
* @return Cli\Arg
|
* @return Arg
|
||||||
*/
|
*/
|
||||||
public function addRequiredArg($letter)
|
public function addRequiredArg($letter)
|
||||||
{
|
{
|
||||||
@ -100,17 +103,17 @@ class Cli {
|
|||||||
/**
|
/**
|
||||||
* @param string $letter
|
* @param string $letter
|
||||||
* @param bool $required
|
* @param bool $required
|
||||||
* @param Cli\Arg|null $arg
|
* @param Arg|null $arg
|
||||||
* @return Cli\Arg
|
* @return Arg
|
||||||
* @throws \InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function addArgument($letter, $required, Cli\Arg $arg = null)
|
public function addArgument($letter, $required, Arg $arg = null)
|
||||||
{
|
{
|
||||||
if (! preg_match('/^[a-zA-Z]$/', $letter)) {
|
if (! preg_match('/^[a-zA-Z]$/', $letter)) {
|
||||||
throw new \InvalidArgumentException('$letter must be in [a-zA-z]');
|
throw new InvalidArgumentException('$letter must be in [a-zA-Z]');
|
||||||
}
|
}
|
||||||
if (! $arg) {
|
if (! $arg) {
|
||||||
$arg = new Cli\Arg($required);
|
$arg = new Arg($required);
|
||||||
}
|
}
|
||||||
$this->_args[$letter] = $arg;
|
$this->_args[$letter] = $arg;
|
||||||
return $arg;
|
return $arg;
|
||||||
@ -118,7 +121,7 @@ class Cli {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $letter
|
* @param string $letter
|
||||||
* @return Cli\Arg|null
|
* @return Arg|null
|
||||||
*/
|
*/
|
||||||
public function getArgument($letter)
|
public function getArgument($letter)
|
||||||
{
|
{
|
||||||
@ -143,7 +146,7 @@ class Cli {
|
|||||||
|
|
||||||
$lettersUsed = '';
|
$lettersUsed = '';
|
||||||
foreach ($this->_args as $letter => $arg) {
|
foreach ($this->_args as $letter => $arg) {
|
||||||
/* @var Cli\Arg $arg */
|
/* @var Arg $arg */
|
||||||
$options .= $letter;
|
$options .= $letter;
|
||||||
$lettersUsed .= $letter;
|
$lettersUsed .= $letter;
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ class Cli {
|
|||||||
$this->debug['getopt_return'] = $o;
|
$this->debug['getopt_return'] = $o;
|
||||||
|
|
||||||
foreach ($this->_args as $letter => $arg) {
|
foreach ($this->_args as $letter => $arg) {
|
||||||
/* @var Cli\Arg $arg */
|
/* @var Arg $arg */
|
||||||
$this->values[$letter] = false;
|
$this->values[$letter] = false;
|
||||||
if (isset($o[$letter])) {
|
if (isset($o[$letter])) {
|
||||||
if (is_bool($o[$letter])) {
|
if (is_bool($o[$letter])) {
|
||||||
@ -295,7 +298,7 @@ class Cli {
|
|||||||
{
|
{
|
||||||
$r = "\n";
|
$r = "\n";
|
||||||
foreach ($this->_args as $letter => $arg) {
|
foreach ($this->_args as $letter => $arg) {
|
||||||
/* @var Cli\Arg $arg */
|
/* @var Arg $arg */
|
||||||
$desc = $arg->getDescription();
|
$desc = $arg->getDescription();
|
||||||
$flag = " -$letter ";
|
$flag = " -$letter ";
|
||||||
if ($arg->mayHaveValue) {
|
if ($arg->mayHaveValue) {
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace MrClay\Cli;
|
namespace MrClay\Cli;
|
||||||
|
|
||||||
|
use BadMethodCallException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An argument for a CLI app. This specifies the argument, what values it expects and
|
* An argument for a CLI app. This specifies the argument, what values it expects and
|
||||||
* how it's treated during validation.
|
* how it's treated during validation.
|
||||||
@ -150,7 +152,7 @@ class Arg {
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @param array $args
|
* @param array $args
|
||||||
* @return Arg
|
* @return Arg
|
||||||
* @throws \BadMethodCallException
|
* @throws BadMethodCallException
|
||||||
*/
|
*/
|
||||||
public function __call($name, array $args = array())
|
public function __call($name, array $args = array())
|
||||||
{
|
{
|
||||||
@ -160,7 +162,7 @@ class Arg {
|
|||||||
$this->spec['mustHaveValue'] = true;
|
$this->spec['mustHaveValue'] = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new \BadMethodCallException('Method does not exist');
|
throw new BadMethodCallException('Method does not exist');
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
8
js/jquery.min.js
vendored
8
js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
57
js/jquery.mixitup.min.js
vendored
57
js/jquery.mixitup.min.js
vendored
File diff suppressed because one or more lines are too long
2
js/jquery.tooltipster.min.js
vendored
2
js/jquery.tooltipster.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user