mirror of
https://github.com/claudehohl/Stikked.git
synced 2025-04-25 20:41:20 -05:00
+carabiner
This commit is contained in:
parent
d716d40cf8
commit
b505a2e1f9
708
htdocs/application/libraries/carabiner.php
Normal file
708
htdocs/application/libraries/carabiner.php
Normal file
@ -0,0 +1,708 @@
|
|||||||
|
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Carabiner
|
||||||
|
* Asset Management Library
|
||||||
|
*
|
||||||
|
* Carabiner manages javascript and CSS assets. It will react differently depending on whether
|
||||||
|
* it is in a production or development environment. In a production environment, it will combine,
|
||||||
|
* minify, and cache assets. (As files are changed, new cache files will be generated.) In a
|
||||||
|
* development environment, it will simply include references to the original assets.
|
||||||
|
*
|
||||||
|
* Carabiner requires the JSMin {@link http://codeigniter.com/forums/viewthread/103039/ released here}
|
||||||
|
* and CSSMin {@link http://codeigniter.com/forums/viewthread/103269/ released here} libraries included.
|
||||||
|
* You don't need to include them, unless you'll be using them elsewhise. Carabiner will include them
|
||||||
|
* automatically as needed.
|
||||||
|
*
|
||||||
|
* Notes: Carabiner does not implement GZIP encoding, because I think that the web server should
|
||||||
|
* handle that. If you need GZIP in an Asset Library, AssetLibPro {@link http://code.google.com/p/assetlib-pro/ }
|
||||||
|
* does it. I've also chosen not to implement any kind of javascript obfuscation (like packer),
|
||||||
|
* because of the client-side decompression overhead. More about this idea from {@link http://ejohn.org/blog/library-loading-speed/ John Resig }.
|
||||||
|
* However, that's not to say you can't do it. You can easily provide a production version of a script
|
||||||
|
* that is packed. However, note that combining a packed script with minified scripts could cause
|
||||||
|
* problems. In that case, you can flag it to be not combined.
|
||||||
|
*
|
||||||
|
* Carabiner is inspired by PHP Combine {@link http://rakaz.nl/extra/code/combine/ by Niels Leenheer }
|
||||||
|
* and AssetLibPro {@link http://code.google.com/p/assetlib-pro/ by Vincent Esche }, among others.
|
||||||
|
*
|
||||||
|
* @package CodeIgniter
|
||||||
|
* @subpackage Libraries
|
||||||
|
* @category Asset Management
|
||||||
|
* @author Tony Dewan <tonydewan.com>
|
||||||
|
* @version 1.2
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD licensed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================================
|
||||||
|
USAGE
|
||||||
|
===============================================================================================
|
||||||
|
|
||||||
|
Load the library as normal:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$this->load->library('carabiner');
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Configure it like so:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$carabiner_config = array(
|
||||||
|
'script_dir' => 'assets/scripts/',
|
||||||
|
'style_dir' => 'assets/styles/',
|
||||||
|
'cache_dir' => 'assets/cache/',
|
||||||
|
'base_uri' => $base,
|
||||||
|
'combine' => TRUE,
|
||||||
|
'dev' => FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->carabiner->config($carabiner_config);
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
There are 8 options. 4 are required:
|
||||||
|
|
||||||
|
script_dir
|
||||||
|
STRING Path to the script directory. Relative to the CI front controller (index.php)
|
||||||
|
|
||||||
|
style_dir
|
||||||
|
STRING Path to the style directory. Relative to the CI front controller (index.php)
|
||||||
|
|
||||||
|
cache_dir
|
||||||
|
STRING Path to the cache directory. Must be writable. Relative to the CI front controller (index.php)
|
||||||
|
|
||||||
|
base_uri
|
||||||
|
STRING Base uri of the site, like http://www.example.com/
|
||||||
|
|
||||||
|
|
||||||
|
4 are not required:
|
||||||
|
|
||||||
|
dev
|
||||||
|
BOOL Flags whether your in a development environment or not. See above for what this means.
|
||||||
|
Defaults to FALSE.
|
||||||
|
|
||||||
|
combine
|
||||||
|
BOOLEAN Flags whether to combine files. Defaults to TRUE.
|
||||||
|
|
||||||
|
minify_js
|
||||||
|
BOOLEAN Flags whether to minify javascript. Defaults to TRUE.
|
||||||
|
|
||||||
|
minify_css
|
||||||
|
BOOLEAN Flags whether to minify CSS. Defaults to TRUE.
|
||||||
|
|
||||||
|
|
||||||
|
Add assets like so:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// add a js file
|
||||||
|
$this->carabiner->js('scripts.js');
|
||||||
|
|
||||||
|
// add a css file
|
||||||
|
$this->carabiner->css('reset.css');
|
||||||
|
|
||||||
|
// add a css file with a mediatype
|
||||||
|
$this->carabiner->css('admin/print.css','print');
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To set a (prebuilt) production version of a js asset:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// JS: pass a second string to the method with a path to the production version
|
||||||
|
$this->carabiner->js('wymeditor/wymeditor.js', 'wymeditor/wymeditor.pack.js' );
|
||||||
|
|
||||||
|
// add a css file with prebuilt production version
|
||||||
|
$this->carabiner->css('framework/type.css', 'screen', 'framework/type.pack.css');
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
And to prevent a file from being combined:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// JS: pass a boolean FALSE as the third attribute of the method
|
||||||
|
$this->carabiner->js('wymeditor/wymeditor.js', 'wymeditor.pack.js', FALSE );
|
||||||
|
|
||||||
|
// CSS: pass a boolean FALSE as the fourth attribute of the method
|
||||||
|
$this->carabiner->css('framework/type.css', 'screen', 'framework/type.pack.css', FALSE);
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
You can also pass arrays (and arrays of arrays) to these methods. Like so:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// a single array
|
||||||
|
$this->carabiner->css( array('mobile.css', 'handheld', 'mobile.prod.css') );
|
||||||
|
|
||||||
|
// an array of arrays
|
||||||
|
$js_assets = array(
|
||||||
|
array('dev/jquery.js', 'prod/jquery.js'),
|
||||||
|
array('dev/jquery.ext.js', 'prod/jquery.ext.js'),
|
||||||
|
)
|
||||||
|
|
||||||
|
$this->carabiner->js( $js_assets );
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
To output your assets, including appropriate markup:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// display css
|
||||||
|
$this->carabiner->display('css');
|
||||||
|
|
||||||
|
//display js
|
||||||
|
$this->carabiner->display('js');
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Since Carabiner won't delete old cached files, you'll need to clear them out manually.
|
||||||
|
To do so programatically:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
// clear css cache
|
||||||
|
$this->carabiner->empty_cache('css');
|
||||||
|
|
||||||
|
//clear js cache
|
||||||
|
$this->carabiner->empty_cache('js');
|
||||||
|
|
||||||
|
// clear both
|
||||||
|
$this->carabiner->empty_cache();
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
===============================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Carabiner {
|
||||||
|
|
||||||
|
var $base_uri = '';
|
||||||
|
|
||||||
|
var $script_dir = '';
|
||||||
|
var $script_path = '';
|
||||||
|
var $script_uri = '';
|
||||||
|
|
||||||
|
var $style_dir = '';
|
||||||
|
var $style_path = '';
|
||||||
|
var $style_uri = '';
|
||||||
|
|
||||||
|
var $cache_dir = '';
|
||||||
|
var $cache_path = '';
|
||||||
|
var $cache_uri = '';
|
||||||
|
|
||||||
|
var $dev = FALSE;
|
||||||
|
var $combine = TRUE;
|
||||||
|
|
||||||
|
var $minify_js = TRUE;
|
||||||
|
var $minify_css = TRUE;
|
||||||
|
|
||||||
|
var $js = array();
|
||||||
|
var $css = array();
|
||||||
|
|
||||||
|
var $CI;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->CI =& get_instance();
|
||||||
|
log_message('debug', 'Carabiner Asset Management library initialized.');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Config
|
||||||
|
* @param Array of config variables. Requires script_dir(string), style_dir(string), cache_dir(string), and base_uri(string).
|
||||||
|
* dev(bool), combine(bool), minify_js(bool), minify_css(bool) are optional.
|
||||||
|
*/
|
||||||
|
public function config($config)
|
||||||
|
{
|
||||||
|
foreach ($config as $key => $value)
|
||||||
|
{
|
||||||
|
$this->$key = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the provided values to define the rest of them
|
||||||
|
//$this->script_path = dirname(BASEPATH).'/'.$this->script_dir;
|
||||||
|
$this->script_path = $this->script_dir;
|
||||||
|
$this->script_uri = $this->base_uri.$this->script_dir;
|
||||||
|
|
||||||
|
//$this->style_path = dirname(BASEPATH).'/'.$this->style_dir;
|
||||||
|
$this->style_path = $this->style_dir;
|
||||||
|
$this->style_uri = $this->base_uri.$this->style_dir;
|
||||||
|
|
||||||
|
//$this->cache_path = dirname(BASEPATH).'/'.$this->cache_dir;
|
||||||
|
$this->cache_path = $this->cache_dir;
|
||||||
|
$this->cache_uri = $this->base_uri.$this->cache_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add JS file to queue
|
||||||
|
* @param String of the path to development version of the JS file. Could also be an array, or array of arrays.
|
||||||
|
* @param String of the path to production version of the JS file. NOT REQUIRED
|
||||||
|
* @param Flag whether the file is to be combined NOT REQUIRED
|
||||||
|
*/
|
||||||
|
public function js($dev_file, $prod_file = '', $combine = TRUE)
|
||||||
|
{
|
||||||
|
|
||||||
|
if( is_array($dev_file) ){
|
||||||
|
|
||||||
|
if( is_array($dev_file[0]) ){
|
||||||
|
|
||||||
|
foreach($dev_file as $file){
|
||||||
|
|
||||||
|
$d = $file[0];
|
||||||
|
$p = (isset($file[1])) ? $file[1] : '';
|
||||||
|
$c = (isset($file[2])) ? $file[2] : $combine;
|
||||||
|
|
||||||
|
$this->_asset('js', $d, $p, $c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
$d = $dev_file[0];
|
||||||
|
$p = (isset($dev_file[1])) ? $dev_file[1] : '';
|
||||||
|
$c = (isset($dev_file[2])) ? $dev_file[2] : $combine;
|
||||||
|
|
||||||
|
$this->_asset('js', $d, $p, $c);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
$this->_asset('js', $dev_file, $prod_file, $combine);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add CSS file to queue
|
||||||
|
* @param String of the path to development version of the CSS file. Could also be an array, or array of arrays.
|
||||||
|
* @param String of the media type, usually one of (screen, print, handheld) for css. Defaults to screen.
|
||||||
|
* @param String of the path to production version of the CSS file. NOT REQUIRED
|
||||||
|
* @param Flag whether the file is to be combined. NOT REQUIRED
|
||||||
|
*/
|
||||||
|
public function css($dev_file, $media = 'all', $prod_file = '', $combine = TRUE)
|
||||||
|
{
|
||||||
|
|
||||||
|
if( is_array($dev_file) ){
|
||||||
|
|
||||||
|
if( is_array($dev_file[0]) ){
|
||||||
|
|
||||||
|
foreach($dev_file as $file){
|
||||||
|
|
||||||
|
$d = $file[0];
|
||||||
|
$m = (isset($file[1])) ? $file[1] : $media;
|
||||||
|
$p = (isset($file[2])) ? $file[2] : '';
|
||||||
|
$c = (isset($file[3])) ? $file[3] : $combine;
|
||||||
|
|
||||||
|
$this->_asset('css', $d, $p, $c, $m);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
$d = $dev_file[0];
|
||||||
|
$m = (isset($file[1])) ? $file[1] : $media;
|
||||||
|
$p = (isset($dev_file[2])) ? $dev_file[2] : '';
|
||||||
|
$c = (isset($dev_file[3])) ? $dev_file[3] : $combine;
|
||||||
|
|
||||||
|
$this->_asset('css', $d, $p, $c, $m);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
$this->_asset('css', $dev_file, $prod_file, $combine, $media);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an asset to queue
|
||||||
|
* @param String of the type of asset (lowercase) . css | js
|
||||||
|
* @param String of the path to development version of the asset.
|
||||||
|
* @param String of the path to production version of the asset. NOT REQUIRED
|
||||||
|
* @param Flag whether the file is to be combined. Defaults to true. NOT REQUIRED
|
||||||
|
* @param String of the media type associated with the asset. Only applicable to CSS assets. NOT REQUIRED
|
||||||
|
*/
|
||||||
|
private function _asset($type, $dev_file, $prod_file = '', $combine = TRUE, $media = 'screen')
|
||||||
|
{
|
||||||
|
if ($type == 'css') :
|
||||||
|
|
||||||
|
$this->css[$media][] = array( 'dev'=>$dev_file );
|
||||||
|
$index = count($this->css[$media]) - 1;
|
||||||
|
|
||||||
|
if($prod_file != '') $this->{$type}[$media][$index]['prod'] = $prod_file;
|
||||||
|
$this->css[$media][$index]['combine'] = $combine;
|
||||||
|
|
||||||
|
else :
|
||||||
|
|
||||||
|
$this->{$type}[] = array( 'dev'=>$dev_file );
|
||||||
|
$index = count($this->{$type}) - 1;
|
||||||
|
|
||||||
|
if($prod_file != '') $this->js[$index]['prod'] = $prod_file;
|
||||||
|
$this->js[$index]['combine'] = $combine;
|
||||||
|
|
||||||
|
endif;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display HTML references to the assets
|
||||||
|
* @param Flag the asset type: css|js
|
||||||
|
*/
|
||||||
|
public function display($flag)
|
||||||
|
{
|
||||||
|
switch($flag){
|
||||||
|
|
||||||
|
case 'js':
|
||||||
|
|
||||||
|
if( empty($this->js) ) return; // if there aren't any js files, just stop!
|
||||||
|
|
||||||
|
// if we're in a dev environment
|
||||||
|
if($this->dev){
|
||||||
|
|
||||||
|
foreach($this->js as $ref):
|
||||||
|
|
||||||
|
echo $this->_tag('js', $ref['dev']);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
|
||||||
|
// if we're combining files
|
||||||
|
} elseif($this->combine) {
|
||||||
|
|
||||||
|
$lastmodified = 0;
|
||||||
|
$files = array();
|
||||||
|
$filenames = '';
|
||||||
|
$not_combined = '';
|
||||||
|
|
||||||
|
foreach ($this->js as $ref) {
|
||||||
|
|
||||||
|
// get the last modified date of the most recently modified file
|
||||||
|
$lastmodified = max( $lastmodified , filemtime( realpath($this->script_path.$ref['dev']) ) );
|
||||||
|
$filenames .= $ref['dev'];
|
||||||
|
|
||||||
|
if($ref['combine'] == false):
|
||||||
|
$not_combined .= (isset($ref['prod'])) ? $this->_tag('js', $ref['prod']) : $this->_tag('js', $ref['dev']);
|
||||||
|
else:
|
||||||
|
$files[] = (isset($ref['prod'])) ? array('prod'=>$ref['prod'], 'dev'=>$ref['dev'] ) : array('dev'=>$ref['dev']);
|
||||||
|
endif;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = $lastmodified . md5($filenames).'.js';
|
||||||
|
|
||||||
|
if( !file_exists($this->cache_path.$filename) ) $this->_combine('js', $files, $filename);
|
||||||
|
|
||||||
|
echo $not_combined;
|
||||||
|
echo $this->_tag('js', $filename, TRUE);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// if we're minifying. but not combining
|
||||||
|
} elseif(!$this->combine && $this->minify_js) {
|
||||||
|
|
||||||
|
// minify each file, cache it, and serve it up. Oy.
|
||||||
|
foreach($this->js as $ref):
|
||||||
|
|
||||||
|
if( isset($ref['prod']) ){
|
||||||
|
|
||||||
|
$f = $ref['prod'];
|
||||||
|
|
||||||
|
echo $this->_tag('js', $f, FALSE);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$f = filemtime( realpath( $this->script_path . $ref['dev'] ) ) . md5($ref['dev']) . '.js';
|
||||||
|
|
||||||
|
if( !file_exists($this->cache_path.$f) ):
|
||||||
|
|
||||||
|
$c = $this->_minify( 'js', $ref['dev'] );
|
||||||
|
$this->_cache($f, $c);
|
||||||
|
|
||||||
|
endif;
|
||||||
|
|
||||||
|
echo $this->_tag('js', $f, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
foreach($this->js as $ref):
|
||||||
|
|
||||||
|
$f = (isset($ref['prod'])) ? $ref['prod'] : $ref['dev'];
|
||||||
|
echo $this->_tag('js', $f);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'css':
|
||||||
|
|
||||||
|
if( empty($this->css) ) return; // there aren't any css assets, so just stop!
|
||||||
|
|
||||||
|
if($this->dev){ // we're in a development environment
|
||||||
|
|
||||||
|
foreach($this->css as $media => $refs):
|
||||||
|
|
||||||
|
foreach($refs as $ref):
|
||||||
|
|
||||||
|
echo $this->_tag('css', $ref['dev'], FALSE, $media);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
} elseif($this->combine) { // we're combining and minifying
|
||||||
|
|
||||||
|
foreach($this->css as $media => $refs):
|
||||||
|
|
||||||
|
// lets try to cache it, shall we?
|
||||||
|
$lastmodified = 0;
|
||||||
|
$files = array();
|
||||||
|
$filenames = '';
|
||||||
|
$not_combined = '';
|
||||||
|
|
||||||
|
foreach ($refs as $ref):
|
||||||
|
|
||||||
|
$lastmodified = max($lastmodified, filemtime( realpath( $this->style_path . $ref['dev'] ) ) );
|
||||||
|
$filenames .= $ref['dev'];
|
||||||
|
|
||||||
|
if($ref['combine'] == false):
|
||||||
|
$not_combined .= (isset($ref['prod'])) ? $this->_tag('css', $ref['prod'], $media) : $this->_tag('css', $ref['dev'], $media);
|
||||||
|
else:
|
||||||
|
$files[] = (isset($ref['prod'])) ? array('prod'=>$ref['prod'], 'dev'=>$ref['dev'] ) : array('dev'=>$ref['dev']);
|
||||||
|
endif;
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
$filename = $lastmodified . md5($filenames).'.css';
|
||||||
|
|
||||||
|
if( !file_exists($this->cache_path.$filename) ) $this->_combine('css', $files, $filename);
|
||||||
|
|
||||||
|
echo $not_combined;
|
||||||
|
echo $this->_tag('css', $filename, TRUE, $media);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
} elseif(!$this->combine && $this->minify_css) { // we want to minify, but not combine
|
||||||
|
|
||||||
|
foreach($this->css as $media => $refs):
|
||||||
|
|
||||||
|
foreach($refs as $ref):
|
||||||
|
|
||||||
|
if( isset($ref['prod']) ){
|
||||||
|
|
||||||
|
$f = $this->style_uri . $ref['prod'];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$f = filemtime( realpath( $this->style_path . $ref['dev'] ) ) . md5($ref['dev']) . '.css';
|
||||||
|
|
||||||
|
if( !file_exists($this->cache_path.$f) ):
|
||||||
|
|
||||||
|
$c = $this->_minify( 'css', $ref['dev'] );
|
||||||
|
$this->_cache($f, $c);
|
||||||
|
|
||||||
|
endif;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $this->_tag('css', $f, TRUE, $media);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
}else{ // we're in a production environment, but not minifying or combining
|
||||||
|
|
||||||
|
foreach($this->css as $media => $refs):
|
||||||
|
|
||||||
|
foreach($refs as $ref):
|
||||||
|
|
||||||
|
$f = (isset($ref['prod'])) ? $ref['prod'] : $ref['dev'];
|
||||||
|
echo $this->_tag('css', $f, FALSE, $media);
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for compressing/combining scripts
|
||||||
|
* @param Flag the asset type: css|js
|
||||||
|
* @param array of file references to be combined. Should contain arrays, as included in primary asset arrays: ('dev'=>$dev, 'prod'=>$prod)
|
||||||
|
* @param Filename of the file-to-be
|
||||||
|
*/
|
||||||
|
private function _combine($flag, $files, $filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
$file_data = '';
|
||||||
|
|
||||||
|
$path = ($flag == 'css') ? $this->style_path : $this->script_path;
|
||||||
|
$minify = ($flag == 'css') ? $this->minify_css : $this->minify_js;
|
||||||
|
|
||||||
|
|
||||||
|
foreach($files as $file):
|
||||||
|
|
||||||
|
if($minify):
|
||||||
|
|
||||||
|
$file_data .= $this->_minify( $flag, $file['dev'] ) . "\n";
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
$file_data .= file_get_contents( realpath($path.$file['dev']) ) ."\n";
|
||||||
|
|
||||||
|
endif;
|
||||||
|
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
$this->_cache( $filename, $file_data );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for minifying assets
|
||||||
|
* @param Flag the asset type: css|js
|
||||||
|
* @param Contents to be minified
|
||||||
|
*/
|
||||||
|
private function _minify($flag, $file_ref)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch($flag){
|
||||||
|
|
||||||
|
case 'js':
|
||||||
|
|
||||||
|
$this->CI->load->library('jsmin');
|
||||||
|
|
||||||
|
$contents = file_get_contents( realpath($this->script_path.$file_ref) );
|
||||||
|
return $this->CI->jsmin->minify($contents);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'css':
|
||||||
|
|
||||||
|
$this->CI->load->library('cssmin');
|
||||||
|
$this->CI->cssmin->config(array('relativePath'=>$this->style_uri));
|
||||||
|
|
||||||
|
$contents = file_get_contents( realpath($this->style_path.$file_ref) );
|
||||||
|
return $this->CI->cssmin->minify($contents);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for writing cache files
|
||||||
|
* @param filename of the new file
|
||||||
|
* @param Contents of the new file
|
||||||
|
*/
|
||||||
|
private function _cache($filename, $file_data)
|
||||||
|
{
|
||||||
|
$filepath = $this->cache_path . $filename;
|
||||||
|
//change ernscht: $filepath = realpath($this->cache_path . $filename);
|
||||||
|
file_put_contents( $filepath, $file_data );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for making tag strings
|
||||||
|
* @param flag for type: css|js
|
||||||
|
* @param Reference of file.
|
||||||
|
* @param Flag for cache dir. Defaults to FALSE.
|
||||||
|
* @param Media type for the tag. Only applies to CSS links. defaults to 'screen'
|
||||||
|
*/
|
||||||
|
private function _tag($flag, $ref, $cache = FALSE, $media = 'screen')
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
switch($flag){
|
||||||
|
|
||||||
|
case 'css':
|
||||||
|
|
||||||
|
$dir = ($cache) ? $this->cache_uri : $this->style_uri;
|
||||||
|
|
||||||
|
echo '<link type="text/css" rel="stylesheet" href="'.$dir.$ref.'" media="'.$media.'" />'."\r\n";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'js':
|
||||||
|
|
||||||
|
$dir = ($cache) ? $this->cache_uri : $this->script_uri;
|
||||||
|
|
||||||
|
echo '<script type="text/javascript" src="'.$dir.$ref.'"></script>'."\r\n";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function used to clear the asset cache. If no flag is set, both CSS and JS will be emptied.
|
||||||
|
* @param Flag the asset type: css|js|both
|
||||||
|
*/
|
||||||
|
public function empty_cache($flag)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->CI->load->helper('file');
|
||||||
|
|
||||||
|
$files = get_filenames($this->cache_path);
|
||||||
|
|
||||||
|
switch($flag){
|
||||||
|
|
||||||
|
case 'js':
|
||||||
|
case 'css':
|
||||||
|
|
||||||
|
foreach( $files as $file ){
|
||||||
|
|
||||||
|
$ext = substr( strrchr( $file, '.' ), 1 );
|
||||||
|
|
||||||
|
if ( $ext == $flag ) {
|
||||||
|
|
||||||
|
unlink( $this->cache_path . $file );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
foreach( $files as $file ){
|
||||||
|
|
||||||
|
$ext = substr( strrchr( $file, '.' ), 1 );
|
||||||
|
|
||||||
|
if ( $ext == 'js' || $ext == 'css') {
|
||||||
|
|
||||||
|
unlink( $this->cache_path . $file );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
509
htdocs/application/libraries/cssmin.php
Normal file
509
htdocs/application/libraries/cssmin.php
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CodeIgniter Port of 'Minify_CSS' CSS Compression Library from Minify ( http://code.google.com/p/minify/ )
|
||||||
|
*
|
||||||
|
* Minifies CSS, preserving comments as directed. Note: This port moves the Minify_CommentPreserver
|
||||||
|
* class into this file, and adds a simple meta class to access the normal minify_css class.
|
||||||
|
*
|
||||||
|
* @author Tony Dewan <tony@tonydewan.com>
|
||||||
|
* @version 1.1 (2009-01-28)
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD license, as per the original Minify_CSS class
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================================
|
||||||
|
USAGE
|
||||||
|
===============================================================================================
|
||||||
|
|
||||||
|
Load the library as normal:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$this->load->library('cssmin');
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Minify a string like so:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$this->cssmin->minify( file_get_contents('styles.css') );
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
There are two options:
|
||||||
|
|
||||||
|
'preserveComments'
|
||||||
|
Boolean flag for preserving comments. Only comments starting with /*! are preserved.
|
||||||
|
Defaults to true.
|
||||||
|
|
||||||
|
'relativePath'
|
||||||
|
String that will be prepended to all relative URIs in import/url declarations.
|
||||||
|
Defaults to null.
|
||||||
|
|
||||||
|
|
||||||
|
The options can either be set globally using the config function:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$cssmin_options = array(
|
||||||
|
'preserveComments'=> TRUE,
|
||||||
|
'relativePath'=> 'http://www.example.com/styles/images/'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->cssmin->config($cssmin_options);
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Or on individual calls to the minify function:
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
$this->cssmin->minify( $string, FALSE, $path );
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE: Global settings override settings in individual calls.
|
||||||
|
===============================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
class cssmin {
|
||||||
|
|
||||||
|
public function cssmin()
|
||||||
|
{
|
||||||
|
log_message('debug', 'CSS Minification library initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function config($config)
|
||||||
|
{
|
||||||
|
foreach ($config as $key => $value)
|
||||||
|
{
|
||||||
|
$this->$key = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function minify($css, $preserveComments = TRUE, $relativePath = null)
|
||||||
|
{
|
||||||
|
$c = ( isset($this->preserveComments) ) ? $this->preserveComments : $preserveComments;
|
||||||
|
$p = ( isset($this->relativePath) ) ? $this->relativePath : $relativePath;
|
||||||
|
|
||||||
|
$min = new Minify_CSS();
|
||||||
|
return $min->minify($css, array('preserveComments'=> $c, 'prependRelativePath' => $p));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Minify_CSS
|
||||||
|
* @package Minify
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compress CSS
|
||||||
|
*
|
||||||
|
* This is a heavy regex-based removal of whitespace, unnecessary
|
||||||
|
* comments and tokens, and some CSS value minimization, where practical.
|
||||||
|
* Many steps have been taken to avoid breaking comment-based hacks,
|
||||||
|
* including the ie5/mac filter (and its inversion), but expect tricky
|
||||||
|
* hacks involving comment tokens in 'content' value strings to break
|
||||||
|
* minimization badly. A test suite is available.
|
||||||
|
*
|
||||||
|
* @package Minify
|
||||||
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
|
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
||||||
|
*/
|
||||||
|
class Minify_CSS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines which class to call as part of callbacks, change this
|
||||||
|
* if you extend Minify_CSS
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $className = 'Minify_CSS';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify a CSS string
|
||||||
|
*
|
||||||
|
* @param string $css
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* 'prependRelativePath': (default null) if given, this string will be
|
||||||
|
* prepended to all relative URIs in import/url declarations
|
||||||
|
*
|
||||||
|
* 'currentDir': (default null) if given, this is assumed to be the
|
||||||
|
* directory of the current CSS file. Using this, minify will rewrite
|
||||||
|
* all relative URIs in import/url declarations to correctly point to
|
||||||
|
* the desired files. For this to work, the files *must* exist and be
|
||||||
|
* visible by the PHP process.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function minify($css, $options = array())
|
||||||
|
{
|
||||||
|
if (isset($options['preserveComments'])
|
||||||
|
&& !$options['preserveComments']) {
|
||||||
|
return self::_minify($css, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive calls don't preserve comments
|
||||||
|
$options['preserveComments'] = false;
|
||||||
|
return Minify_CommentPreserver::process(
|
||||||
|
$css
|
||||||
|
,array(self::$className, 'minify')
|
||||||
|
,array($options)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minify a CSS string
|
||||||
|
*
|
||||||
|
* @param string $css
|
||||||
|
*
|
||||||
|
* @param array $options To enable URL rewriting, set the value
|
||||||
|
* for key 'prependRelativePath'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function _minify($css, $options)
|
||||||
|
{
|
||||||
|
$css = str_replace("\r\n", "\n", $css);
|
||||||
|
|
||||||
|
// preserve empty comment after '>'
|
||||||
|
// http://www.webdevout.net/css-hacks#in_css-selectors
|
||||||
|
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
|
||||||
|
|
||||||
|
// preserve empty comment between property and value
|
||||||
|
// http://css-discuss.incutio.com/?page=BoxModelHack
|
||||||
|
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
|
||||||
|
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
||||||
|
|
||||||
|
// apply callback to all valid comments (and strip out surrounding ws
|
||||||
|
self::$_inHack = false;
|
||||||
|
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
||||||
|
,array(self::$className, '_commentCB'), $css);
|
||||||
|
|
||||||
|
// remove ws around { } and last semicolon in declaration block
|
||||||
|
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
||||||
|
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
|
||||||
|
|
||||||
|
// remove ws surrounding semicolons
|
||||||
|
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
||||||
|
|
||||||
|
// remove ws around urls
|
||||||
|
$css = preg_replace('/
|
||||||
|
url\\( # url(
|
||||||
|
\\s*
|
||||||
|
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
||||||
|
\\s*
|
||||||
|
\\) # )
|
||||||
|
/x', 'url($1)', $css);
|
||||||
|
|
||||||
|
// remove ws between rules and colons
|
||||||
|
$css = preg_replace('/
|
||||||
|
\\s*
|
||||||
|
([{;]) # 1 = beginning of block or rule separator
|
||||||
|
\\s*
|
||||||
|
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
|
||||||
|
\\s*
|
||||||
|
:
|
||||||
|
\\s*
|
||||||
|
(\\b|[#\'"]) # 3 = first character of a value
|
||||||
|
/x', '$1$2:$3', $css);
|
||||||
|
|
||||||
|
// remove ws in selectors
|
||||||
|
$css = preg_replace_callback('/
|
||||||
|
(?: # non-capture
|
||||||
|
\\s*
|
||||||
|
[^~>+,\\s]+ # selector part
|
||||||
|
\\s*
|
||||||
|
[,>+~] # combinators
|
||||||
|
)+
|
||||||
|
\\s*
|
||||||
|
[^~>+,\\s]+ # selector part
|
||||||
|
{ # open declaration block
|
||||||
|
/x'
|
||||||
|
,array(self::$className, '_selectorsCB'), $css);
|
||||||
|
|
||||||
|
// minimize hex colors
|
||||||
|
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
||||||
|
, '$1#$2$3$4$5', $css);
|
||||||
|
|
||||||
|
// remove spaces between font families
|
||||||
|
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
||||||
|
,array(self::$className, '_fontFamilyCB'), $css);
|
||||||
|
|
||||||
|
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
||||||
|
|
||||||
|
// replace any ws involving newlines with a single newline
|
||||||
|
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
||||||
|
|
||||||
|
// separate common descendent selectors w/ newlines (to limit line lengths)
|
||||||
|
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
||||||
|
|
||||||
|
// Use newline after 1st numeric value (to limit line lengths).
|
||||||
|
$css = preg_replace('/
|
||||||
|
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
||||||
|
\\s+
|
||||||
|
/x'
|
||||||
|
,"$1\n", $css);
|
||||||
|
|
||||||
|
$rewrite = false;
|
||||||
|
if (isset($options['prependRelativePath'])) {
|
||||||
|
self::$_tempPrepend = $options['prependRelativePath'];
|
||||||
|
$rewrite = true;
|
||||||
|
} elseif (isset($options['currentDir'])) {
|
||||||
|
self::$_tempCurrentDir = $options['currentDir'];
|
||||||
|
$rewrite = true;
|
||||||
|
}
|
||||||
|
if ($rewrite) {
|
||||||
|
$css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
|
||||||
|
,array(self::$className, '_urlCB'), $css);
|
||||||
|
$css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
|
||||||
|
,array(self::$className, '_urlCB'), $css);
|
||||||
|
}
|
||||||
|
self::$_tempPrepend = self::$_tempCurrentDir = '';
|
||||||
|
return trim($css);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace what looks like a set of selectors
|
||||||
|
*
|
||||||
|
* @param array $m regex matches
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function _selectorsCB($m)
|
||||||
|
{
|
||||||
|
// remove ws around the combinators
|
||||||
|
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool Are we "in" a hack?
|
||||||
|
*
|
||||||
|
* I.e. are some browsers targetted until the next comment?
|
||||||
|
*/
|
||||||
|
protected static $_inHack = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string string to be prepended to relative URIs
|
||||||
|
*/
|
||||||
|
protected static $_tempPrepend = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string directory of this stylesheet for rewriting purposes
|
||||||
|
*/
|
||||||
|
protected static $_tempCurrentDir = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a comment and return a replacement
|
||||||
|
*
|
||||||
|
* @param array $m regex matches
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function _commentCB($m)
|
||||||
|
{
|
||||||
|
$m = $m[1];
|
||||||
|
// $m is the comment content w/o the surrounding tokens,
|
||||||
|
// but the return value will replace the entire comment.
|
||||||
|
if ($m === 'keep') {
|
||||||
|
return '/**/';
|
||||||
|
}
|
||||||
|
if ($m === '" "') {
|
||||||
|
// component of http://tantek.com/CSS/Examples/midpass.html
|
||||||
|
return '/*" "*/';
|
||||||
|
}
|
||||||
|
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
||||||
|
// component of http://tantek.com/CSS/Examples/midpass.html
|
||||||
|
return '/*";}}/* */';
|
||||||
|
}
|
||||||
|
if (self::$_inHack) {
|
||||||
|
// inversion: feeding only to one browser
|
||||||
|
if (preg_match('@
|
||||||
|
^/ # comment started like /*/
|
||||||
|
\\s*
|
||||||
|
(\\S[\\s\\S]+?) # has at least some non-ws content
|
||||||
|
\\s*
|
||||||
|
/\\* # ends like /*/ or /**/
|
||||||
|
@x', $m, $n)) {
|
||||||
|
// end hack mode after this comment, but preserve the hack and comment content
|
||||||
|
self::$_inHack = false;
|
||||||
|
return "/*/{$n[1]}/**/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (substr($m, -1) === '\\') { // comment ends like \*/
|
||||||
|
// begin hack mode and preserve hack
|
||||||
|
self::$_inHack = true;
|
||||||
|
return '/*\\*/';
|
||||||
|
}
|
||||||
|
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
||||||
|
// begin hack mode and preserve hack
|
||||||
|
self::$_inHack = true;
|
||||||
|
return '/*/*/';
|
||||||
|
}
|
||||||
|
if (self::$_inHack) {
|
||||||
|
// a regular comment ends hack mode but should be preserved
|
||||||
|
self::$_inHack = false;
|
||||||
|
return '/**/';
|
||||||
|
}
|
||||||
|
return ''; // remove all other comments
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function _urlCB($m)
|
||||||
|
{
|
||||||
|
$isImport = (0 === strpos($m[0], '@import'));
|
||||||
|
if ($isImport) {
|
||||||
|
$quote = $m[1];
|
||||||
|
$url = $m[2];
|
||||||
|
} else {
|
||||||
|
// is url()
|
||||||
|
// $m[1] is either quoted or not
|
||||||
|
$quote = ($m[1][0] === "'" || $m[1][0] === '"')
|
||||||
|
? $m[1][0]
|
||||||
|
: '';
|
||||||
|
$url = ($quote === '')
|
||||||
|
? $m[1]
|
||||||
|
: substr($m[1], 1, strlen($m[1]) - 2);
|
||||||
|
}
|
||||||
|
if ('/' !== $url[0]) {
|
||||||
|
if (strpos($url, '//') > 0) {
|
||||||
|
// probably starts with protocol, do not alter
|
||||||
|
} else {
|
||||||
|
// relative URI, rewrite!
|
||||||
|
if (self::$_tempPrepend) {
|
||||||
|
$url = self::$_tempPrepend . $url;
|
||||||
|
} else {
|
||||||
|
// rewrite absolute url from scratch!
|
||||||
|
// prepend path with current dir separator (OS-independent)
|
||||||
|
$path = self::$_tempCurrentDir
|
||||||
|
. DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR);
|
||||||
|
// strip doc root
|
||||||
|
$path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT'])));
|
||||||
|
// fix to absolute URL
|
||||||
|
$url = strtr($path, DIRECTORY_SEPARATOR, '/');
|
||||||
|
// remove /./ and /../ where possible
|
||||||
|
$url = str_replace('/./', '/', $url);
|
||||||
|
// inspired by patch from Oleg Cherniy
|
||||||
|
do {
|
||||||
|
$url = preg_replace('@/[^/]+/\\.\\./@', '/', $url, -1, $changed);
|
||||||
|
} while ($changed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $isImport
|
||||||
|
? "@import {$quote}{$url}{$quote}"
|
||||||
|
: "url({$quote}{$url}{$quote})";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a font-family listing and return a replacement
|
||||||
|
*
|
||||||
|
* @param array $m regex matches
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function _fontFamilyCB($m)
|
||||||
|
{
|
||||||
|
$m[1] = preg_replace('/
|
||||||
|
\\s*
|
||||||
|
(
|
||||||
|
"[^"]+" # 1 = family in double qutoes
|
||||||
|
|\'[^\']+\' # or 1 = family in single quotes
|
||||||
|
|[\\w\\-]+ # or 1 = unquoted family
|
||||||
|
)
|
||||||
|
\\s*
|
||||||
|
/x', '$1', $m[1]);
|
||||||
|
return 'font-family:' . $m[1] . $m[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Minify_CommentPreserver
|
||||||
|
* @package Minify
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a string in pieces preserving C-style comments that begin with "/*!"
|
||||||
|
*
|
||||||
|
* @package Minify
|
||||||
|
* @author Stephen Clay <steve@mrclay.org>
|
||||||
|
*/
|
||||||
|
class Minify_CommentPreserver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String to be prepended to each preserved comment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $prepend = "\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String to be appended to each preserved comment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $append = "\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a string outside of C-style comments that begin with "/*!"
|
||||||
|
*
|
||||||
|
* On each non-empty string outside these comments, the given processor
|
||||||
|
* function will be called. The first "!" will be removed from the
|
||||||
|
* preserved comments, and the comments will be surrounded by
|
||||||
|
* Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @param callback $processor function
|
||||||
|
* @param array $args array of extra arguments to pass to the processor
|
||||||
|
* function (default = array())
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function process($content, $processor, $args = array())
|
||||||
|
{
|
||||||
|
$ret = '';
|
||||||
|
while (true) {
|
||||||
|
list($beforeComment, $comment, $afterComment) = self::_nextComment($content);
|
||||||
|
if ('' !== $beforeComment) {
|
||||||
|
$callArgs = $args;
|
||||||
|
array_unshift($callArgs, $beforeComment);
|
||||||
|
$ret .= call_user_func_array($processor, $callArgs);
|
||||||
|
}
|
||||||
|
if (false === $comment) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$ret .= $comment;
|
||||||
|
$content = $afterComment;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract comments that YUI Compressor preserves.
|
||||||
|
*
|
||||||
|
* @param string $in input
|
||||||
|
*
|
||||||
|
* @return array 3 elements are returned. If a YUI comment is found, the
|
||||||
|
* 2nd element is the comment and the 1st and 2nd are the surrounding
|
||||||
|
* strings. If no comment is found, the entire string is returned as the
|
||||||
|
* 1st element and the other two are false.
|
||||||
|
*/
|
||||||
|
private static function _nextComment($in)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
false === ($start = strpos($in, '/*!'))
|
||||||
|
|| false === ($end = strpos($in, '*/', $start + 3))
|
||||||
|
) {
|
||||||
|
return array($in, false, false);
|
||||||
|
}
|
||||||
|
$ret = array(
|
||||||
|
substr($in, 0, $start)
|
||||||
|
,self::$prepend . '/*' . substr($in, $start + 3, $end - $start - 1) . self::$append
|
||||||
|
);
|
||||||
|
$endChars = (strlen($in) - $end - 2);
|
||||||
|
$ret[] = (0 === $endChars)
|
||||||
|
? ''
|
||||||
|
: substr($in, -$endChars);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
309
htdocs/application/libraries/jsmin.php
Normal file
309
htdocs/application/libraries/jsmin.php
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CodeIgniter Port of JSMin Library
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Minifies JavaScript
|
||||||
|
*
|
||||||
|
* @package CodeIgniter
|
||||||
|
* @subpackage Libraries
|
||||||
|
* @category Javascript Minification
|
||||||
|
* @author Tony Dewan <tonydewan.com>
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* string as output.
|
||||||
|
*
|
||||||
|
* PHP 5 or higher is required.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use this version of the library under the
|
||||||
|
* same terms as jsmin.c, which has the following license:
|
||||||
|
*
|
||||||
|
* --
|
||||||
|
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* The Software shall be used for Good, not Evil.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
* --
|
||||||
|
*
|
||||||
|
* @package JSMin
|
||||||
|
* @author Ryan Grove <ryan@wonko.com>
|
||||||
|
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
||||||
|
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
||||||
|
* @copyright 2009 Tony Dewan <tony@tonydewan.com> (CodeIgniter port)
|
||||||
|
* @license http://opensource.org/licenses/mit-license.php MIT License
|
||||||
|
* @version 1.1.1 (2008-03-02)
|
||||||
|
* @link http://code.google.com/p/jsmin-php/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class JSMin {
|
||||||
|
const ORD_LF = 10;
|
||||||
|
const ORD_SPACE = 32;
|
||||||
|
|
||||||
|
protected $a = '';
|
||||||
|
protected $b = '';
|
||||||
|
protected $input = '';
|
||||||
|
protected $inputIndex = 0;
|
||||||
|
protected $inputLength = 0;
|
||||||
|
protected $lookAhead = null;
|
||||||
|
protected $output = '';
|
||||||
|
|
||||||
|
// -- Public Static Methods --------------------------------------------------
|
||||||
|
|
||||||
|
public static function minify($js) {
|
||||||
|
$jsmin = new JSMin($js);
|
||||||
|
return $jsmin->min();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Public Instance Methods ------------------------------------------------
|
||||||
|
|
||||||
|
public function __construct($input = '') {
|
||||||
|
|
||||||
|
log_message('debug', 'JSMin library initialized.');
|
||||||
|
|
||||||
|
$this->input = str_replace("\r\n", "\n", $input);
|
||||||
|
$this->inputLength = strlen($this->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Protected Instance Methods ---------------------------------------------
|
||||||
|
|
||||||
|
protected function action($d) {
|
||||||
|
switch($d) {
|
||||||
|
case 1:
|
||||||
|
$this->output .= $this->a;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
$this->a = $this->b;
|
||||||
|
|
||||||
|
if ($this->a === "'" || $this->a === '"') {
|
||||||
|
for (;;) {
|
||||||
|
$this->output .= $this->a;
|
||||||
|
$this->a = $this->get();
|
||||||
|
|
||||||
|
if ($this->a === $this->b) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ord($this->a) <= self::ORD_LF) {
|
||||||
|
throw new JSMinException('Unterminated string literal.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->a === '\\') {
|
||||||
|
$this->output .= $this->a;
|
||||||
|
$this->a = $this->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
$this->b = $this->next();
|
||||||
|
|
||||||
|
if ($this->b === '/' && (
|
||||||
|
$this->a === '(' || $this->a === ',' || $this->a === '=' ||
|
||||||
|
$this->a === ':' || $this->a === '[' || $this->a === '!' ||
|
||||||
|
$this->a === '&' || $this->a === '|' || $this->a === '?')) {
|
||||||
|
|
||||||
|
$this->output .= $this->a . $this->b;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
$this->a = $this->get();
|
||||||
|
|
||||||
|
if ($this->a === '/') {
|
||||||
|
break;
|
||||||
|
} elseif ($this->a === '\\') {
|
||||||
|
$this->output .= $this->a;
|
||||||
|
$this->a = $this->get();
|
||||||
|
} elseif (ord($this->a) <= self::ORD_LF) {
|
||||||
|
throw new JSMinException('Unterminated regular expression '.
|
||||||
|
'literal.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->output .= $this->a;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->b = $this->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function get() {
|
||||||
|
$c = $this->lookAhead;
|
||||||
|
$this->lookAhead = null;
|
||||||
|
|
||||||
|
if ($c === null) {
|
||||||
|
if ($this->inputIndex < $this->inputLength) {
|
||||||
|
$c = $this->input[$this->inputIndex];
|
||||||
|
$this->inputIndex += 1;
|
||||||
|
} else {
|
||||||
|
$c = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($c === "\r") {
|
||||||
|
return "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isAlphaNum($c) {
|
||||||
|
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function min() {
|
||||||
|
|
||||||
|
$this->a = "\n";
|
||||||
|
$this->action(3);
|
||||||
|
|
||||||
|
while ($this->a !== null) {
|
||||||
|
switch ($this->a) {
|
||||||
|
case ' ':
|
||||||
|
if ($this->isAlphaNum($this->b)) {
|
||||||
|
$this->action(1);
|
||||||
|
} else {
|
||||||
|
$this->action(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "\n":
|
||||||
|
switch ($this->b) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
case '(':
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
$this->action(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
$this->action(3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ($this->isAlphaNum($this->b)) {
|
||||||
|
$this->action(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->action(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch ($this->b) {
|
||||||
|
case ' ':
|
||||||
|
if ($this->isAlphaNum($this->a)) {
|
||||||
|
$this->action(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->action(3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "\n":
|
||||||
|
switch ($this->a) {
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
case ')':
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '"':
|
||||||
|
case "'":
|
||||||
|
$this->action(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ($this->isAlphaNum($this->a)) {
|
||||||
|
$this->action(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->action(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->action(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->output;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function next() {
|
||||||
|
$c = $this->get();
|
||||||
|
|
||||||
|
if ($c === '/') {
|
||||||
|
switch($this->peek()) {
|
||||||
|
case '/':
|
||||||
|
for (;;) {
|
||||||
|
$c = $this->get();
|
||||||
|
|
||||||
|
if (ord($c) <= self::ORD_LF) {
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
$this->get();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
switch($this->get()) {
|
||||||
|
case '*':
|
||||||
|
if ($this->peek() === '/') {
|
||||||
|
$this->get();
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case null:
|
||||||
|
throw new JSMinException('Unterminated comment.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function peek() {
|
||||||
|
$this->lookAhead = $this->get();
|
||||||
|
return $this->lookAhead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Exceptions ---------------------------------------------------------------
|
||||||
|
class JSMinException extends Exception {}
|
||||||
|
?>
|
Loading…
x
Reference in New Issue
Block a user