Showing preview only (339K chars total). Download the full file or copy to clipboard to get everything.
Repository: slav123/CodeIgniter-minify
Branch: master
Commit: 76c03757bd04
Files: 33
Total size: 325.2 KB
Directory structure:
gitextract_uq89ngc_/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── application/
│ ├── config/
│ │ ├── autoload.php
│ │ ├── config.php
│ │ ├── constants.php
│ │ ├── mimes.php
│ │ ├── minify.php
│ │ └── routes.php
│ ├── controllers/
│ │ ├── index.html
│ │ └── welcome.php
│ ├── errors/
│ │ ├── error_404.php
│ │ ├── error_db.php
│ │ ├── error_general.php
│ │ ├── error_php.php
│ │ └── index.html
│ ├── libraries/
│ │ ├── Minify.php
│ │ └── minify/
│ │ ├── JSMin.php
│ │ ├── JSMinPlus.php
│ │ ├── cssmin-v3.0.1.php
│ │ └── cssminify.php
│ └── views/
│ ├── index.html
│ └── welcome_message.php
├── assets/
│ ├── css/
│ │ ├── browser-specific.css
│ │ └── style.css
│ └── js/
│ ├── helpers.js
│ └── jqModal.js
├── composer.json
├── index.php
├── phpunit.xml
└── tests/
├── MinifyTest.php
└── bootstrap.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
================================================
FILE: .travis.yml
================================================
language: php
php:
- 5.6
- 7.0
- 7.1
- 7.2
before_script:
- travis_retry composer install --dev
================================================
FILE: LICENSE
================================================
Copyright (c) 2015 Slawomir Jasinski
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 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.
================================================
FILE: README.md
================================================
# CodeIgniter - minify [](https://travis-ci.org/slav123/CodeIgniter-minify)
Simple CodeIgniter library to compress **CSS and JavaScript** files on the fly.
Library is based on few other scripts like <http://code.google.com/p/minify/>
or <https://code.google.com/p/cssmin> to minify CSS and it uses
[Google Closure compiler](https://developers.google.com/closure/compiler/) to
compress JavaScript
## Installation
Just put `Minify.php` file in libraries path, and create `minify.php` config file on config directory.
## Using the library
#### Configure the library:
All directories needs to be writable. Next you can set your own values for config file.
```php
// enable/disable library (default value: 'TRUE')
$config['enabled'] = TRUE;
// output path where the compiled files will be stored (default value: 'assets')
$config['assets_dir'] = 'assets';
// optional - path where the compiled css files will be stored (default value: '' - for backward compatibility)
$config['assets_dir_css'] = '';
// optional - path where the compiled js files will be stored (default value: '' - for backward compatibility)
$config['assets_dir_js'] = '';
// optional - handy when your assets are in a different domain than main website (default value: '')
$config['base_url'] = '';
// where to look for css files (default value: 'assets/css')
$config['css_dir'] = 'assets/css';
// where to look for js files (default value: 'assets/js')
$config['js_dir'] = 'assets/js';
// default file name for css (default value: 'style.css')
$config['css_file'] = 'styles.css';
// default file name for js (default value: 'scripts.js')
$config['js_file'] = 'scripts.js';
// default tag for css (default value: '<link href="%s" rel="stylesheet" type="text/css" />')
$config['css_tag'] = '<link href="%s" rel="stylesheet" type="text/css" />';
// default tag for js (default value: '<script type="text/javascript" src="%s"></script>')
$config['js_tag'] = '<script type="text/javascript" src="%s"></script>';
// use html tags on output and return as a string (default value: 'TRUE')
// if html_tags === FALSE - array with links to assets is returned
$config['html_tags'] = TRUE;
// use automatic file names (default value: 'FALSE')
$config['auto_names'] = FALSE;
// use to enable versioning your assets (default value: 'FALSE')
$config['versioning'] = FALSE;
// automatically deploy when there are any changes in files (default value: 'TRUE')
$config['deploy_on_change'] = TRUE;
// compress files or not (default value: 'TRUE')
$config['compress'] = TRUE;
// compression engine setting (default values: 'minify' and 'closurecompiler')
$config['compression_engine'] = array(
'css' => 'minify', // minify || cssmin
'js' => 'closurecompiler' // closurecompiler || jsmin || jsminplus
);
// when you use closurecompiler as compression engine you can choose compression level (default value: 'SIMPLE_OPTIMIZATIONS')
// avaliable options: "WHITESPACE_ONLY", "SIMPLE_OPTIMIZATIONS" or "ADVANCED_OPTIMIZATIONS"
$config['closurecompiler']['compilation_level'] = 'SIMPLE_OPTIMIZATIONS';
```
#### Available engines
* CSS - `minify` or `cssmin` - both of them are local, just try out which one is better for you,
* JS - `closurecompiler` makes API call to external server, it's slower then regular inline engine, but it's super efficient with compression, `jsmin` and `jsminplus` are local
#### Run the library
In the controller:
```php
// load the library
$this->load->library('minify');
// or load and assign custom config (will override values from config file)
$this->load->library('minify', $config);
// by default library's functionality is enabled, but in some cases you would like to return
// assets without compilation and compression - when debugging or in development environment
// in that case you can use config variable to disable it
$config['enabled'] = FALSE;
// or
$this->minify->enabled = FALSE;
```
In controller or view:
```php
// set css files - you can use array or string with commas
// when using this method, you replaces previously added files
$this->minify->css(array('reset.css', 'style.css', 'tinybox.css'));
$this->minify->css('reset.css, style.css, tinybox.css');
// add css files - you can use array or string with commas
// when using this method, you're adding new files to previous ones
$this->minify->add_css(array('reset.css'))->add_css('style.css, tinybox.css');
// set js files - you can use array or string with commas
// when using this method, you replaces previously added files
$this->minify->js(array('html5.js', 'main.js'));
$this->minify->js('html5.js, main.js');
// set js files - you can use array or string with commas
// when using this method, you're adding new files to previous ones
$this->minify->add_js(array('html5.js'))->add_js('main.js');
// with methods: css(), js(), add_css() and add_js()
// you can pass group name for given files as second parameter
// default group name is "default"
$this->minify->js(array('html5.js', 'main.js'), 'extra');
$this->minify->add_css('style.css, tinybox.css', 'another');
// deploy css
// bool argument for rebuild css - false means skip rebuilding (default value: TRUE)
echo $this->minify->deploy_css(TRUE);
//Output: '<link href="path-to-compiled-css" rel="stylesheet" type="text/css" />'
// deploy js
// bool argument for rebuild js - false means skip rebuilding (default value: FALSE)
echo $this->minify->deploy_js();
//Output: '<script type="text/javascript" src="path-to-compiled-js"></script>'.
// you can use automatic file name for particular deploy when you have $config['auto_names'] set to FALSE
// to do so, you must set file name to 'auto' during deploy
echo $this->minify->deploy_css(TRUE, 'auto');
echo $this->minify->deploy_js(TRUE, 'auto');
//Output: '<link href="path-to-compiled-css-with-auto-file-name" rel="stylesheet" type="text/css" />'
//Output: '<script type="text/javascript" src="path-to-compiled-js-with-auto-file-name"></script>'.
// you can deploy only particular group of files
echo $this->minify->deploy_css(TRUE, NULL, 'another');
echo $this->minify->deploy_js(TRUE, 'auto', 'extra');
//Output: '<link href="path-to-compiled-css-group" rel="stylesheet" type="text/css" />'
//Output: '<script type="text/javascript" src="path-to-compiled-js-group-with-auto-file-name"></script>'.
// you can enable versioning your your assets via config variable `$config['versioning']` or manually
$this->minify->versioning = TRUE;
echo $this->minify->deploy_js();
//Output: '<script type="text/javascript" src="path-to-compiled.js?v=hash-here"></script>'.
```
## Changelog
01 Mar 2021
* comments fixing
* config checks only when deploy
26 Jul 2019
* added option to manually change version number for assets (thanks [screamingjungle](https://github.com/screamingjungle))
11 Feb 2019
* fixed an issue where not all config variables from the constructor were taken into account
02 Feb 2019
* new config variable to allow of use a custom domain/subdomain for your assets: `$config['base_url']` (default to '')
25 Jul 2018
* new config variable to disable default behavior - deploy when any file is changed: `$config['change_on_deploy']` (default to TRUE)
24 Jul 2018
* handle errors for closurecompiler engine
26 Feb 2018
* new config variable to determine if we want to return html tags (as string result) or only links to the assets (as array): `$config['html_tags']` (default to TRUE)
* we can now specify what HTML tag will be used for CSS and JS through `$config['css_tag']` and `$config['js_tag']`
17 Jun 2017
* new config variable to enable versioning assets `$config['versioning']` (default to FALSE)
* new config variable to enable/disable library - useful for debugging: `$config['enabled']` (default to TRUE)
29 Dec 2016
* introduce option to save compiled css and js files in different folders - new config variables: `$config['assets_dir_css']` and `$config['assets_dir_js']`.
29 Apr 2015
* allow using automatic file name for particular deploy when you have `$config['auto_names']` set to `FALSE`
* documentation update
20 Apr 2015
* Closure compiler configuration extracted to config file
22 Mar 2015
* method chaining support
* new methods: `add_css()` and `add_js()` - gives ability for adding files to existing files arrays
* added support to run library with custom array config, assigned as second parameter (during loading) `$this->load->library('minify', $config);`
* added support for *groups* in files arrays - as second (optional) parameter in methods: `css()`, `js()`, `add_css()` and `add_js()` (i.e. `$this->minify->js(array('script.js'), 'extra');` - default group name is *default*)
* added support for strings as first parameter in methods: `css()`, `js()`, `add_css()` and `add_js()` (i.e. `$this->minify->js('first.js, second.js');`)
* added support for automatic files names: `$config['auto_names'] = TRUE;`
* external compression classes moved to *minify* folder
* unit tests for new features
10 Feb 2015
* Unit testing
09 Feb 2015
* 2 new engines to compress JS files
* documentation update
13 Oct 2014
* changed way of generating JS file
14 July 2014
* small bug fixes in JS compression
4 July 2014
* sample JavaScript files to see how it works
* detection of empty JS file causes force refresh
23 May 2014
* you can chose your compression engine library in config file (CSS only)
* speed optimisations
* force CSS rewrite using $this->minify->deploy_css(TRUE);
11 Mar 2014
* completely rewrite CSS parser - uses cssmin compress CSS,
* detects file modification time no longer force rewrites,
* example usage now included withing app
## Any questions?
Report theme here: <https://github.com/slav123/CodeIgniter-minify/issues>
================================================
FILE: application/config/autoload.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| AUTO-LOADER
| -------------------------------------------------------------------
| This file specifies which systems should be loaded by default.
|
| In order to keep the framework as light-weight as possible only the
| absolute minimal resources are loaded by default. For example,
| the database is not connected to automatically since no assumption
| is made regarding whether you intend to use it. This file lets
| you globally define which systems you would like loaded with every
| request.
|
| -------------------------------------------------------------------
| Instructions
| -------------------------------------------------------------------
|
| These are the things you can load automatically:
|
| 1. Packages
| 2. Libraries
| 3. Helper files
| 4. Custom config files
| 5. Language files
| 6. Models
|
*/
/*
| -------------------------------------------------------------------
| Auto-load Packges
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
|
*/
$autoload['packages'] = array();
/*
| -------------------------------------------------------------------
| Auto-load Libraries
| -------------------------------------------------------------------
| These are the classes located in the system/libraries folder
| or in your application/libraries folder.
|
| Prototype:
|
| $autoload['libraries'] = array('database', 'session', 'xmlrpc');
*/
$autoload['libraries'] = array();
/*
| -------------------------------------------------------------------
| Auto-load Helper Files
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['helper'] = array('url', 'file');
*/
$autoload['helper'] = array();
/*
| -------------------------------------------------------------------
| Auto-load Config files
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['config'] = array('config1', 'config2');
|
| NOTE: This item is intended for use ONLY if you have created custom
| config files. Otherwise, leave it blank.
|
*/
$autoload['config'] = array();
/*
| -------------------------------------------------------------------
| Auto-load Language files
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['language'] = array('lang1', 'lang2');
|
| NOTE: Do not include the "_lang" part of your file. For example
| "codeigniter_lang.php" would be referenced as array('codeigniter');
|
*/
$autoload['language'] = array();
/*
| -------------------------------------------------------------------
| Auto-load Models
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['model'] = array('model1', 'model2');
|
*/
$autoload['model'] = array();
/* End of file autoload.php */
/* Location: ./application/config/autoload.php */
================================================
FILE: application/config/config.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
|--------------------------------------------------------------------------
| Base Site URL
|--------------------------------------------------------------------------
|
| URL to your CodeIgniter root. Typically this will be your base URL,
| WITH a trailing slash:
|
| http://example.com/
|
| If this is not set then CodeIgniter will guess the protocol, domain and
| path to your installation.
|
*/
$config['base_url'] = 'http://minify.localhost/';
/*
|--------------------------------------------------------------------------
| Index File
|--------------------------------------------------------------------------
|
| Typically this will be your index.php file, unless you've renamed it to
| something else. If you are using mod_rewrite to remove the page set this
| variable so that it is blank.
|
*/
$config['index_page'] = 'index.php';
/*
|--------------------------------------------------------------------------
| URI PROTOCOL
|--------------------------------------------------------------------------
|
| This item determines which server global should be used to retrieve the
| URI string. The default setting of 'AUTO' works for most servers.
| If your links do not seem to work, try one of the other delicious flavors:
|
| 'AUTO' Default - auto detects
| 'PATH_INFO' Uses the PATH_INFO
| 'QUERY_STRING' Uses the QUERY_STRING
| 'REQUEST_URI' Uses the REQUEST_URI
| 'ORIG_PATH_INFO' Uses the ORIG_PATH_INFO
|
*/
$config['uri_protocol'] = 'AUTO';
/*
|--------------------------------------------------------------------------
| URL suffix
|--------------------------------------------------------------------------
|
| This option allows you to add a suffix to all URLs generated by CodeIgniter.
| For more information please see the user guide:
|
| http://codeigniter.com/user_guide/general/urls.html
*/
$config['url_suffix'] = '';
/*
|--------------------------------------------------------------------------
| Default Language
|--------------------------------------------------------------------------
|
| This determines which set of language files should be used. Make sure
| there is an available translation if you intend to use something other
| than english.
|
*/
$config['language'] = 'english';
/*
|--------------------------------------------------------------------------
| Default Character Set
|--------------------------------------------------------------------------
|
| This determines which character set is used by default in various methods
| that require a character set to be provided.
|
*/
$config['charset'] = 'UTF-8';
/*
|--------------------------------------------------------------------------
| Enable/Disable System Hooks
|--------------------------------------------------------------------------
|
| If you would like to use the 'hooks' feature you must enable it by
| setting this variable to TRUE (boolean). See the user guide for details.
|
*/
$config['enable_hooks'] = FALSE;
/*
|--------------------------------------------------------------------------
| Class Extension Prefix
|--------------------------------------------------------------------------
|
| This item allows you to set the filename/classname prefix when extending
| native libraries. For more information please see the user guide:
|
| http://codeigniter.com/user_guide/general/core_classes.html
| http://codeigniter.com/user_guide/general/creating_libraries.html
|
*/
$config['subclass_prefix'] = 'MY_';
/*
|--------------------------------------------------------------------------
| Allowed URL Characters
|--------------------------------------------------------------------------
|
| This lets you specify with a regular expression which characters are permitted
| within your URLs. When someone tries to submit a URL with disallowed
| characters they will get a warning message.
|
| As a security measure you are STRONGLY encouraged to restrict URLs to
| as few characters as possible. By default only these are allowed: a-z 0-9~%.:_-
|
| Leave blank to allow all characters -- but only if you are insane.
|
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
*/
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
/*
|--------------------------------------------------------------------------
| Enable Query Strings
|--------------------------------------------------------------------------
|
| By default CodeIgniter uses search-engine friendly segment based URLs:
| example.com/who/what/where/
|
| By default CodeIgniter enables access to the $_GET array. If for some
| reason you would like to disable it, set 'allow_get_array' to FALSE.
|
| You can optionally enable standard query string based URLs:
| example.com?who=me&what=something&where=here
|
| Options are: TRUE or FALSE (boolean)
|
| The other items let you set the query string 'words' that will
| invoke your controllers and its functions:
| example.com/index.php?c=controller&m=function
|
| Please note that some of the helpers won't work as expected when
| this feature is enabled, since CodeIgniter is designed primarily to
| use segment based URLs.
|
*/
$config['allow_get_array'] = TRUE;
$config['enable_query_strings'] = FALSE;
$config['controller_trigger'] = 'c';
$config['function_trigger'] = 'm';
$config['directory_trigger'] = 'd'; // experimental not currently in use
/*
|--------------------------------------------------------------------------
| Error Logging Threshold
|--------------------------------------------------------------------------
|
| If you have enabled error logging, you can set an error threshold to
| determine what gets logged. Threshold options are:
| You can enable error logging by setting a threshold over zero. The
| threshold determines what gets logged. Threshold options are:
|
| 0 = Disables logging, Error logging TURNED OFF
| 1 = Error Messages (including PHP errors)
| 2 = Debug Messages
| 3 = Informational Messages
| 4 = All Messages
|
| For a live site you'll usually only enable Errors (1) to be logged otherwise
| your log files will fill up very fast.
|
*/
$config['log_threshold'] = 0;
/*
|--------------------------------------------------------------------------
| Error Logging Directory Path
|--------------------------------------------------------------------------
|
| Leave this BLANK unless you would like to set something other than the default
| application/logs/ folder. Use a full server path with trailing slash.
|
*/
$config['log_path'] = '';
/*
|--------------------------------------------------------------------------
| Date Format for Logs
|--------------------------------------------------------------------------
|
| Each item that is logged has an associated date. You can use PHP date
| codes to set your own date formatting
|
*/
$config['log_date_format'] = 'Y-m-d H:i:s';
/*
|--------------------------------------------------------------------------
| Cache Directory Path
|--------------------------------------------------------------------------
|
| Leave this BLANK unless you would like to set something other than the default
| system/cache/ folder. Use a full server path with trailing slash.
|
*/
$config['cache_path'] = '';
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| If you use the Encryption class or the Session class you
| MUST set an encryption key. See the user guide for info.
|
*/
$config['encryption_key'] = '74dpbs2r';
/*
|--------------------------------------------------------------------------
| Session Variables
|--------------------------------------------------------------------------
|
| 'sess_cookie_name' = the name you want for the cookie
| 'sess_expiration' = the number of SECONDS you want the session to last.
| by default sessions last 7200 seconds (two hours). Set to zero for no expiration.
| 'sess_expire_on_close' = Whether to cause the session to expire automatically
| when the browser window is closed
| 'sess_encrypt_cookie' = Whether to encrypt the cookie
| 'sess_use_database' = Whether to save the session data to a database
| 'sess_table_name' = The name of the session database table
| 'sess_match_ip' = Whether to match the user's IP address when reading the session data
| 'sess_match_useragent' = Whether to match the User Agent when reading the session data
| 'sess_time_to_update' = how many seconds between CI refreshing Session Information
|
*/
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 7200;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = FALSE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 300;
/*
|--------------------------------------------------------------------------
| Cookie Related Variables
|--------------------------------------------------------------------------
|
| 'cookie_prefix' = Set a prefix if you need to avoid collisions
| 'cookie_domain' = Set to .your-domain.com for site-wide cookies
| 'cookie_path' = Typically will be a forward slash
| 'cookie_secure' = Cookies will only be set if a secure HTTPS connection exists.
|
*/
$config['cookie_prefix'] = "";
$config['cookie_domain'] = "";
$config['cookie_path'] = "/";
$config['cookie_secure'] = FALSE;
/*
|--------------------------------------------------------------------------
| Global XSS Filtering
|--------------------------------------------------------------------------
|
| Determines whether the XSS filter is always active when GET, POST or
| COOKIE data is encountered
|
*/
$config['global_xss_filtering'] = FALSE;
/*
|--------------------------------------------------------------------------
| Cross Site Request Forgery
|--------------------------------------------------------------------------
| Enables a CSRF cookie token to be set. When set to TRUE, token will be
| checked on a submitted form. If you are accepting user data, it is strongly
| recommended CSRF protection be enabled.
|
| 'csrf_token_name' = The token name
| 'csrf_cookie_name' = The cookie name
| 'csrf_expire' = The number in seconds the token should expire.
*/
$config['csrf_protection'] = FALSE;
$config['csrf_token_name'] = 'csrf_test_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
/*
|--------------------------------------------------------------------------
| Output Compression
|--------------------------------------------------------------------------
|
| Enables Gzip output compression for faster page loads. When enabled,
| the output class will test whether your server supports Gzip.
| Even if it does, however, not all browsers support compression
| so enable only if you are reasonably sure your visitors can handle it.
|
| VERY IMPORTANT: If you are getting a blank page when compression is enabled it
| means you are prematurely outputting something to your browser. It could
| even be a line of whitespace at the end of one of your scripts. For
| compression to work, nothing can be sent before the output buffer is called
| by the output class. Do not 'echo' any values with compression enabled.
|
*/
$config['compress_output'] = FALSE;
/*
|--------------------------------------------------------------------------
| Master Time Reference
|--------------------------------------------------------------------------
|
| Options are 'local' or 'gmt'. This pref tells the system whether to use
| your server's local time as the master 'now' reference, or convert it to
| GMT. See the 'date helper' page of the user guide for information
| regarding date handling.
|
*/
$config['time_reference'] = 'local';
/*
|--------------------------------------------------------------------------
| Rewrite PHP Short Tags
|--------------------------------------------------------------------------
|
| If your PHP installation does not have short tag support enabled CI
| can rewrite the tags on-the-fly, enabling you to utilize that syntax
| in your view files. Options are TRUE or FALSE (boolean)
|
*/
$config['rewrite_short_tags'] = FALSE;
/*
|--------------------------------------------------------------------------
| Reverse Proxy IPs
|--------------------------------------------------------------------------
|
| If your server is behind a reverse proxy, you must whitelist the proxy IP
| addresses from which CodeIgniter should trust the HTTP_X_FORWARDED_FOR
| header in order to properly identify the visitor's IP address.
| Comma-delimited, e.g. '10.0.1.200,10.0.1.201'
|
*/
$config['proxy_ips'] = '';
/* End of file config.php */
/* Location: ./application/config/config.php */
================================================
FILE: application/config/constants.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
|--------------------------------------------------------------------------
| File and Directory Modes
|--------------------------------------------------------------------------
|
| These prefs are used when checking and setting modes when working
| with the file system. The defaults are fine on servers with proper
| security, but you may wish (or even need) to change the values in
| certain environments (Apache running a separate process for each
| user, PHP under CGI with Apache suEXEC, etc.). Octal values should
| always be used to set the mode correctly.
|
*/
define('FILE_READ_MODE', 0644);
define('FILE_WRITE_MODE', 0666);
define('DIR_READ_MODE', 0755);
define('DIR_WRITE_MODE', 0777);
/*
|--------------------------------------------------------------------------
| File Stream Modes
|--------------------------------------------------------------------------
|
| These modes are used when working with fopen()/popen()
|
*/
define('FOPEN_READ', 'rb');
define('FOPEN_READ_WRITE', 'r+b');
define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); // truncates existing file data, use with care
define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE', 'w+b'); // truncates existing file data, use with care
define('FOPEN_WRITE_CREATE', 'ab');
define('FOPEN_READ_WRITE_CREATE', 'a+b');
define('FOPEN_WRITE_CREATE_STRICT', 'xb');
define('FOPEN_READ_WRITE_CREATE_STRICT', 'x+b');
/* End of file constants.php */
/* Location: ./application/config/constants.php */
================================================
FILE: application/config/mimes.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| MIME TYPES
| -------------------------------------------------------------------
| This file contains an array of mime types. It is used by the
| Upload class to help identify allowed file types.
|
*/
$mimes = array( 'hqx' => 'application/mac-binhex40',
'cpt' => 'application/mac-compactpro',
'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'),
'bin' => 'application/macbinary',
'dms' => 'application/octet-stream',
'lha' => 'application/octet-stream',
'lzh' => 'application/octet-stream',
'exe' => array('application/octet-stream', 'application/x-msdownload'),
'class' => 'application/octet-stream',
'psd' => 'application/x-photoshop',
'so' => 'application/octet-stream',
'sea' => 'application/octet-stream',
'dll' => 'application/octet-stream',
'oda' => 'application/oda',
'pdf' => array('application/pdf', 'application/x-download'),
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
'smi' => 'application/smil',
'smil' => 'application/smil',
'mif' => 'application/vnd.mif',
'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'),
'wbxml' => 'application/wbxml',
'wmlc' => 'application/wmlc',
'dcr' => 'application/x-director',
'dir' => 'application/x-director',
'dxr' => 'application/x-director',
'dvi' => 'application/x-dvi',
'gtar' => 'application/x-gtar',
'gz' => 'application/x-gzip',
'php' => 'application/x-httpd-php',
'php4' => 'application/x-httpd-php',
'php3' => 'application/x-httpd-php',
'phtml' => 'application/x-httpd-php',
'phps' => 'application/x-httpd-php-source',
'js' => 'application/x-javascript',
'swf' => 'application/x-shockwave-flash',
'sit' => 'application/x-stuffit',
'tar' => 'application/x-tar',
'tgz' => array('application/x-tar', 'application/x-gzip-compressed'),
'xhtml' => 'application/xhtml+xml',
'xht' => 'application/xhtml+xml',
'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mpga' => 'audio/mpeg',
'mp2' => 'audio/mpeg',
'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
'aif' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'ram' => 'audio/x-pn-realaudio',
'rm' => 'audio/x-pn-realaudio',
'rpm' => 'audio/x-pn-realaudio-plugin',
'ra' => 'audio/x-realaudio',
'rv' => 'video/vnd.rn-realvideo',
'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'),
'bmp' => array('image/bmp', 'image/x-windows-bmp'),
'gif' => 'image/gif',
'jpeg' => array('image/jpeg', 'image/pjpeg'),
'jpg' => array('image/jpeg', 'image/pjpeg'),
'jpe' => array('image/jpeg', 'image/pjpeg'),
'png' => array('image/png', 'image/x-png'),
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'css' => 'text/css',
'html' => 'text/html',
'htm' => 'text/html',
'shtml' => 'text/html',
'txt' => 'text/plain',
'text' => 'text/plain',
'log' => array('text/plain', 'text/x-log'),
'rtx' => 'text/richtext',
'rtf' => 'text/rtf',
'xml' => 'text/xml',
'xsl' => 'text/xml',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
'avi' => 'video/x-msvideo',
'movie' => 'video/x-sgi-movie',
'doc' => 'application/msword',
'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'),
'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'),
'word' => array('application/msword', 'application/octet-stream'),
'xl' => 'application/excel',
'eml' => 'message/rfc822',
'json' => array('application/json', 'text/json')
);
/* End of file mimes.php */
/* Location: ./application/config/mimes.php */
================================================
FILE: application/config/minify.php
================================================
<?php
/**
* Minify config Class
*
* PHP Version 5.3
*
* @category PHP
* @package Controller
* @author Slawomir Jasinski <slav123@gmail.com>
* @copyright 2015 All Rights Reserved SpiderSoft
* @license Copyright 2015 All Rights Reserved SpiderSoft
* @link http://www.spidersoft.com.au/projects/codeigniter-minify/
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Minify config file
*
* @category PHP
* @package Controller
* @author Slawomir Jasinski <slav123@gmail.com>
* @copyright 2015 All Rights Reserved SpiderSoft
* @license Copyright 2015 All Rights Reserved SpiderSoft
* @link http://www.spidersoft.com.au/projects/codeigniter-minify/
*/
// enable/disable library (default value: 'TRUE')
// when enabled === FALSE library return assets without compilation and compression
// usefull when debugging or in development environment
$config['enabled'] = TRUE;
// output path where the compiled files will be stored (default value: 'assets')
$config['assets_dir'] = 'assets';
// optional - path where the compiled css files will be stored (default value: '' - for backward compatibility)
$config['assets_dir_css'] = '';
// optional - path where the compiled js files will be stored (default value: '' - for backward compatibility)
$config['assets_dir_js'] = '';
// optional - handy when your assets are in a different domain than main website (default value: '')
$config['base_url'] = '';
// where to look for css files (default value: 'assets/css')
$config['css_dir'] = 'assets/css';
// where to look for js files (default value: 'assets/js')
$config['js_dir'] = 'assets/js';
// default file name for css (default value: 'style.css')
$config['css_file'] = 'styles.css';
// default file name for js (default value: 'scripts.js')
$config['js_file'] = 'scripts.js';
// default tag for css (default value: '<link href="%s" rel="stylesheet" type="text/css" />')
$config['css_tag'] = '<link href="%s" rel="stylesheet" type="text/css" />';
// default tag for js (default value: '<script type="text/javascript" src="%s"></script>')
$config['js_tag'] = '<script type="text/javascript" src="%s"></script>';
// use html tags on output and return as a string (default value: 'TRUE')
// if html_tags === FALSE - array with links to assets is returned
$config['html_tags'] = TRUE;
// use automatic file names (default value: 'FALSE')
$config['auto_names'] = FALSE;
// use to enable versioning your assets (default value: 'FALSE')
$config['versioning'] = FALSE;
// override version md5 with a number (default value: 'NULL')
$config['version_number'] = NULL;
// automatically deploy when there are any changes in files (default value: 'TRUE')
$config['deploy_on_change'] = TRUE;
// compress files or not (default value: 'TRUE')
$config['compress'] = TRUE;
// compression engine setting (default values: 'minify' and 'closurecompiler')
$config['compression_engine'] = array(
'css' => 'cssmin', // minify || cssmin
'js' => 'closurecompiler' // closurecompiler || jsmin || jsminplus
);
// when you use closurecompiler as compression engine you can choose compression level (default value: 'SIMPLE_OPTIMIZATIONS')
// avaliable options: "WHITESPACE_ONLY", "SIMPLE_OPTIMIZATIONS" or "ADVANCED_OPTIMIZATIONS"
$config['closurecompiler']['compilation_level'] = 'SIMPLE_OPTIMIZATIONS';
// End of file minify.php
// Location: ./application/config/minify.php
================================================
FILE: application/config/routes.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| URI ROUTING
| -------------------------------------------------------------------------
| This file lets you re-map URI requests to specific controller functions.
|
| Typically there is a one-to-one relationship between a URL string
| and its corresponding controller class/method. The segments in a
| URL normally follow this pattern:
|
| example.com/class/method/id/
|
| In some instances, however, you may want to remap this relationship
| so that a different class/function is called than the one
| corresponding to the URL.
|
| Please see the user guide for complete details:
|
| http://codeigniter.com/user_guide/general/routing.html
|
| -------------------------------------------------------------------------
| RESERVED ROUTES
| -------------------------------------------------------------------------
|
| There area two reserved routes:
|
| $route['default_controller'] = 'welcome';
|
| This route indicates which controller class should be loaded if the
| URI contains no data. In the above example, the "welcome" class
| would be loaded.
|
| $route['404_override'] = 'errors/page_missing';
|
| This route will tell the Router what URI segments to use if those provided
| in the URL cannot be matched to a valid route.
|
*/
$route['default_controller'] = "welcome";
$route['404_override'] = '';
/* End of file routes.php */
/* Location: ./application/config/routes.php */
================================================
FILE: application/controllers/index.html
================================================
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>
================================================
FILE: application/controllers/welcome.php
================================================
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Welcome extends CI_Controller {
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* @see http://codeigniter.com/user_guide/general/urls.html
*/
public function index()
{
$this->load->library('minify');
$this->load->helper('url');
$this->load->view('welcome_message');
}
}
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */
================================================
FILE: application/errors/error_404.php
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<title>404 Page Not Found</title>
<style type="text/css">
::selection{ background-color: #E13300; color: white; }
::moz-selection{ background-color: #E13300; color: white; }
::webkit-selection{ background-color: #E13300; color: white; }
body {
background-color: #fff;
margin: 40px;
font: 13px/20px normal Helvetica, Arial, sans-serif;
color: #4F5155;
}
a {
color: #003399;
background-color: transparent;
font-weight: normal;
}
h1 {
color: #444;
background-color: transparent;
border-bottom: 1px solid #D0D0D0;
font-size: 19px;
font-weight: normal;
margin: 0 0 14px 0;
padding: 14px 15px 10px 15px;
}
code {
font-family: Consolas, Monaco, Courier New, Courier, monospace;
font-size: 12px;
background-color: #f9f9f9;
border: 1px solid #D0D0D0;
color: #002166;
display: block;
margin: 14px 0 14px 0;
padding: 12px 10px 12px 10px;
}
#container {
margin: 10px;
border: 1px solid #D0D0D0;
-webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
margin: 12px 15px 12px 15px;
}
</style>
</head>
<body>
<div id="container">
<h1><?php echo $heading; ?></h1>
<?php echo $message; ?>
</div>
</body>
</html>
================================================
FILE: application/errors/error_db.php
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<title>Database Error</title>
<style type="text/css">
::selection{ background-color: #E13300; color: white; }
::moz-selection{ background-color: #E13300; color: white; }
::webkit-selection{ background-color: #E13300; color: white; }
body {
background-color: #fff;
margin: 40px;
font: 13px/20px normal Helvetica, Arial, sans-serif;
color: #4F5155;
}
a {
color: #003399;
background-color: transparent;
font-weight: normal;
}
h1 {
color: #444;
background-color: transparent;
border-bottom: 1px solid #D0D0D0;
font-size: 19px;
font-weight: normal;
margin: 0 0 14px 0;
padding: 14px 15px 10px 15px;
}
code {
font-family: Consolas, Monaco, Courier New, Courier, monospace;
font-size: 12px;
background-color: #f9f9f9;
border: 1px solid #D0D0D0;
color: #002166;
display: block;
margin: 14px 0 14px 0;
padding: 12px 10px 12px 10px;
}
#container {
margin: 10px;
border: 1px solid #D0D0D0;
-webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
margin: 12px 15px 12px 15px;
}
</style>
</head>
<body>
<div id="container">
<h1><?php echo $heading; ?></h1>
<?php echo $message; ?>
</div>
</body>
</html>
================================================
FILE: application/errors/error_general.php
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<title>Error</title>
<style type="text/css">
::selection{ background-color: #E13300; color: white; }
::moz-selection{ background-color: #E13300; color: white; }
::webkit-selection{ background-color: #E13300; color: white; }
body {
background-color: #fff;
margin: 40px;
font: 13px/20px normal Helvetica, Arial, sans-serif;
color: #4F5155;
}
a {
color: #003399;
background-color: transparent;
font-weight: normal;
}
h1 {
color: #444;
background-color: transparent;
border-bottom: 1px solid #D0D0D0;
font-size: 19px;
font-weight: normal;
margin: 0 0 14px 0;
padding: 14px 15px 10px 15px;
}
code {
font-family: Consolas, Monaco, Courier New, Courier, monospace;
font-size: 12px;
background-color: #f9f9f9;
border: 1px solid #D0D0D0;
color: #002166;
display: block;
margin: 14px 0 14px 0;
padding: 12px 10px 12px 10px;
}
#container {
margin: 10px;
border: 1px solid #D0D0D0;
-webkit-box-shadow: 0 0 8px #D0D0D0;
}
p {
margin: 12px 15px 12px 15px;
}
</style>
</head>
<body>
<div id="container">
<h1><?php echo $heading; ?></h1>
<?php echo $message; ?>
</div>
</body>
</html>
================================================
FILE: application/errors/error_php.php
================================================
<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
<h4>A PHP Error was encountered</h4>
<p>Severity: <?php echo $severity; ?></p>
<p>Message: <?php echo $message; ?></p>
<p>Filename: <?php echo $filepath; ?></p>
<p>Line Number: <?php echo $line; ?></p>
</div>
================================================
FILE: application/errors/index.html
================================================
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>
================================================
FILE: application/libraries/Minify.php
================================================
<?php
/**
* Minify Library Class
*
* PHP Version 5.3
*
* @category PHP
* @package Library
* @author Slawomir Jasinski <slav123@gmail.com>
* @copyright 2015 All Rights Reserved SpiderSoft
* @license Copyright 2015 All Rights Reserved SpiderSoft
* @link Location: http://github.com/slav123/CodeIgniter-Minify
*/
defined('BASEPATH') or exit('No direct script access allowed');
/**
* the Minify LibraryClass
*
* @category PHP
* @package Controller
* @author Slawomir Jasinski <slav123@gmail.com>
* @copyright 2016 All Rights Reserved SpiderSoft
* @license Copyright 2015 All Rights Reserved SpiderSoft
* @link http://www.spidersoft.com.au
*/
class Minify {
/**
* CodeIgniter global.
*
* @var object
*/
protected $ci;
/**
* Css files array.
*
* @var array
*/
protected $css_array = array();
/**
* Js files array.
*
* @var array
*/
protected $js_array = array();
/**
* Enable/disable.
*
* @var bool
*/
public $enabled = TRUE;
/**
* Assets dir.
*
* @var string
*/
public $assets_dir = 'assets';
/**
* Assets dir for css (optional).
*
* @var string
*/
public $assets_dir_css = '';
/**
* Assets dir for js (optional).
*
* @var string
*/
public $assets_dir_js = '';
/**
* Base URL.
*
* @var string
*/
public $base_url = '';
/**
* Css dir.
*
* @var string
*/
public $css_dir = 'assets/css';
/**
* Js dir.
*
* @var string
*/
public $js_dir = 'assets/js';
/**
* Output css file name.
*
* @var string
*/
public $css_file = 'styles.css';
/**
* Output js file name.
*
* @var string
*/
public $js_file = 'scripts.js';
/**
* Output css tag template.
*
* @var string
*/
public $css_tag = '<link href="%s" rel="stylesheet" type="text/css" />';
/**
* Output js tag template.
*
* @var string
*/
public $js_tag = '<script type="text/javascript" src="%s"></script>';
/**
* Use html tags on output.
*
* @var string
*/
public $html_tags = TRUE;
/**
* Automatic file names.
*
* @var bool
*/
public $auto_names = FALSE;
/**
* Automatic deploy on change.
*
* @var bool
*/
public $deploy_on_change = TRUE;
/**
* File versioning.
*
* @var bool
*/
public $versioning = FALSE;
/**
* File version number override.
*
* @var string
*/
public $version_number = NULL;
/**
* Compress files or not.
*
* @var bool
*/
public $compress = TRUE;
/**
* Compression engines.
*
* @var array
*/
public $compression_engine = array('css' => 'minify', 'js' => 'closurecompiler');
/**
* Closurecompiler settings.
*
* @var array
*/
public $closurecompiler = array('compilation_level' => 'SIMPLE_OPTIMIZATIONS');
/**
* Css file name with path.
*
* @var string
*/
private $_css_file = '';
/**
* Js file name with path.
*
* @var string
*/
private $_js_file = '';
/**
* Last modification.
*
* @var array
*/
private $_lmod = array('css' => 0, 'js' => 0);
/**
* Constructor
*
* @param array $config Config array
*/
public function __construct($config = array())
{
$this->ci = get_instance();
$this->ci->load->config('minify', TRUE, TRUE);
// user specified settings from config file
$this->enabled = $this->ci->config->item('enabled', 'minify') ?: $this->enabled;
$this->assets_dir = $this->ci->config->item('assets_dir', 'minify') ?: $this->assets_dir;
$this->assets_dir_css = $this->ci->config->item('assets_dir_css', 'minify') ?: $this->assets_dir_css;
$this->assets_dir_js = $this->ci->config->item('assets_dir_js', 'minify') ?: $this->assets_dir_js;
$this->base_url = $this->ci->config->item('base_url', 'minify') ?: $this->base_url;
$this->css_dir = $this->ci->config->item('css_dir', 'minify') ?: $this->css_dir;
$this->js_dir = $this->ci->config->item('js_dir', 'minify') ?: $this->js_dir;
$this->css_file = $this->ci->config->item('css_file', 'minify') ?: $this->css_file;
$this->js_file = $this->ci->config->item('js_file', 'minify') ?: $this->js_file;
$this->css_tag = $this->ci->config->item('css_tag', 'minify') ?: $this->css_tag;
$this->js_tag = $this->ci->config->item('js_tag', 'minify') ?: $this->js_tag;
$this->html_tags = $this->ci->config->item('html_tags', 'minify') ?: $this->html_tags;
$this->auto_names = $this->ci->config->item('auto_names', 'minify') ?: $this->auto_names;
$this->deploy_on_change = $this->ci->config->item('deploy_on_change', 'minify') ?: $this->deploy_on_change;
$this->versioning = $this->ci->config->item('versioning', 'minify') ?: $this->versioning;
$this->version_number = $this->ci->config->item('version_number', 'minify') ?: $this->version_number;
$this->compress = $this->ci->config->item('compress', 'minify') ?: $this->compress;
$this->compression_engine = $this->ci->config->item('compression_engine',
'minify') ?: $this->compression_engine;
$this->closurecompiler = $this->ci->config->item('closurecompiler', 'minify') ?: $this->closurecompiler;
if (count($config) > 0)
{
// custom config array
foreach ($config as $key => $val)
{
if (isset($this->$key))
{
$this->$key = $val;
}
}
}
// save default names for later use/reset
$this->css_file_default = $this->css_file;
$this->js_file_default = $this->js_file;
log_message('debug', "Minify Class Initialized");
}
/**
* Declare css files list
*
* @param mixed $css File or files names
* @param bool $group Set group for files
*
* @return Minify
*/
public function css($css, $group = 'default')
{
if (is_array($css))
{
$this->css_array[$group] = $css;
}
else
{
$this->css_array[$group] = array_map('trim', explode(',', $css));
}
return $this;
}
/**
* Declare js files list
*
* @param mixed $js File or files names
* @param bool $group Set group for files
*
* @return Minify
*/
public function js($js, $group = 'default')
{
if (is_array($js))
{
$this->js_array[$group] = $js;
}
else
{
$this->js_array[$group] = array_map('trim', explode(',', $js));
}
return $this;
}
/**
* Declare css files list
*
* @param mixed $css File or files names
* @param bool $group Set group for files
*
* @return Minify
*/
public function add_css($css, $group = 'default')
{
if ( ! isset($this->css_array[$group]))
{
$this->css_array[$group] = array();
}
if (is_array($css))
{
$this->css_array[$group] = array_unique(array_merge($this->css_array[$group], $css));
}
else
{
$this->css_array[$group] = array_unique(array_merge($this->css_array[$group],
array_map('trim', explode(',', $css))));
}
return $this;
}
/**
* Declare js files list
*
* @param mixed $js File or files names
* @param bool $group Set group for files
*
* @return Minify
*/
public function add_js($js, $group = 'default')
{
if ( ! isset($this->js_array[$group]))
{
$this->js_array[$group] = array();
}
if (is_array($js))
{
$this->js_array[$group] = array_unique(array_merge($this->js_array[$group], $js));
}
else
{
$this->js_array[$group] = array_unique(array_merge($this->js_array[$group],
array_map('trim', explode(',', $js))));
}
return $this;
}
/**
* Deploy and minify CSS
*
* @param bool $force Force to rewrite file
* @param null $file_name File name to create
* @param null $group Group name
*
* @return string|array
*/
public function deploy_css($force = TRUE, $file_name = NULL, $group = NULL)
{
// perform checks
$this->_config_checks('css');
$return = array();
if (is_null($file_name))
{
$file_name = $this->css_file_default;
}
if (is_null($group))
{
foreach ($this->css_array as $group_name => $group_array)
{
$return = array_merge($return, $this->_deploy_css($force, $file_name, $group_name));
}
}
else
{
$return = array_merge($return, $this->_deploy_css($force, $file_name, $group));
}
return $this->_output($return, 'css');
}
/**
* Deploy and minify js
*
* @param bool $force Force rewriting js file
* @param null $file_name File name
* @param null $group Group name
*
* @return string|array
*/
public function deploy_js($force = FALSE, $file_name = NULL, $group = NULL)
{
// perform checks
$this->_config_checks('js');
$return = array();
if (is_null($file_name))
{
$file_name = $this->js_file_default;
}
if (is_null($group))
{
foreach ($this->js_array as $group_name => $group_array)
{
$return = array_merge($return, $this->_deploy_js($force, $file_name, $group_name));
}
}
else
{
$return = array_merge($return, $this->_deploy_js($force, $file_name, $group));
}
return $this->_output($return, 'js');
}
/**
* Build and minify CSS
*
* @param bool $force Force to rewrite file
* @param null $file_name File name to create
* @param null $group Group name
*
* @return array
*/
private function _deploy_css($force = TRUE, $file_name = NULL, $group = NULL)
{
if ($this->enabled === FALSE)
{
return $this->_simple_output('css', $group);
}
if ($this->auto_names or $file_name === 'auto')
{
$file_name = md5(serialize($this->css_array[$group])) . '.css';
}
else
{
$file_name = ($group === 'default') ? $file_name : $group . '_' . $file_name;
}
$this->_set('css_file', $file_name);
$this->_scan_files('css', $force, $group);
if ($this->versioning)
{
$this->_css_file = $this->_css_file . '?v=' . $this->_version_number($this->_css_file);
}
return [$this->_css_file];
}
/**
* Build and minify js
*
* @param bool $force Force rewriting js file
* @param null $file_name File name
* @param null $group Group name
*
* @return array
*/
private function _deploy_js($force = FALSE, $file_name = NULL, $group = NULL)
{
if ($this->enabled === FALSE)
{
return $this->_simple_output('js', $group);
}
if ($this->auto_names or $file_name === 'auto')
{
$file_name = md5(serialize($this->js_array[$group])) . '.js';
}
else
{
$file_name = ($group === 'default') ? $file_name : $group . '_' . $file_name;
}
$this->_set('js_file', $file_name);
$this->_scan_files('js', $force, $group);
if ($this->versioning)
{
$this->_js_file = $this->_js_file . '?v=' . $this->_version_number($this->_js_file);
}
return [$this->_js_file];
}
/**
* construct js_file and css_file
*
* @param string $name File type
* @param string $value File name
*
* @return void
*/
private function _set($name, $value)
{
switch ($name)
{
case 'js_file':
if ($this->compress)
{
if ( ! preg_match("/\.min\.js$/", $value))
{
$value = str_replace('.js', '.min.js', $value);
}
$this->js_file = $value;
}
// determine if we have special dir for js specified
$assets_dir = empty($this->assets_dir_js) ? $this->assets_dir : $this->assets_dir_js;
$this->_js_file = $assets_dir . '/' . $value;
if ( ! file_exists($this->_js_file) && ! touch($this->_js_file))
{
throw new Exception('Can not create file ' . $this->_js_file);
}
else
{
$this->_lmod['js'] = filemtime($this->_js_file);
}
break;
case 'css_file':
if ($this->compress)
{
if ( ! preg_match("/\.min\.css$/", $value))
{
$value = str_replace('.css', '.min.css', $value);
}
$this->css_file = $value;
}
// determine if we have special dir for css specified
$assets_dir = empty($this->assets_dir_css) ? $this->assets_dir : $this->assets_dir_css;
$this->_css_file = $assets_dir . '/' . $value;
if ( ! file_exists($this->_css_file) && ! touch($this->_css_file))
{
throw new Exception('Can not create file ' . $this->_css_file);
}
else
{
$this->_lmod['css'] = filemtime($this->_css_file);
}
break;
}
}
/**
* scan CSS directory and look for changes
*
* @param string $type Type (css | js)
* @param bool $force Rewrite no mather what
* @param string $group Group name
*/
private function _scan_files($type, $force, $group)
{
switch ($type)
{
case 'css':
$files_array = $this->css_array[$group];
$directory = $this->css_dir;
$out_file = $this->_css_file;
break;
case 'js':
$files_array = $this->js_array[$group];
$directory = $this->js_dir;
$out_file = $this->_js_file;
}
// if multiple files
if (is_array($files_array))
{
$compile = FALSE;
foreach ($files_array as $file)
{
$filename = $directory . '/' . $file;
if (file_exists($filename))
{
if ($this->deploy_on_change && filemtime($filename) > $this->_lmod[$type])
{
$compile = TRUE;
}
}
else
{
throw new Exception('File ' . $filename . ' is missing');
}
}
// check if this is init build
if (file_exists($out_file) && filesize($out_file) === 0)
{
$force = TRUE;
}
if ($compile or $force)
{
$this->_concat_files($files_array, $directory, $out_file);
}
}
}
/**
* output files with proper template for html_tags
* or without as array
*
* @param array $files Files array
* @param string $type Type (css | js)
*
* @return string|array
*/
private function _output($files, $type)
{
switch ($type)
{
case 'css':
$template = $this->css_tag;
break;
case 'js':
$template = $this->js_tag;
}
$output = array();
foreach ($files as $file)
{
$output[] = $this->html_tags ? sprintf($template, $this->_base_url($file)) : $this->_base_url($file);
}
if ( ! empty($output))
{
return $this->html_tags ? implode(PHP_EOL, $output) : $output;
}
return $this->html_tags ? '' : array();
}
/**
* simple output files - no compress, no compile (files in = files out)
* good for debugging or development env
*
* @param string $type Type (css | js)
* @param string $group Group name
*
* @return array
*/
private function _simple_output($type, $group)
{
switch ($type)
{
case 'css':
$files = $this->css_array[$group];
$directory = $this->css_dir;
$template = $this->css_tag;
break;
case 'js':
$files = $this->js_array[$group];
$directory = $this->js_dir;
$template = $this->js_tag;
}
$output = array();
foreach ($files as $file)
{
$filename = $directory . '/' . $file;
if ($this->versioning)
{
$filename .= '?v=' . $this->_version_number($filename);
}
$output[] = $filename;
}
return $output;
}
/**
* add merge files
*
* @param string $file_array Input file array
* @param string $directory Directory
* @param string $out_file Output file
*
* @return void
*/
private function _concat_files($file_array, $directory, $out_file)
{
if ($fh = fopen($out_file, 'w'))
{
foreach ($file_array as $file_name)
{
$file_name = $directory . '/' . $file_name;
$contents = file_get_contents($file_name);
// if this is javascript file, check if we have ; at the end
if (preg_match("/.js$/i", $out_file))
{
if (substr(rtrim($contents), - 1) !== ';')
{
$contents .= ';';
}
$contents .= "\n";
}
fwrite($fh, $contents);
}
fclose($fh);
}
else
{
throw new Exception('Can\'t write to ' . $out_file);
}
if ($this->compress)
{
// read output file contest (already concated)
$contents = file_get_contents($out_file);
// recreate file
$handle = fopen($out_file, 'w');
if (preg_match("/.css$/i", $out_file))
{
$engine = '_' . $this->compression_engine['css'];
}
if (preg_match("/.js$/i", $out_file))
{
$engine = '_' . $this->compression_engine['js'];
}
// call function name to compress file
fwrite($handle, call_user_func(array($this, $engine), $contents));
fclose($handle);
}
}
/**
* Compress javascript using closure compiler service
*
* @param string $data Source to compress
*
* @return mixed
*/
private function _closurecompiler($data)
{
$config = $this->closurecompiler;
$ch = curl_init('https://closure-compiler.appspot.com/compile');
//if server is not https
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off')
{
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
'output_info=compiled_code&output_info=errors&output_format=text&compilation_level=' . $config['compilation_level'] . '&js_code=' . urlencode($data));
$output = curl_exec($ch);
curl_close($ch);
if (preg_match('/Input_0:[0-9]+: ERROR/', $output))
{
throw new Exception('Closure Compiler error: ' . $output);
}
return $output;
}
/**
* Implements jsmin as alternative to closure compiler
*
* @param string $data Source to compress
*
* @return string
*/
private function _jsmin($data)
{
require_once(APPPATH . 'libraries/minify/JSMin.php');
return JSMin::minify($data);
}
/**
* Implements jsminplus as alternative to closure compiler
*
* @param string $data Source to compress
*
* @return string
*/
private function _jsminplus($data)
{
require_once(APPPATH . 'libraries/minify/JSMinPlus.php');
return JSMinPlus::minify($data);
}
/**
* Implements cssmin compression engine
*
* @param string $data Source to compress
*
* @return string
*/
private function _cssmin($data)
{
require_once(APPPATH . 'libraries/minify/cssmin-v3.0.1.php');
return CssMin::minify($data);
}
/**
* Implements cssminify compression engine
*
* @param string $data Source to compress
*
* @return string
*/
private function _minify($data)
{
require_once(APPPATH . 'libraries/minify/cssminify.php');
$cssminify = new cssminify();
return $cssminify->compress($data);
}
/**
* Build correct URL for file
*
* @param string $file File with path
*
* @return string
*/
private function _base_url($file)
{
if ($this->base_url === '')
{
return base_url($file);
}
return rtrim($this->base_url, '/') . '/' . $file;
}
/**
* Perform config checks
*
* @param $type string CSS / JS check
*
* @return void
* @throws Exception
*/
private function _config_checks($type)
{
switch ($type)
{
case 'css':
if (empty($this->assets_dir_css) && ! is_writable($this->assets_dir))
{
throw new Exception('Assets directory ' . $this->assets_dir . ' is not writable');
}
if ( ! empty($this->assets_dir_css) && ! is_writable($this->assets_dir_css))
{
throw new Exception('Assets directory for css ' . $this->assets_dir_css . ' is not writable');
}
if (empty($this->css_dir))
{
throw new Exception('CSS directory must be set');
}
if ($this->html_tags === TRUE && empty($this->css_tag))
{
throw new Exception('CSS tag template must be set');
}
if ( ! $this->auto_names)
{
if (empty($this->css_file))
{
throw new Exception('CSS file name can\'t be empty');
}
}
if ($this->compress)
{
if ( ! isset($this->compression_engine['css']) or empty($this->compression_engine['css']))
{
throw new Exception('Compression engine for CSS is required');
}
}
break;
case 'js':
if (empty($this->assets_dir_js) && ! is_writable($this->assets_dir))
{
throw new Exception('Assets directory ' . $this->assets_dir . ' is not writable');
}
if ( ! empty($this->assets_dir_js) && ! is_writable($this->assets_dir_js))
{
throw new Exception('Assets directory for js ' . $this->assets_dir_js . ' is not writable');
}
if (empty($this->js_dir))
{
throw new Exception('JS directory must be set');
}
if ($this->html_tags === TRUE && empty($this->js_tag))
{
throw new Exception('JS tag template must be set');
}
if ( ! $this->auto_names)
{
if (empty($this->js_file))
{
throw new Exception('JS file name can\'t be empty');
}
}
if ($this->compress)
{
if ( ! isset($this->compression_engine['js']) or empty($this->compression_engine['js']))
{
throw new Exception('Compression engine for JS is required');
}
if ($this->compression_engine['js'] === 'closurecompiler' && ( ! isset($this->closurecompiler['compilation_level']) or empty($this->closurecompiler['compilation_level'])))
{
throw new Exception('Compilation level for closurecompiler is needed');
}
}
break;
}
}
/**
* Get Version Number for file
*
* @param string $file File with path
*
* @return string
*/
private function _version_number($file)
{
if ( ! empty($this->version_number))
{
return $this->version_number;
}
return md5_file($file);
}
}
/* End of file Minify.php */
/* Location: ./libraries/Minify.php */
================================================
FILE: application/libraries/minify/JSMin.php
================================================
<?php
/**
* JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
*
* <code>
* $minifiedJs = JSMin::minify($js);
* </code>
*
* This is a modified port of jsmin.c. Improvements:
*
* 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
* converted to post-inc/dec. E.g. a + ++b -> a+ ++b
*
* Preserves multi-line comments that begin with /*!
*
* 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> (PHP port)
* @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
* @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
* @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
* @link http://code.google.com/p/jsmin-php/
*/
class JSMin {
const ORD_LF = 10;
const ORD_SPACE = 32;
const ACTION_KEEP_A = 1;
const ACTION_DELETE_A = 2;
const ACTION_DELETE_A_B = 3;
protected $a = "\n";
protected $b = '';
protected $input = '';
protected $inputIndex = 0;
protected $inputLength = 0;
protected $lookAhead = null;
protected $output = '';
protected $lastByteOut = '';
protected $keptComment = '';
/**
* Minify Javascript.
*
* @param string $js Javascript to be minified
*
* @return string
*/
public static function minify($js)
{
$jsmin = new JSMin($js);
return $jsmin->min();
}
/**
* @param string $input
*/
public function __construct($input)
{
$this->input = $input;
}
/**
* Perform minification, return result
*
* @return string
*/
public function min()
{
if ($this->output !== '') { // min already run
return $this->output;
}
$mbIntEnc = null;
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
$mbIntEnc = mb_internal_encoding();
mb_internal_encoding('8bit');
}
$this->input = str_replace("\r\n", "\n", $this->input);
$this->inputLength = strlen($this->input);
$this->action(self::ACTION_DELETE_A_B);
while ($this->a !== null) {
// determine next command
$command = self::ACTION_KEEP_A; // default
if ($this->a === ' ') {
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
&& ($this->b === $this->lastByteOut)) {
// Don't delete this space. If we do, the addition/subtraction
// could be parsed as a post-increment
} elseif (! $this->isAlphaNum($this->b)) {
$command = self::ACTION_DELETE_A;
}
} elseif ($this->a === "\n") {
if ($this->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
} elseif ($this->b === null
|| (false === strpos('{[(+-!~', $this->b)
&& ! $this->isAlphaNum($this->b))) {
$command = self::ACTION_DELETE_A;
}
} elseif (! $this->isAlphaNum($this->a)) {
if ($this->b === ' '
|| ($this->b === "\n"
&& (false === strpos('}])+-"\'', $this->a)))) {
$command = self::ACTION_DELETE_A_B;
}
}
$this->action($command);
}
$this->output = trim($this->output);
if ($mbIntEnc !== null) {
mb_internal_encoding($mbIntEnc);
}
return $this->output;
}
/**
* ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
* ACTION_DELETE_A = Copy B to A. Get the next B.
* ACTION_DELETE_A_B = Get the next B.
*
* @param int $command
* @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
*/
protected function action($command)
{
// make sure we don't compress "a + ++b" to "a+++b", etc.
if ($command === self::ACTION_DELETE_A_B
&& $this->b === ' '
&& ($this->a === '+' || $this->a === '-')) {
// Note: we're at an addition/substraction operator; the inputIndex
// will certainly be a valid index
if ($this->input[$this->inputIndex] === $this->a) {
// This is "+ +" or "- -". Don't delete the space.
$command = self::ACTION_KEEP_A;
}
}
switch ($command) {
case self::ACTION_KEEP_A: // 1
$this->output .= $this->a;
if ($this->keptComment) {
$this->output = rtrim($this->output, "\n");
$this->output .= $this->keptComment;
$this->keptComment = '';
}
$this->lastByteOut = $this->a;
// fallthrough intentional
case self::ACTION_DELETE_A: // 2
$this->a = $this->b;
if ($this->a === "'" || $this->a === '"') { // string literal
$str = $this->a; // in case needed for exception
for(;;) {
$this->output .= $this->a;
$this->lastByteOut = $this->a;
$this->a = $this->get();
if ($this->a === $this->b) { // end quote
break;
}
if ($this->isEOF($this->a)) {
throw new JSMin_UnterminatedStringException(
"JSMin: Unterminated String at byte {$this->inputIndex}: {$str}");
}
$str .= $this->a;
if ($this->a === '\\') {
$this->output .= $this->a;
$this->lastByteOut = $this->a;
$this->a = $this->get();
$str .= $this->a;
}
}
}
// fallthrough intentional
case self::ACTION_DELETE_A_B: // 3
$this->b = $this->next();
if ($this->b === '/' && $this->isRegexpLiteral()) {
$this->output .= $this->a . $this->b;
$pattern = '/'; // keep entire pattern in case we need to report it in the exception
for(;;) {
$this->a = $this->get();
$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
break; // while (true)
} elseif ($this->a === '\\') {
$this->output .= $this->a;
$this->a = $this->get();
$pattern .= $this->a;
} elseif ($this->isEOF($this->a)) {
throw new JSMin_UnterminatedRegExpException(
"JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}");
}
$this->output .= $this->a;
$this->lastByteOut = $this->a;
}
$this->b = $this->next();
}
// end case ACTION_DELETE_A_B
}
}
/**
* @return bool
*/
protected function isRegexpLiteral()
{
if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
// we obviously aren't dividing
return true;
}
if ($this->a === ' ' || $this->a === "\n") {
$length = strlen($this->output);
if ($length < 2) { // weird edge case
return true;
}
// you can't divide a keyword
if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) {
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 false;
}
/**
* 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
*/
protected function get()
{
$c = $this->lookAhead;
$this->lookAhead = null;
if ($c === null) {
// getc(stdin)
if ($this->inputIndex < $this->inputLength) {
$c = $this->input[$this->inputIndex];
$this->inputIndex += 1;
} else {
$c = null;
}
}
if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
return $c;
}
if ($c === "\r") {
return "\n";
}
return ' ';
}
/**
* 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
*/
protected function peek()
{
$this->lookAhead = $this->get();
return $this->lookAhead;
}
/**
* Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
*
* @param string $c
*
* @return bool
*/
protected function isAlphaNum($c)
{
return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
}
/**
* Consume a single line comment from input (possibly retaining it)
*/
protected function consumeSingleLineComment()
{
$comment = '';
while (true) {
$get = $this->get();
$comment .= $get;
if (ord($get) <= self::ORD_LF) { // end of line reached
// if IE conditional comment
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
$this->keptComment .= "/{$comment}";
}
return;
}
}
}
/**
* Consume a multiple line comment from input (possibly retaining it)
*
* @throws JSMin_UnterminatedCommentException
*/
protected function consumeMultipleLineComment()
{
$this->get();
$comment = '';
for(;;) {
$get = $this->get();
if ($get === '*') {
if ($this->peek() === '/') { // end of comment reached
$this->get();
if (0 === strpos($comment, '!')) {
// 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}*/";
}
return;
}
} elseif ($get === null) {
throw new JSMin_UnterminatedCommentException(
"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
}
$comment .= $get;
}
}
/**
* Get the next character, skipping over comments. Some comments may be preserved.
*
* @return string
*/
protected function next()
{
$get = $this->get();
if ($get === '/') {
switch ($this->peek()) {
case '/':
$this->consumeSingleLineComment();
$get = "\n";
break;
case '*':
$this->consumeMultipleLineComment();
$get = ' ';
break;
}
}
return $get;
}
}
class JSMin_UnterminatedStringException extends Exception {}
class JSMin_UnterminatedCommentException extends Exception {}
class JSMin_UnterminatedRegExpException extends Exception {}
================================================
FILE: application/libraries/minify/JSMinPlus.php
================================================
<?php
/**
* JSMinPlus version 1.4
*
* Minifies a javascript file using a javascript parser
*
* This implements a PHP port of Brendan Eich's Narcissus open source javascript engine (in javascript)
* References: http://en.wikipedia.org/wiki/Narcissus_(JavaScript_engine)
* Narcissus sourcecode: http://mxr.mozilla.org/mozilla/source/js/narcissus/
* JSMinPlus weblog: http://crisp.tweakblogs.net/blog/cat/716
*
* Tino Zijdel <crisp@tweakers.net>
*
* Usage: $minified = JSMinPlus::minify($script [, $filename])
*
* Versionlog (see also changelog.txt):
* 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top
* reduce memory footprint by minifying by block-scope
* some small byte-saving and performance improvements
* 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs
* 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes
* 12-04-2009 - some small bugfixes and performance improvements
* 09-04-2009 - initial open sourced version 1.0
*
* Latest version of this script: http://files.tweakers.net/jsminplus/jsminplus.zip
*
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Narcissus JavaScript engine.
*
* The Initial Developer of the Original Code is
* Brendan Eich <brendan@mozilla.org>.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Tino Zijdel <crisp@tweakers.net>
* PHP port, modifications and minifier routine are (C) 2009-2011
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define('TOKEN_END', 1);
define('TOKEN_NUMBER', 2);
define('TOKEN_IDENTIFIER', 3);
define('TOKEN_STRING', 4);
define('TOKEN_REGEXP', 5);
define('TOKEN_NEWLINE', 6);
define('TOKEN_CONDCOMMENT_START', 7);
define('TOKEN_CONDCOMMENT_END', 8);
define('JS_SCRIPT', 100);
define('JS_BLOCK', 101);
define('JS_LABEL', 102);
define('JS_FOR_IN', 103);
define('JS_CALL', 104);
define('JS_NEW_WITH_ARGS', 105);
define('JS_INDEX', 106);
define('JS_ARRAY_INIT', 107);
define('JS_OBJECT_INIT', 108);
define('JS_PROPERTY_INIT', 109);
define('JS_GETTER', 110);
define('JS_SETTER', 111);
define('JS_GROUP', 112);
define('JS_LIST', 113);
define('JS_MINIFIED', 999);
define('DECLARED_FORM', 0);
define('EXPRESSED_FORM', 1);
define('STATEMENT_FORM', 2);
/* Operators */
define('OP_SEMICOLON', ';');
define('OP_COMMA', ',');
define('OP_HOOK', '?');
define('OP_COLON', ':');
define('OP_OR', '||');
define('OP_AND', '&&');
define('OP_BITWISE_OR', '|');
define('OP_BITWISE_XOR', '^');
define('OP_BITWISE_AND', '&');
define('OP_STRICT_EQ', '===');
define('OP_EQ', '==');
define('OP_ASSIGN', '=');
define('OP_STRICT_NE', '!==');
define('OP_NE', '!=');
define('OP_LSH', '<<');
define('OP_LE', '<=');
define('OP_LT', '<');
define('OP_URSH', '>>>');
define('OP_RSH', '>>');
define('OP_GE', '>=');
define('OP_GT', '>');
define('OP_INCREMENT', '++');
define('OP_DECREMENT', '--');
define('OP_PLUS', '+');
define('OP_MINUS', '-');
define('OP_MUL', '*');
define('OP_DIV', '/');
define('OP_MOD', '%');
define('OP_NOT', '!');
define('OP_BITWISE_NOT', '~');
define('OP_DOT', '.');
define('OP_LEFT_BRACKET', '[');
define('OP_RIGHT_BRACKET', ']');
define('OP_LEFT_CURLY', '{');
define('OP_RIGHT_CURLY', '}');
define('OP_LEFT_PAREN', '(');
define('OP_RIGHT_PAREN', ')');
define('OP_CONDCOMMENT_END', '@*/');
define('OP_UNARY_PLUS', 'U+');
define('OP_UNARY_MINUS', 'U-');
/* Keywords */
define('KEYWORD_BREAK', 'break');
define('KEYWORD_CASE', 'case');
define('KEYWORD_CATCH', 'catch');
define('KEYWORD_CONST', 'const');
define('KEYWORD_CONTINUE', 'continue');
define('KEYWORD_DEBUGGER', 'debugger');
define('KEYWORD_DEFAULT', 'default');
define('KEYWORD_DELETE', 'delete');
define('KEYWORD_DO', 'do');
define('KEYWORD_ELSE', 'else');
define('KEYWORD_ENUM', 'enum');
define('KEYWORD_FALSE', 'false');
define('KEYWORD_FINALLY', 'finally');
define('KEYWORD_FOR', 'for');
define('KEYWORD_FUNCTION', 'function');
define('KEYWORD_IF', 'if');
define('KEYWORD_IN', 'in');
define('KEYWORD_INSTANCEOF', 'instanceof');
define('KEYWORD_NEW', 'new');
define('KEYWORD_NULL', 'null');
define('KEYWORD_RETURN', 'return');
define('KEYWORD_SWITCH', 'switch');
define('KEYWORD_THIS', 'this');
define('KEYWORD_THROW', 'throw');
define('KEYWORD_TRUE', 'true');
define('KEYWORD_TRY', 'try');
define('KEYWORD_TYPEOF', 'typeof');
define('KEYWORD_VAR', 'var');
define('KEYWORD_VOID', 'void');
define('KEYWORD_WHILE', 'while');
define('KEYWORD_WITH', 'with');
class JSMinPlus
{
private $parser;
private $reserved = array(
'break', 'case', 'catch', 'continue', 'default', 'delete', 'do',
'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof',
'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var',
'void', 'while', 'with',
// Words reserved for future use
'abstract', 'boolean', 'byte', 'char', 'class', 'const', 'debugger',
'double', 'enum', 'export', 'extends', 'final', 'float', 'goto',
'implements', 'import', 'int', 'interface', 'long', 'native',
'package', 'private', 'protected', 'public', 'short', 'static',
'super', 'synchronized', 'throws', 'transient', 'volatile',
// These are not reserved, but should be taken into account
// in isValidIdentifier (See jslint source code)
'arguments', 'eval', 'true', 'false', 'Infinity', 'NaN', 'null', 'undefined'
);
private function __construct()
{
$this->parser = new JSParser($this);
}
public static function minify($js, $filename='')
{
static $instance;
// this is a singleton
if(!$instance)
$instance = new JSMinPlus();
return $instance->min($js, $filename);
}
private function min($js, $filename)
{
try
{
$n = $this->parser->parse($js, $filename, 1);
return $this->parseTree($n);
}
catch(Exception $e)
{
echo $e->getMessage() . "\n";
}
return false;
}
public function parseTree($n, $noBlockGrouping = false)
{
$s = '';
switch ($n->type)
{
case JS_MINIFIED:
$s = $n->value;
break;
case JS_SCRIPT:
// we do nothing yet with funDecls or varDecls
$noBlockGrouping = true;
// FALL THROUGH
case JS_BLOCK:
$childs = $n->treeNodes;
$lastType = 0;
for ($c = 0, $i = 0, $j = count($childs); $i < $j; $i++)
{
$type = $childs[$i]->type;
$t = $this->parseTree($childs[$i]);
if (strlen($t))
{
if ($c)
{
$s = rtrim($s, ';');
if ($type == KEYWORD_FUNCTION && $childs[$i]->functionForm == DECLARED_FORM)
{
// put declared functions on a new line
$s .= "\n";
}
elseif ($type == KEYWORD_VAR && $type == $lastType)
{
// mutiple var-statements can go into one
$t = ',' . substr($t, 4);
}
else
{
// add terminator
$s .= ';';
}
}
$s .= $t;
$c++;
$lastType = $type;
}
}
if ($c > 1 && !$noBlockGrouping)
{
$s = '{' . $s . '}';
}
break;
case KEYWORD_FUNCTION:
$s .= 'function' . ($n->name ? ' ' . $n->name : '') . '(';
$params = $n->params;
for ($i = 0, $j = count($params); $i < $j; $i++)
$s .= ($i ? ',' : '') . $params[$i];
$s .= '){' . $this->parseTree($n->body, true) . '}';
break;
case KEYWORD_IF:
$s = 'if(' . $this->parseTree($n->condition) . ')';
$thenPart = $this->parseTree($n->thenPart);
$elsePart = $n->elsePart ? $this->parseTree($n->elsePart) : null;
// empty if-statement
if ($thenPart == '')
$thenPart = ';';
if ($elsePart)
{
// be carefull and always make a block out of the thenPart; could be more optimized but is a lot of trouble
if ($thenPart != ';' && $thenPart[0] != '{')
$thenPart = '{' . $thenPart . '}';
$s .= $thenPart . 'else';
// we could check for more, but that hardly ever applies so go for performance
if ($elsePart[0] != '{')
$s .= ' ';
$s .= $elsePart;
}
else
{
$s .= $thenPart;
}
break;
case KEYWORD_SWITCH:
$s = 'switch(' . $this->parseTree($n->discriminant) . '){';
$cases = $n->cases;
for ($i = 0, $j = count($cases); $i < $j; $i++)
{
$case = $cases[$i];
if ($case->type == KEYWORD_CASE)
$s .= 'case' . ($case->caseLabel->type != TOKEN_STRING ? ' ' : '') . $this->parseTree($case->caseLabel) . ':';
else
$s .= 'default:';
$statement = $this->parseTree($case->statements, true);
if ($statement)
{
$s .= $statement;
// no terminator for last statement
if ($i + 1 < $j)
$s .= ';';
}
}
$s .= '}';
break;
case KEYWORD_FOR:
$s = 'for(' . ($n->setup ? $this->parseTree($n->setup) : '')
. ';' . ($n->condition ? $this->parseTree($n->condition) : '')
. ';' . ($n->update ? $this->parseTree($n->update) : '') . ')';
$body = $this->parseTree($n->body);
if ($body == '')
$body = ';';
$s .= $body;
break;
case KEYWORD_WHILE:
$s = 'while(' . $this->parseTree($n->condition) . ')';
$body = $this->parseTree($n->body);
if ($body == '')
$body = ';';
$s .= $body;
break;
case JS_FOR_IN:
$s = 'for(' . ($n->varDecl ? $this->parseTree($n->varDecl) : $this->parseTree($n->iterator)) . ' in ' . $this->parseTree($n->object) . ')';
$body = $this->parseTree($n->body);
if ($body == '')
$body = ';';
$s .= $body;
break;
case KEYWORD_DO:
$s = 'do{' . $this->parseTree($n->body, true) . '}while(' . $this->parseTree($n->condition) . ')';
break;
case KEYWORD_BREAK:
case KEYWORD_CONTINUE:
$s = $n->value . ($n->label ? ' ' . $n->label : '');
break;
case KEYWORD_TRY:
$s = 'try{' . $this->parseTree($n->tryBlock, true) . '}';
$catchClauses = $n->catchClauses;
for ($i = 0, $j = count($catchClauses); $i < $j; $i++)
{
$t = $catchClauses[$i];
$s .= 'catch(' . $t->varName . ($t->guard ? ' if ' . $this->parseTree($t->guard) : '') . '){' . $this->parseTree($t->block, true) . '}';
}
if ($n->finallyBlock)
$s .= 'finally{' . $this->parseTree($n->finallyBlock, true) . '}';
break;
case KEYWORD_THROW:
case KEYWORD_RETURN:
$s = $n->type;
if ($n->value)
{
$t = $this->parseTree($n->value);
if (strlen($t))
{
if ($this->isWordChar($t[0]) || $t[0] == '\\')
$s .= ' ';
$s .= $t;
}
}
break;
case KEYWORD_WITH:
$s = 'with(' . $this->parseTree($n->object) . ')' . $this->parseTree($n->body);
break;
case KEYWORD_VAR:
case KEYWORD_CONST:
$s = $n->value . ' ';
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
{
$t = $childs[$i];
$s .= ($i ? ',' : '') . $t->name;
$u = $t->initializer;
if ($u)
$s .= '=' . $this->parseTree($u);
}
break;
case KEYWORD_IN:
case KEYWORD_INSTANCEOF:
$left = $this->parseTree($n->treeNodes[0]);
$right = $this->parseTree($n->treeNodes[1]);
$s = $left;
if ($this->isWordChar(substr($left, -1)))
$s .= ' ';
$s .= $n->type;
if ($this->isWordChar($right[0]) || $right[0] == '\\')
$s .= ' ';
$s .= $right;
break;
case KEYWORD_DELETE:
case KEYWORD_TYPEOF:
$right = $this->parseTree($n->treeNodes[0]);
$s = $n->type;
if ($this->isWordChar($right[0]) || $right[0] == '\\')
$s .= ' ';
$s .= $right;
break;
case KEYWORD_VOID:
$s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')';
break;
case KEYWORD_DEBUGGER:
throw new Exception('NOT IMPLEMENTED: DEBUGGER');
break;
case TOKEN_CONDCOMMENT_START:
case TOKEN_CONDCOMMENT_END:
$s = $n->value . ($n->type == TOKEN_CONDCOMMENT_START ? ' ' : '');
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
$s .= $this->parseTree($childs[$i]);
break;
case OP_SEMICOLON:
if ($expression = $n->expression)
$s = $this->parseTree($expression);
break;
case JS_LABEL:
$s = $n->label . ':' . $this->parseTree($n->statement);
break;
case OP_COMMA:
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);
break;
case OP_ASSIGN:
$s = $this->parseTree($n->treeNodes[0]) . $n->value . $this->parseTree($n->treeNodes[1]);
break;
case OP_HOOK:
$s = $this->parseTree($n->treeNodes[0]) . '?' . $this->parseTree($n->treeNodes[1]) . ':' . $this->parseTree($n->treeNodes[2]);
break;
case OP_OR: case OP_AND:
case OP_BITWISE_OR: case OP_BITWISE_XOR: case OP_BITWISE_AND:
case OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE:
case OP_LT: case OP_LE: case OP_GE: case OP_GT:
case OP_LSH: case OP_RSH: case OP_URSH:
case OP_MUL: case OP_DIV: case OP_MOD:
$s = $this->parseTree($n->treeNodes[0]) . $n->type . $this->parseTree($n->treeNodes[1]);
break;
case OP_PLUS:
case OP_MINUS:
$left = $this->parseTree($n->treeNodes[0]);
$right = $this->parseTree($n->treeNodes[1]);
switch ($n->treeNodes[1]->type)
{
case OP_PLUS:
case OP_MINUS:
case OP_INCREMENT:
case OP_DECREMENT:
case OP_UNARY_PLUS:
case OP_UNARY_MINUS:
$s = $left . $n->type . ' ' . $right;
break;
case TOKEN_STRING:
//combine concatted strings with same quotestyle
if ($n->type == OP_PLUS && substr($left, -1) == $right[0])
{
$s = substr($left, 0, -1) . substr($right, 1);
break;
}
// FALL THROUGH
default:
$s = $left . $n->type . $right;
}
break;
case OP_NOT:
case OP_BITWISE_NOT:
case OP_UNARY_PLUS:
case OP_UNARY_MINUS:
$s = $n->value . $this->parseTree($n->treeNodes[0]);
break;
case OP_INCREMENT:
case OP_DECREMENT:
if ($n->postfix)
$s = $this->parseTree($n->treeNodes[0]) . $n->value;
else
$s = $n->value . $this->parseTree($n->treeNodes[0]);
break;
case OP_DOT:
$s = $this->parseTree($n->treeNodes[0]) . '.' . $this->parseTree($n->treeNodes[1]);
break;
case JS_INDEX:
$s = $this->parseTree($n->treeNodes[0]);
// See if we can replace named index with a dot saving 3 bytes
if ( $n->treeNodes[0]->type == TOKEN_IDENTIFIER &&
$n->treeNodes[1]->type == TOKEN_STRING &&
$this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1))
)
$s .= '.' . substr($n->treeNodes[1]->value, 1, -1);
else
$s .= '[' . $this->parseTree($n->treeNodes[1]) . ']';
break;
case JS_LIST:
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);
break;
case JS_CALL:
$s = $this->parseTree($n->treeNodes[0]) . '(' . $this->parseTree($n->treeNodes[1]) . ')';
break;
case KEYWORD_NEW:
case JS_NEW_WITH_ARGS:
$s = 'new ' . $this->parseTree($n->treeNodes[0]) . '(' . ($n->type == JS_NEW_WITH_ARGS ? $this->parseTree($n->treeNodes[1]) : '') . ')';
break;
case JS_ARRAY_INIT:
$s = '[';
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
{
$s .= ($i ? ',' : '') . $this->parseTree($childs[$i]);
}
$s .= ']';
break;
case JS_OBJECT_INIT:
$s = '{';
$childs = $n->treeNodes;
for ($i = 0, $j = count($childs); $i < $j; $i++)
{
$t = $childs[$i];
if ($i)
$s .= ',';
if ($t->type == JS_PROPERTY_INIT)
{
// Ditch the quotes when the index is a valid identifier
if ( $t->treeNodes[0]->type == TOKEN_STRING &&
$this->isValidIdentifier(substr($t->treeNodes[0]->value, 1, -1))
)
$s .= substr($t->treeNodes[0]->value, 1, -1);
else
$s .= $t->treeNodes[0]->value;
$s .= ':' . $this->parseTree($t->treeNodes[1]);
}
else
{
$s .= $t->type == JS_GETTER ? 'get' : 'set';
$s .= ' ' . $t->name . '(';
$params = $t->params;
for ($i = 0, $j = count($params); $i < $j; $i++)
$s .= ($i ? ',' : '') . $params[$i];
$s .= '){' . $this->parseTree($t->body, true) . '}';
}
}
$s .= '}';
break;
case TOKEN_NUMBER:
$s = $n->value;
if (preg_match('/^([1-9]+)(0{3,})$/', $s, $m))
$s = $m[1] . 'e' . strlen($m[2]);
break;
case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE:
case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP:
$s = $n->value;
break;
case JS_GROUP:
if (in_array(
$n->treeNodes[0]->type,
array(
JS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP,
TOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER,
KEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE
)
))
{
$s = $this->parseTree($n->treeNodes[0]);
}
else
{
$s = '(' . $this->parseTree($n->treeNodes[0]) . ')';
}
break;
default:
throw new Exception('UNKNOWN TOKEN TYPE: ' . $n->type);
}
return $s;
}
private function isValidIdentifier($string)
{
return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved);
}
private function isWordChar($char)
{
return $char == '_' || $char == '$' || ctype_alnum($char);
}
}
class JSParser
{
private $t;
private $minifier;
private $opPrecedence = array(
';' => 0,
',' => 1,
'=' => 2, '?' => 2, ':' => 2,
// The above all have to have the same precedence, see bug 330975
'||' => 4,
'&&' => 5,
'|' => 6,
'^' => 7,
'&' => 8,
'==' => 9, '!=' => 9, '===' => 9, '!==' => 9,
'<' => 10, '<=' => 10, '>=' => 10, '>' => 10, 'in' => 10, 'instanceof' => 10,
'<<' => 11, '>>' => 11, '>>>' => 11,
'+' => 12, '-' => 12,
'*' => 13, '/' => 13, '%' => 13,
'delete' => 14, 'void' => 14, 'typeof' => 14,
'!' => 14, '~' => 14, 'U+' => 14, 'U-' => 14,
'++' => 15, '--' => 15,
'new' => 16,
'.' => 17,
JS_NEW_WITH_ARGS => 0, JS_INDEX => 0, JS_CALL => 0,
JS_ARRAY_INIT => 0, JS_OBJECT_INIT => 0, JS_GROUP => 0
);
private $opArity = array(
',' => -2,
'=' => 2,
'?' => 3,
'||' => 2,
'&&' => 2,
'|' => 2,
'^' => 2,
'&' => 2,
'==' => 2, '!=' => 2, '===' => 2, '!==' => 2,
'<' => 2, '<=' => 2, '>=' => 2, '>' => 2, 'in' => 2, 'instanceof' => 2,
'<<' => 2, '>>' => 2, '>>>' => 2,
'+' => 2, '-' => 2,
'*' => 2, '/' => 2, '%' => 2,
'delete' => 1, 'void' => 1, 'typeof' => 1,
'!' => 1, '~' => 1, 'U+' => 1, 'U-' => 1,
'++' => 1, '--' => 1,
'new' => 1,
'.' => 2,
JS_NEW_WITH_ARGS => 2, JS_INDEX => 2, JS_CALL => 2,
JS_ARRAY_INIT => 1, JS_OBJECT_INIT => 1, JS_GROUP => 1,
TOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1
);
public function __construct($minifier=null)
{
$this->minifier = $minifier;
$this->t = new JSTokenizer();
}
public function parse($s, $f, $l)
{
// initialize tokenizer
$this->t->init($s, $f, $l);
$x = new JSCompilerContext(false);
$n = $this->Script($x);
if (!$this->t->isDone())
throw $this->t->newSyntaxError('Syntax error');
return $n;
}
private function Script($x)
{
$n = $this->Statements($x);
$n->type = JS_SCRIPT;
$n->funDecls = $x->funDecls;
$n->varDecls = $x->varDecls;
// minify by scope
if ($this->minifier)
{
$n->value = $this->minifier->parseTree($n);
// clear tree from node to save memory
$n->treeNodes = null;
$n->funDecls = null;
$n->varDecls = null;
$n->type = JS_MINIFIED;
}
return $n;
}
private function Statements($x)
{
$n = new JSNode($this->t, JS_BLOCK);
array_push($x->stmtStack, $n);
while (!$this->t->isDone() && $this->t->peek() != OP_RIGHT_CURLY)
$n->addNode($this->Statement($x));
array_pop($x->stmtStack);
return $n;
}
private function Block($x)
{
$this->t->mustMatch(OP_LEFT_CURLY);
$n = $this->Statements($x);
$this->t->mustMatch(OP_RIGHT_CURLY);
return $n;
}
private function Statement($x)
{
$tt = $this->t->get();
$n2 = null;
// Cases for statements ending in a right curly return early, avoiding the
// common semicolon insertion magic after this switch.
switch ($tt)
{
case KEYWORD_FUNCTION:
return $this->FunctionDefinition(
$x,
true,
count($x->stmtStack) > 1 ? STATEMENT_FORM : DECLARED_FORM
);
break;
case OP_LEFT_CURLY:
$n = $this->Statements($x);
$this->t->mustMatch(OP_RIGHT_CURLY);
return $n;
case KEYWORD_IF:
$n = new JSNode($this->t);
$n->condition = $this->ParenExpression($x);
array_push($x->stmtStack, $n);
$n->thenPart = $this->Statement($x);
$n->elsePart = $this->t->match(KEYWORD_ELSE) ? $this->Statement($x) : null;
array_pop($x->stmtStack);
return $n;
case KEYWORD_SWITCH:
$n = new JSNode($this->t);
$this->t->mustMatch(OP_LEFT_PAREN);
$n->discriminant = $this->Expression($x);
$this->t->mustMatch(OP_RIGHT_PAREN);
$n->cases = array();
$n->defaultIndex = -1;
array_push($x->stmtStack, $n);
$this->t->mustMatch(OP_LEFT_CURLY);
while (($tt = $this->t->get()) != OP_RIGHT_CURLY)
{
switch ($tt)
{
case KEYWORD_DEFAULT:
if ($n->defaultIndex >= 0)
throw $this->t->newSyntaxError('More than one switch default');
// FALL THROUGH
case KEYWORD_CASE:
$n2 = new JSNode($this->t);
if ($tt == KEYWORD_DEFAULT)
$n->defaultIndex = count($n->cases);
else
$n2->caseLabel = $this->Expression($x, OP_COLON);
break;
default:
throw $this->t->newSyntaxError('Invalid switch case');
}
$this->t->mustMatch(OP_COLON);
$n2->statements = new JSNode($this->t, JS_BLOCK);
while (($tt = $this->t->peek()) != KEYWORD_CASE && $tt != KEYWORD_DEFAULT && $tt != OP_RIGHT_CURLY)
$n2->statements->addNode($this->Statement($x));
array_push($n->cases, $n2);
}
array_pop($x->stmtStack);
return $n;
case KEYWORD_FOR:
$n = new JSNode($this->t);
$n->isLoop = true;
$this->t->mustMatch(OP_LEFT_PAREN);
if (($tt = $this->t->peek()) != OP_SEMICOLON)
{
$x->inForLoopInit = true;
if ($tt == KEYWORD_VAR || $tt == KEYWORD_CONST)
{
$this->t->get();
$n2 = $this->Variables($x);
}
else
{
$n2 = $this->Expression($x);
}
$x->inForLoopInit = false;
}
if ($n2 && $this->t->match(KEYWORD_IN))
{
$n->type = JS_FOR_IN;
if ($n2->type == KEYWORD_VAR)
{
if (count($n2->treeNodes) != 1)
{
throw $this->t->SyntaxError(
'Invalid for..in left-hand side',
$this->t->filename,
$n2->lineno
);
}
// NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name.
$n->iterator = $n2->treeNodes[0];
$n->varDecl = $n2;
}
else
{
$n->iterator = $n2;
$n->varDecl = null;
}
$n->object = $this->Expression($x);
}
else
{
$n->setup = $n2 ? $n2 : null;
$this->t->mustMatch(OP_SEMICOLON);
$n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x);
$this->t->mustMatch(OP_SEMICOLON);
$n->update = $this->t->peek() == OP_RIGHT_PAREN ? null : $this->Expression($x);
}
$this->t->mustMatch(OP_RIGHT_PAREN);
$n->body = $this->nest($x, $n);
return $n;
case KEYWORD_WHILE:
$n = new JSNode($this->t);
$n->isLoop = true;
$n->condition = $this->ParenExpression($x);
$n->body = $this->nest($x, $n);
return $n;
case KEYWORD_DO:
$n = new JSNode($this->t);
$n->isLoop = true;
$n->body = $this->nest($x, $n, KEYWORD_WHILE);
$n->condition = $this->ParenExpression($x);
if (!$x->ecmaStrictMode)
{
// <script language="JavaScript"> (without version hints) may need
// automatic semicolon insertion without a newline after do-while.
// See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
$this->t->match(OP_SEMICOLON);
return $n;
}
break;
case KEYWORD_BREAK:
case KEYWORD_CONTINUE:
$n = new JSNode($this->t);
if ($this->t->peekOnSameLine() == TOKEN_IDENTIFIER)
{
$this->t->get();
$n->label = $this->t->currentToken()->value;
}
$ss = $x->stmtStack;
$i = count($ss);
$label = $n->label;
if ($label)
{
do
{
if (--$i < 0)
throw $this->t->newSyntaxError('Label not found');
}
while ($ss[$i]->label != $label);
}
else
{
do
{
if (--$i < 0)
throw $this->t->newSyntaxError('Invalid ' . $tt);
}
while (!$ss[$i]->isLoop && ($tt != KEYWORD_BREAK || $ss[$i]->type != KEYWORD_SWITCH));
}
$n->target = $ss[$i];
break;
case KEYWORD_TRY:
$n = new JSNode($this->t);
$n->tryBlock = $this->Block($x);
$n->catchClauses = array();
while ($this->t->match(KEYWORD_CATCH))
{
$n2 = new JSNode($this->t);
$this->t->mustMatch(OP_LEFT_PAREN);
$n2->varName = $this->t->mustMatch(TOKEN_IDENTIFIER)->value;
if ($this->t->match(KEYWORD_IF))
{
if ($x->ecmaStrictMode)
throw $this->t->newSyntaxError('Illegal catch guard');
if (count($n->catchClauses) && !end($n->catchClauses)->guard)
throw $this->t->newSyntaxError('Guarded catch after unguarded');
$n2->guard = $this->Expression($x);
}
else
{
$n2->guard = null;
}
$this->t->mustMatch(OP_RIGHT_PAREN);
$n2->block = $this->Block($x);
array_push($n->catchClauses, $n2);
}
if ($this->t->match(KEYWORD_FINALLY))
$n->finallyBlock = $this->Block($x);
if (!count($n->catchClauses) && !$n->finallyBlock)
throw $this->t->newSyntaxError('Invalid try statement');
return $n;
case KEYWORD_CATCH:
case KEYWORD_FINALLY:
throw $this->t->newSyntaxError($tt + ' without preceding try');
case KEYWORD_THROW:
$n = new JSNode($this->t);
$n->value = $this->Expression($x);
break;
case KEYWORD_RETURN:
if (!$x->inFunction)
throw $this->t->newSyntaxError('Invalid return');
$n = new JSNode($this->t);
$tt = $this->t->peekOnSameLine();
if ($tt != TOKEN_END && $tt != TOKEN_NEWLINE && $tt != OP_SEMICOLON && $tt != OP_RIGHT_CURLY)
$n->value = $this->Expression($x);
else
$n->value = null;
break;
case KEYWORD_WITH:
$n = new JSNode($this->t);
$n->object = $this->ParenExpression($x);
$n->body = $this->nest($x, $n);
return $n;
case KEYWORD_VAR:
case KEYWORD_CONST:
$n = $this->Variables($x);
break;
case TOKEN_CONDCOMMENT_START:
case TOKEN_CONDCOMMENT_END:
$n = new JSNode($this->t);
return $n;
case KEYWORD_DEBUGGER:
$n = new JSNode($this->t);
break;
case TOKEN_NEWLINE:
case OP_SEMICOLON:
$n = new JSNode($this->t, OP_SEMICOLON);
$n->expression = null;
return $n;
default:
if ($tt == TOKEN_IDENTIFIER)
{
$this->t->scanOperand = false;
$tt = $this->t->peek();
$this->t->scanOperand = true;
if ($tt == OP_COLON)
{
$label = $this->t->currentToken()->value;
$ss = $x->stmtStack;
for ($i = count($ss) - 1; $i >= 0; --$i)
{
if ($ss[$i]->label == $label)
throw $this->t->newSyntaxError('Duplicate label');
}
$this->t->get();
$n = new JSNode($this->t, JS_LABEL);
$n->label = $label;
$n->statement = $this->nest($x, $n);
return $n;
}
}
$n = new JSNode($this->t, OP_SEMICOLON);
$this->t->unget();
$n->expression = $this->Expression($x);
$n->end = $n->expression->end;
break;
}
if ($this->t->lineno == $this->t->currentToken()->lineno)
{
$tt = $this->t->peekOnSameLine();
if ($tt != TOKEN_END && $tt != TOKEN_NEWLINE && $tt != OP_SEMICOLON && $tt != OP_RIGHT_CURLY)
throw $this->t->newSyntaxError('Missing ; before statement');
}
$this->t->match(OP_SEMICOLON);
return $n;
}
private function FunctionDefinition($x, $requireName, $functionForm)
{
$f = new JSNode($this->t);
if ($f->type != KEYWORD_FUNCTION)
$f->type = ($f->value == 'get') ? JS_GETTER : JS_SETTER;
if ($this->t->match(TOKEN_IDENTIFIER))
$f->name = $this->t->currentToken()->value;
elseif ($requireName)
throw $this->t->newSyntaxError('Missing function identifier');
$this->t->mustMatch(OP_LEFT_PAREN);
$f->params = array();
while (($tt = $this->t->get()) != OP_RIGHT_PAREN)
{
if ($tt != TOKEN_IDENTIFIER)
throw $this->t->newSyntaxError('Missing formal parameter');
array_push($f->params, $this->t->currentToken()->value);
if ($this->t->peek() != OP_RIGHT_PAREN)
$this->t->mustMatch(OP_COMMA);
}
$this->t->mustMatch(OP_LEFT_CURLY);
$x2 = new JSCompilerContext(true);
$f->body = $this->Script($x2);
$this->t->mustMatch(OP_RIGHT_CURLY);
$f->end = $this->t->currentToken()->end;
$f->functionForm = $functionForm;
if ($functionForm == DECLARED_FORM)
array_push($x->funDecls, $f);
return $f;
}
private function Variables($x)
{
$n = new JSNode($this->t);
do
{
$this->t->mustMatch(TOKEN_IDENTIFIER);
$n2 = new JSNode($this->t);
$n2->name = $n2->value;
if ($this->t->match(OP_ASSIGN))
{
if ($this->t->currentToken()->assignOp)
throw $this->t->newSyntaxError('Invalid variable initialization');
$n2->initializer = $this->Expression($x, OP_COMMA);
}
$n2->readOnly = $n->type == KEYWORD_CONST;
$n->addNode($n2);
array_push($x->varDecls, $n2);
}
while ($this->t->match(OP_COMMA));
return $n;
}
private function Expression($x, $stop=false)
{
$operators = array();
$operands = array();
$n = false;
$bl = $x->bracketLevel;
$cl = $x->curlyLevel;
$pl = $x->parenLevel;
$hl = $x->hookLevel;
while (($tt = $this->t->get()) != TOKEN_END)
{
if ($tt == $stop &&
$x->bracketLevel == $bl &&
$x->curlyLevel == $cl &&
$x->parenLevel == $pl &&
$x->hookLevel == $hl
)
{
// Stop only if tt matches the optional stop parameter, and that
// token is not quoted by some kind of bracket.
break;
}
switch ($tt)
{
case OP_SEMICOLON:
// NB: cannot be empty, Statement handled that.
break 2;
case OP_HOOK:
if ($this->t->scanOperand)
break 2;
while ( !empty($operators) &&
$this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt]
)
$this->reduce($operators, $operands);
array_push($operators, new JSNode($this->t));
++$x->hookLevel;
$this->t->scanOperand = true;
$n = $this->Expression($x);
if (!$this->t->match(OP_COLON))
break 2;
--$x->hookLevel;
array_push($operands, $n);
break;
case OP_COLON:
if ($x->hookLevel)
break 2;
throw $this->t->newSyntaxError('Invalid label');
break;
case OP_ASSIGN:
if ($this->t->scanOperand)
break 2;
// Use >, not >=, for right-associative ASSIGN
while ( !empty($operators) &&
$this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt]
)
$this->reduce($operators, $operands);
array_push($operators, new JSNode($this->t));
end($operands)->assignOp = $this->t->currentToken()->assignOp;
$this->t->scanOperand = true;
break;
case KEYWORD_IN:
// An in operator should not be parsed if we're parsing the head of
// a for (...) loop, unless it is in the then part of a conditional
// expression, or parenthesized somehow.
if ($x->inForLoopInit && !$x->hookLevel &&
!$x->bracketLevel && !$x->curlyLevel &&
!$x->parenLevel
)
break 2;
// FALL THROUGH
case OP_COMMA:
// A comma operator should not be parsed if we're parsing the then part
// of a conditional expression unless it's parenthesized somehow.
if ($tt == OP_COMMA && $x->hookLevel &&
!$x->bracketLevel && !$x->curlyLevel &&
!$x->parenLevel
)
break 2;
// Treat comma as left-associative so reduce can fold left-heavy
// COMMA trees into a single array.
// FALL THROUGH
case OP_OR:
case OP_AND:
case OP_BITWISE_OR:
case OP_BITWISE_XOR:
case OP_BITWISE_AND:
case OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE:
case OP_LT: case OP_LE: case OP_GE: case OP_GT:
case KEYWORD_INSTANCEOF:
case OP_LSH: case OP_RSH: case OP_URSH:
case OP_PLUS: case OP_MINUS:
case OP_MUL: case OP_DIV: case OP_MOD:
case OP_DOT:
if ($this->t->scanOperand)
break 2;
while ( !empty($operators) &&
$this->opPrecedence[end($operators)->type] >= $this->opPrecedence[$tt]
)
$this->reduce($operators, $operands);
if ($tt == OP_DOT)
{
$this->t->mustMatch(TOKEN_IDENTIFIER);
array_push($operands, new JSNode($this->t, OP_DOT, array_pop($operands), new JSNode($this->t)));
}
else
{
array_push($operators, new JSNode($this->t));
$this->t->scanOperand = true;
}
break;
case KEYWORD_DELETE: case KEYWORD_VOID: case KEYWORD_TYPEOF:
case OP_NOT: case OP_BITWISE_NOT: case OP_UNARY_PLUS: case OP_UNARY_MINUS:
case KEYWORD_NEW:
if (!$this->t->scanOperand)
break 2;
array_push($operators, new JSNode($this->t));
break;
case OP_INCREMENT: case OP_DECREMENT:
if ($this->t->scanOperand)
{
array_push($operators, new JSNode($this->t)); // prefix increment or decrement
}
else
{
// Don't cross a line boundary for postfix {in,de}crement.
$t = $this->t->tokens[($this->t->tokenIndex + $this->t->lookahead - 1) & 3];
if ($t && $t->lineno != $this->t->lineno)
break 2;
if (!empty($operators))
{
// Use >, not >=, so postfix has higher precedence than prefix.
while ($this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt])
$this->reduce($operators, $operands);
}
$n = new JSNode($this->t, $tt, array_pop($operands));
$n->postfix = true;
array_push($operands, $n);
}
break;
case KEYWORD_FUNCTION:
if (!$this->t->scanOperand)
break 2;
array_push($operands, $this->FunctionDefinition($x, false, EXPRESSED_FORM));
$this->t->scanOperand = false;
break;
case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE:
case TOKEN_IDENTIFIER: case TOKEN_NUMBER: case TOKEN_STRING: case TOKEN_REGEXP:
if (!$this->t->scanOperand)
break 2;
array_push($operands, new JSNode($this->t));
$this->t->scanOperand = false;
break;
case TOKEN_CONDCOMMENT_START:
case TOKEN_CONDCOMMENT_END:
if ($this->t->scanOperand)
array_push($operators, new JSNode($this->t));
else
array_push($operands, new JSNode($this->t));
break;
case OP_LEFT_BRACKET:
if ($this->t->scanOperand)
{
// Array initialiser. Parse using recursive descent, as the
// sub-grammar here is not an operator grammar.
$n = new JSNode($this->t, JS_ARRAY_INIT);
while (($tt = $this->t->peek()) != OP_RIGHT_BRACKET)
{
if ($tt == OP_COMMA)
{
$this->t->get();
$n->addNode(null);
continue;
}
$n->addNode($this->Expression($x, OP_COMMA));
if (!$this->t->match(OP_COMMA))
break;
}
$this->t->mustMatch(OP_RIGHT_BRACKET);
array_push($operands, $n);
$this->t->scanOperand = false;
}
else
{
// Property indexing operator.
array_push($operators, new JSNode($this->t, JS_INDEX));
$this->t->scanOperand = true;
++$x->bracketLevel;
}
break;
case OP_RIGHT_BRACKET:
if ($this->t->scanOperand || $x->bracketLevel == $bl)
break 2;
while ($this->reduce($operators, $operands)->type != JS_INDEX)
continue;
--$x->bracketLevel;
break;
case OP_LEFT_CURLY:
if (!$this->t->scanOperand)
break 2;
// Object initialiser. As for array initialisers (see above),
// parse using recursive descent.
++$x->curlyLevel;
$n = new JSNode($this->t, JS_OBJECT_INIT);
while (!$this->t->match(OP_RIGHT_CURLY))
{
do
{
$tt = $this->t->get();
$tv = $this->t->currentToken()->value;
if (($tv == 'get' || $tv == 'set') && $this->t->peek() == TOKEN_IDENTIFIER)
{
if ($x->ecmaStrictMode)
throw $this->t->newSyntaxError('Illegal property accessor');
$n->addNode($this->FunctionDefinition($x, true, EXPRESSED_FORM));
}
else
{
switch ($tt)
{
case TOKEN_IDENTIFIER:
case TOKEN_NUMBER:
case TOKEN_STRING:
$id = new JSNode($this->t);
break;
case OP_RIGHT_CURLY:
if ($x->ecmaStrictMode)
throw $this->t->newSyntaxError('Illegal trailing ,');
break 3;
default:
throw $this->t->newSyntaxError('Invalid property name');
}
$this->t->mustMatch(OP_COLON);
$n->addNode(new JSNode($this->t, JS_PROPERTY_INIT, $id, $this->Expression($x, OP_COMMA)));
}
}
while ($this->t->match(OP_COMMA));
$this->t->mustMatch(OP_RIGHT_CURLY);
break;
}
array_push($operands, $n);
$this->t->scanOperand = false;
--$x->curlyLevel;
break;
case OP_RIGHT_CURLY:
if (!$this->t->scanOperand && $x->curlyLevel != $cl)
throw new Exception('PANIC: right curly botch');
break 2;
case OP_LEFT_PAREN:
if ($this->t->scanOperand)
{
array_push($operators, new JSNode($this->t, JS_GROUP));
}
else
{
while ( !empty($operators) &&
$this->opPrecedence[end($operators)->type] > $this->opPrecedence[KEYWORD_NEW]
)
$this->reduce($operators, $operands);
// Handle () now, to regularize the n-ary case for n > 0.
// We must set scanOperand in case there are arguments and
// the first one is a regexp or unary+/-.
$n = end($operators);
$this->t->scanOperand = true;
if ($this->t->match(OP_RIGHT_PAREN))
{
if ($n && $n->type == KEYWORD_NEW)
{
array_pop($operators);
$n->addNode(array_pop($operands));
}
else
{
$n = new JSNode($this->t, JS_CALL, array_pop($operands), new JSNode($this->t, JS_LIST));
}
array_push($operands, $n);
$this->t->scanOperand = false;
break;
}
if ($n && $n->type == KEYWORD_NEW)
$n->type = JS_NEW_WITH_ARGS;
else
array_push($operators, new JSNode($this->t, JS_CALL));
}
++$x->parenLevel;
break;
case OP_RIGHT_PAREN:
if ($this->t->scanOperand || $x->parenLevel == $pl)
break 2;
while (($tt = $this->reduce($operators, $operands)->type) != JS_GROUP &&
$tt != JS_CALL && $tt != JS_NEW_WITH_ARGS
)
{
continue;
}
if ($tt != JS_GROUP)
{
$n = end($operands);
if ($n->treeNodes[1]->type != OP_COMMA)
$n->treeNodes[1] = new JSNode($this->t, JS_LIST, $n->treeNodes[1]);
else
$n->treeNodes[1]->type = JS_LIST;
}
--$x->parenLevel;
break;
// Automatic semicolon insertion means we may scan across a newline
// and into the beginning of another statement. If so, break out of
// the while loop and let the t.scanOperand logic handle errors.
default:
break 2;
}
}
if ($x->hookLevel != $hl)
throw $this->t->newSyntaxError('Missing : in conditional expression');
if ($x->parenLevel != $pl)
throw $this->t->newSyntaxError('Missing ) in parenthetical');
if ($x->bracketLevel != $bl)
throw $this->t->newSyntaxError('Missing ] in index expression');
if ($this->t->scanOperand)
throw $this->t->newSyntaxError('Missing operand');
// Resume default mode, scanning for operands, not operators.
$this->t->scanOperand = true;
$this->t->unget();
while (count($operators))
$this->reduce($operators, $operands);
return array_pop($operands);
}
private function ParenExpression($x)
{
$this->t->mustMatch(OP_LEFT_PAREN);
$n = $this->Expression($x);
$this->t->mustMatch(OP_RIGHT_PAREN);
return $n;
}
// Statement stack and nested statement handler.
private function nest($x, $node, $end = false)
{
array_push($x->stmtStack, $node);
$n = $this->statement($x);
array_pop($x->stmtStack);
if ($end)
$this->t->mustMatch($end);
return $n;
}
private function reduce(&$operators, &$operands)
{
$n = array_pop($operators);
$op = $n->type;
$arity = $this->opArity[$op];
$c = count($operands);
if ($arity == -2)
{
// Flatten left-associative trees
if ($c >= 2)
{
$left = $operands[$c - 2];
if ($left->type == $op)
{
$right = array_pop($operands);
$left->addNode($right);
return $left;
}
}
$arity = 2;
}
// Always use push to add operands to n, to update start and end
$a = array_splice($operands, $c - $arity);
for ($i = 0; $i < $arity; $i++)
$n->addNode($a[$i]);
// Include closing bracket or postfix operator in [start,end]
$te = $this->t->currentToken()->end;
if ($n->end < $te)
$n->end = $te;
array_push($operands, $n);
return $n;
}
}
class JSCompilerContext
{
public $inFunction = false;
public $inForLoopInit = false;
public $ecmaStrictMode = false;
public $bracketLevel = 0;
public $curlyLevel = 0;
public $parenLevel = 0;
public $hookLevel = 0;
public $stmtStack = array();
public $funDecls = array();
public $varDecls = array();
public function __construct($inFunction)
{
$this->inFunction = $inFunction;
}
}
class JSNode
{
private $type;
private $value;
private $lineno;
private $start;
private $end;
public $treeNodes = array();
public $funDecls = array();
public $varDecls = array();
public function __construct($t, $type=0)
{
if ($token = $t->currentToken())
{
$this->type = $type ? $type : $token->type;
$this->value = $token->value;
$this->lineno = $token->lineno;
$this->start = $token->start;
$this->end = $token->end;
}
else
{
$this->type = $type;
$this->lineno = $t->lineno;
}
if (($numargs = func_num_args()) > 2)
{
$args = func_get_args();
for ($i = 2; $i < $numargs; $i++)
$this->addNode($args[$i]);
}
}
// we don't want to bloat our object with all kind of specific properties, so we use overloading
public function __set($name, $value)
{
$this->$name = $value;
}
public function __get($name)
{
if (isset($this->$name))
return $this->$name;
return null;
}
public function addNode($node)
{
if ($node !== null)
{
if ($node->start < $this->start)
$this->start = $node->start;
if ($this->end < $node->end)
$this->end = $node->end;
}
$this->treeNodes[] = $node;
}
}
class JSTokenizer
{
private $cursor = 0;
private $source;
public $tokens = array();
public $tokenIndex = 0;
public $lookahead = 0;
public $scanNewlines = false;
public $scanOperand = true;
public $filename;
public $lineno;
private $keywords = array(
'break',
'case', 'catch', 'const', 'continue',
'debugger', 'default', 'delete', 'do',
'else', 'enum',
'false', 'finally', 'for', 'function',
'if', 'in', 'instanceof',
'new', 'null',
'return',
'switch',
'this', 'throw', 'true', 'try', 'typeof',
'var', 'void',
'while', 'with'
);
private $opTypeNames = array(
';', ',', '?', ':', '||', '&&', '|', '^',
'&', '===', '==', '=', '!==', '!=', '<<', '<=',
'<', '>>>', '>>', '>=', '>', '++', '--', '+',
'-', '*', '/', '%', '!', '~', '.', '[',
']', '{', '}', '(', ')', '@*/'
);
private $assignOps = array('|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%');
private $opRegExp;
public function __construct()
{
$this->opRegExp = '#^(' . implode('|', array_map('preg_quote', $this->opTypeNames)) . ')#';
}
public function init($source, $filename = '', $lineno = 1)
{
$this->source = $source;
$this->filename = $filename ? $filename : '[inline]';
$this->lineno = $lineno;
$this->cursor = 0;
$this->tokens = array();
$this->tokenIndex = 0;
$this->lookahead = 0;
$this->scanNewlines = false;
$this->scanOperand = true;
}
public function getInput($chunksize)
{
if ($chunksize)
return substr($this->source, $this->cursor, $chunksize);
return substr($this->source, $this->cursor);
}
public function isDone()
{
return $this->peek() == TOKEN_END;
}
public function match($tt)
{
return $this->get() == $tt || $this->unget();
}
public function mustMatch($tt)
{
if (!$this->match($tt))
throw $this->newSyntaxError('Unexpected token; token ' . $tt . ' expected');
return $this->currentToken();
}
public function peek()
{
if ($this->lookahead)
{
$next = $this->tokens[($this->tokenIndex + $this->lookahead) & 3];
if ($this->scanNewlines && $next->lineno != $this->lineno)
$tt = TOKEN_NEWLINE;
else
$tt = $next->type;
}
else
{
$tt = $this->get();
$this->unget();
}
return $tt;
}
public function peekOnSameLine()
{
$this->scanNewlines = true;
$tt = $this->peek();
$this->scanNewlines = false;
return $tt;
}
public function currentToken()
{
if (!empty($this->tokens))
return $this->tokens[$this->tokenIndex];
}
public function get($chunksize = 1000)
{
while($this->lookahead)
{
$this->lookahead--;
$this->tokenIndex = ($this->tokenIndex + 1) & 3;
$token = $this->tokens[$this->tokenIndex];
if ($token->type != TOKEN_NEWLINE || $this->scanNewlines)
return $token->type;
}
$conditional_comment = false;
// strip whitespace and comments
while(true)
{
$input = $this->getInput($chunksize);
// whitespace handling; gobble up \r as well (effectively we don't have support for MAC newlines!)
$re = $this->scanNewlines ? '/^[ \r\t]+/' : '/^\s+/';
if (preg_match($re, $input, $match))
{
$spaces = $match[0];
$spacelen = strlen($spaces);
$this->cursor += $spacelen;
if (!$this->scanNewlines)
$this->lineno += substr_count($spaces, "\n");
if ($spacelen == $chunksize)
continue; // complete chunk contained whitespace
$input = $this->getInput($chunksize);
if ($input == '' || $input[0] != '/')
break;
}
// Comments
if (!preg_match('/^\/(?:\*(@(?:cc_on|if|elif|else|end))?.*?\*\/|\/[^\n]*)/s', $input, $match))
{
if (!$chunksize)
break;
// retry with a full chunk fetch; this also prevents breakage of long regular expressions (which will never match a comment)
$chunksize = null;
continue;
}
// check if this is a conditional (JScript) comment
if (!empty($match[1]))
{
$match[0] = '/*' . $match[1];
$conditional_comment = true;
break;
}
else
{
$this->cursor += strlen($match[0]);
$this->lineno += substr_count($match[0], "\n");
}
}
if ($input == '')
{
$tt = TOKEN_END;
$match = array('');
}
elseif ($conditional_comment)
{
$tt = TOKEN_CONDCOMMENT_START;
}
else
{
switch ($input[0])
{
case '0':
// hexadecimal
if (($input[1] == 'x' || $input[1] == 'X') && preg_match('/^0x[0-9a-f]+/i', $input, $match))
{
$tt = TOKEN_NUMBER;
break;
}
// FALL THROUGH
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
// should always match
preg_match('/^\d+(?:\.\d*)?(?:[eE][-+]?\d+)?/', $input, $match);
$tt = TOKEN_NUMBER;
break;
case "'":
if (preg_match('/^\'(?:[^\\\\\'\r\n]++|\\\\(?:.|\r?\n))*\'/', $input, $match))
{
$tt = TOKEN_STRING;
}
else
{
if ($chunksize)
return $this->get(null); // retry with a full chunk fetch
throw $this->newSyntaxError('Unterminated string literal');
}
break;
case '"':
if (preg_match('/^"(?:[^\\\\"\r\n]++|\\\\(?:.|\r?\n))*"/', $input, $match))
{
$tt = TOKEN_STRING;
}
else
{
if ($chunksize)
return $this->get(null); // retry with a full chunk fetch
throw $this->newSyntaxError('Unterminated string literal');
}
break;
case '/':
if ($this->scanOperand && preg_match('/^\/((?:\\\\.|\[(?:\\\\.|[^\]])*\]|[^\/])+)\/([gimy]*)/', $input, $match))
{
$tt = TOKEN_REGEXP;
break;
}
// FALL THROUGH
case '|':
case '^':
case '&':
case '<':
case '>':
case '+':
case '-':
case '*':
case '%':
case '=':
case '!':
// should always match
preg_match($this->opRegExp, $input, $match);
$op = $match[0];
if (in_array($op, $this->assignOps) && $input[strlen($op)] == '=')
{
$tt = OP_ASSIGN;
$match[0] .= '=';
}
else
{
$tt = $op;
if ($this->scanOperand)
{
if ($op == OP_PLUS)
$tt = OP_UNARY_PLUS;
elseif ($op == OP_MINUS)
$tt = OP_UNARY_MINUS;
}
$op = null;
}
break;
case '.':
if (preg_match('/^\.\d+(?:[eE][-+]?\d+)?/', $input, $match))
{
$tt = TOKEN_NUMBER;
break;
}
// FALL THROUGH
case ';':
case ',':
case '?':
case ':':
case '~':
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
// these are all single
$match = array($input[0]);
$tt = $input[0];
break;
case '@':
// check end of conditional comment
if (substr($input, 0, 3) == '@*/')
{
$match = array('@*/');
$tt = TOKEN_CONDCOMMENT_END;
}
else
throw $this->newSyntaxError('Illegal token');
break;
case "\n":
if ($this->scanNewlines)
{
$match = array("\n");
$tt = TOKEN_NEWLINE;
}
else
throw $this->newSyntaxError('Illegal token');
break;
default:
// FIXME: add support for unicode and unicode escape sequence \uHHHH
if (preg_match('/^[$\w]+/', $input, $match))
{
$tt = in_array($match[0], $this->keywords) ? $match[0] : TOKEN_IDENTIFIER;
}
else
throw $this->newSyntaxError('Illegal token');
}
}
$this->tokenIndex = ($this->tokenIndex + 1) & 3;
if (!isset($this->tokens[$this->tokenIndex]))
$this->tokens[$this->tokenIndex] = new JSToken();
$token = $this->tokens[$this->tokenIndex];
$token->type = $tt;
if ($tt == OP_ASSIGN)
$token->assignOp = $op;
$token->start = $this->cursor;
$token->value = $match[0];
$this->cursor += strlen($match[0]);
$token->end = $this->cursor;
$token->lineno = $this->lineno;
return $tt;
}
public function unget()
{
if (++$this->lookahead == 4)
throw $this->newSyntaxError('PANIC: too much lookahead!');
$this->tokenIndex = ($this->tokenIndex - 1) & 3;
}
public function newSyntaxError($m)
{
return new Exception('Parse error: ' . $m . ' in file \'' . $this->filename . '\' on line ' . $this->lineno);
}
}
class JSToken
{
public $type;
public $value;
public $start;
public $end;
public $lineno;
public $assignOp;
}
================================================
FILE: application/libraries/minify/cssmin-v3.0.1.php
================================================
<?php
/**
* CssMin - A (simple) css minifier with benefits
*
* --
* Copyright (c) 2011 Joe Scylla <joe.scylla@gmail.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 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 CssMin
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
/**
* Abstract definition of a CSS token class.
*
* Every token has to extend this class.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssToken
{
/**
* Returns the token as string.
*
* @return string
*/
abstract public function __toString();
}
/**
* Abstract definition of a for a ruleset start token.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssRulesetStartToken extends aCssToken
{
}
/**
* Abstract definition of a for ruleset end token.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssRulesetEndToken extends aCssToken
{
/**
* Implements {@link aCssToken::__toString()}.
*
* @return string
*/
public function __toString()
{
return "}";
}
}
/**
* Abstract definition of a parser plugin.
*
* Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a
* stylesheet.
*
* @package CssMin/Parser/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssParserPlugin
{
/**
* Plugin configuration.
*
* @var array
*/
protected $configuration = array();
/**
* The CssParser of the plugin.
*
* @var CssParser
*/
protected $parser = null;
/**
* Plugin buffer.
*
* @var string
*/
protected $buffer = "";
/**
* Constructor.
*
* @param CssParser $parser The CssParser object of this plugin.
* @param array $configuration Plugin configuration [optional]
* @return void
*/
public function __construct(CssParser $parser, array $configuration = null)
{
$this->configuration = $configuration;
$this->parser = $parser;
}
/**
* Returns the array of chars triggering the parser plugin.
*
* @return array
*/
abstract public function getTriggerChars();
/**
* Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin.
*
* @return array
*/
abstract public function getTriggerStates();
/**
* Parser routine of the plugin.
*
* @param integer $index Current index
* @param string $char Current char
* @param string $previousChar Previous char
* @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
*/
abstract public function parse($index, $char, $previousChar, $state);
}
/**
* Abstract definition of a minifier plugin class.
*
* Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to
* extend this class.
*
* @package CssMin/Minifier/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssMinifierPlugin
{
/**
* Plugin configuration.
*
* @var array
*/
protected $configuration = array();
/**
* The CssMinifier of the plugin.
*
* @var CssMinifier
*/
protected $minifier = null;
/**
* Constructor.
*
* @param CssMinifier $minifier The CssMinifier object of this plugin.
* @param array $configuration Plugin configuration [optional]
* @return void
*/
public function __construct(CssMinifier $minifier, array $configuration = array())
{
$this->configuration = $configuration;
$this->minifier = $minifier;
}
/**
* Apply the plugin to the token.
*
* @param aCssToken $token Token to process
* @return boolean Return TRUE to break the processing of this token; FALSE to continue
*/
abstract public function apply(aCssToken &$token);
/**
* --
*
* @return array
*/
abstract public function getTriggerTokens();
}
/**
* Abstract definition of a minifier filter class.
*
* Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter
* has to extend this class.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssMinifierFilter
{
/**
* Filter configuration.
*
* @var array
*/
protected $configuration = array();
/**
* The CssMinifier of the filter.
*
* @var CssMinifier
*/
protected $minifier = null;
/**
* Constructor.
*
* @param CssMinifier $minifier The CssMinifier object of this plugin.
* @param array $configuration Filter configuration [optional]
* @return void
*/
public function __construct(CssMinifier $minifier, array $configuration = array())
{
$this->configuration = $configuration;
$this->minifier = $minifier;
}
/**
* Filter the tokens.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
abstract public function apply(array &$tokens);
}
/**
* Abstract formatter definition.
*
* Every formatter have to extend this class.
*
* @package CssMin/Formatter
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssFormatter
{
/**
* Indent string.
*
* @var string
*/
protected $indent = " ";
/**
* Declaration padding.
*
* @var integer
*/
protected $padding = 0;
/**
* Tokens.
*
* @var array
*/
protected $tokens = array();
/**
* Constructor.
*
* @param array $tokens Array of CssToken
* @param string $indent Indent string [optional]
* @param integer $padding Declaration value padding [optional]
*/
public function __construct(array $tokens, $indent = null, $padding = null)
{
$this->tokens = $tokens;
$this->indent = !is_null($indent) ? $indent : $this->indent;
$this->padding = !is_null($padding) ? $padding : $this->padding;
}
/**
* Returns the array of aCssToken as formatted string.
*
* @return string
*/
abstract public function __toString();
}
/**
* Abstract definition of a ruleset declaration token.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssDeclarationToken extends aCssToken
{
/**
* Is the declaration flagged as important?
*
* @var boolean
*/
public $IsImportant = false;
/**
* Is the declaration flagged as last one of the ruleset?
*
* @var boolean
*/
public $IsLast = false;
/**
* Property name of the declaration.
*
* @var string
*/
public $Property = "";
/**
* Value of the declaration.
*
* @var string
*/
public $Value = "";
/**
* Set the properties of the @font-face declaration.
*
* @param string $property Property of the declaration
* @param string $value Value of the declaration
* @param boolean $isImportant Is the !important flag is set?
* @param boolean $IsLast Is the declaration the last one of the block?
* @return void
*/
public function __construct($property, $value, $isImportant = false, $isLast = false)
{
$this->Property = $property;
$this->Value = $value;
$this->IsImportant = $isImportant;
$this->IsLast = $isLast;
}
/**
* Implements {@link aCssToken::__toString()}.
*
* @return string
*/
public function __toString()
{
return $this->Property . ":" . $this->Value . ($this->IsImportant ? " !important" : "") . ($this->IsLast ? "" : ";");
}
}
/**
* Abstract definition of a for at-rule block start token.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssAtBlockStartToken extends aCssToken
{
}
/**
* Abstract definition of a for at-rule block end token.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
abstract class aCssAtBlockEndToken extends aCssToken
{
/**
* Implements {@link aCssToken::__toString()}.
*
* @return string
*/
public function __toString()
{
return "}";
}
}
/**
* {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}.
*
* @package CssMin/Formatter
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssWhitesmithsFormatter extends aCssFormatter
{
/**
* Implements {@link aCssFormatter::__toString()}.
*
* @return string
*/
public function __toString()
{
$r = array();
$level = 0;
for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
{
$token = $this->tokens[$i];
$class = get_class($token);
$indent = str_repeat($this->indent, $level);
if ($class === "CssCommentToken")
{
$lines = array_map("trim", explode("\n", $token->Comment));
for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
{
$r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii];
}
}
elseif ($class === "CssAtCharsetToken")
{
$r[] = $indent . "@charset " . $token->Charset . ";";
}
elseif ($class === "CssAtFontFaceStartToken")
{
$r[] = $indent . "@font-face";
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class === "CssAtImportToken")
{
$r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";";
}
elseif ($class === "CssAtKeyframesStartToken")
{
$r[] = $indent . "@keyframes \"" . $token->Name . "\"";
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class === "CssAtMediaStartToken")
{
$r[] = $indent . "@media " . implode(", ", $token->MediaTypes);
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class === "CssAtPageStartToken")
{
$r[] = $indent . "@page";
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class === "CssAtVariablesStartToken")
{
$r[] = $indent . "@variables " . implode(", ", $token->MediaTypes);
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken")
{
$r[] = $indent . implode(", ", $token->Selectors);
$r[] = $this->indent . $indent . "{";
$level++;
}
elseif ($class == "CssAtFontFaceDeclarationToken"
|| $class === "CssAtKeyframesRulesetDeclarationToken"
|| $class === "CssAtPageDeclarationToken"
|| $class == "CssAtVariablesDeclarationToken"
|| $class === "CssRulesetDeclarationToken"
)
{
$declaration = $indent . $token->Property . ": ";
if ($this->padding)
{
$declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT);
}
$r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";";
}
elseif ($class === "CssAtFontFaceEndToken"
|| $class === "CssAtMediaEndToken"
|| $class === "CssAtKeyframesEndToken"
|| $class === "CssAtKeyframesRulesetEndToken"
|| $class === "CssAtPageEndToken"
|| $class === "CssAtVariablesEndToken"
|| $class === "CssRulesetEndToken"
)
{
$r[] = $indent . "}";
$level--;
}
}
return implode("\n", $r);
}
}
/**
* This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value.
*
* This plugin only apply the variable values. The variable values itself will get parsed by the
* {@link CssVariablesMinifierFilter}.
*
* Example:
* <code>
* @variables
* {
* defaultColor: black;
* }
* color: var(defaultColor);
* </code>
*
* Will get converted to:
* <code>
* color:black;
* </code>
*
* @package CssMin/Minifier/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssVariablesMinifierPlugin extends aCssMinifierPlugin
{
/**
* Regular expression matching a value.
*
* @var string
*/
private $reMatch = "/var\((.+)\)/iSU";
/**
* Parsed variables.
*
* @var array
*/
private $variables = null;
/**
* Returns the variables.
*
* @return array
*/
public function getVariables()
{
return $this->variables;
}
/**
* Implements {@link aCssMinifierPlugin::minify()}.
*
* @param aCssToken $token Token to process
* @return boolean Return TRUE to break the processing of this token; FALSE to continue
*/
public function apply(aCssToken &$token)
{
if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m))
{
$mediaTypes = $token->MediaTypes;
if (!in_array("all", $mediaTypes))
{
$mediaTypes[] = "all";
}
for ($i = 0, $l = count($m[0]); $i < $l; $i++)
{
$variable = trim($m[1][$i]);
foreach ($mediaTypes as $mediaType)
{
if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable]))
{
// Variable value found => set the declaration value to the variable value and return
$token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value);
continue 2;
}
}
// If no value was found trigger an error and replace the token with a CssNullToken
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": No value found for variable <code>" . $variable . "</code> in media types <code>" . implode(", ", $mediaTypes) . "</code>", (string) $token));
$token = new CssNullToken();
return true;
}
}
return false;
}
/**
* Implements {@link aMinifierPlugin::getTriggerTokens()}
*
* @return array
*/
public function getTriggerTokens()
{
return array
(
"CssAtFontFaceDeclarationToken",
"CssAtPageDeclarationToken",
"CssRulesetDeclarationToken"
);
}
/**
* Sets the variables.
*
* @param array $variables Variables to set
* @return void
*/
public function setVariables(array $variables)
{
$this->variables = $variables;
}
}
/**
* This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule
* blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to
* declaration.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssVariablesMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$variables = array();
$defaultMediaTypes = array("all");
$mediaTypes = array();
$remove = array();
for($i = 0, $l = count($tokens); $i < $l; $i++)
{
// @variables at-rule block found
if (get_class($tokens[$i]) === "CssAtVariablesStartToken")
{
$remove[] = $i;
$mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes);
foreach ($mediaTypes as $mediaType)
{
if (!isset($variables[$mediaType]))
{
$variables[$mediaType] = array();
}
}
// Read the variable declaration tokens
for($i = $i; $i < $l; $i++)
{
// Found a variable declaration => read the variable values
if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken")
{
foreach ($mediaTypes as $mediaType)
{
$variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value;
}
$remove[] = $i;
}
// Found the variables end token => break;
elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken")
{
$remove[] = $i;
break;
}
}
}
}
// Variables in @variables at-rule blocks
foreach($variables as $mediaType => $null)
{
foreach($variables[$mediaType] as $variable => $value)
{
// If a var() statement in a variable value found...
if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m))
{
// ... then replace the var() statement with the variable values.
for ($i = 0, $l = count($m[0]); $i < $l; $i++)
{
$variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), $variables[$mediaType][$variable]);
}
}
}
}
// Remove the complete @variables at-rule block
foreach ($remove as $i)
{
$tokens[$i] = null;
}
if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin")))
{
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>CssVariablesMinifierPlugin</code> was not found but is required for <code>" . __CLASS__ . "</code>"));
}
else
{
$plugin->setVariables($variables);
}
return count($remove);
}
}
/**
* {@link aCssParserPlugin Parser plugin} for preserve parsing url() values.
*
* This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly.
*
* @package CssMin/Parser/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssUrlParserPlugin extends aCssParserPlugin
{
/**
* Implements {@link aCssParserPlugin::getTriggerChars()}.
*
* @return array
*/
public function getTriggerChars()
{
return array("(", ")");
}
/**
* Implements {@link aCssParserPlugin::getTriggerStates()}.
*
* @return array
*/
public function getTriggerStates()
{
return false;
}
/**
* Implements {@link aCssParserPlugin::parse()}.
*
* @param integer $index Current index
* @param string $char Current char
* @param string $previousChar Previous char
* @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
*/
public function parse($index, $char, $previousChar, $state)
{
// Start of string
if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" && $state !== "T_URL")
{
$this->parser->pushState("T_URL");
$this->parser->setExclusive(__CLASS__);
}
// Escaped LF in url => remove escape backslash and LF
elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL")
{
$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
}
// Parse error: Unescaped LF in string literal
elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL")
{
$line = $this->parser->getBuffer();
$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . ")"); // Replace the LF with the url string delimiter
$this->parser->popState();
$this->parser->unsetExclusive();
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_"));
}
// End of string
elseif ($char === ")" && $state === "T_URL")
{
$this->parser->popState();
$this->parser->unsetExclusive();
}
else
{
return false;
}
return true;
}
}
/**
* {@link aCssParserPlugin Parser plugin} for preserve parsing string values.
*
* This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly.
*
* @package CssMin/Parser/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssStringParserPlugin extends aCssParserPlugin
{
/**
* Current string delimiter char.
*
* @var string
*/
private $delimiterChar = null;
/**
* Implements {@link aCssParserPlugin::getTriggerChars()}.
*
* @return array
*/
public function getTriggerChars()
{
return array("\"", "'", "\n");
}
/**
* Implements {@link aCssParserPlugin::getTriggerStates()}.
*
* @return array
*/
public function getTriggerStates()
{
return false;
}
/**
* Implements {@link aCssParserPlugin::parse()}.
*
* @param integer $index Current index
* @param string $char Current char
* @param string $previousChar Previous char
* @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
*/
public function parse($index, $char, $previousChar, $state)
{
// Start of string
if (($char === "\"" || $char === "'") && $state !== "T_STRING")
{
$this->delimiterChar = $char;
$this->parser->pushState("T_STRING");
$this->parser->setExclusive(__CLASS__);
}
// Escaped LF in string => remove escape backslash and LF
elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING")
{
$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
}
// Parse error: Unescaped LF in string literal
elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING")
{
$line = $this->parser->getBuffer();
$this->parser->popState();
$this->parser->unsetExclusive();
$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_"));
$this->delimiterChar = null;
}
// End of string
elseif ($char === $this->delimiterChar && $state === "T_STRING")
{
// If the Previous char is a escape char count the amount of the previous escape chars. If the amount of
// escape chars is uneven do not end the string
if ($previousChar == "\\")
{
$source = $this->parser->getSource();
$c = 1;
$i = $index - 2;
while (substr($source, $i, 1) === "\\")
{
$c++; $i--;
}
if ($c % 2)
{
return false;
}
}
$this->parser->popState();
$this->parser->unsetExclusive();
$this->delimiterChar = null;
}
else
{
return false;
}
return true;
}
}
/**
* This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Rowan Beentje <http://assanka.net>
* @copyright Rowan Beentje <http://assanka.net>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
// Only look for ruleset start rules
if (get_class($tokens[$i]) !== "CssRulesetStartToken") { continue; }
// Look for the corresponding ruleset end
$endIndex = false;
for ($ii = $i + 1; $ii < $l; $ii++)
{
if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { continue; }
$endIndex = $ii;
break;
}
if (!$endIndex) { break; }
$startIndex = $i;
$i = $endIndex;
// Skip if there's only one token in this ruleset
if ($endIndex - $startIndex <= 2) { continue; }
// Ensure that everything between the start and end is a declaration token, for safety
for ($ii = $startIndex + 1; $ii < $endIndex; $ii++)
{
if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { continue(2); }
}
$declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1);
// Check whether a sort is required
$sortRequired = $lastPropertyName = false;
foreach ($declarations as $declaration)
{
if ($lastPropertyName)
{
if (strcmp($lastPropertyName, $declaration->Property) > 0)
{
$sortRequired = true;
break;
}
}
$lastPropertyName = $declaration->Property;
}
if (!$sortRequired) { continue; }
// Arrange the declarations alphabetically by name
usort($declarations, array(__CLASS__, "userDefinedSort1"));
// Update "IsLast" property
for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++)
{
if ($ii == $ll)
{
$declarations[$ii]->IsLast = true;
}
else
{
$declarations[$ii]->IsLast = false;
}
}
// Splice back into the array.
array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations);
$r += $endIndex - $startIndex - 1;
}
return $r;
}
/**
* User defined sort function.
*
* @return integer
*/
public static function userDefinedSort1($a, $b)
{
return strcmp($a->Property, $b->Property);
}
}
/**
* This {@link aCssToken CSS token} represents the start of a ruleset.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRulesetStartToken extends aCssRulesetStartToken
{
/**
* Array of selectors.
*
* @var array
*/
public $Selectors = array();
/**
* Set the properties of a ruleset token.
*
* @param array $selectors Selectors of the ruleset
* @return void
*/
public function __construct(array $selectors = array())
{
$this->Selectors = $selectors;
}
/**
* Implements {@link aCssToken::__toString()}.
*
* @return string
*/
public function __toString()
{
return implode(",", $this->Selectors) . "{";
}
}
/**
* {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations.
*
* Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the
* parser; including declarations as {@link CssRulesetDeclarationToken}.
*
* @package CssMin/Parser/Plugins
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRulesetParserPlugin extends aCssParserPlugin
{
/**
* Implements {@link aCssParserPlugin::getTriggerChars()}.
*
* @return array
*/
public function getTriggerChars()
{
return array(",", "{", "}", ":", ";");
}
/**
* Implements {@link aCssParserPlugin::getTriggerStates()}.
*
* @return array
*/
public function getTriggerStates()
{
return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION");
}
/**
* Selectors.
*
* @var array
*/
private $selectors = array();
/**
* Implements {@link aCssParserPlugin::parse()}.
*
* @param integer $index Current index
* @param string $char Current char
* @param string $previousChar Previous char
* @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
*/
public function parse($index, $char, $previousChar, $state)
{
// Start of Ruleset and selectors
if ($char === "," && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS"))
{
if ($state !== "T_RULESET::SELECTORS")
{
$this->parser->pushState("T_RULESET::SELECTORS");
}
$this->selectors[] = $this->parser->getAndClearBuffer(",{");
}
// End of selectors and start of declarations
elseif ($char === "{" && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS"))
{
if ($this->parser->getBuffer() !== "")
{
$this->selectors[] = $this->parser->getAndClearBuffer(",{");
if ($state == "T_RULESET::SELECTORS")
{
$this->parser->popState();
}
$this->parser->pushState("T_RULESET");
$this->parser->appendToken(new CssRulesetStartToken($this->selectors));
$this->selectors = array();
}
}
// Start of declaration
elseif ($char === ":" && $state === "T_RULESET")
{
$this->parser->pushState("T_RULESET_DECLARATION");
$this->buffer = $this->parser->getAndClearBuffer(":;", true);
}
// Unterminated ruleset declaration
elseif ($char === ":" && $state === "T_RULESET_DECLARATION")
{
// Ignore Internet Explorer filter declarations
if ($this->buffer === "filter")
{
return false;
}
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
}
// End of declaration
elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION")
{
$value = $this->parser->getAndClearBuffer(";}");
if (strtolower(substr($value, -10, 10)) === "!important")
{
$value = trim(substr($value, 0, -10));
$isImportant = true;
}
else
{
$isImportant = false;
}
$this->parser->popState();
$this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant));
// Declaration ends with a right curly brace; so we have to end the ruleset
if ($char === "}")
{
$this->parser->appendToken(new CssRulesetEndToken());
$this->parser->popState();
}
$this->buffer = "";
}
// End of ruleset
elseif ($char === "}" && $state === "T_RULESET")
{
$this->parser->popState();
$this->parser->clearBuffer();
$this->parser->appendToken(new CssRulesetEndToken());
$this->buffer = "";
$this->selectors = array();
}
else
{
return false;
}
return true;
}
}
/**
* This {@link aCssToken CSS token} represents the end of a ruleset.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRulesetEndToken extends aCssRulesetEndToken
{
}
/**
* This {@link aCssToken CSS token} represents a ruleset declaration.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRulesetDeclarationToken extends aCssDeclarationToken
{
/**
* Media types of the declaration.
*
* @var array
*/
public $MediaTypes = array("all");
/**
* Set the properties of a ddocument- or at-rule @media level declaration.
*
* @param string $property Property of the declaration
* @param string $value Value of the declaration
* @param mixed $mediaTypes Media types of the declaration
* @param boolean $isImportant Is the !important flag is set
* @param boolean $isLast Is the declaration the last one of the ruleset
* @return void
*/
public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false)
{
parent::__construct($property, $value, $isImportant, $isLast);
$this->MediaTypes = $mediaTypes ? $mediaTypes : array("all");
}
}
/**
* This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset,
* @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified
* without tailing semicolon.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
$current = get_class($tokens[$i]);
$next = isset($tokens[$i+1]) ? get_class($tokens[$i+1]) : false;
if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") ||
($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") ||
($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken"))
{
$tokens[$i]->IsLast = true;
}
}
return 0;
}
}
/**
* This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block
* rulesets).
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
$current = get_class($tokens[$i]);
$next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;
if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") ||
($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors)))
)
{
$tokens[$i] = null;
$tokens[$i + 1] = null;
$i++;
$r = $r + 2;
}
}
return $r;
}
}
/**
* This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page
* at-rule blocks.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
$current = get_class($tokens[$i]);
$next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;
if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") ||
($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") ||
($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") ||
($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken"))
{
$tokens[$i] = null;
$tokens[$i + 1] = null;
$i++;
$r = $r + 2;
}
}
return $r;
}
}
/**
* This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter
{
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
*/
public function apply(array &$tokens)
{
$r = 0;
for ($i = 0, $l = count($tokens); $i < $l; $i++)
{
if (get_class($tokens[$i]) === "CssCommentToken")
{
$tokens[$i] = null;
$r++;
}
}
return $r;
}
}
/**
* CSS Parser.
*
* @package CssMin/Parser
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssParser
{
/**
* Parse buffer.
*
* @var string
*/
private $buffer = "";
/**
* {@link aCssParserPlugin Plugins}.
*
* @var array
*/
private $plugins = array();
/**
* Source to parse.
*
* @var string
*/
private $source = "";
/**
* Current state.
*
* @var integer
*/
private $state = "T_DOCUMENT";
/**
* Exclusive state.
*
* @var string
*/
private $stateExclusive = false;
/**
* Media types state.
*
* @var mixed
*/
private $stateMediaTypes = false;
/**
* State stack.
*
* @var array
*/
private $states = array("T_DOCUMENT");
/**
* Parsed tokens.
*
* @var array
*/
private $tokens = array();
/**
* Constructer.
*
* Create instances of the used {@link aCssParserPlugin plugins}.
*
* @param string $source CSS source [optional]
* @param array $plugins Plugin configuration [optional]
* @return void
*/
public function __construct($source = null, array $plugins = null)
{
$plugins = array_merge(array
(
"Comment" => true,
"String" => true,
"Url" => true,
"Expression" => true,
"Ruleset" => true,
"AtCharset" => true,
"AtFontFace" => true,
"AtImport" => true,
"AtKeyframes" => true,
"AtMedia" => true,
"AtPage" => true,
"AtVariables" => true
), is_array($plugins) ? $plugins : array());
// Create plugin instances
foreach ($plugins as $name => $config)
{
if ($config !== false)
{
$class = "Css" . $name . "ParserPlugin";
$config = is_array($config) ? $config : array();
if (class_exists($class))
{
$this->plugins[] = new $class($this, $config);
}
else
{
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
}
}
}
if (!is_null($source))
{
$this->parse($source);
}
}
/**
* Append a token to the array of tokens.
*
* @param aCssToken $token Token to append
* @return void
*/
public function appendToken(aCssToken $token)
{
$this->tokens[] = $token;
}
/**
* Clears the current buffer.
*
* @return void
*/
public function clearBuffer()
{
$this->buffer = "";
}
/**
* Returns and clear the current buffer.
*
* @param string $trim Chars to use to trim the returned buffer
* @param boolean $tolower if TRUE the returned buffer will get converted to lower case
* @return string
*/
public function getAndClearBuffer($trim = "", $tolower = false)
{
$r = $this->getBuffer($trim, $tolower);
$this->buffer = "";
return $r;
}
/**
* Returns the current buffer.
*
* @param string $trim Chars to use to trim the returned buffer
* @param boolean $tolower if TRUE the returned buffer will get converted to lower case
* @return string
*/
public function getBuffer($trim = "", $tolower = false)
{
$r = $this->buffer;
if ($trim)
{
$r = trim($r, " \t\n\r\0\x0B" . $trim);
}
if ($tolower)
{
$r = strtolower($r);
}
return $r;
}
/**
* Returns the current media types state.
*
* @return array
*/
public function getMediaTypes()
{
return $this->stateMediaTypes;
}
/**
* Returns the CSS source.
*
* @return string
*/
public function getSource()
{
return $this->source;
}
/**
* Returns the current state.
*
* @return integer The current state
*/
public function getState()
{
return $this->state;
}
/**
* Returns a plugin by class name.
*
* @param string $name Class name of the plugin
* @return aCssParserPlugin
*/
public function getPlugin($class)
{
static $index = null;
if (is_null($index))
{
$index = array();
for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
{
$index[get_class($this->plugins[$i])] = $i;
}
}
return isset($index[$class]) ? $this->plugins[$index[$class]] : false;
}
/**
* Returns the parsed tokens.
*
* @return array
*/
public function getTokens()
{
return $this->tokens;
}
/**
* Returns if the current state equals the passed state.
*
* @param integer $state State to compare with the current state
* @return boolean TRUE is the state equals to the passed state; FALSE if not
*/
public function isState($state)
{
return ($this->state == $state);
}
/**
* Parse the CSS source and return a array with parsed tokens.
*
* @param string $source CSS source
* @return array Array with tokens
*/
public function parse($source)
{
// Reset
$this->source = "";
$this->tokens = array();
// Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create
// several helper variables for plugin handling
$globalTriggerChars = "";
$plugins = $this->plugins;
$pluginCount = count($plugins);
$pluginIndex = array();
$pluginTriggerStates = array();
$pluginTriggerChars = array();
for ($i = 0, $l = count($plugins); $i < $l; $i++)
{
$tPluginClassName = get_class($plugins[$i]);
$pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars());
$tPluginTriggerStates = $plugins[$i]->getTriggerStates();
$pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|" . implode("|", $tPluginTriggerStates) . "|";
$pluginIndex[$tPluginClassName] = $i;
for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++)
{
$c = substr($pluginTriggerChars[$i], $ii, 1);
if (strpos($globalTriggerChars, $c) === false)
{
$globalTriggerChars .= $c;
}
}
}
// Normalise line endings
$source = str_replace("\r\n", "\n", $source); // Windows to Unix line endings
$source = str_replace("\r", "\n", $source); // Mac to Unix line endings
$this->source = $source;
// Variables
$buffer = &$this->buffer;
$exclusive = &$this->stateExclusive;
$state = &$this->state;
$c = $p = null;
// --
for ($i = 0, $l = strlen($source); $i < $l; $i++)
{
// Set the current Char
$c = $source[$i]; // Is faster than: $c = substr($source, $i, 1);
// Normalize and filter double whitespace characters
if ($exclusive === false)
{
if ($c === "\n" || $c === "\t")
{
$c = " ";
}
if ($c === " " && $p === " ")
{
continue;
}
}
$buffer .= $c;
// Extended processing only if the current char is a global trigger char
if (strpos($globalTriggerChars, $c) !== false)
{
// Exclusive state is set; process with the exclusive plugin
if ($exclusive)
{
$tPluginIndex = $pluginIndex[$exclusive];
if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false))
{
$r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state);
// Return value is TRUE => continue with next char
if ($r === true)
{
continue;
}
// Return value is numeric => set new index and continue with next char
elseif ($r !== false && $r != $i)
{
$i = $r;
continue;
}
}
}
// Else iterate through the plugins
else
{
$triggerState = "|" . $state . "|";
for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++)
{
// Only process if the current char is one of the plugin trigger chars
if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false))
{
// Process with the plugin
$r = $plugins[$ii]->parse($i, $c, $p, $state);
// Return value is TRUE => break the plugin loop and and continue with next char
if ($r === true)
{
break;
}
// Return value is numeric => set new index, break the plugin loop and and continue with next char
elseif ($r !== false && $r != $i)
{
$i = $r;
break;
}
}
}
}
}
$p = $c; // Set the parent char
}
return $this->tokens;
}
/**
* Remove the last state of the state stack and return the removed stack value.
*
* @return integer Removed state value
*/
public function popState()
{
$r = array_pop($this->states);
$this->state = $this->states[count($this->states) - 1];
return $r;
}
/**
* Adds a new state onto the state stack.
*
* @param integer $state State to add onto the state stack.
* @return integer The index of the added state in the state stacks
*/
public function pushState($state)
{
$r = array_push($this->states, $state);
$this->state = $this->states[count($this->states) - 1];
return $r;
}
/**
* Sets/restores the buffer.
*
* @param string $buffer Buffer to set
* @return void
*/
public function setBuffer($buffer)
{
$this->buffer = $buffer;
}
/**
* Set the exclusive state.
*
* @param string $exclusive Exclusive state
* @return void
*/
public function setExclusive($exclusive)
{
$this->stateExclusive = $exclusive;
}
/**
* Set the media types state.
*
* @param array $mediaTypes Media types state
* @return void
*/
public function setMediaTypes(array $mediaTypes)
{
$this->stateMediaTypes = $mediaTypes;
}
/**
* Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}.
*
* @param integer $state State to set
* @return integer
*/
public function setState($state)
{
$r = array_pop($this->states);
array_push($this->states, $state);
$this->state = $this->states[count($this->states) - 1];
return $r;
}
/**
* Removes the exclusive state.
*
* @return void
*/
public function unsetExclusive()
{
$this->stateExclusive = false;
}
/**
* Removes the media types state.
*
* @return void
*/
public function unsetMediaTypes()
{
$this->stateMediaTypes = false;
}
}
/**
* {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style).
*
* @package CssMin/Formatter
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssOtbsFormatter extends aCssFormatter
{
/**
* Implements {@link aCssFormatter::__toString()}.
*
* @return string
*/
public function __toString()
{
$r = array();
$level = 0;
for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
{
$token = $this->tokens[$i];
$class = get_class($token);
$indent = str_repeat($this->indent, $level);
if ($class === "CssCommentToken")
{
$lines = array_map("trim", explode("\n", $token->Comment));
for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
{
$r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii];
}
}
elseif ($class === "CssAtCharsetToken")
{
$r[] = $indent . "@charset " . $token->Charset . ";";
}
elseif ($class === "CssAtFontFaceStartToken")
{
$r[] = $indent . "@font-face {";
$level++;
}
elseif ($class === "CssAtImportToken")
{
$r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";";
}
elseif ($class === "CssAtKeyframesStartToken")
{
$r[] = $indent . "@keyframes \"" . $token->Name . "\" {";
$level++;
}
elseif ($class === "CssAtMediaStartToken")
{
$r[] = $indent . "@media " . implode(", ", $token->MediaTypes) . " {";
$level++;
}
elseif ($class === "CssAtPageStartToken")
{
$r[] = $indent . "@page {";
$level++;
}
elseif ($class === "CssAtVariablesStartToken")
{
$r[] = $indent . "@variables " . implode(", ", $token->MediaTypes) . " {";
$level++;
}
elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken")
{
$r[] = $indent . implode(", ", $token->Selectors) . " {";
$level++;
}
elseif ($class == "CssAtFontFaceDeclarationToken"
|| $class === "CssAtKeyframesRulesetDeclarationToken"
|| $class === "CssAtPageDeclarationToken"
|| $class == "CssAtVariablesDeclarationToken"
|| $class === "CssRulesetDeclarationToken"
)
{
$declaration = $indent . $token->Property . ": ";
if ($this->padding)
{
$declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT);
}
$r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";";
}
elseif ($class === "CssAtFontFaceEndToken"
|| $class === "CssAtMediaEndToken"
|| $class === "CssAtKeyframesEndToken"
|| $class === "CssAtKeyframesRulesetEndToken"
|| $class === "CssAtPageEndToken"
|| $class === "CssAtVariablesEndToken"
|| $class === "CssRulesetEndToken"
)
{
$level--;
$r[] = str_repeat($indent, $level) . "}";
}
}
return implode("\n", $r);
}
}
/**
* This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string.
*
* @package CssMin/Tokens
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssNullToken extends aCssToken
{
/**
* Implements {@link aCssToken::__toString()}.
*
* @return string
*/
public function __toString()
{
return "";
}
}
/**
* CSS Minifier.
*
* @package CssMin/Minifier
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssMinifier
{
/**
* {@link aCssMinifierFilter Filters}.
*
* @var array
*/
private $filters = array();
/**
* {@link aCssMinifierPlugin Plugins}.
*
* @var array
*/
private $plugins = array();
/**
* Minified source.
*
* @var string
*/
private $minified = "";
/**
* Constructer.
*
* Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}.
*
* @param string $source CSS source [optional]
* @param array $filters Filter configuration [optional]
* @param array $plugins Plugin configuration [optional]
* @return void
*/
public function __construct($source = null, array $filters = null, array $plugins = null)
{
$filters = array_merge(array
(
"ImportImports" => false,
"RemoveComments" => true,
"RemoveEmptyRulesets" => true,
"RemoveEmptyAtBlocks" => true,
"ConvertLevel3Properties" => false,
"ConvertLevel3AtKeyframes" => false,
"Variables" => true,
"RemoveLastDelarationSemiColon" => true
), is_array($filters) ? $filters : array());
$plugins = array_merge(array
(
"Variables" => true,
"ConvertFontWeight" => false,
"ConvertHslColors" => false,
"ConvertRgbColors" => false,
"ConvertNamedColors" => false,
"CompressColorValues" => false,
"CompressUnitValues" => false,
"CompressExpressionValues" => false
), is_array($plugins) ? $plugins : array());
// Filters
foreach ($filters as $name => $config)
{
if ($config !== false)
{
$class = "Css" . $name . "MinifierFilter";
$config = is_array($config) ? $config : array();
if (class_exists($class))
{
$this->filters[] = new $class($this, $config);
}
else
{
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The filter <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
}
}
}
// Plugins
foreach ($plugins as $name => $config)
{
if ($config !== false)
{
$class = "Css" . $name . "MinifierPlugin";
$config = is_array($config) ? $config : array();
if (class_exists($class))
{
$this->plugins[] = new $class($this, $config);
}
else
{
CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
}
}
}
// --
if (!is_null($source))
{
$this->minify($source);
}
}
/**
* Returns the minified Source.
*
* @return string
*/
public function getMinified()
{
return $this->minified;
}
/**
* Returns a plugin by class name.
*
* @param string $name Class name of the plugin
* @return aCssMinifierPlugin
*/
public function getPlugin($class)
{
static $index = null;
if (is_null($index))
{
$index = array();
for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
{
$index[get_class($this->plugins[$i])] = $i;
}
}
return isset($index[$class]) ? $this->plugins[$index[$class]] : false;
}
/**
* Minifies the CSS source.
*
* @param string $source CSS source
* @return string
*/
public function minify($source)
{
// Variables
$r = "";
$parser = new CssParser($source);
$tokens = $parser->getTokens();
$filters = $this->filters;
$filterCount = count($this->filters);
$plugins = $this->plugins;
$pluginCount = count($plugins);
$pluginIndex = array();
$pluginTriggerTokens = array();
$globalTriggerTokens = array();
for ($i = 0, $l = count($plugins); $i < $l; $i++)
{
$tPluginClassName = get_class($plugins[$i]);
$pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens();
foreach ($pluginTriggerTokens[$i] as $v)
{
if (!in_array($v, $globalTriggerTokens))
{
$globalTriggerTokens[] = $v;
}
}
$pluginTriggerTokens[$i] = "|" . implode("|", $pluginTriggerTokens[$i]) . "|";
$pluginIndex[$tPluginClassName] = $i;
}
$globalTriggerTokens = "|" . implode("|", $globalTriggerTokens) . "|";
/*
* Apply filters
*/
for($i = 0; $i < $filterCount; $i++)
{
// Apply the filter; if the return value is larger than 0...
if ($filters[$i]->apply($tokens) > 0)
{
// ...then filter null values and rebuild the token array
$tokens = array_values(array_filter($tokens));
}
}
$tokenCount = count($tokens);
/*
* Apply plugins
*/
for($i = 0; $i < $tokenCount; $i++)
{
$triggerToken = "|" . get_class($tokens[$i]) . "|";
if (strpos($globalTriggerTokens, $triggerToken) !== false)
{
for($ii = 0; $ii < $pluginCount; $ii++)
{
if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false)
{
// Apply the plugin; if the return value is TRUE continue to the next token
if ($plugins[$ii]->apply($tokens[$i]) === true)
{
continue 2;
}
}
}
}
}
// Stringify the tokens
for($i = 0; $i < $tokenCount; $i++)
{
$r .= (string) $tokens[$i];
}
$this->minified = $r;
return $r;
}
}
/**
* CssMin - A (simple) css minifier with benefits
*
* --
* Copyright (c) 2011 Joe Scylla <joe.scylla@gmail.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 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 CssMin
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssMin
{
/**
* Index of classes
*
* @var array
*/
private static $classIndex = array();
/**
* Parse/minify errors
*
* @var array
*/
private static $errors = array();
/**
* Verbose output.
*
* @var boolean
*/
private static $isVerbose = false;
/**
* {@link http://goo.gl/JrW54 Autoload} function of CssMin.
*
* @param string $class Name of the class
* @return void
*/
public static function autoload($class)
{
if (isset(self::$classIndex[$class]))
{
require(self::$classIndex[$class]);
}
}
/**
* Return errors
*
* @return array of {CssError}.
*/
public static function getErrors()
{
return self::$errors;
}
/**
* Returns if there were errors.
*
* @return boolean
*/
public static function hasErrors()
{
return count(self::$errors) > 0;
}
/**
* Initialises CssMin.
*
* @return void
*/
public static function initialise()
{
// Create the class index for autoloading or including
$paths = array(dirname(__FILE__));
// changed by michalsn on 2019/07/26
// each function was deprecated
foreach ($paths as $i => $path)
{
$subDirectorys = glob($path . "*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);
if (is_array($subDirectorys))
{
foreach ($subDirectorys as $subDirectory)
{
$paths[] = $subDirectory;
}
}
$files = glob($path . "*.php", 0);
if (is_array($files))
{
foreach ($files as $file)
{
$class = substr(basename($file), 0, -4);
self::$classIndex[$class] = $file;
}
}
}
krsort(self::$classIndex);
// Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because
// __autoload() breaks if spl_autoload_register() is used.
if (function_exists("spl_autoload_register") && !is_callable("__autoload"))
{
spl_autoload_register(array(__CLASS__, "autoload"));
}
// Otherwise include all class files
else
{
foreach (self::$classIndex as $class => $file)
{
if (!class_exists($class))
{
require_once($file);
}
}
}
}
/**
* Minifies CSS source.
*
* @param string $source CSS source
* @param array $filters Filter configuration [optional]
* @param array $plugins Plugin configuration [optional]
* @return string Minified CSS
*/
public static function minify($source, array $filters = null, array $plugins = null)
{
self::$errors = array();
$minifier = new CssMinifier($source, $filters, $plugins);
return $minifier->getMinified();
}
/**
* Parse the CSS source.
*
* @param string $source CSS source
* @param array $plugins Plugin configuration [optional]
* @return array Array of aCssToken
*/
public static function parse($source, array $plugins = null)
{
self::$errors = array();
$parser = new CssParser($source, $plugins);
return $parser->getTokens();
}
/**
* --
*
* @param boolean $to
* @return boolean
*/
public static function setVerbose($to)
{
self::$isVerbose = (boolean) $to;
return self::$isVerbose;
}
/**
* --
*
* @param CssError $error
* @return void
*/
public static function triggerError(CssError $error)
{
self::$errors[] = $error;
if (self::$isVerbose)
{
trigger_error((string) $error, E_USER_WARNING);
}
}
}
// Initialises CssMin
CssMin::initialise();
/**
* This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the
* current stylesheet.
*
* @package CssMin/Minifier/Filters
* @link http://code.google.com/p/cssmin/
* @author Joe Scylla <joe.scylla@gmail.com>
* @copyright 2008 - 2011 Joe Scylla <joe.scylla@gmail.com>
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 3.0.1
*/
class CssImportImportsMinifierFilter extends aCssMinifierFilter
{
/**
* Array with already imported external stylesheets.
*
* @var array
*/
private $imported = array();
/**
* Implements {@link aCssMinifierFilter::filter()}.
*
* @param array $tokens Array of objects of type aCssToken
* @return integer C
gitextract_uq89ngc_/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── application/
│ ├── config/
│ │ ├── autoload.php
│ │ ├── config.php
│ │ ├── constants.php
│ │ ├── mimes.php
│ │ ├── minify.php
│ │ └── routes.php
│ ├── controllers/
│ │ ├── index.html
│ │ └── welcome.php
│ ├── errors/
│ │ ├── error_404.php
│ │ ├── error_db.php
│ │ ├── error_general.php
│ │ ├── error_php.php
│ │ └── index.html
│ ├── libraries/
│ │ ├── Minify.php
│ │ └── minify/
│ │ ├── JSMin.php
│ │ ├── JSMinPlus.php
│ │ ├── cssmin-v3.0.1.php
│ │ └── cssminify.php
│ └── views/
│ ├── index.html
│ └── welcome_message.php
├── assets/
│ ├── css/
│ │ ├── browser-specific.css
│ │ └── style.css
│ └── js/
│ ├── helpers.js
│ └── jqModal.js
├── composer.json
├── index.php
├── phpunit.xml
└── tests/
├── MinifyTest.php
└── bootstrap.php
SYMBOL INDEX (357 symbols across 9 files)
FILE: application/controllers/welcome.php
class Welcome (line 3) | class Welcome extends CI_Controller {
method index (line 20) | public function index()
FILE: application/libraries/Minify.php
class Minify (line 27) | class Minify {
method __construct (line 208) | public function __construct($config = array())
method css (line 263) | public function css($css, $group = 'default')
method js (line 285) | public function js($js, $group = 'default')
method add_css (line 307) | public function add_css($css, $group = 'default')
method add_js (line 335) | public function add_js($js, $group = 'default')
method deploy_css (line 364) | public function deploy_css($force = TRUE, $file_name = NULL, $group = ...
method deploy_js (line 400) | public function deploy_js($force = FALSE, $file_name = NULL, $group = ...
method _deploy_css (line 436) | private function _deploy_css($force = TRUE, $file_name = NULL, $group ...
method _deploy_js (line 473) | private function _deploy_js($force = FALSE, $file_name = NULL, $group ...
method _set (line 509) | private function _set($name, $value)
method _scan_files (line 576) | private function _scan_files($type, $force, $group)
method _output (line 634) | private function _output($files, $type)
method _simple_output (line 669) | private function _simple_output($type, $group)
method _concat_files (line 710) | private function _concat_files($file_array, $directory, $out_file)
method _closurecompiler (line 770) | private function _closurecompiler($data)
method _jsmin (line 805) | private function _jsmin($data)
method _jsminplus (line 819) | private function _jsminplus($data)
method _cssmin (line 833) | private function _cssmin($data)
method _minify (line 847) | private function _minify($data)
method _base_url (line 862) | private function _base_url($file)
method _config_checks (line 880) | private function _config_checks($type)
method _version_number (line 967) | private function _version_number($file)
FILE: application/libraries/minify/JSMin.php
class JSMin (line 57) | class JSMin {
method minify (line 81) | public static function minify($js)
method __construct (line 90) | public function __construct($input)
method min (line 100) | public function min()
method action (line 163) | protected function action($command)
method isRegexpLiteral (line 269) | protected function isRegexpLiteral()
method get (line 301) | protected function get()
method isEOF (line 329) | protected function isEOF($a)
method peek (line 339) | protected function peek()
method isAlphaNum (line 352) | protected function isAlphaNum($c)
method consumeSingleLineComment (line 360) | protected function consumeSingleLineComment()
method consumeMultipleLineComment (line 381) | protected function consumeMultipleLineComment()
method next (line 416) | protected function next()
class JSMin_UnterminatedStringException (line 435) | class JSMin_UnterminatedStringException extends Exception {}
class JSMin_UnterminatedCommentException (line 436) | class JSMin_UnterminatedCommentException extends Exception {}
class JSMin_UnterminatedRegExpException (line 437) | class JSMin_UnterminatedRegExpException extends Exception {}
FILE: application/libraries/minify/JSMinPlus.php
class JSMinPlus (line 174) | class JSMinPlus
method __construct (line 193) | private function __construct()
method minify (line 198) | public static function minify($js, $filename='')
method min (line 209) | private function min($js, $filename)
method parseTree (line 224) | public function parseTree($n, $noBlockGrouping = false)
method isValidIdentifier (line 662) | private function isValidIdentifier($string)
method isWordChar (line 667) | private function isWordChar($char)
class JSParser (line 673) | class JSParser
method __construct (line 726) | public function __construct($minifier=null)
method parse (line 732) | public function parse($s, $f, $l)
method Script (line 745) | private function Script($x)
method Statements (line 768) | private function Statements($x)
method Block (line 781) | private function Block($x)
method Statement (line 790) | private function Statement($x)
method FunctionDefinition (line 1108) | private function FunctionDefinition($x, $requireName, $functionForm)
method Variables (line 1149) | private function Variables($x)
method Expression (line 1178) | private function Expression($x, $stop=false)
method ParenExpression (line 1564) | private function ParenExpression($x)
method nest (line 1574) | private function nest($x, $node, $end = false)
method reduce (line 1586) | private function reduce(&$operators, &$operands)
class JSCompilerContext (line 1624) | class JSCompilerContext
method __construct (line 1638) | public function __construct($inFunction)
class JSNode (line 1644) | class JSNode
method __construct (line 1656) | public function __construct($t, $type=0)
method __set (line 1681) | public function __set($name, $value)
method __get (line 1686) | public function __get($name)
method addNode (line 1694) | public function addNode($node)
class JSTokenizer (line 1708) | class JSTokenizer
method __construct (line 1748) | public function __construct()
method init (line 1753) | public function init($source, $filename = '', $lineno = 1)
method getInput (line 1767) | public function getInput($chunksize)
method isDone (line 1775) | public function isDone()
method match (line 1780) | public function match($tt)
method mustMatch (line 1785) | public function mustMatch($tt)
method peek (line 1793) | public function peek()
method peekOnSameLine (line 1812) | public function peekOnSameLine()
method currentToken (line 1821) | public function currentToken()
method get (line 1827) | public function get($chunksize = 1000)
method unget (line 2064) | public function unget()
method newSyntaxError (line 2072) | public function newSyntaxError($m)
class JSToken (line 2078) | class JSToken
FILE: application/libraries/minify/cssmin-v3.0.1.php
class aCssToken (line 46) | abstract class aCssToken
method __toString (line 53) | abstract public function __toString();
class aCssRulesetStartToken (line 66) | abstract class aCssRulesetStartToken extends aCssToken
class aCssRulesetEndToken (line 81) | abstract class aCssRulesetEndToken extends aCssToken
method __toString (line 88) | public function __toString()
class aCssParserPlugin (line 107) | abstract class aCssParserPlugin
method __construct (line 134) | public function __construct(CssParser $parser, array $configuration = ...
method getTriggerChars (line 144) | abstract public function getTriggerChars();
method getTriggerStates (line 150) | abstract public function getTriggerStates();
method parse (line 159) | abstract public function parse($index, $char, $previousChar, $state);
class aCssMinifierPlugin (line 175) | abstract class aCssMinifierPlugin
method __construct (line 196) | public function __construct(CssMinifier $minifier, array $configuratio...
method apply (line 207) | abstract public function apply(aCssToken &$token);
method getTriggerTokens (line 213) | abstract public function getTriggerTokens();
class aCssMinifierFilter (line 229) | abstract class aCssMinifierFilter
method __construct (line 250) | public function __construct(CssMinifier $minifier, array $configuratio...
method apply (line 261) | abstract public function apply(array &$tokens);
class aCssFormatter (line 276) | abstract class aCssFormatter
method __construct (line 303) | public function __construct(array $tokens, $indent = null, $padding = ...
method __toString (line 314) | abstract public function __toString();
class aCssDeclarationToken (line 327) | abstract class aCssDeclarationToken extends aCssToken
method __construct (line 362) | public function __construct($property, $value, $isImportant = false, $...
method __toString (line 374) | public function __toString()
class aCssAtBlockStartToken (line 390) | abstract class aCssAtBlockStartToken extends aCssToken
class aCssAtBlockEndToken (line 405) | abstract class aCssAtBlockEndToken extends aCssToken
method __toString (line 412) | public function __toString()
class CssWhitesmithsFormatter (line 428) | class CssWhitesmithsFormatter extends aCssFormatter
method __toString (line 435) | public function __toString()
class CssVariablesMinifierPlugin (line 554) | class CssVariablesMinifierPlugin extends aCssMinifierPlugin
method getVariables (line 573) | public function getVariables()
method apply (line 583) | public function apply(aCssToken &$token)
method getTriggerTokens (line 617) | public function getTriggerTokens()
method setVariables (line 632) | public function setVariables(array $variables)
class CssVariablesMinifierFilter (line 650) | class CssVariablesMinifierFilter extends aCssMinifierFilter
method apply (line 658) | public function apply(array &$tokens)
class CssUrlParserPlugin (line 744) | class CssUrlParserPlugin extends aCssParserPlugin
method getTriggerChars (line 751) | public function getTriggerChars()
method getTriggerStates (line 760) | public function getTriggerStates()
method parse (line 772) | public function parse($index, $char, $previousChar, $state)
class CssStringParserPlugin (line 820) | class CssStringParserPlugin extends aCssParserPlugin
method getTriggerChars (line 833) | public function getTriggerChars()
method getTriggerStates (line 842) | public function getTriggerStates()
method parse (line 854) | public function parse($index, $char, $previousChar, $state)
class CssSortRulesetPropertiesMinifierFilter (line 919) | class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter
method apply (line 927) | public function apply(array &$tokens)
method userDefinedSort1 (line 993) | public static function userDefinedSort1($a, $b)
class CssRulesetStartToken (line 1009) | class CssRulesetStartToken extends aCssRulesetStartToken
method __construct (line 1023) | public function __construct(array $selectors = array())
method __toString (line 1032) | public function __toString()
class CssRulesetParserPlugin (line 1051) | class CssRulesetParserPlugin extends aCssParserPlugin
method getTriggerChars (line 1058) | public function getTriggerChars()
method getTriggerStates (line 1067) | public function getTriggerStates()
method parse (line 1085) | public function parse($index, $char, $previousChar, $state)
class CssRulesetEndToken (line 1177) | class CssRulesetEndToken extends aCssRulesetEndToken
class CssRulesetDeclarationToken (line 1192) | class CssRulesetDeclarationToken extends aCssDeclarationToken
method __construct (line 1210) | public function __construct($property, $value, $mediaTypes = null, $is...
class CssRemoveLastDelarationSemiColonMinifierFilter (line 1229) | class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifie...
method apply (line 1237) | public function apply(array &$tokens)
class CssRemoveEmptyRulesetsMinifierFilter (line 1265) | class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter
method apply (line 1273) | public function apply(array &$tokens)
class CssRemoveEmptyAtBlocksMinifierFilter (line 1305) | class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter
method apply (line 1313) | public function apply(array &$tokens)
class CssRemoveCommentsMinifierFilter (line 1345) | class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter
method apply (line 1353) | public function apply(array &$tokens)
class CssParser (line 1378) | class CssParser
method __construct (line 1437) | public function __construct($source = null, array $plugins = null)
method appendToken (line 1482) | public function appendToken(aCssToken $token)
method clearBuffer (line 1491) | public function clearBuffer()
method getAndClearBuffer (line 1502) | public function getAndClearBuffer($trim = "", $tolower = false)
method getBuffer (line 1515) | public function getBuffer($trim = "", $tolower = false)
method getMediaTypes (line 1533) | public function getMediaTypes()
method getSource (line 1542) | public function getSource()
method getState (line 1551) | public function getState()
method getPlugin (line 1561) | public function getPlugin($class)
method getTokens (line 1579) | public function getTokens()
method isState (line 1589) | public function isState($state)
method parse (line 1599) | public function parse($source)
method popState (line 1713) | public function popState()
method pushState (line 1725) | public function pushState($state)
method setBuffer (line 1737) | public function setBuffer($buffer)
method setExclusive (line 1747) | public function setExclusive($exclusive)
method setMediaTypes (line 1757) | public function setMediaTypes(array $mediaTypes)
method setState (line 1767) | public function setState($state)
method unsetExclusive (line 1779) | public function unsetExclusive()
method unsetMediaTypes (line 1788) | public function unsetMediaTypes()
class CssOtbsFormatter (line 1804) | class CssOtbsFormatter extends aCssFormatter
method __toString (line 1811) | public function __toString()
class CssNullToken (line 1907) | class CssNullToken extends aCssToken
method __toString (line 1914) | public function __toString()
class CssMinifier (line 1930) | class CssMinifier
method __construct (line 1960) | public function __construct($source = null, array $filters = null, arr...
method getMinified (line 2029) | public function getMinified()
method getPlugin (line 2039) | public function getPlugin($class)
method minify (line 2058) | public function minify($source)
class CssMin (line 2162) | class CssMin
method autoload (line 2188) | public static function autoload($class)
method getErrors (line 2200) | public static function getErrors()
method hasErrors (line 2209) | public static function hasErrors()
method initialise (line 2218) | public static function initialise()
method minify (line 2271) | public static function minify($source, array $filters = null, array $p...
method parse (line 2284) | public static function parse($source, array $plugins = null)
method setVerbose (line 2296) | public static function setVerbose($to)
method triggerError (line 2307) | public static function triggerError(CssError $error)
class CssImportImportsMinifierFilter (line 2330) | class CssImportImportsMinifierFilter extends aCssMinifierFilter
method apply (line 2344) | public function apply(array &$tokens)
class CssExpressionParserPlugin (line 2535) | class CssExpressionParserPlugin extends aCssParserPlugin
method getTriggerChars (line 2554) | public function getTriggerChars()
method getTriggerStates (line 2563) | public function getTriggerStates()
method parse (line 2575) | public function parse($index, $char, $previousChar, $state)
class CssError (line 2618) | class CssError
method __construct (line 2651) | public function __construct($file, $line, $message, $source = "")
method __toString (line 2663) | public function __toString()
class CssConvertRgbColorsMinifierPlugin (line 2689) | class CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin
method apply (line 2703) | public function apply(aCssToken &$token)
method getTriggerTokens (line 2725) | public function getTriggerTokens()
class CssConvertNamedColorsMinifierPlugin (line 2758) | class CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin
method __construct (line 2927) | public function __construct(CssMinifier $minifier, array $configuratio...
method apply (line 2938) | public function apply(aCssToken &$token)
method getTriggerTokens (line 2958) | public function getTriggerTokens()
class CssConvertLevel3PropertiesMinifierFilter (line 2980) | class CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter
method apply (line 3199) | public function apply(array &$tokens)
method filter (line 3249) | private static function filter($token)
method opacity (line 3263) | private static function opacity($token)
method whiteSpace (line 3283) | private static function whiteSpace($token)
class CssConvertLevel3AtKeyframesMinifierFilter (line 3319) | class CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter
method apply (line 3327) | public function apply(array &$tokens)
class CssConvertHslColorsMinifierPlugin (line 3398) | class CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin
method apply (line 3412) | public function apply(aCssToken &$token)
method getTriggerTokens (line 3425) | public function getTriggerTokens()
method hsl2hex (line 3444) | private function hsl2hex($hue, $saturation, $lightness)
method hue2rgb (line 3480) | private function hue2rgb($v1, $v2, $hue)
class CssConvertFontWeightMinifierPlugin (line 3528) | class CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin
method __construct (line 3572) | public function __construct(CssMinifier $minifier)
method apply (line 3583) | public function apply(aCssToken &$token)
method getTriggerTokens (line 3596) | public function getTriggerTokens()
class CssCompressUnitValuesMinifierPlugin (line 3633) | class CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin
method apply (line 3658) | public function apply(aCssToken &$token)
method getTriggerTokens (line 3674) | public function getTriggerTokens()
class CssCompressExpressionValuesMinifierPlugin (line 3698) | class CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin
method apply (line 3706) | public function apply(aCssToken &$token)
method getTriggerTokens (line 3722) | public function getTriggerTokens()
class CssCompressColorValuesMinifierPlugin (line 3754) | class CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin
method apply (line 3768) | public function apply(aCssToken &$token)
method getTriggerTokens (line 3785) | public function getTriggerTokens()
class CssCommentToken (line 3806) | class CssCommentToken extends aCssToken
method __construct (line 3820) | public function __construct($comment)
method __toString (line 3829) | public function __toString()
class CssCommentParserPlugin (line 3847) | class CssCommentParserPlugin extends aCssParserPlugin
method getTriggerChars (line 3854) | public function getTriggerChars()
method getTriggerStates (line 3863) | public function getTriggerStates()
method parse (line 3881) | public function parse($index, $char, $previousChar, $state)
class CssAtVariablesStartToken (line 3914) | class CssAtVariablesStartToken extends aCssAtBlockStartToken
method __construct (line 3928) | public function __construct($mediaTypes = null)
method __toString (line 3937) | public function __toString()
class CssAtVariablesParserPlugin (line 3956) | class CssAtVariablesParserPlugin extends aCssParserPlugin
method getTriggerChars (line 3963) | public function getTriggerChars()
method getTriggerStates (line 3972) | public function getTriggerStates()
method parse (line 3984) | public function parse($index, $char, $previousChar, $state)
class CssAtVariablesEndToken (line 4058) | class CssAtVariablesEndToken extends aCssAtBlockEndToken
method __toString (line 4065) | public function __toString()
class CssAtVariablesDeclarationToken (line 4081) | class CssAtVariablesDeclarationToken extends aCssDeclarationToken
method __toString (line 4088) | public function __toString()
class CssAtPageStartToken (line 4104) | class CssAtPageStartToken extends aCssAtBlockStartToken
method __construct (line 4118) | public function __construct($selector = "")
method __toString (line 4127) | public function __toString()
class CssAtPageParserPlugin (line 4146) | class CssAtPageParserPlugin extends aCssParserPlugin
method getTriggerChars (line 4153) | public function getTriggerChars()
method getTriggerStates (line 4162) | public function getTriggerStates()
method parse (line 4174) | public function parse($index, $char, $previousChar, $state)
class CssAtPageEndToken (line 4255) | class CssAtPageEndToken extends aCssAtBlockEndToken
class CssAtPageDeclarationToken (line 4270) | class CssAtPageDeclarationToken extends aCssDeclarationToken
class CssAtMediaStartToken (line 4285) | class CssAtMediaStartToken extends aCssAtBlockStartToken
method __construct (line 4293) | public function __construct(array $mediaTypes = array())
method __toString (line 4302) | public function __toString()
class CssAtMediaParserPlugin (line 4322) | class CssAtMediaParserPlugin extends aCssParserPlugin
method getTriggerChars (line 4329) | public function getTriggerChars()
method getTriggerStates (line 4338) | public function getTriggerStates()
method parse (line 4350) | public function parse($index, $char, $previousChar, $state)
class CssAtMediaEndToken (line 4390) | class CssAtMediaEndToken extends aCssAtBlockEndToken
class CssAtKeyframesStartToken (line 4405) | class CssAtKeyframesStartToken extends aCssAtBlockStartToken
method __construct (line 4425) | public function __construct($name, $atRuleName = null)
method __toString (line 4438) | public function __toString()
class CssAtKeyframesRulesetStartToken (line 4454) | class CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken
method __construct (line 4468) | public function __construct(array $selectors = array())
method __toString (line 4477) | public function __toString()
class CssAtKeyframesRulesetEndToken (line 4493) | class CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken
class CssAtKeyframesRulesetDeclarationToken (line 4508) | class CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken
class CssAtKeyframesParserPlugin (line 4523) | class CssAtKeyframesParserPlugin extends aCssParserPlugin
method getTriggerChars (line 4540) | public function getTriggerChars()
method getTriggerStates (line 4549) | public function getTriggerStates()
method parse (line 4561) | public function parse($index, $char, $previousChar, $state)
class CssAtKeyframesEndToken (line 4683) | class CssAtKeyframesEndToken extends aCssAtBlockEndToken
class CssAtImportToken (line 4698) | class CssAtImportToken extends aCssToken
method __construct (line 4719) | public function __construct($import, $mediaTypes)
method __toString (line 4729) | public function __toString()
class CssAtImportParserPlugin (line 4747) | class CssAtImportParserPlugin extends aCssParserPlugin
method getTriggerChars (line 4754) | public function getTriggerChars()
method getTriggerStates (line 4763) | public function getTriggerStates()
method parse (line 4775) | public function parse($index, $char, $previousChar, $state)
class CssAtFontFaceStartToken (line 4829) | class CssAtFontFaceStartToken extends aCssAtBlockStartToken
method __toString (line 4836) | public function __toString()
class CssAtFontFaceParserPlugin (line 4855) | class CssAtFontFaceParserPlugin extends aCssParserPlugin
method getTriggerChars (line 4862) | public function getTriggerChars()
method getTriggerStates (line 4871) | public function getTriggerStates()
method parse (line 4883) | public function parse($index, $char, $previousChar, $state)
class CssAtFontFaceEndToken (line 4963) | class CssAtFontFaceEndToken extends aCssAtBlockEndToken
class CssAtFontFaceDeclarationToken (line 4978) | class CssAtFontFaceDeclarationToken extends aCssDeclarationToken
class CssAtCharsetToken (line 4993) | class CssAtCharsetToken extends aCssToken
method __construct (line 5007) | public function __construct($charset)
method __toString (line 5016) | public function __toString()
class CssAtCharsetParserPlugin (line 5034) | class CssAtCharsetParserPlugin extends aCssParserPlugin
method getTriggerChars (line 5041) | public function getTriggerChars()
method getTriggerStates (line 5050) | public function getTriggerStates()
method parse (line 5062) | public function parse($index, $char, $previousChar, $state)
FILE: application/libraries/minify/cssminify.php
class cssminify (line 10) | class cssminify {
method compress (line 19) | public function compress($css)
method _selectorsCB (line 111) | protected function _selectorsCB($m)
method _commentCB (line 124) | protected function _commentCB($m)
method _fontFamilyCB (line 195) | protected function _fontFamilyCB($m)
FILE: assets/js/helpers.js
function string_contains (line 1) | function string_contains(haystack, needle) {
function str_replace (line 9) | function str_replace(search, replace, subject, count) {
function htmlspecialchars (line 44) | function htmlspecialchars(string, quote_style, charset, double_encode) {
function initDataTable (line 92) | function initDataTable() {
function addslashes (line 128) | function addslashes(str) {
function nl2br (line 132) | function nl2br(str, is_xhtml) {
function replaceAndSymbol (line 141) | function replaceAndSymbol(str) {
function removeCommas (line 146) | function removeCommas(str) {
function setCaretPosition (line 150) | function setCaretPosition(elemId, caretPos) {
function setStartTimeNow (line 170) | function setStartTimeNow(textarea) {
function setCopy (line 189) | function setCopy(textarea) {
function closeCopy (line 193) | function closeCopy(textarea) {
FILE: tests/MinifyTest.php
class MinifyTest (line 9) | class MinifyTest extends PHPUnit_Framework_TestCase {
method setUp (line 13) | public function setUp() {
method testInit (line 18) | public function testInit()
method testJsDisabled (line 29) | public function testJsDisabled()
method testCssDisabled (line 46) | public function testCssDisabled()
method testJsNoHtmlTagsWithDisabled (line 63) | public function testJsNoHtmlTagsWithDisabled()
method testCssNoHtmlTagsWithDisabled (line 79) | public function testCssNoHtmlTagsWithDisabled()
method testJsNoHtmlTagsWithEnabled (line 95) | public function testJsNoHtmlTagsWithEnabled()
method testCssNoHtmlTagsWithEnabled (line 110) | public function testCssNoHtmlTagsWithEnabled()
method testJsCompress (line 125) | public function testJsCompress()
method testJsCompressWithClosureCompiler (line 139) | public function testJsCompressWithClosureCompiler()
method testCssCompress (line 158) | public function testCssCompress()
method testJsCompressWithAutoNames (line 172) | public function testJsCompressWithAutoNames()
method testCssCompressWithAutoNames (line 187) | public function testCssCompressWithAutoNames()
method testJsCompressWithAdd (line 202) | public function testJsCompressWithAdd()
method testCssCompressWithAdd (line 216) | public function testCssCompressWithAdd()
method testJsCompressWithIndividualAutoName (line 230) | public function testJsCompressWithIndividualAutoName()
method testCssCompressWithIndividualAutoName (line 243) | public function testCssCompressWithIndividualAutoName()
method testCustomJsPathForAssets (line 257) | public function testCustomJsPathForAssets()
method testCustomCssPathForAssets (line 270) | public function testCustomCssPathForAssets()
method testCssCompressWithGroupNames (line 282) | public function testCssCompressWithGroupNames()
method testJsCompressWithGroupNames (line 300) | public function testJsCompressWithGroupNames()
method testJsVersioning (line 319) | public function testJsVersioning()
method testCssVersioning (line 336) | public function testCssVersioning()
method testJsVersioningCustomNumber (line 353) | public function testJsVersioningCustomNumber()
method testCssVersioningCustomNumber (line 371) | public function testCssVersioningCustomNumber()
method testJsDeployOnChangeFalse (line 389) | public function testJsDeployOnChangeFalse()
method testCssDeployOnChangeFalse (line 407) | public function testCssDeployOnChangeFalse()
method testJsWithChangedBaseUrl (line 425) | public function testJsWithChangedBaseUrl()
method testCssWithChangedBaseUrl (line 441) | public function testCssWithChangedBaseUrl()
method testJsWithCustomConstructorConfig (line 457) | public function testJsWithCustomConstructorConfig()
method testCssWithCustomConstructorConfig (line 473) | public function testCssWithCustomConstructorConfig()
FILE: tests/bootstrap.php
function get_instance (line 8) | function get_instance()
function base_url (line 13) | function base_url($string) {
function link_tag (line 25) | function link_tag($string) {
function log_message (line 29) | function log_message($string1, $string2) {
class CI (line 33) | class CI
method __construct (line 37) | public function __construct()
method config (line 43) | public function config()
class CI_Loader (line 55) | class CI_Loader
method __construct (line 57) | public function __construct()
method __call (line 62) | public function __call($method, $params = array())
class CI_Config (line 70) | class CI_Config
method __call (line 72) | public function __call($method, $params = array())
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (372K chars).
[
{
"path": ".gitignore",
"chars": 7,
"preview": ".idea/\n"
},
{
"path": ".travis.yml",
"chars": 107,
"preview": "language: php\n\nphp:\n - 5.6\n - 7.0\n - 7.1\n - 7.2\n\nbefore_script:\n - travis_retry composer install --dev"
},
{
"path": "LICENSE",
"chars": 1060,
"preview": "Copyright (c) 2015 Slawomir Jasinski\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
},
{
"path": "README.md",
"chars": 9797,
"preview": "# CodeIgniter - minify [](https://tra"
},
{
"path": "application/config/autoload.php",
"chars": 3088,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| ---------------------------------------"
},
{
"path": "application/config/config.php",
"chars": 12840,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\n/*\n|---------------------------------------"
},
{
"path": "application/config/constants.php",
"chars": 1558,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\n/*\n|---------------------------------------"
},
{
"path": "application/config/mimes.php",
"chars": 4453,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| ---------------------------------------"
},
{
"path": "application/config/minify.php",
"chars": 3435,
"preview": "<?php\n/**\n * Minify config Class\n *\n * PHP Version 5.3\n *\n * @category PHP\n * @package Controller\n * @author Slawo"
},
{
"path": "application/config/routes.php",
"chars": 1543,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n/*\n| ---------------------------------------"
},
{
"path": "application/controllers/index.html",
"chars": 114,
"preview": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
},
{
"path": "application/controllers/welcome.php",
"chars": 834,
"preview": "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n\nclass Welcome extends CI_Controller {\n\n\t/**\n"
},
{
"path": "application/errors/error_404.php",
"chars": 1160,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>404 Page Not Found</title>\n<style type=\"text/css\">\n\n::selection{ backgrou"
},
{
"path": "application/errors/error_db.php",
"chars": 1156,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>Database Error</title>\n<style type=\"text/css\">\n\n::selection{ background-c"
},
{
"path": "application/errors/error_general.php",
"chars": 1147,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<title>Error</title>\n<style type=\"text/css\">\n\n::selection{ background-color: #E1"
},
{
"path": "application/errors/error_php.php",
"chars": 288,
"preview": "<div style=\"border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;\">\n\n<h4>A PHP Error was encountered</h4>\n\n<p>Se"
},
{
"path": "application/errors/index.html",
"chars": 114,
"preview": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
},
{
"path": "application/libraries/Minify.php",
"chars": 21359,
"preview": "<?php\n/**\n * Minify Library Class\n *\n * PHP Version 5.3\n *\n * @category PHP\n * @package Library\n * @author Slawomi"
},
{
"path": "application/libraries/minify/JSMin.php",
"chars": 15537,
"preview": "<?php\n/**\n * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.\n *\n * <code>\n * $minifiedJs = JSMin::"
},
{
"path": "application/libraries/minify/JSMinPlus.php",
"chars": 52368,
"preview": "<?php\n\n/**\n * JSMinPlus version 1.4\n *\n * Minifies a javascript file using a javascript parser\n *\n * This implements a P"
},
{
"path": "application/libraries/minify/cssmin-v3.0.1.php",
"chars": 155114,
"preview": "<?php\n/**\n * CssMin - A (simple) css minifier with benefits\n * \n * --\n * Copyright (c) 2011 Joe Scylla <joe.scylla@gmail"
},
{
"path": "application/libraries/minify/cssminify.php",
"chars": 6032,
"preview": "<?php\n/**\n * Created by PhpStorm.\n * User: slav\n * Date: 10/02/15\n * Time: 12:20 PM\n */\n\n\nclass cssminify {\n\t/**\n\t * Min"
},
{
"path": "application/views/index.html",
"chars": 114,
"preview": "<html>\n<head>\n\t<title>403 Forbidden</title>\n</head>\n<body>\n\n<p>Directory access is forbidden.</p>\n\n</body>\n</html>"
},
{
"path": "application/views/welcome_message.php",
"chars": 880,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>Welcome to CodeIgniter</title>\n\t<?php // add css"
},
{
"path": "assets/css/browser-specific.css",
"chars": 178,
"preview": "::selection{ background-color: #E13300; color: white; }\n::moz-selection{ background-color: #E13300; color: white; }\n::we"
},
{
"path": "assets/css/style.css",
"chars": 995,
"preview": "body {\n background-color: #fff;\n margin: 40px;\n font: 13px/20px normal Helvetica, Arial, sans-serif;\n color:"
},
{
"path": "assets/js/helpers.js",
"chars": 5137,
"preview": "function string_contains(haystack, needle) {\n if (haystack.indexOf(needle) == -1) {\n return false;\n } else "
},
{
"path": "assets/js/jqModal.js",
"chars": 3356,
"preview": "/*\n * jqModal - Minimalist Modaling with jQuery\n * (http://dev.iceburg.net/jquery/jqModal/)\n *\n * Copyright (c) 2007,2"
},
{
"path": "composer.json",
"chars": 104,
"preview": "{\n \"require-dev\": {\n \"phpunit/phpunit\": \"5.*\"\n },\n \"require\": {\n \"ext-curl\": \"*\"\n }\n}\n"
},
{
"path": "index.php",
"chars": 10261,
"preview": "<?php\n/**\n * CodeIgniter\n *\n * An open source application development framework for PHP\n *\n * This content is released u"
},
{
"path": "phpunit.xml",
"chars": 722,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit bootstrap=\"./tests/bootstrap.php\" colors=\"true\">\n\n\t<testsuites>\n\t\t<test"
},
{
"path": "tests/MinifyTest.php",
"chars": 17055,
"preview": "<?php\n/**\n * Created by PhpStorm.\n * User: slav\n * Date: 10/02/15\n * Time: 9:51 AM\n */\n\nclass MinifyTest extends PHPUnit"
},
{
"path": "tests/bootstrap.php",
"chars": 1130,
"preview": "<?php\n\ndefine('BASEPATH', 'application');\ndefine('APPPATH', 'application/');\n\n\n\nfunction get_instance()\n{\n\treturn new CI"
}
]
About this extraction
This page contains the full source code of the slav123/CodeIgniter-minify GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (325.2 KB), approximately 98.2k tokens, and a symbol index with 357 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.