
190 changed files with 12638 additions and 119 deletions
@ -0,0 +1 @@ |
|||
@font-face{font-family:'fontello';src:url('../font/fontello.eot?5025401');src:url('../font/fontello.eot?5025401#iefix') format('embedded-opentype'), url('../font/fontello.woff2?5025401') format('woff2'), url('../font/fontello.woff?5025401') format('woff'), url('../font/fontello.ttf?5025401') format('truetype'), url('../font/fontello.svg?5025401#fontello') format('svg');font-weight:normal;font-style:normal;}[class^="icon-"]:before,[class*=" icon-"]:before{font-family:"fontello";font-style:normal;font-weight:normal;speak:never;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.icon-ynh:before{content:'\e800';}.icon-home:before{content:'\e801';}.icon-right-open:before{content:'\e802';}.icon-doc-text-inv:before{content:'\e803';}.icon-git:before{content:'\f1d3';} |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
@ -0,0 +1,70 @@ |
|||
# 3.1.0 |
|||
- [All Changes](https://github.com/wikimedia/less.php/compare/v3.0.0...v3.1.0) |
|||
* PHP 8.0 support: Drop use of curly braces for sub-string eval (James D. Forrester) |
|||
* Make `Directive::__construct` $rules arg optional (fix PHP 7.4 warning) (Sam Reed) |
|||
* ProcessExtends: Improve performance by using a map for selectors and parents (Andrey Legayev) |
|||
* build: Run CI tests on PHP 8.0 too (James D. Forrester) |
|||
* code: Fix PSR12.Properties.ConstantVisibility.NotFound (Sam Reed) |
|||
|
|||
# 3.0.0 |
|||
- [All Changes](https://github.com/wikimedia/less.php/compare/v2.0.0...v3.0.0) |
|||
- Raise PHP requirement from 7.1 to 7.2.9 (James Forrester) |
|||
- build: Upgrade phpunit to ^8.5 and make pass (James Forrester) |
|||
- build: Install php-parallel-lint (James Forrester) |
|||
- build: Install minus-x and make pass (James Forrester) |
|||
|
|||
# 2.0.0 |
|||
- [All Changes](https://github.com/wikimedia/less.php/compare/1.8.2...v2.0.0) |
|||
- Relax PHP requirement down to 7.1, from 7.2.9 (Franz Liedke) |
|||
- Reflect recent breaking changes properly with the semantic versioning (James Forrester) |
|||
|
|||
# 1.8.2 |
|||
- [All Changes](https://github.com/wikimedia/less.php/compare/1.8.1...1.8.2) |
|||
- Require PHP 7.2.9+, up from 5.3+ (James Forrester) |
|||
- Release: Update Version.php with the current release ID (COBadger) |
|||
- Fix access array offset on value of type null (Michele Locati) |
|||
- Fixed test suite on PHP 7.4 (Sergei Morozov) |
|||
- docs: Fix 1.8.1 "All changes" link (Timo Tijhof) |
|||
|
|||
# 1.8.1 |
|||
- [All Changes](https://github.com/wikimedia/less.php/compare/v1.8.0...1.8.1) |
|||
- Another PHP 7.3 compatibility tweak |
|||
|
|||
# 1.8.0 |
|||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.13...v1.8.0) |
|||
- Wikimedia fork |
|||
- Supports up to PHP 7.3 |
|||
- No longer tested against PHP 5, though it's still remains allowed in `composer.json` for HHVM compatibility |
|||
- Switched to [semantic versioning](https://semver.org/), hence version numbers now use 3 digits |
|||
|
|||
# 1.7.0.13 |
|||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.12...v1.7.0.13) |
|||
- Fix composer.json (PSR-4 was invalid) |
|||
|
|||
# 1.7.0.12 |
|||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.11...v1.7.0.12) |
|||
- set bin/lessc bit executable |
|||
- Add 'gettingVariables' method in Less_Parser |
|||
|
|||
# 1.7.0.11 |
|||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.10...v1.7.0.11) |
|||
- Fix realpath issue (windows) |
|||
- Set Less_Tree_Call property back to public ( Fix 258 266 267 issues from oyejorge/less.php) |
|||
|
|||
# 1.7.0.10 |
|||
|
|||
- [All Changes](https://github.com/oyejorge/less.php/compare/v1.7.0.9...v1.7.10) |
|||
- Add indentation option |
|||
- Add 'optional' modifier for @import |
|||
- fix $color in Exception messages |
|||
- don't use set_time_limit when running cli |
|||
- take relative-url into account when building the cache filename |
|||
- urlArgs should be string no array() |
|||
- add bug-report fixtures [#6dc898f](https://github.com/oyejorge/less.php/commit/6dc898f5d75b447464906bdf19d79c2e19d95e33) |
|||
- fix #269, missing on NameValue type [#a8dac63](https://github.com/oyejorge/less.php/commit/a8dac63d93fb941c54fb78b12588abf635747c1b) |
|||
|
|||
# 1.7.0.9 |
|||
|
|||
- [All Changes](https://github.com/oyejorge/less.php/compare/v1.7.0.8...v1.7.0.9) |
|||
- Remove space at beginning of Version.php |
|||
- Revert require() paths in test interface |
@ -0,0 +1,178 @@ |
|||
|
|||
Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
@ -0,0 +1,315 @@ |
|||
[](https://github.com/wikimedia/less.php/actions) |
|||
|
|||
[Less.php](http://lessphp.typesettercms.com) |
|||
======== |
|||
|
|||
This is the Wikimedia fork of a PHP port of the official LESS processor <http://lesscss.org>. |
|||
|
|||
* [About](#about) |
|||
* [Installation](#installation) |
|||
* [Basic Use](#basic-use) |
|||
* [Caching](#caching) |
|||
* [Source Maps](#source-maps) |
|||
* [Command Line](#command-line) |
|||
* [Integration with other projects](#integration-with-other-projects) |
|||
* [Transitioning from Leafo/lessphp](#transitioning-from-leafolessphp) |
|||
* [Credits](#credits) |
|||
|
|||
|
|||
|
|||
About |
|||
--- |
|||
The code structure of less.php mirrors that of the official processor which helps us ensure compatibility and allows for easy maintenance. |
|||
|
|||
Please note, there are a few unsupported LESS features: |
|||
|
|||
- Evaluation of JavaScript expressions within back-ticks (for obvious reasons). |
|||
- Definition of custom functions. |
|||
|
|||
|
|||
Installation |
|||
--- |
|||
|
|||
You can install the library with Composer or manually. |
|||
|
|||
#### Composer |
|||
|
|||
1. [Install Composer](https://getcomposer.org/download/) |
|||
2. Run `composer require wikimedia/less.php` |
|||
|
|||
#### Manually From Release |
|||
|
|||
Step 1. [Download a release](https://github.com/wikimedia/less.php/releases) and upload the PHP files to your server. |
|||
|
|||
Step 2. Include the library: |
|||
|
|||
```php |
|||
require_once '[path to less.php]/lib/Less/Autoloader.php'; |
|||
Less_Autoloader::register(); |
|||
``` |
|||
|
|||
Basic Use |
|||
--- |
|||
|
|||
#### Parsing Strings |
|||
|
|||
```php |
|||
$parser = new Less_Parser(); |
|||
$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
|
|||
#### Parsing LESS Files |
|||
The parseFile() function takes two arguments: |
|||
|
|||
1. The absolute path of the .less file to be parsed |
|||
2. The url root to prepend to any relative image or @import urls in the .less file. |
|||
|
|||
```php |
|||
$parser = new Less_Parser(); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
|
|||
#### Handling Invalid LESS |
|||
An exception will be thrown if the compiler encounters invalid LESS. |
|||
|
|||
```php |
|||
try{ |
|||
$parser = new Less_Parser(); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
}catch(Exception $e){ |
|||
$error_message = $e->getMessage(); |
|||
} |
|||
``` |
|||
|
|||
|
|||
#### Parsing Multiple Sources |
|||
less.php can parse multiple sources to generate a single CSS file. |
|||
|
|||
```php |
|||
$parser = new Less_Parser(); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
#### Getting Info About The Parsed Files |
|||
less.php can tell you which .less files were imported and parsed. |
|||
|
|||
```php |
|||
$parser = new Less_Parser(); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
$imported_files = $parser->allParsedFiles(); |
|||
``` |
|||
|
|||
|
|||
#### Compressing Output |
|||
You can tell less.php to remove comments and whitespace to generate minimized CSS files. |
|||
|
|||
```php |
|||
$options = array( 'compress'=>true ); |
|||
$parser = new Less_Parser( $options ); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
#### Getting Variables |
|||
You can use the getVariables() method to get an all variables defined and |
|||
their value in a php associative array. Note that LESS has to be previously |
|||
compiled. |
|||
```php |
|||
$parser = new Less_Parser; |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less'); |
|||
$css = $parser->getCss(); |
|||
$variables = $parser->getVariables(); |
|||
|
|||
``` |
|||
|
|||
|
|||
|
|||
#### Setting Variables |
|||
You can use the ModifyVars() method to customize your CSS if you have variables stored in PHP associative arrays. |
|||
|
|||
```php |
|||
$parser = new Less_Parser(); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$parser->ModifyVars( array('font-size-base'=>'16px') ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
|
|||
#### Import Directories |
|||
By default, less.php will look for @imports in the directory of the file passed to parseFile(). |
|||
If you're using parse() or if @imports reside in different directories, you can tell less.php where to look. |
|||
|
|||
```php |
|||
$directories = array( '/var/www/mysite/bootstrap/' => '/mysite/bootstrap/' ); |
|||
$parser = new Less_Parser(); |
|||
$parser->SetImportDirs( $directories ); |
|||
$parser->parseFile( '/var/www/mysite/theme.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
|
|||
Caching |
|||
--- |
|||
Compiling LESS code into CSS is a time consuming process, caching your results is highly recommended. |
|||
|
|||
|
|||
#### Caching CSS |
|||
Use the Less_Cache class to save and reuse the results of compiled LESS files. |
|||
This method will check the modified time and size of each LESS file (including imported files) and regenerate a new CSS file when changes are found. |
|||
Note: When changes are found, this method will return a different file name for the new cached content. |
|||
|
|||
```php |
|||
$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' ); |
|||
$options = array( 'cache_dir' => '/var/www/writable_folder' ); |
|||
$css_file_name = Less_Cache::Get( $less_files, $options ); |
|||
$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name ); |
|||
``` |
|||
|
|||
#### Caching CSS With Variables |
|||
Passing options to Less_Cache::Get() |
|||
|
|||
```php |
|||
$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' ); |
|||
$options = array( 'cache_dir' => '/var/www/writable_folder' ); |
|||
$variables = array( 'width' => '100px' ); |
|||
$css_file_name = Less_Cache::Get( $less_files, $options, $variables ); |
|||
$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name ); |
|||
``` |
|||
|
|||
|
|||
#### Parser Caching |
|||
less.php will save serialized parser data for each .less file if a writable folder is passed to the SetCacheDir() method. |
|||
Note: This feature only caches intermediate parsing results to improve the performance of repeated CSS generation. |
|||
Your application should cache any CSS generated by less.php. |
|||
|
|||
```php |
|||
$options = array('cache_dir'=>'/var/www/writable_folder'); |
|||
$parser = new Less_Parser( $options ); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
You can specify the caching technique used by changing the ```cache_method``` option. Supported methods are: |
|||
* ```php```: Creates valid PHP files which can be included without any changes (default method). |
|||
* ```var_export```: Like "php", but using PHP's ```var_export()``` function without any optimizations. |
|||
It's recommended to use "php" instead. |
|||
* ```serialize```: Faster, but pretty memory-intense. |
|||
* ```callback```: Use custom callback functions to implement your own caching method. Give the "cache_callback_get" and |
|||
"cache_callback_set" options with callables (see PHP's ```call_user_func()``` and ```is_callable()``` functions). less.php |
|||
will pass the parser object (class ```Less_Parser```), the path to the parsed .less file ("/some/path/to/file.less") and |
|||
an identifier that will change every time the .less file is modified. The ```get``` callback must return the ruleset |
|||
(an array with ```Less_Tree``` objects) provided as fourth parameter of the ```set``` callback. If something goes wrong, |
|||
return ```NULL``` (cache doesn't exist) or ```FALSE```. |
|||
|
|||
|
|||
|
|||
Source Maps |
|||
--- |
|||
Less.php supports v3 sourcemaps |
|||
|
|||
#### Inline |
|||
The sourcemap will be appended to the generated CSS file. |
|||
|
|||
```php |
|||
$options = array( 'sourceMap' => true ); |
|||
$parser = new Less_Parser($options); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
#### Saving to Map File |
|||
|
|||
```php |
|||
$options = array( |
|||
'sourceMap' => true, |
|||
'sourceMapWriteTo' => '/var/www/mysite/writable_folder/filename.map', |
|||
'sourceMapURL' => '/mysite/writable_folder/filename.map', |
|||
); |
|||
$parser = new Less_Parser($options); |
|||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); |
|||
$css = $parser->getCss(); |
|||
``` |
|||
|
|||
|
|||
Command line |
|||
--- |
|||
An additional script has been included to use the compiler from the command line. |
|||
In the simplest invocation, you specify an input file and the compiled CSS is written to standard out: |
|||
|
|||
``` |
|||
$ lessc input.less > output.css |
|||
``` |
|||
|
|||
By using the -w flag you can watch a specified input file and have it compile as needed to the output file: |
|||
|
|||
``` |
|||
$ lessc -w input.less output.css |
|||
``` |
|||
|
|||
Errors from watch mode are written to standard out. |
|||
|
|||
For more help, run `lessc --help` |
|||
|
|||
|
|||
Integration with other projects |
|||
--- |
|||
|
|||
#### Drupal 7 |
|||
|
|||
This library can be used as drop-in replacement of lessphp to work with [Drupal 7 less module](https://drupal.org/project/less). |
|||
|
|||
How to install: |
|||
|
|||
1. [Download the less.php source code](https://github.com/wikimedia/less.php/archive/master.zip) and unzip it so that 'lessc.inc.php' is located at 'sites/all/libraries/lessphp/lessc.inc.php'. |
|||
2. Download and install [Drupal 7 less module](https://drupal.org/project/less) as usual. |
|||
3. That's it :) |
|||
|
|||
#### JBST WordPress theme |
|||
|
|||
JBST has a built-in LESS compiler based on lessphp. Customize your WordPress theme with LESS. |
|||
|
|||
How to use / install: |
|||
|
|||
1. [Download the latest release](https://github.com/bassjobsen/jamedo-bootstrap-start-theme) copy the files to your {wordpress/}wp-content/themes folder and activate it. |
|||
2. Find the compiler under Appearance > LESS Compiler in your WordPress dashboard |
|||
3. Enter your LESS code in the text area and press (re)compile |
|||
|
|||
Use the built-in compiler to: |
|||
- set any [Bootstrap](http://getbootstrap.com/customize/) variable or use Bootstrap's mixins: |
|||
-`@navbar-default-color: blue;` |
|||
- create a custom button: `.btn-custom { |
|||
.button-variant(white; red; blue); |
|||
}` |
|||
- set any built-in LESS variable: for example `@footer_bg_color: black;` sets the background color of the footer to black |
|||
- use built-in mixins: - add a custom font: `.include-custom-font(@family: arial,@font-path, @path: @custom-font-dir, @weight: normal, @style: normal);` |
|||
|
|||
The compiler can also be downloaded as [plugin](http://wordpress.org/plugins/wp-less-to-css/) |
|||
|
|||
#### WordPress |
|||
|
|||
This simple plugin will simply make the library available to other plugins and themes and can be used as a dependency using the [TGM Library](http://tgmpluginactivation.com/) |
|||
|
|||
How to install: |
|||
|
|||
1. Install the plugin from your WordPress Dashboard: http://wordpress.org/plugins/lessphp/ |
|||
2. That's it :) |
|||
|
|||
|
|||
Transitioning from Leafo/lessphp |
|||
--- |
|||
Projects looking for an easy transition from leafo/lessphp can use the lessc.inc.php adapter. To use, [Download the less.php source code](https://github.com/wikimedia/less.php/archive/master.zip) and unzip the files into your project so that the new 'lessc.inc.php' replaces the existing 'lessc.inc.php'. |
|||
|
|||
Note, the 'setPreserveComments' will no longer have any effect on the compiled LESS. |
|||
|
|||
Credits |
|||
--- |
|||
less.php was originally ported to PHP by [Matt Agar](https://github.com/agar) and then updated by [Martin Jantošovič](https://github.com/Mordred). This Wikimedia-maintained fork was split off from [Josh Schmidt's version](https://github.com/oyejorge/less.php). |
|||
|
@ -0,0 +1,191 @@ |
|||
#!/usr/bin/env php |
|||
<?php |
|||
|
|||
require_once dirname(__FILE__) . '/../lib/Less/Autoloader.php'; |
|||
Less_Autoloader::register(); |
|||
|
|||
// Create our environment |
|||
$env = array('compress' => false, 'relativeUrls' => false); |
|||
$silent = false; |
|||
$watch = false; |
|||
$rootpath = ''; |
|||
|
|||
// Check for arguments |
|||
array_shift($argv); |
|||
if (!count($argv)) { |
|||
$argv[] = '-h'; |
|||
} |
|||
|
|||
// parse arguments |
|||
foreach ($argv as $key => $arg) { |
|||
if (preg_match('/^--?([a-z][0-9a-z-]*)(?:=([^\s]+))?$/i', $arg, $matches)) { |
|||
$option = $matches[1]; |
|||
$value = isset($matches[2]) ? $matches[2] : false; |
|||
unset($argv[$key]); |
|||
|
|||
switch ($option) { |
|||
case 'h': |
|||
case 'help': |
|||
echo <<<EOD |
|||
Usage: lessc [options] sources [destination] |
|||
|
|||
-h, --help Print help (this message) and exit. |
|||
-s, --silent Suppress output of error messages. |
|||
-v, --version Print version number and exit. |
|||
-x, --compress Compress output by removing some whitespaces. |
|||
--include-path=PATHS Set include paths. Separated by `:'. Use `;' on Windows. |
|||
--strict-imports Force evaluation of imports. |
|||
-sm=on|off Turn on or off strict math, where in strict mode, math |
|||
--strict-math=on|off requires brackets. This option may default to on and then |
|||
be removed in the future. |
|||
-su=on|off Allow mixed units, e.g. 1px+1em or 1px*1px which have units |
|||
--strict-units=on|off that cannot be represented. |
|||
-ru, --relative-urls re-write relative urls to the base less file. |
|||
-rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls. |
|||
Works with or without the relative-urls option. |
|||
-w, --watch Watch input files for changes. |
|||
|
|||
|
|||
EOD; |
|||
exit; |
|||
case 's': |
|||
case 'silent': |
|||
$silent = true; |
|||
break; |
|||
|
|||
case 'w': |
|||
case 'watch': |
|||
$watch = true; |
|||
break; |
|||
|
|||
case 'v': |
|||
case 'version': |
|||
echo "lessc " . Less_Version::version . " (less.php)\n\n"; |
|||
exit; |
|||
|
|||
case 'rp': |
|||
case 'rootpath': |
|||
$rootpath = $value; |
|||
break; |
|||
|
|||
|
|||
//parser options |
|||
case 'compress': |
|||
$env['compress'] = true; |
|||
break; |
|||
|
|||
case 'ru': |
|||
case 'relative-urls': |
|||
$env['relativeUrls'] = true; |
|||
break; |
|||
|
|||
case 'su': |
|||
case 'strict-units': |
|||
$env['strictUnits'] = ($value === 'on'); |
|||
break; |
|||
|
|||
case 'sm': |
|||
case 'strict-math': |
|||
$env['strictMath'] = ($value === 'on'); |
|||
break; |
|||
|
|||
case 'x': |
|||
case 'include-path': |
|||
$env['import_dirs'] = preg_split('#;|\:#', $value); |
|||
break; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
if (count($argv) > 1) { |
|||
$output = array_pop($argv); |
|||
$inputs = $argv; |
|||
} |
|||
else { |
|||
$inputs = $argv; |
|||
$output = false; |
|||
} |
|||
|
|||
if (!count($inputs)) { |
|||
echo("lessc: no input files\n"); |
|||
exit; |
|||
} |
|||
|
|||
if ($watch) { |
|||
if (!$output) { |
|||
echo("lessc: you must specify the output file if --watch is given\n"); |
|||
exit; |
|||
} |
|||
|
|||
$lastAction = 0; |
|||
|
|||
echo("lessc: watching input files\n"); |
|||
|
|||
while (1) { |
|||
clearstatcache(); |
|||
|
|||
$updated = false; |
|||
foreach ($inputs as $input) { |
|||
if ($input == '-') { |
|||
if (count($inputs) == 1) { |
|||
echo("lessc: during watching files is not possible to watch stdin\n"); |
|||
exit; |
|||
} |
|||
else { |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
if (filemtime($input) > $lastAction) { |
|||
$updated = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if ($updated) { |
|||
$lastAction = time(); |
|||
$parser = new Less_Parser($env); |
|||
foreach ($inputs as $input) { |
|||
try { |
|||
$parser->parseFile($input, $rootpath); |
|||
} |
|||
catch (Exception $e) { |
|||
echo("lessc: " . $e->getMessage() . " \n"); |
|||
continue; // Invalid processing |
|||
} |
|||
} |
|||
|
|||
file_put_contents($output, $parser->getCss()); |
|||
echo("lessc: output file recompiled\n"); |
|||
} |
|||
|
|||
sleep(1); |
|||
} |
|||
} |
|||
else { |
|||
$parser = new Less_Parser($env); |
|||
foreach ($inputs as $input) { |
|||
if ($input == '-') { |
|||
$content = file_get_contents('php://stdin'); |
|||
$parser->parse($content); |
|||
} |
|||
else { |
|||
try { |
|||
$parser->parseFile($input); |
|||
} |
|||
catch (Exception $e) { |
|||
if (!$silent) { |
|||
echo("lessc: " . ((string)$e) . " \n"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if ($output) { |
|||
file_put_contents($output, $parser->getCss()); |
|||
} |
|||
else { |
|||
echo $parser->getCss(); |
|||
} |
|||
} |
@ -0,0 +1,49 @@ |
|||
{ |
|||
"name": "wikimedia/less.php", |
|||
"description": "PHP port of the Javascript version of LESS http://lesscss.org (Originally maintained by Josh Schmidt)", |
|||
"keywords": [ "less", "css", "php", "stylesheet", "less.js", "lesscss" ], |
|||
"license": "Apache-2.0", |
|||
"authors": [ |
|||
{ |
|||
"name": "Josh Schmidt", |
|||
"homepage": "https://github.com/oyejorge" |
|||
}, |
|||
{ |
|||
"name": "Matt Agar", |
|||
"homepage": "https://github.com/agar" |
|||
}, |
|||
{ |
|||
"name": "Martin Jantošovič", |
|||
"homepage": "https://github.com/Mordred" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": ">=7.2.9" |
|||
}, |
|||
"require-dev": { |
|||
"mediawiki/mediawiki-codesniffer": "34.0.0", |
|||
"mediawiki/minus-x": "1.0.0", |
|||
"php-parallel-lint/php-console-highlighter": "0.5.0", |
|||
"php-parallel-lint/php-parallel-lint": "1.2.0", |
|||
"phpunit/phpunit": "^8.5" |
|||
}, |
|||
"scripts": { |
|||
"test": [ |
|||
"parallel-lint . --exclude vendor", |
|||
"phpcs -sp", |
|||
"phpunit", |
|||
"minus-x check ." |
|||
], |
|||
"fix": [ |
|||
"minus-x fix .", |
|||
"phpcbf" |
|||
] |
|||
}, |
|||
"autoload": { |
|||
"psr-0": { "Less": "lib/" }, |
|||
"classmap": ["lessc.inc.php"] |
|||
}, |
|||
"bin": [ |
|||
"bin/lessc" |
|||
] |
|||
} |
@ -0,0 +1,274 @@ |
|||
<?php |
|||
/** |
|||
* This file provides the part of lessphp API (https://github.com/leafo/lessphp) |
|||
* to be a drop-in replacement for following products: |
|||
* - Drupal 7, by the less module v3.0+ (https://drupal.org/project/less) |
|||
* - Symfony 2 |
|||
*/ |
|||
|
|||
// Register autoloader for non-composer installations |
|||
if ( !class_exists( 'Less_Parser' ) ) { |
|||
require_once __DIR__ . '/lib/Less/Autoloader.php'; |
|||
Less_Autoloader::register(); |
|||
} |
|||
|
|||
class lessc { |
|||
|
|||
static public $VERSION = Less_Version::less_version; |
|||
|
|||
public $importDir = ''; |
|||
protected $allParsedFiles = array(); |
|||
protected $libFunctions = array(); |
|||
protected $registeredVars = array(); |
|||
private $formatterName; |
|||
private $options = array(); |
|||
|
|||
public function __construct( $lessc = null, $sourceName = null ) { |
|||
} |
|||
|
|||
public function setImportDir( $dirs ) { |
|||
$this->importDir = (array)$dirs; |
|||
} |
|||
|
|||
public function addImportDir( $dir ) { |
|||
$this->importDir = (array)$this->importDir; |
|||
$this->importDir[] = $dir; |
|||
} |
|||
|
|||
public function setFormatter( $name ) { |
|||
$this->formatterName = $name; |
|||
} |
|||
|
|||
public function setPreserveComments( $preserve ) { |
|||
} |
|||
|
|||
public function registerFunction( $name, $func ) { |
|||
$this->libFunctions[$name] = $func; |
|||
} |
|||
|
|||
public function unregisterFunction( $name ) { |
|||
unset( $this->libFunctions[$name] ); |
|||
} |
|||
|
|||
public function setVariables( $variables ) { |
|||
foreach ( $variables as $name => $value ) { |
|||
$this->setVariable( $name, $value ); |
|||
} |
|||
} |
|||
|
|||
public function setVariable( $name, $value ) { |
|||
$this->registeredVars[$name] = $value; |
|||
} |
|||
|
|||
public function unsetVariable( $name ) { |
|||
unset( $this->registeredVars[$name] ); |
|||
} |
|||
|
|||
public function setOptions( $options ) { |
|||
foreach ( $options as $name => $value ) { |
|||
$this->setOption( $name, $value ); |
|||
} |
|||
} |
|||
|
|||
public function setOption( $name, $value ) { |
|||
$this->options[$name] = $value; |
|||
} |
|||
|
|||
public function parse( $buffer, $presets = array() ) { |
|||
$this->setVariables( $presets ); |
|||
|
|||
$parser = new Less_Parser( $this->getOptions() ); |
|||
$parser->setImportDirs( $this->getImportDirs() ); |
|||
foreach ( $this->libFunctions as $name => $func ) { |
|||
$parser->registerFunction( $name, $func ); |
|||
} |
|||
$parser->parse( $buffer ); |
|||
if ( count( $this->registeredVars ) ) { |
|||
$parser->ModifyVars( $this->registeredVars ); |
|||
} |
|||
|
|||
return $parser->getCss(); |
|||
} |
|||
|
|||
protected function getOptions() { |
|||
$options = array( 'relativeUrls' => false ); |
|||
switch ( $this->formatterName ) { |
|||
case 'compressed': |
|||
$options['compress'] = true; |
|||
break; |
|||
} |
|||
if ( is_array( $this->options ) ) { |
|||
$options = array_merge( $options, $this->options ); |
|||
} |
|||
return $options; |
|||
} |
|||
|
|||
protected function getImportDirs() { |
|||
$dirs_ = (array)$this->importDir; |
|||
$dirs = array(); |
|||
foreach ( $dirs_ as $dir ) { |
|||
$dirs[$dir] = ''; |
|||
} |
|||
return $dirs; |
|||
} |
|||
|
|||
public function compile( $string, $name = null ) { |
|||
$oldImport = $this->importDir; |
|||
$this->importDir = (array)$this->importDir; |
|||
|
|||
$this->allParsedFiles = array(); |
|||
|
|||
$parser = new Less_Parser( $this->getOptions() ); |
|||
$parser->SetImportDirs( $this->getImportDirs() ); |
|||
if ( count( $this->registeredVars ) ) { |
|||
$parser->ModifyVars( $this->registeredVars ); |
|||
} |
|||
foreach ( $this->libFunctions as $name => $func ) { |
|||
$parser->registerFunction( $name, $func ); |
|||
} |
|||
$parser->parse( $string ); |
|||
$out = $parser->getCss(); |
|||
|
|||
$parsed = Less_Parser::AllParsedFiles(); |
|||
foreach ( $parsed as $file ) { |
|||
$this->addParsedFile( $file ); |
|||
} |
|||
|
|||
$this->importDir = $oldImport; |
|||
|
|||
return $out; |
|||
} |
|||
|
|||
public function compileFile( $fname, $outFname = null ) { |
|||
if ( !is_readable( $fname ) ) { |
|||
throw new Exception( 'load error: failed to find '.$fname ); |
|||
} |
|||
|
|||
$pi = pathinfo( $fname ); |
|||
|
|||
$oldImport = $this->importDir; |
|||
|
|||
$this->importDir = (array)$this->importDir; |
|||
$this->importDir[] = Less_Parser::AbsPath( $pi['dirname'] ).'/'; |
|||
|
|||
$this->allParsedFiles = array(); |
|||
$this->addParsedFile( $fname ); |
|||
|
|||
$parser = new Less_Parser( $this->getOptions() ); |
|||
$parser->SetImportDirs( $this->getImportDirs() ); |
|||
if ( count( $this->registeredVars ) ) { |
|||
$parser->ModifyVars( $this->registeredVars ); |
|||
} |
|||
foreach ( $this->libFunctions as $name => $func ) { |
|||
$parser->registerFunction( $name, $func ); |
|||
} |
|||
$parser->parseFile( $fname ); |
|||
$out = $parser->getCss(); |
|||
|
|||
$parsed = Less_Parser::AllParsedFiles(); |
|||
foreach ( $parsed as $file ) { |
|||
$this->addParsedFile( $file ); |
|||
} |
|||
|
|||
$this->importDir = $oldImport; |
|||
|
|||
if ( $outFname !== null ) { |
|||
return file_put_contents( $outFname, $out ); |
|||
} |
|||
|
|||
return $out; |
|||
} |
|||
|
|||
public function checkedCompile( $in, $out ) { |
|||
if ( !is_file( $out ) || filemtime( $in ) > filemtime( $out ) ) { |
|||
$this->compileFile( $in, $out ); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Execute lessphp on a .less file or a lessphp cache structure |
|||
* |
|||
* The lessphp cache structure contains information about a specific |
|||
* less file having been parsed. It can be used as a hint for future |
|||
* calls to determine whether or not a rebuild is required. |
|||
* |
|||
* The cache structure contains two important keys that may be used |
|||
* externally: |
|||
* |
|||
* compiled: The final compiled CSS |
|||
* updated: The time (in seconds) the CSS was last compiled |
|||
* |
|||
* The cache structure is a plain-ol' PHP associative array and can |
|||
* be serialized and unserialized without a hitch. |
|||
* |
|||
* @param mixed $in Input |
|||
* @param bool $force Force rebuild? |
|||
* @return array lessphp cache structure |
|||
*/ |
|||
public function cachedCompile( $in, $force = false ) { |
|||
// assume no root |
|||
$root = null; |
|||
|
|||
if ( is_string( $in ) ) { |
|||
$root = $in; |
|||
} elseif ( is_array( $in ) and isset( $in['root'] ) ) { |
|||
if ( $force or !isset( $in['files'] ) ) { |
|||
// If we are forcing a recompile or if for some reason the |
|||
// structure does not contain any file information we should |
|||
// specify the root to trigger a rebuild. |
|||
$root = $in['root']; |
|||
} elseif ( isset( $in['files'] ) and is_array( $in['files'] ) ) { |
|||
foreach ( $in['files'] as $fname => $ftime ) { |
|||
if ( !file_exists( $fname ) or filemtime( $fname ) > $ftime ) { |
|||
// One of the files we knew about previously has changed |
|||
// so we should look at our incoming root again. |
|||
$root = $in['root']; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} else { |
|||
// TODO: Throw an exception? We got neither a string nor something |
|||
// that looks like a compatible lessphp cache structure. |
|||
return null; |
|||
} |
|||
|
|||
if ( $root !== null ) { |
|||
// If we have a root value which means we should rebuild. |
|||
$out = array(); |
|||
$out['root'] = $root; |
|||
$out['compiled'] = $this->compileFile( $root ); |
|||
$out['files'] = $this->allParsedFiles(); |
|||
$out['updated'] = time(); |
|||
return $out; |
|||
} else { |
|||
// No changes, pass back the structure |
|||
// we were given initially. |
|||
return $in; |
|||
} |
|||
} |
|||
|
|||
public function ccompile( $in, $out, $less = null ) { |
|||
if ( $less === null ) { |
|||
$less = new self; |
|||
} |
|||
return $less->checkedCompile( $in, $out ); |
|||
} |
|||
|
|||
public static function cexecute( $in, $force = false, $less = null ) { |
|||
if ( $less === null ) { |
|||
$less = new self; |
|||
} |
|||
return $less->cachedCompile( $in, $force ); |
|||
} |
|||
|
|||
public function allParsedFiles() { |
|||
return $this->allParsedFiles; |
|||
} |
|||
|
|||
protected function addParsedFile( $file ) { |
|||
$this->allParsedFiles[Less_Parser::AbsPath( $file )] = filemtime( $file ); |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
.easymin |
|||
Autoloader.php |
@ -0,0 +1,77 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Autoloader |
|||
* |
|||
* @package Less |
|||
* @subpackage autoload |
|||
*/ |
|||
class Less_Autoloader { |
|||
|
|||
/** |
|||
* Registered flag |
|||
* |
|||
* @var boolean |
|||
*/ |
|||
protected static $registered = false; |
|||
|
|||
/** |
|||
* Library directory |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected static $libDir; |
|||
|
|||
/** |
|||
* Register the autoloader in the spl autoloader |
|||
* |
|||
* @return void |
|||
* @throws Exception If there was an error in registration |
|||
*/ |
|||
public static function register() { |
|||
if ( self::$registered ) { |
|||
return; |
|||
} |
|||
|
|||
self::$libDir = dirname( __FILE__ ); |
|||
|
|||
if ( false === spl_autoload_register( array( 'Less_Autoloader', 'loadClass' ) ) ) { |
|||
throw new Exception( 'Unable to register Less_Autoloader::loadClass as an autoloading method.' ); |
|||
} |
|||
|
|||
self::$registered = true; |
|||
} |
|||
|
|||
/** |
|||
* Unregisters the autoloader |
|||
* |
|||
* @return void |
|||
*/ |
|||
public static function unregister() { |
|||
spl_autoload_unregister( array( 'Less_Autoloader', 'loadClass' ) ); |
|||
self::$registered = false; |
|||
} |
|||
|
|||
/** |
|||
* Loads the class |
|||
* |
|||
* @param string $className The class to load |
|||
*/ |
|||
public static function loadClass( $className ) { |
|||
// handle only package classes |
|||
if ( strpos( $className, 'Less_' ) !== 0 ) { |
|||
return; |
|||
} |
|||
|
|||
$className = substr( $className, 5 ); |
|||
$fileName = self::$libDir . DIRECTORY_SEPARATOR . str_replace( '_', DIRECTORY_SEPARATOR, $className ) . '.php'; |
|||
|
|||
if ( file_exists( $fileName ) ) { |
|||
require $fileName; |
|||
return true; |
|||
} else { |
|||
throw new Exception( 'file not loadable '.$fileName ); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,293 @@ |
|||
<?php |
|||
|
|||
require_once dirname( __FILE__ ).'/Version.php'; |
|||
|
|||
/** |
|||
* Utility for handling the generation and caching of css files |
|||
* |
|||
* @package Less |
|||
* @subpackage cache |
|||
* |
|||
*/ |
|||
class Less_Cache { |
|||
|
|||
// directory less.php can use for storing data |
|||
public static $cache_dir = false; |
|||
|
|||
// prefix for the storing data |
|||
public static $prefix = 'lessphp_'; |
|||
|
|||
// prefix for the storing vars |
|||
public static $prefix_vars = 'lessphpvars_'; |
|||
|
|||
// specifies the number of seconds after which data created by less.php will be seen as 'garbage' and potentially cleaned up |
|||
public static $gc_lifetime = 604800; |
|||
|
|||
/** |
|||
* Save and reuse the results of compiled less files. |
|||
* The first call to Get() will generate css and save it. |
|||
* Subsequent calls to Get() with the same arguments will return the same css filename |
|||
* |
|||
* @param array $less_files Array of .less files to compile |
|||
* @param array $parser_options Array of compiler options |
|||
* @param array $modify_vars Array of variables |
|||
* @return string Name of the css file |
|||
*/ |
|||
public static function Get( $less_files, $parser_options = array(), $modify_vars = array() ) { |
|||
// check $cache_dir |
|||
if ( isset( $parser_options['cache_dir'] ) ) { |
|||
Less_Cache::$cache_dir = $parser_options['cache_dir']; |
|||
} |
|||
|
|||
if ( empty( Less_Cache::$cache_dir ) ) { |
|||
throw new Exception( 'cache_dir not set' ); |
|||
} |
|||
|
|||
if ( isset( $parser_options['prefix'] ) ) { |
|||
Less_Cache::$prefix = $parser_options['prefix']; |
|||
} |
|||
|
|||
if ( empty( Less_Cache::$prefix ) ) { |
|||
throw new Exception( 'prefix not set' ); |
|||
} |
|||
|
|||
if ( isset( $parser_options['prefix_vars'] ) ) { |
|||
Less_Cache::$prefix_vars = $parser_options['prefix_vars']; |
|||
} |
|||
|
|||
if ( empty( Less_Cache::$prefix_vars ) ) { |
|||
throw new Exception( 'prefix_vars not set' ); |
|||
} |
|||
|
|||
self::CheckCacheDir(); |
|||
$less_files = (array)$less_files; |
|||
|
|||
// create a file for variables |
|||
if ( !empty( $modify_vars ) ) { |
|||
$lessvars = Less_Parser::serializeVars( $modify_vars ); |
|||
$vars_file = Less_Cache::$cache_dir . Less_Cache::$prefix_vars . sha1( $lessvars ) . '.less'; |
|||
|
|||
if ( !file_exists( $vars_file ) ) { |
|||
file_put_contents( $vars_file, $lessvars ); |
|||
} |
|||
|
|||
$less_files += array( $vars_file => '/' ); |
|||
} |
|||
|
|||
// generate name for compiled css file |
|||
$hash = md5( json_encode( $less_files ) ); |
|||
$list_file = Less_Cache::$cache_dir . Less_Cache::$prefix . $hash . '.list'; |
|||
|
|||
// check cached content |
|||
if ( !isset( $parser_options['use_cache'] ) || $parser_options['use_cache'] === true ) { |
|||
if ( file_exists( $list_file ) ) { |
|||
|
|||
self::ListFiles( $list_file, $list, $cached_name ); |
|||
$compiled_name = self::CompiledName( $list, $hash ); |
|||
|
|||
// if $cached_name is the same as the $compiled name, don't regenerate |
|||
if ( !$cached_name || $cached_name === $compiled_name ) { |
|||
|
|||
$output_file = self::OutputFile( $compiled_name, $parser_options ); |
|||
|
|||
if ( $output_file && file_exists( $output_file ) ) { |
|||
@touch( $list_file ); |
|||
return basename( $output_file ); // for backwards compatibility, we just return the name of the file |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
$compiled = self::Cache( $less_files, $parser_options ); |
|||
if ( !$compiled ) { |
|||
return false; |
|||
} |
|||
|
|||
$compiled_name = self::CompiledName( $less_files, $hash ); |
|||
$output_file = self::OutputFile( $compiled_name, $parser_options ); |
|||
|
|||
// save the file list |
|||
$list = $less_files; |
|||
$list[] = $compiled_name; |
|||
$cache = implode( "\n", $list ); |
|||
file_put_contents( $list_file, $cache ); |
|||
|
|||
// save the css |
|||
file_put_contents( $output_file, $compiled ); |
|||
|
|||
// clean up |
|||
self::CleanCache(); |
|||
|
|||
return basename( $output_file ); |
|||
} |
|||
|
|||
/** |
|||
* Force the compiler to regenerate the cached css file |
|||
* |
|||
* @param array $less_files Array of .less files to compile |
|||
* @param array $parser_options Array of compiler options |
|||
* @param array $modify_vars Array of variables |
|||
* @return string Name of the css file |
|||
*/ |
|||
public static function Regen( $less_files, $parser_options = array(), $modify_vars = array() ) { |
|||
$parser_options['use_cache'] = false; |
|||
return self::Get( $less_files, $parser_options, $modify_vars ); |
|||
} |
|||
|
|||
public static function Cache( &$less_files, $parser_options = array() ) { |
|||
// get less.php if it exists |
|||
$file = dirname( __FILE__ ) . '/Less.php'; |
|||
if ( file_exists( $file ) && !class_exists( 'Less_Parser' ) ) { |
|||
require_once $file; |
|||
} |
|||
|
|||
$parser_options['cache_dir'] = Less_Cache::$cache_dir; |
|||
$parser = new Less_Parser( $parser_options ); |
|||
|
|||
// combine files |
|||
foreach ( $less_files as $file_path => $uri_or_less ) { |
|||
|
|||
// treat as less markup if there are newline characters |
|||
if ( strpos( $uri_or_less, "\n" ) !== false ) { |
|||
$parser->Parse( $uri_or_less ); |
|||
continue; |
|||
} |
|||
|
|||
$parser->ParseFile( $file_path, $uri_or_less ); |
|||
} |
|||
|
|||
$compiled = $parser->getCss(); |
|||
|
|||
$less_files = $parser->allParsedFiles(); |
|||
|
|||
return $compiled; |
|||
} |
|||
|
|||
private static function OutputFile( $compiled_name, $parser_options ) { |
|||
// custom output file |
|||
if ( !empty( $parser_options['output'] ) ) { |
|||
|
|||
// relative to cache directory? |
|||
if ( preg_match( '#[\\\\/]#', $parser_options['output'] ) ) { |
|||
return $parser_options['output']; |
|||
} |
|||
|
|||
return Less_Cache::$cache_dir.$parser_options['output']; |
|||
} |
|||
|
|||
return Less_Cache::$cache_dir.$compiled_name; |
|||
} |
|||
|
|||
private static function CompiledName( $files, $extrahash ) { |
|||
// save the file list |
|||
$temp = array( Less_Version::cache_version ); |
|||
foreach ( $files as $file ) { |
|||
$temp[] = filemtime( $file )."\t".filesize( $file )."\t".$file; |
|||
} |
|||
|
|||
return Less_Cache::$prefix.sha1( json_encode( $temp ).$extrahash ).'.css'; |
|||
} |
|||
|
|||
public static function SetCacheDir( $dir ) { |
|||
Less_Cache::$cache_dir = $dir; |
|||
self::CheckCacheDir(); |
|||
} |
|||
|
|||
public static function CheckCacheDir() { |
|||
Less_Cache::$cache_dir = str_replace( '\\', '/', Less_Cache::$cache_dir ); |
|||
Less_Cache::$cache_dir = rtrim( Less_Cache::$cache_dir, '/' ).'/'; |
|||
|
|||
if ( !file_exists( Less_Cache::$cache_dir ) ) { |
|||
if ( !mkdir( Less_Cache::$cache_dir ) ) { |
|||
throw new Less_Exception_Parser( 'Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir ); |
|||
} |
|||
|
|||
} elseif ( !is_dir( Less_Cache::$cache_dir ) ) { |
|||
throw new Less_Exception_Parser( 'Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir ); |
|||
|
|||
} elseif ( !is_writable( Less_Cache::$cache_dir ) ) { |
|||
throw new Less_Exception_Parser( 'Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir ); |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Delete unused less.php files |
|||
* |
|||
*/ |
|||
public static function CleanCache() { |
|||
static $clean = false; |
|||
|
|||
if ( $clean || empty( Less_Cache::$cache_dir ) ) { |
|||
return; |
|||
} |
|||
|
|||
$clean = true; |
|||
|
|||
// only remove files with extensions created by less.php |
|||
// css files removed based on the list files |
|||
$remove_types = array( 'lesscache' => 1,'list' => 1,'less' => 1,'map' => 1 ); |
|||
|
|||
$files = scandir( Less_Cache::$cache_dir ); |
|||
if ( !$files ) { |
|||
return; |
|||
} |
|||
|
|||
$check_time = time() - self::$gc_lifetime; |
|||
foreach ( $files as $file ) { |
|||
|
|||
// don't delete if the file wasn't created with less.php |
|||
if ( strpos( $file, Less_Cache::$prefix ) !== 0 ) { |
|||
continue; |
|||
} |
|||
|
|||
$parts = explode( '.', $file ); |
|||
$type = array_pop( $parts ); |
|||
|
|||
if ( !isset( $remove_types[$type] ) ) { |
|||
continue; |
|||
} |
|||
|
|||
$full_path = Less_Cache::$cache_dir . $file; |
|||
$mtime = filemtime( $full_path ); |
|||
|
|||
// don't delete if it's a relatively new file |
|||
if ( $mtime > $check_time ) { |
|||
continue; |
|||
} |
|||
|
|||
// delete the list file and associated css file |
|||
if ( $type === 'list' ) { |
|||
self::ListFiles( $full_path, $list, $css_file_name ); |
|||
if ( $css_file_name ) { |
|||
$css_file = Less_Cache::$cache_dir . $css_file_name; |
|||
if ( file_exists( $css_file ) ) { |
|||
unlink( $css_file ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
unlink( $full_path ); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Get the list of less files and generated css file from a list file |
|||
* |
|||
*/ |
|||
static function ListFiles( $list_file, &$list, &$css_file_name ) { |
|||
$list = explode( "\n", file_get_contents( $list_file ) ); |
|||
|
|||
// pop the cached name that should match $compiled_name |
|||
$css_file_name = array_pop( $list ); |
|||
|
|||
if ( !preg_match( '/^' . Less_Cache::$prefix . '[a-f0-9]+\.css$/', $css_file_name ) ) { |
|||
$list[] = $css_file_name; |
|||
$css_file_name = false; |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,169 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Utility for css colors |
|||
* |
|||
* @package Less |
|||
* @subpackage color |
|||
*/ |
|||
class Less_Colors { |
|||
|
|||
public static $colors = array( |
|||
'aliceblue' => '#f0f8ff', |
|||
'antiquewhite' => '#faebd7', |
|||
'aqua' => '#00ffff', |
|||
'aquamarine' => '#7fffd4', |
|||
'azure' => '#f0ffff', |
|||
'beige' => '#f5f5dc', |
|||
'bisque' => '#ffe4c4', |
|||
'black' => '#000000', |
|||
'blanchedalmond' => '#ffebcd', |
|||
'blue' => '#0000ff', |
|||
'blueviolet' => '#8a2be2', |
|||
'brown' => '#a52a2a', |
|||
'burlywood' => '#deb887', |
|||
'cadetblue' => '#5f9ea0', |
|||
'chartreuse' => '#7fff00', |
|||
'chocolate' => '#d2691e', |
|||
'coral' => '#ff7f50', |
|||
'cornflowerblue' => '#6495ed', |
|||
'cornsilk' => '#fff8dc', |
|||
'crimson' => '#dc143c', |
|||
'cyan' => '#00ffff', |
|||
'darkblue' => '#00008b', |
|||
'darkcyan' => '#008b8b', |
|||
'darkgoldenrod' => '#b8860b', |
|||
'darkgray' => '#a9a9a9', |
|||
'darkgrey' => '#a9a9a9', |
|||
'darkgreen' => '#006400', |
|||
'darkkhaki' => '#bdb76b', |
|||
'darkmagenta' => '#8b008b', |
|||
'darkolivegreen' => '#556b2f', |
|||
'darkorange' => '#ff8c00', |
|||
'darkorchid' => '#9932cc', |
|||
'darkred' => '#8b0000', |
|||
'darksalmon' => '#e9967a', |
|||
'darkseagreen' => '#8fbc8f', |
|||
'darkslateblue' => '#483d8b', |
|||
'darkslategray' => '#2f4f4f', |
|||
'darkslategrey' => '#2f4f4f', |
|||
'darkturquoise' => '#00ced1', |
|||
'darkviolet' => '#9400d3', |
|||
'deeppink' => '#ff1493', |
|||
'deepskyblue' => '#00bfff', |
|||
'dimgray' => '#696969', |
|||
'dimgrey' => '#696969', |
|||
'dodgerblue' => '#1e90ff', |
|||
'firebrick' => '#b22222', |
|||
'floralwhite' => '#fffaf0', |
|||
'forestgreen' => '#228b22', |
|||
'fuchsia' => '#ff00ff', |
|||
'gainsboro' => '#dcdcdc', |
|||
'ghostwhite' => '#f8f8ff', |
|||
'gold' => '#ffd700', |
|||
'goldenrod' => '#daa520', |
|||
'gray' => '#808080', |
|||
'grey' => '#808080', |
|||
'green' => '#008000', |
|||
'greenyellow' => '#adff2f', |
|||
'honeydew' => '#f0fff0', |
|||
'hotpink' => '#ff69b4', |
|||
'indianred' => '#cd5c5c', |
|||
'indigo' => '#4b0082', |
|||
'ivory' => '#fffff0', |
|||
'khaki' => '#f0e68c', |
|||
'lavender' => '#e6e6fa', |
|||
'lavenderblush' => '#fff0f5', |
|||
'lawngreen' => '#7cfc00', |
|||
'lemonchiffon' => '#fffacd', |
|||
'lightblue' => '#add8e6', |
|||
'lightcoral' => '#f08080', |
|||
'lightcyan' => '#e0ffff', |
|||
'lightgoldenrodyellow' => '#fafad2', |
|||
'lightgray' => '#d3d3d3', |
|||
'lightgrey' => '#d3d3d3', |
|||
'lightgreen' => '#90ee90', |
|||
'lightpink' => '#ffb6c1', |
|||
'lightsalmon' => '#ffa07a', |
|||
'lightseagreen' => '#20b2aa', |
|||
'lightskyblue' => '#87cefa', |
|||
'lightslategray' => '#778899', |
|||
'lightslategrey' => '#778899', |
|||
'lightsteelblue' => '#b0c4de', |
|||
'lightyellow' => '#ffffe0', |
|||
'lime' => '#00ff00', |
|||
'limegreen' => '#32cd32', |
|||
'linen' => '#faf0e6', |
|||
'magenta' => '#ff00ff', |
|||
'maroon' => '#800000', |
|||
'mediumaquamarine' => '#66cdaa', |
|||
'mediumblue' => '#0000cd', |
|||
'mediumorchid' => '#ba55d3', |
|||
'mediumpurple' => '#9370d8', |
|||
'mediumseagreen' => '#3cb371', |
|||
'mediumslateblue' => '#7b68ee', |
|||
'mediumspringgreen' => '#00fa9a', |
|||
'mediumturquoise' => '#48d1cc', |
|||
'mediumvioletred' => '#c71585', |
|||
'midnightblue' => '#191970', |
|||
'mintcream' => '#f5fffa', |
|||
'mistyrose' => '#ffe4e1', |
|||
'moccasin' => '#ffe4b5', |
|||
'navajowhite' => '#ffdead', |
|||
'navy' => '#000080', |
|||
'oldlace' => '#fdf5e6', |
|||
'olive' => '#808000', |
|||
'olivedrab' => '#6b8e23', |
|||
'orange' => '#ffa500', |
|||
'orangered' => '#ff4500', |
|||
'orchid' => '#da70d6', |
|||
'palegoldenrod' => '#eee8aa', |
|||
'palegreen' => '#98fb98', |
|||
'paleturquoise' => '#afeeee', |
|||
'palevioletred' => '#d87093', |
|||
'papayawhip' => '#ffefd5', |
|||
'peachpuff' => '#ffdab9', |
|||
'peru' => '#cd853f', |
|||
'pink' => '#ffc0cb', |
|||
'plum' => '#dda0dd', |
|||
'powderblue' => '#b0e0e6', |
|||
'purple' => '#800080', |
|||
'red' => '#ff0000', |
|||
'rosybrown' => '#bc8f8f', |
|||
'royalblue' => '#4169e1', |
|||
'saddlebrown' => '#8b4513', |
|||
'salmon' => '#fa8072', |
|||
'sandybrown' => '#f4a460', |
|||
'seagreen' => '#2e8b57', |
|||
'seashell' => '#fff5ee', |
|||
'sienna' => '#a0522d', |
|||
'silver' => '#c0c0c0', |
|||
'skyblue' => '#87ceeb', |
|||
'slateblue' => '#6a5acd', |
|||
'slategray' => '#708090', |
|||
'slategrey' => '#708090', |
|||
'snow' => '#fffafa', |
|||
'springgreen' => '#00ff7f', |
|||
'steelblue' => '#4682b4', |
|||
'tan' => '#d2b48c', |
|||
'teal' => '#008080', |
|||
'thistle' => '#d8bfd8', |
|||
'tomato' => '#ff6347', |
|||
'turquoise' => '#40e0d0', |
|||
'violet' => '#ee82ee', |
|||
'wheat' => '#f5deb3', |
|||
'white' => '#ffffff', |
|||
'whitesmoke' => '#f5f5f5', |
|||
'yellow' => '#ffff00', |
|||
'yellowgreen' => '#9acd32' |
|||
); |
|||
|
|||
public static function hasOwnProperty( $color ) { |
|||
return isset( self::$colors[$color] ); |
|||
} |
|||
|
|||
public static function color( $color ) { |
|||
return self::$colors[$color]; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,66 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Configurable |
|||
* |
|||
* @package Less |
|||
* @subpackage Core |
|||
*/ |
|||
abstract class Less_Configurable { |
|||
|
|||
/** |
|||
* Array of options |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $options = array(); |
|||
|
|||
/** |
|||
* Array of default options |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $defaultOptions = array(); |
|||
|
|||
/** |
|||
* Set options |
|||
* |
|||
* If $options is an object it will be converted into an array by called |
|||
* it's toArray method. |
|||
* |
|||
* @throws Exception |
|||
* @param array|object $options |
|||
* |
|||
*/ |
|||
public function setOptions( $options ) { |
|||
$options = array_intersect_key( $options, $this->defaultOptions ); |
|||
$this->options = array_merge( $this->defaultOptions, $this->options, $options ); |
|||
} |
|||
|
|||
/** |
|||
* Get an option value by name |
|||
* |
|||
* If the option is empty or not set a NULL value will be returned. |
|||
* |
|||
* @param string $name |
|||
* @param mixed $default Default value if confiuration of $name is not present |
|||
* @return mixed |
|||
*/ |
|||
public function getOption( $name, $default = null ) { |
|||
if ( isset( $this->options[$name] ) ) { |
|||
return $this->options[$name]; |
|||
} |
|||
return $default; |
|||
} |
|||
|
|||
/** |
|||
* Set an option |
|||
* |
|||
* @param string $name |
|||
* @param mixed $value |
|||
*/ |
|||
public function setOption( $name, $value ) { |
|||
$this->options[$name] = $value; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,157 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Environment |
|||
* |
|||
* @package Less |
|||
* @subpackage environment |
|||
*/ |
|||
class Less_Environment { |
|||
|
|||
// public $paths = array(); // option - unmodified - paths to search for imports on |
|||
//public static $files = array(); // list of files that have been imported, used for import-once |
|||
//public $rootpath; // option - rootpath to append to URL's |
|||
//public static $strictImports = null; // option - |
|||
//public $insecure; // option - whether to allow imports from insecure ssl hosts |
|||
//public $processImports; // option - whether to process imports. if false then imports will not be imported |
|||
//public $javascriptEnabled; // option - whether JavaScript is enabled. if undefined, defaults to true |
|||
//public $useFileCache; // browser only - whether to use the per file session cache |
|||
public $currentFileInfo; // information about the current file - for error reporting and importing and making urls relative etc. |
|||
|
|||
public $importMultiple = false; // whether we are currently importing multiple copies |
|||
|
|||
/** |
|||
* @var array |
|||
*/ |
|||
public $frames = array(); |
|||
|
|||
/** |
|||
* @var array |
|||
*/ |
|||
public $mediaBlocks = array(); |
|||
|
|||
/** |
|||
* @var array |
|||
*/ |
|||
public $mediaPath = array(); |
|||
|
|||
public static $parensStack = 0; |
|||
|
|||
public static $tabLevel = 0; |
|||
|
|||
public static $lastRule = false; |
|||
|
|||
public static $_outputMap; |
|||
|
|||
public static $mixin_stack = 0; |
|||
|
|||
/** |
|||
* @var array |
|||
*/ |
|||