mirror of
https://github.com/mrclay/minify.git
synced 2025-08-12 17:14:24 +02:00
builder app improvements and bookmarklet
JSMin.php : + YUI and IE conditional comment preserving
This commit is contained in:
21
README
21
README
@@ -16,16 +16,6 @@ directory: i.e. you will have: /home/user/www/public_html/min
|
||||
you to the Minify URI Builder application, which will help you
|
||||
quickly start using Minify to serve content on your site.
|
||||
|
||||
UNIT TESTING:
|
||||
|
||||
1. Place the /min_extras/ directory as a child of your DOCUMENT_ROOT
|
||||
directory: i.e. you will have: /home/user/www/public_html/min_extras
|
||||
|
||||
2. To run unit tests, access: http://yourdomain/min_extras/unit_tests/test_all.php
|
||||
|
||||
Other test_*.php files in that directory can be run to test individual
|
||||
components more verbosely.
|
||||
|
||||
|
||||
FILE ENCODINGS
|
||||
|
||||
@@ -35,3 +25,14 @@ encodings like ISO 8859/Windows-1252. By default Minify appends
|
||||
|
||||
Leading UTF-8 BOMs are stripped from all sources to prevent
|
||||
duplication in output files, and files are converted to Unix newlines.
|
||||
|
||||
|
||||
UNIT TESTING:
|
||||
|
||||
1. Place the /min_extras/ directory as a child of your DOCUMENT_ROOT
|
||||
directory: i.e. you will have: /home/user/www/public_html/min_extras
|
||||
|
||||
2. To run unit tests, access: http://yourdomain/min_extras/unit_tests/test_all.php
|
||||
|
||||
Other test_*.php files in that directory can be run to test individual
|
||||
components more verbosely.
|
||||
|
@@ -1,41 +1,50 @@
|
||||
// @todo update test links when reordering, app instructions
|
||||
var MUB = {
|
||||
_uid : 0
|
||||
/**
|
||||
* Get markup for new source LI element
|
||||
*/
|
||||
,newLi : function () {
|
||||
return '<li id="li' + MUB._uid + '">http://' + location.host + '/<input type=text size=20>'
|
||||
+ ' <button title="Remove">x</button> <button title="Include Earlier">↑</button>'
|
||||
+ ' <button title="Include Later">↓</button> <span></span></li>';
|
||||
}
|
||||
/**
|
||||
* Add new empty source LI and attach handlers to buttons
|
||||
*/
|
||||
,addLi : function () {
|
||||
$('#sources').append(MUB.newLi());
|
||||
var li = $('#li' + MUB._uid)[0];
|
||||
$('button[title=Remove]', li).click(function () {
|
||||
$('#results').hide();
|
||||
var hadValue = !!$('input', li)[0].value;
|
||||
$(li).remove();
|
||||
hadValue && MUB.update();
|
||||
});
|
||||
$('button[title$=Earlier]', li).click(function () {
|
||||
$(li).prev('li').find('input').each(function () {
|
||||
$('#results').hide();
|
||||
// this = previous li input
|
||||
var tmp = this.value;
|
||||
this.value = $('input', li).val();
|
||||
$('input', li).val(tmp);
|
||||
MUB.updateAllTestLinks();
|
||||
MUB.update();
|
||||
});
|
||||
});
|
||||
$('button[title$=Later]', li).click(function () {
|
||||
$(li).next('li').find('input').each(function () {
|
||||
$('#results').hide();
|
||||
// this = next li input
|
||||
var tmp = this.value;
|
||||
this.value = $('input', li).val();
|
||||
$('input', li).val(tmp);
|
||||
MUB.updateAllTestLinks();
|
||||
MUB.update();
|
||||
});
|
||||
});
|
||||
++MUB._uid;
|
||||
}
|
||||
/**
|
||||
* In the context of a source LI element, this will analyze the URI in
|
||||
* the INPUT and check the URL on the site.
|
||||
*/
|
||||
,liUpdateTestLink : function () { // call in context of li element
|
||||
if (! $('input', this)[0].value)
|
||||
return;
|
||||
@@ -58,9 +67,19 @@ var MUB = {
|
||||
,dataType : 'text'
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Check all source URLs
|
||||
*/
|
||||
,updateAllTestLinks : function () {
|
||||
$('#sources li').each(MUB.liUpdateTestLink);
|
||||
}
|
||||
/**
|
||||
* In a given array of strings, find the character they all have at
|
||||
* a particular index
|
||||
* @param Array arr array of strings
|
||||
* @param Number pos index to check
|
||||
* @return mixed a common char or '' if any do not match
|
||||
*/
|
||||
,getCommonCharAtPos : function (arr, pos) {
|
||||
var i
|
||||
,l = arr.length
|
||||
@@ -72,6 +91,10 @@ var MUB = {
|
||||
return '';
|
||||
return c;
|
||||
}
|
||||
/**
|
||||
* Get the shortest URI to minify the set of source files
|
||||
* @param Array sources URIs
|
||||
*/
|
||||
,getBestUri : function (sources) {
|
||||
var pos = 0
|
||||
,base = ''
|
||||
@@ -103,6 +126,9 @@ var MUB = {
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
/**
|
||||
* Create the Minify URI for the sources
|
||||
*/
|
||||
,update : function () {
|
||||
MUB.updateAllTestLinks();
|
||||
var sources = []
|
||||
@@ -139,21 +165,56 @@ var MUB = {
|
||||
);
|
||||
$('#results').show();
|
||||
}
|
||||
/**
|
||||
* Handler for the "Add file +" button
|
||||
*/
|
||||
,addButtonClick : function () {
|
||||
$('#results').hide();
|
||||
MUB.addLi();
|
||||
MUB.updateAllTestLinks();
|
||||
$('#update').show().click(MUB.update);
|
||||
}
|
||||
/**
|
||||
* Runs on DOMready
|
||||
*/
|
||||
,init : function () {
|
||||
$('#sources').html('');
|
||||
$('#add button').click(MUB.addButtonClick);
|
||||
// make easier to copy text out of
|
||||
$('#uriHtml, #groupConfig').click(function () {
|
||||
this.select();
|
||||
}).focus(function () {
|
||||
this.select();
|
||||
});
|
||||
$('a.ext').attr({target:'_blank'});
|
||||
MUB.addButtonClick();
|
||||
if (location.hash) {
|
||||
// make links out of URIs from bookmarklet
|
||||
$('#getBm').hide();
|
||||
$('#bmUris').html('<p><strong>Found by bookmarklet:</strong> /<a href=#>'
|
||||
+ location.hash.substr(1).split(',').join('</a> | /<a href=#>')
|
||||
+ '</a></p>'
|
||||
);
|
||||
$('#bmUris a').click(function () {
|
||||
MUB.addButtonClick();
|
||||
$('#sources li:last input').val(this.innerHTML)
|
||||
MUB.liUpdateTestLink.call($('#sources li:last')[0]);
|
||||
$('#results').hide();
|
||||
return false;
|
||||
}).attr({title:'Add file +'});
|
||||
} else {
|
||||
// copy bookmarklet code into href
|
||||
var bmUri = location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1);
|
||||
$.ajax({
|
||||
url : '../?f=' + bmUri
|
||||
,success : function (code) {
|
||||
$('#bm')[0].href = code
|
||||
.replace('%BUILDER_URL%', location.href)
|
||||
.replace(/\n/g, ' ');
|
||||
}
|
||||
,dataType : 'text'
|
||||
});
|
||||
MUB.addButtonClick();
|
||||
}
|
||||
}
|
||||
};
|
||||
window.onload = MUB.init;
|
29
min/builder/bm.js
Normal file
29
min/builder/bm.js
Normal file
@@ -0,0 +1,29 @@
|
||||
javascript:(function() {
|
||||
function add(uri) {
|
||||
(0 === uri.indexOf(home))
|
||||
&& (!/[\?&]/.test(uri))
|
||||
&& uris.push(escape(uri.substr(home.length)));
|
||||
}
|
||||
function sheet(ss) {
|
||||
ss.href && add(ss.href);
|
||||
if (ss.cssRules) {
|
||||
var i = 0, r;
|
||||
while (r = ss.cssRules[i++])
|
||||
r.styleSheet && sheet(r.styleSheet);
|
||||
}
|
||||
}
|
||||
var d = document
|
||||
,uris = []
|
||||
,i = 0
|
||||
,o
|
||||
,home = (location + '').split('/').splice(0, 3).join('/') + '/';
|
||||
while (o = d.getElementsByTagName('script')[i++])
|
||||
o.src && !(o.type && /vbs/i.test(o.type)) && add(o.src);
|
||||
i = 0;
|
||||
while (o = d.styleSheets[i++])
|
||||
sheet(o);
|
||||
if (uris.length)
|
||||
window.open('%BUILDER_URL%#' + uris.join(','));
|
||||
else
|
||||
alert('No minifiable resources found.');
|
||||
})();
|
@@ -45,6 +45,8 @@ and click [Update].</p>
|
||||
<ol id=sources><li></li></ol>
|
||||
<div id=add><button>Add file +</button></div>
|
||||
|
||||
<div id=bmUris></div>
|
||||
|
||||
<p><button id=update>Update</button></p>
|
||||
|
||||
<div id=results>
|
||||
@@ -53,7 +55,7 @@ and click [Update].</p>
|
||||
<p>Place this URI in your HTML to serve the files above combined, minified, compressed and with cache headers.</p>
|
||||
<table id=uriTable>
|
||||
<tr><th>URI</th><td><a id=uriA class=ext>/min</a> <small>(opens in new window)</small></td></tr>
|
||||
<tr><th>HTML</th><td><input id=uriHtml type=text size=80 readonly></td></tr>
|
||||
<tr><th>HTML</th><td><input id=uriHtml type=text size=100 readonly></td></tr>
|
||||
</table>
|
||||
|
||||
<h2>How to serve these files as a group</h2>
|
||||
@@ -63,12 +65,21 @@ and click [Update].</p>
|
||||
|
||||
<pre><code>return array(
|
||||
<span style="color:#666">... your existing groups here ...</span>
|
||||
<input id=groupConfig size=80 type=text readonly>
|
||||
<input id=groupConfig size=100 type=text readonly>
|
||||
);</code></pre>
|
||||
|
||||
<p><em>Make sure to replace <code>keyName</code> with a unique key for this group.</em></p>
|
||||
</div>
|
||||
|
||||
<div id=getBm>
|
||||
<h3>Find URIs on a Page</h3>
|
||||
<p>You can use the bookmarklet below to fetch all CSS & Javascript URIs from a page
|
||||
on your site. When you active it, this page will open in a new window with a list of
|
||||
available URIs to add.</p>
|
||||
|
||||
<p><a id=bm>Create Minify URIs</a> <small>(right-click, add to favorites/bookmarks)</small></p>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<p>Need help? Search or post to the <a class=ext href="http://groups.google.com/group/minify">Minify discussion list</a>.</p>
|
||||
<p><small>This app is minified :) <a class=ext href="http://code.google.com/p/minify/source/browse/trunk/min/builder/index.php">view source</a></small></p>
|
||||
@@ -81,7 +92,6 @@ and click [Update].</p>
|
||||
document.write('<\script type="text/javascript" src="../?f=' + src + '"><\/script>');
|
||||
</script>
|
||||
|
||||
<!--[ This comment remains because the "[" makes it look like an IE conditional comment :) -->
|
||||
<?php
|
||||
|
||||
$serveOpts = array(
|
||||
|
@@ -2,10 +2,14 @@
|
||||
/**
|
||||
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
||||
*
|
||||
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
||||
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
||||
* outputs to stdout, this library accepts a string as input and returns another
|
||||
* This is a direct port of jsmin.c to PHP with a few PHP performance tweaks and
|
||||
* modifications to preserve some comments (see below). Also, rather than using
|
||||
* stdin/stdout, JSMin::minify() accepts a string as input and returns another
|
||||
* string as output.
|
||||
*
|
||||
* Comments containing IE conditional compilation are preserved, as are multi-line
|
||||
* comments that begin with "/*!" (for documentation purposes). In the latter case
|
||||
* newlines are inserted around the comment to enhance readability.
|
||||
*
|
||||
* PHP 5 or higher is required.
|
||||
*
|
||||
@@ -38,6 +42,7 @@
|
||||
*
|
||||
* @package JSMin
|
||||
* @author Ryan Grove <ryan@wonko.com>
|
||||
* @author Steve Clay <steve@mrclay.org> (modifications)
|
||||
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
||||
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
||||
* @license http://opensource.org/licenses/mit-license.php MIT License
|
||||
@@ -242,42 +247,54 @@ class JSMin {
|
||||
}
|
||||
|
||||
protected function next() {
|
||||
$c = $this->get();
|
||||
$get = $this->get();
|
||||
|
||||
if ($c === '/') {
|
||||
if ($get === '/') {
|
||||
$commentContents = '';
|
||||
switch($this->peek()) {
|
||||
case '/':
|
||||
// "//" comment
|
||||
for (;;) {
|
||||
$c = $this->get();
|
||||
|
||||
if (ord($c) <= self::ORD_LF) {
|
||||
return $c;
|
||||
$get = $this->get();
|
||||
$commentContents .= $get;
|
||||
if (ord($get) <= self::ORD_LF) {
|
||||
return preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $commentContents)
|
||||
? "/{$commentContents}"
|
||||
: $get;
|
||||
}
|
||||
}
|
||||
|
||||
case '*':
|
||||
// "/* */" comment
|
||||
$this->get();
|
||||
|
||||
for (;;) {
|
||||
switch($this->get()) {
|
||||
$get = $this->get();
|
||||
switch($get) {
|
||||
case '*':
|
||||
if ($this->peek() === '/') {
|
||||
$this->get();
|
||||
return ' ';
|
||||
if (0 === strpos($commentContents, '!')) {
|
||||
// YUI Compressor style
|
||||
return "\n/*" . substr($commentContents, 1) . "*/\n";
|
||||
}
|
||||
return preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $commentContents)
|
||||
? "/*{$commentContents}*/" // IE conditional compilation
|
||||
: ' ';
|
||||
}
|
||||
break;
|
||||
|
||||
case null:
|
||||
throw new JSMinException('Unterminated comment.');
|
||||
}
|
||||
$commentContents .= $get;
|
||||
}
|
||||
|
||||
default:
|
||||
return $c;
|
||||
return $get;
|
||||
}
|
||||
}
|
||||
|
||||
return $c;
|
||||
return $get;
|
||||
}
|
||||
|
||||
protected function peek() {
|
||||
|
@@ -8,7 +8,7 @@ require 'JSMin.php';
|
||||
|
||||
/**
|
||||
* Compress Javascript using Ryan Grove's JSMin class
|
||||
*
|
||||
*
|
||||
* @package Minify
|
||||
* @author Stephen Clay <steve@mrclay.org>
|
||||
*/
|
||||
@@ -19,28 +19,13 @@ class Minify_Javascript {
|
||||
*
|
||||
* @param string $js
|
||||
*
|
||||
* @param array $options available options:
|
||||
*
|
||||
* 'preserveComments': (default true) multi-line comments that begin
|
||||
* with "/*!" will be preserved with newlines before and after to
|
||||
* enhance readability.
|
||||
* @param array $options available options (none currently)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function minify($js, $options = array())
|
||||
{
|
||||
if (isset($options['preserveComments'])
|
||||
&& !$options['preserveComments']) {
|
||||
return trim(JSMin::minify($js));
|
||||
}
|
||||
require_once 'Minify/CommentPreserver.php';
|
||||
// recursive calls don't preserve comments
|
||||
$options['preserveComments'] = false;
|
||||
return Minify_CommentPreserver::process(
|
||||
$js
|
||||
,array('Minify_Javascript', 'minify')
|
||||
,array($options)
|
||||
);
|
||||
return trim(JSMin::minify($js));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -32,4 +32,18 @@ if (is.ua.indexOf('opera') >= 0) {
|
||||
if (is.ua.indexOf('gecko') >= 0) {
|
||||
is.ie = is.ns = false;
|
||||
is.gecko = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*@cc_on
|
||||
/*@if (@_win32)
|
||||
document.write("OS is 32-bit, browser is IE.");
|
||||
@else @*/
|
||||
document.write("Browser is not IE (ie: is Firefox) or Browser is not 32 bit IE.");
|
||||
/*@end
|
||||
@*/
|
||||
|
||||
//@cc_on/*
|
||||
|
||||
alert("Hello !IE browser");
|
||||
|
||||
//@cc_on*/
|
||||
|
@@ -1,4 +1,3 @@
|
||||
|
||||
/* is.js
|
||||
|
||||
(c) 2001 Douglas Crockford
|
||||
@@ -9,4 +8,9 @@ var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaE
|
||||
* preserve this comment, too
|
||||
*/
|
||||
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
|
||||
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}
|
||||
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on
|
||||
/*@if (@_win32)
|
||||
document.write("OS is 32-bit, browser is IE.");
|
||||
@else @*/document.write("Browser is not IE (ie: is Firefox) or Browser is not 32 bit IE.");/*@end
|
||||
@*///@cc_on/*
|
||||
alert("Hello !IE browser");//@cc_on*/
|
@@ -1,3 +0,0 @@
|
||||
var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'}
|
||||
is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;}
|
||||
if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}
|
@@ -243,3 +243,18 @@
|
||||
/* 33 */ is.ie = is.ns = false;
|
||||
/* 34 */ is.gecko = true;
|
||||
/* 35 */ }
|
||||
/* 36 */
|
||||
/* 37 */ /*@cc_on
|
||||
/* 38 *| /*@if (@_win32)
|
||||
/* 39 *| document.write("OS is 32-bit, browser is IE.");
|
||||
/* 40 *| @else @*/
|
||||
/* 41 */ document.write("Browser is not IE (ie: is Firefox) or Browser is not 32 bit IE.");
|
||||
/* 42 */ /*@end
|
||||
/* 43 *| @*/
|
||||
/* 44 */
|
||||
/* 45 */ //@cc_on/*
|
||||
/* 46 *|
|
||||
/* 47 *| alert("Hello !IE browser");
|
||||
/* 48 *|
|
||||
/* 49 *| //@cc_on*/
|
||||
/* 50 */
|
||||
|
@@ -18,20 +18,6 @@ function test_Javascript()
|
||||
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
||||
}
|
||||
|
||||
//$src = file_get_contents($thisDir . '/_test_files/js/before.js');
|
||||
$minExpected = file_get_contents($thisDir . '/_test_files/js/before_noComments.min.js');
|
||||
$minOutput = Minify_Javascript::minify($src, array(
|
||||
'preserveComments' => false
|
||||
));
|
||||
|
||||
$passed = assertTrue($minExpected == $minOutput, 'Minify_Javascript');
|
||||
|
||||
if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) {
|
||||
echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n";
|
||||
echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n";
|
||||
echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
test_Javascript();
|
||||
|
Reference in New Issue
Block a user