WP-LESS - Version 1.4.2

Version Description

= 1.4 =

As lessphp has been upgraded to 0.3.0, its behavior changed a little bit.

Please check your LESS syntax according to the document before applying this update.

Download this release

Release Info

Developer oncletom
Plugin Icon wp plugin WP-LESS
Version 1.4.2
Comparing to
See all releases

Code changes from version 1.4.1 to 1.4.2

bootstrap.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: WP LESS
4
  Description: LESS extends CSS with variables, mixins, operations and nested rules. This plugin magically parse all your <code>*.less</code> files queued with <code>wp_enqueue_style</code> in WordPress.
5
  Author: Oncle Tom
6
- Version: 1.4.1
7
  Author URI: http://case.oncle-tom.net/
8
  Plugin URI: http://wordpress.org/extend/plugins/wp-less/
9
 
3
  Plugin Name: WP LESS
4
  Description: LESS extends CSS with variables, mixins, operations and nested rules. This plugin magically parse all your <code>*.less</code> files queued with <code>wp_enqueue_style</code> in WordPress.
5
  Author: Oncle Tom
6
+ Version: 1.4.2
7
  Author URI: http://case.oncle-tom.net/
8
  Plugin URI: http://wordpress.org/extend/plugins/wp-less/
9
 
lib/Compiler.class.php CHANGED
@@ -39,29 +39,45 @@ class WPLessCompiler extends lessc
39
  do_action('wp-less_compiler_parse_pre', $this, $text, $variables);
40
  return apply_filters('wp-less_compiler_parse', parent::parse($text, $variables));
41
  }
42
-
43
  /**
44
- * Returns the LESS buffer
 
45
  *
46
- * @since 1.1
47
- * @return string current buffer
48
- * @deprecated
49
  */
50
- public function getBuffer()
51
  {
52
- return $this->buffer;
 
 
 
53
  }
54
 
55
  /**
56
- * Enables to overload the current LESS buffer
57
- * Use at your own risks.
 
58
  *
59
- * @since 1.1
60
- * @param $css string CSS you'd like to see in the buffer, before being parse
61
- * @deprecated
62
  */
63
- public function setBuffer($css)
64
  {
65
- $this->buffer = $css;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
  }
39
  do_action('wp-less_compiler_parse_pre', $this, $text, $variables);
40
  return apply_filters('wp-less_compiler_parse', parent::parse($text, $variables));
41
  }
42
+
43
  /**
44
+ * Registers a set of functions
45
+ * Originally stored in WPLessConfiguration instance
46
  *
47
+ * @param array $functions
 
 
48
  */
49
+ public function registerFunctions(array $functions = array())
50
  {
51
+ foreach ($functions as $name => $args)
52
+ {
53
+ $this->registerFunction($name, $args['callback']);
54
+ }
55
  }
56
 
57
  /**
58
+ * Process a WPLessStylesheet
59
+ *
60
+ * This logic was previously held in WPLessStylesheet::save()
61
  *
62
+ * @since 1.4.2
 
 
63
  */
64
+ public function saveStylesheet(WPLessStylesheet $stylesheet)
65
  {
66
+ wp_mkdir_p(dirname($stylesheet->getTargetPath()));
67
+
68
+ try
69
+ {
70
+ do_action('wp-less_stylesheet_save_pre', $stylesheet, $stylesheet->getVariables());
71
+
72
+ file_put_contents($stylesheet->getTargetPath(), apply_filters('wp-less_stylesheet_save', $this->parse(null, $stylesheet->getVariables()), $stylesheet));
73
+ chmod($stylesheet->getTargetPath(), 0666);
74
+
75
+ $stylesheet->save();
76
+ do_action('wp-less_stylesheet_save_post', $stylesheet);
77
+ }
78
+ catch(Exception $e)
79
+ {
80
+ wp_die($e->getMessage());
81
+ }
82
  }
83
  }
lib/Configuration.class.php CHANGED
@@ -17,6 +17,12 @@ class WPLessConfiguration extends WPPluginToolkitConfiguration
17
  */
18
  protected $variables = array();
19
 
 
 
 
 
 
 
20
 
21
  protected function configure()
22
  {
@@ -58,4 +64,41 @@ class WPLessConfiguration extends WPPluginToolkitConfiguration
58
  {
59
  $this->variables = $variables;
60
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
17
  */
18
  protected $variables = array();
19
 
20
+ /**
21
+ * @protected
22
+ * @see http://leafo.net/lessphp/docs/index.html#custom_functions
23
+ */
24
+ protected $functions = array();
25
+
26
 
27
  protected function configure()
28
  {
64
  {
65
  $this->variables = $variables;
66
  }
67
+
68
+ /**
69
+ * Return LESS functions
70
+ *
71
+ * @since 1.4.2
72
+ * @return array
73
+ */
74
+ public function getFunctions()
75
+ {
76
+ return $this->functions;
77
+ }
78
+
79
+ /**
80
+ * Registers a new LESS function
81
+ *
82
+ * @param string $name
83
+ * @param Closure|function $callback
84
+ * @param array $scope CSS handles to limit callback registration to (if empty, applies to every stylesheet) – not used yet
85
+ * @see http://leafo.net/lessphp/docs/index.html#custom_functions
86
+ */
87
+ public function registerFunction($name, $callback, $scope = array())
88
+ {
89
+ $this->functions[$name] = array(
90
+ 'callback' => $callback,
91
+ 'scope' => $scope,
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Unregisters a LESS function
97
+ *
98
+ * @see http://leafo.net/lessphp/docs/index.html#custom_functions
99
+ */
100
+ public function unregisterFunction($name)
101
+ {
102
+ unset($this->functions[$name]);
103
+ }
104
  }
lib/Plugin.class.php CHANGED
@@ -22,17 +22,6 @@ class WPLessPlugin extends WPPluginToolkitPlugin
22
  */
23
  public static $match_pattern = '/\.less$/U';
24
 
25
- /**
26
- * Proxy method
27
- *
28
- * @see WPLessConfiguration::setVariables()
29
- * @since 1.4
30
- */
31
- public function addVariable($name, $value)
32
- {
33
- $this->getConfiguration()->addVariable($name, $value);
34
- }
35
-
36
  /**
37
  * Dispatches all events of the plugin
38
  *
@@ -118,7 +107,7 @@ class WPLessPlugin extends WPPluginToolkitPlugin
118
  *
119
  * @author oncletom
120
  * @since 1.1
121
- * @version 1.2
122
  * @param string $handle
123
  * @param $force boolean If set to true, rebuild all stylesheets, without considering they are updated or not
124
  * @return WPLessStylesheet
@@ -126,11 +115,13 @@ class WPLessPlugin extends WPPluginToolkitPlugin
126
  public function processStylesheet($handle, $force = false)
127
  {
128
  $wp_styles = $this->getStyles();
129
- $stylesheet = new WPLessStylesheet($wp_styles->registered[$handle]);
130
 
131
  if ((is_bool($force) && $force) || $stylesheet->hasToCompile())
132
  {
133
- $stylesheet->save($this->getConfiguration()->getVariables());
 
 
134
  }
135
 
136
  $wp_styles->registered[$handle]->src = $stylesheet->getTargetUri();
@@ -202,6 +193,17 @@ class WPLessPlugin extends WPPluginToolkitPlugin
202
  return $this->is_hooks_registered = true;
203
  }
204
 
 
 
 
 
 
 
 
 
 
 
 
205
  /**
206
  * Proxy method
207
  *
@@ -212,4 +214,26 @@ class WPLessPlugin extends WPPluginToolkitPlugin
212
  {
213
  $this->getConfiguration()->setVariables($variables);
214
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  }
22
  */
23
  public static $match_pattern = '/\.less$/U';
24
 
 
 
 
 
 
 
 
 
 
 
 
25
  /**
26
  * Dispatches all events of the plugin
27
  *
107
  *
108
  * @author oncletom
109
  * @since 1.1
110
+ * @version 1.3
111
  * @param string $handle
112
  * @param $force boolean If set to true, rebuild all stylesheets, without considering they are updated or not
113
  * @return WPLessStylesheet
115
  public function processStylesheet($handle, $force = false)
116
  {
117
  $wp_styles = $this->getStyles();
118
+ $stylesheet = new WPLessStylesheet($wp_styles->registered[$handle], $this->getConfiguration()->getVariables());
119
 
120
  if ((is_bool($force) && $force) || $stylesheet->hasToCompile())
121
  {
122
+ $compiler = new WPLessCompiler($stylesheet->getSourcePath());
123
+ $compiler->registerFunctions($this->getConfiguration()->getFunctions());
124
+ $compiler->saveStylesheet($stylesheet);
125
  }
126
 
127
  $wp_styles->registered[$handle]->src = $stylesheet->getTargetUri();
193
  return $this->is_hooks_registered = true;
194
  }
195
 
196
+ /**
197
+ * Proxy method
198
+ *
199
+ * @see WPLessConfiguration::setVariables()
200
+ * @since 1.4
201
+ */
202
+ public function addVariable($name, $value)
203
+ {
204
+ $this->getConfiguration()->addVariable($name, $value);
205
+ }
206
+
207
  /**
208
  * Proxy method
209
  *
214
  {
215
  $this->getConfiguration()->setVariables($variables);
216
  }
217
+
218
+ /**
219
+ * Proxy method
220
+ *
221
+ * @see WPLessConfiguration::registerFunction()
222
+ * @since 1.4.2
223
+ */
224
+ public function registerFunction($name, $callback, $scope = array())
225
+ {
226
+ $this->getConfiguration()->registerFunction($name, $callback, $scope);
227
+ }
228
+
229
+ /**
230
+ * Proxy method
231
+ *
232
+ * @see WPLessConfiguration::unregisterFunction()
233
+ * @since 1.4.2
234
+ */
235
+ public function unregisterFunction($name)
236
+ {
237
+ $this->getConfiguration()->unregisterFunction($name);
238
+ }
239
  }
lib/Stylesheet.class.php CHANGED
@@ -11,13 +11,15 @@ require dirname(__FILE__).'/vendor/lessphp/lessc.inc.php';
11
  class WPLessStylesheet
12
  {
13
  protected $compiler,
14
- $stylesheet;
 
15
 
16
  protected $is_new = true,
 
17
  $source_path,
 
18
  $source_uri,
19
  $target_path,
20
- $target_timestamp,
21
  $target_uri;
22
 
23
  public static $upload_dir,
@@ -28,21 +30,29 @@ class WPLessStylesheet
28
  *
29
  * @author oncletom
30
  * @since 1.0
31
- * @version 1.0
32
  * @throws WPLessException if something is not properly configured
33
  * @param _WP_Dependency $stylesheet
 
34
  */
35
- public function __construct(_WP_Dependency $stylesheet)
36
  {
37
  $this->stylesheet = $stylesheet;
 
38
 
39
  if (!self::$upload_dir || !self::$upload_uri)
40
  {
41
  throw new WPLessException('You must configure `upload_dir` and `upload_uri` static attributes before constructing this object.');
42
  }
43
 
 
44
  $this->configurePath();
45
- $this->configureVersion();
 
 
 
 
 
46
 
47
  do_action('wp-less_stylesheet_construct', $this);
48
  }
@@ -60,7 +70,7 @@ class WPLessStylesheet
60
  $target_path = preg_replace('#^'.get_theme_root_uri().'#U', '', $this->stylesheet->src);
61
  $target_path = preg_replace('/.less$/U', '', $target_path);
62
 
63
- $target_path .= '.css';
64
 
65
  return apply_filters('wp-less_stylesheet_compute_target_path', $target_path);
66
  }
@@ -72,7 +82,7 @@ class WPLessStylesheet
72
  * @protected
73
  * @author oncletom
74
  * @since 1.0
75
- * @version 1.0
76
  */
77
  protected function configurePath()
78
  {
@@ -82,38 +92,23 @@ class WPLessStylesheet
82
  $this->source_uri = $this->stylesheet->src;
83
  $this->target_path = self::$upload_dir.$target_file;
84
  $this->target_uri = self::$upload_uri.$target_file;
 
 
85
  }
86
 
87
  /**
88
- * Configures version and timestamp
89
- *
90
- * It can be run only after paths have been configured. Otherwise (or if the calculation went wrong),
91
- * an exception will be thrown.
92
- *
93
  * @author oncletom
94
- * @since 1.2
95
  * @version 1.0
96
- * @throws WPLessException
97
  */
98
- public function configureVersion()
99
  {
100
- if (!$this->getTargetPath())
101
- {
102
- throw new WPLessException("Can't configure any version if there is no target path.");
103
- }
104
-
105
- if (file_exists($this->getTargetPath()))
106
- {
107
- $this->is_new = false;
108
- $this->target_timestamp = filemtime($this->getTargetPath());
109
- }
110
- else
111
- {
112
- $this->is_new = true;
113
- $this->target_timestamp = time();
114
- }
115
-
116
- $this->stylesheet->ver = $this->target_timestamp;
117
  }
118
 
119
  /**
@@ -165,7 +160,7 @@ class WPLessStylesheet
165
  */
166
  public function getTargetPath()
167
  {
168
- return $this->target_path;
169
  }
170
 
171
  /**
@@ -178,9 +173,21 @@ class WPLessStylesheet
178
  * @param string $version_prefix
179
  * @return string
180
  */
181
- public function getTargetUri($append_version = false, $version_prefix = '?ver=')
 
 
 
 
 
 
 
 
 
 
 
 
182
  {
183
- return $this->target_uri.(!!$append_version ? $version_prefix.$this->target_timestamp : '');
184
  }
185
 
186
  /**
@@ -188,40 +195,22 @@ class WPLessStylesheet
188
  *
189
  * @author oncletom
190
  * @since 1.0
191
- * @version 1.0
192
  * @return boolean
193
  */
194
  public function hasToCompile()
195
  {
196
- return $this->is_new || filemtime($this->getSourcePath()) > $this->target_timestamp;
197
  }
198
 
199
  /**
200
  * Save the current stylesheet as a parsed css file
201
  *
202
- * @author oncletom
203
- * @since 1.0
204
- * @version 1.3
205
- * @throws Exception in case of parsing went bad
206
  */
207
- public function save(array $variables = array())
208
  {
209
- wp_mkdir_p(dirname($this->getTargetPath()));
210
-
211
- try
212
- {
213
- do_action('wp-less_stylesheet_save_pre', $this, $variables);
214
- $compiler = new WPLessCompiler($this->getSourcePath());
215
-
216
- file_put_contents($this->getTargetPath(), apply_filters('wp-less_stylesheet_save', $compiler->parse(null, $variables), $this));
217
- chmod($this->getTargetPath(), 0666);
218
-
219
- $this->is_new = false;
220
- do_action('wp-less_stylesheet_save_post', $this);
221
- }
222
- catch(Exception $e)
223
- {
224
- wp_die($e->getMessage());
225
- }
226
  }
227
  }
11
  class WPLessStylesheet
12
  {
13
  protected $compiler,
14
+ $stylesheet,
15
+ $variables = array();
16
 
17
  protected $is_new = true,
18
+ $signature,
19
  $source_path,
20
+ $source_timestamp,
21
  $source_uri,
22
  $target_path,
 
23
  $target_uri;
24
 
25
  public static $upload_dir,
30
  *
31
  * @author oncletom
32
  * @since 1.0
33
+ * @version 1.1
34
  * @throws WPLessException if something is not properly configured
35
  * @param _WP_Dependency $stylesheet
36
+ * @param array $variables
37
  */
38
+ public function __construct(_WP_Dependency $stylesheet, array $variables = array())
39
  {
40
  $this->stylesheet = $stylesheet;
41
+ $this->variables = $variables;
42
 
43
  if (!self::$upload_dir || !self::$upload_uri)
44
  {
45
  throw new WPLessException('You must configure `upload_dir` and `upload_uri` static attributes before constructing this object.');
46
  }
47
 
48
+ $this->stylesheet->ver = null;
49
  $this->configurePath();
50
+ $this->configureSignature();
51
+
52
+ if (file_exists($this->getTargetPath()))
53
+ {
54
+ $this->is_new = false;
55
+ }
56
 
57
  do_action('wp-less_stylesheet_construct', $this);
58
  }
70
  $target_path = preg_replace('#^'.get_theme_root_uri().'#U', '', $this->stylesheet->src);
71
  $target_path = preg_replace('/.less$/U', '', $target_path);
72
 
73
+ $target_path .= '-%s.css';
74
 
75
  return apply_filters('wp-less_stylesheet_compute_target_path', $target_path);
76
  }
82
  * @protected
83
  * @author oncletom
84
  * @since 1.0
85
+ * @version 1.1
86
  */
87
  protected function configurePath()
88
  {
92
  $this->source_uri = $this->stylesheet->src;
93
  $this->target_path = self::$upload_dir.$target_file;
94
  $this->target_uri = self::$upload_uri.$target_file;
95
+
96
+ $this->source_timestamp = filemtime($this->source_path);
97
  }
98
 
99
  /**
100
+ * Configures the file signature
101
+ *
102
+ * It corresponds to a unique hash taking care of file timestamp and variables.
103
+ * It should be called each time stylesheet variables are updated.
104
+ *
105
  * @author oncletom
106
+ * @since 1.4.2
107
  * @version 1.0
 
108
  */
109
+ protected function configureSignature()
110
  {
111
+ $this->signature = substr(sha1(serialize($this->variables) . $this->source_timestamp), 0, 10);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
 
114
  /**
160
  */
161
  public function getTargetPath()
162
  {
163
+ return sprintf($this->target_path, $this->signature);
164
  }
165
 
166
  /**
173
  * @param string $version_prefix
174
  * @return string
175
  */
176
+ public function getTargetUri()
177
+ {
178
+ return sprintf($this->target_uri, $this->signature);
179
+ }
180
+
181
+ /**
182
+ * Returns stylesheet variables
183
+ *
184
+ * @author oncletom
185
+ * @since 1.4.2
186
+ * @return array
187
+ */
188
+ public function getVariables()
189
  {
190
+ return $this->variables;
191
  }
192
 
193
  /**
195
  *
196
  * @author oncletom
197
  * @since 1.0
198
+ * @version 1.2
199
  * @return boolean
200
  */
201
  public function hasToCompile()
202
  {
203
+ return ($this->is_new || (defined('WP_DEBUG') && WP_DEBUG));
204
  }
205
 
206
  /**
207
  * Save the current stylesheet as a parsed css file
208
  *
209
+ * @deprecated
210
+ * @see WPLessCompiler::saveStylesheet()
 
 
211
  */
212
+ public function save()
213
  {
214
+ $this->is_new = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  }
216
  }
lib/helper/ThemeHelper.php CHANGED
@@ -14,6 +14,21 @@ function less_add_variable($name, $value)
14
  WPPluginToolkitPlugin::getInstance('WPLess')->addVariable($name, $value);
15
  }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  /**
18
  * LESSify a stylesheet on the fly
19
  *
@@ -55,7 +70,7 @@ function wp_lessify($stylesheet_uri, $cache_key = null, $version_prefix = '?ver=
55
  wp_register_style($cache_key, $stylesheet_uri);
56
  $stylesheet = WPLessPlugin::getInstance()->processStylesheet($cache_key);
57
  wp_deregister_style($cache_key);
58
- $wp_less_uri_cache[$cache_key] = $stylesheet->getTargetUri(true, $version_prefix);
59
 
60
  unset($stylesheet);
61
  return $wp_less_uri_cache[$cache_key];
14
  WPPluginToolkitPlugin::getInstance('WPLess')->addVariable($name, $value);
15
  }
16
 
17
+ /**
18
+ * Creates easily a LESS function to be replaced on compilation
19
+ *
20
+ * @author oncletom
21
+ * @since 1.4.2
22
+ * @version 1.0
23
+ * @param string $name
24
+ * @param string $callback
25
+ * @return null
26
+ */
27
+ function less_register_function($name, $callback)
28
+ {
29
+ WPPluginToolkitPlugin::getInstance('WPLess')->registerFunction($name, $callback);
30
+ }
31
+
32
  /**
33
  * LESSify a stylesheet on the fly
34
  *
70
  wp_register_style($cache_key, $stylesheet_uri);
71
  $stylesheet = WPLessPlugin::getInstance()->processStylesheet($cache_key);
72
  wp_deregister_style($cache_key);
73
+ $wp_less_uri_cache[$cache_key] = $stylesheet->getTargetUri();
74
 
75
  unset($stylesheet);
76
  return $wp_less_uri_cache[$cache_key];
lib/vendor/lessphp/README.md CHANGED
@@ -1,10 +1,12 @@
1
- # lessphp v0.3.0
2
- #### <http://leafo.net/lessphp>
3
 
4
  `lessphp` is a compiler for LESS written in PHP. The documentation is great,
5
- so check it out: <http://leafo.net/lessphp/docs/>. Here's a quick tutorial:
6
 
7
- ### How to use in your php project
 
 
8
 
9
  Copy `lessc.inc.php` to your include directory and include it into your project.
10
 
@@ -15,10 +17,13 @@ is newer than the output file.
15
 
16
  try {
17
  lessc::ccompile('input.less', 'output.css');
18
- catch (exception $ex) {
19
  exit($ex->getMessage());
20
  }
21
 
 
 
 
22
  Note that all failures with lessc are reported through exceptions.
23
  If you need more control you can make your own instance of lessc.
24
 
@@ -42,17 +47,17 @@ An additional script has been included to use the compiler from the command
42
  line. In the simplest invocation, you specify an input file and the compiled
43
  css is written to standard out:
44
 
45
- ~> plessc input.less > output.css
46
 
47
  Using the -r flag, you can specify LESS code directly as an argument or, if
48
  the argument is left off, from standard in:
49
 
50
- ~> plessc -r "my less code here"
51
 
52
  Finally, by using the -w flag you can watch a specified input file and have it
53
  compile as needed to the output file
54
 
55
- ~> plessc -w input-file output-file
56
 
57
  Errors from watch mode are written to standard out.
58
 
1
+ # lessphp v0.3.1
2
+ ### <http://leafo.net/lessphp>
3
 
4
  `lessphp` is a compiler for LESS written in PHP. The documentation is great,
5
+ so check it out: <http://leafo.net/lessphp/docs/>.
6
 
7
+ Here's a quick tutorial:
8
+
9
+ ### How to use in your PHP project
10
 
11
  Copy `lessc.inc.php` to your include directory and include it into your project.
12
 
17
 
18
  try {
19
  lessc::ccompile('input.less', 'output.css');
20
+ } catch (exception $ex) {
21
  exit($ex->getMessage());
22
  }
23
 
24
+ `lessc::ccompile` is not aware of imported files that change. Read [about
25
+ `lessc::cexecute`](http://leafo.net/lessphp/docs/#compiling_automatically).
26
+
27
  Note that all failures with lessc are reported through exceptions.
28
  If you need more control you can make your own instance of lessc.
29
 
47
  line. In the simplest invocation, you specify an input file and the compiled
48
  css is written to standard out:
49
 
50
+ $ plessc input.less > output.css
51
 
52
  Using the -r flag, you can specify LESS code directly as an argument or, if
53
  the argument is left off, from standard in:
54
 
55
+ $ plessc -r "my less code here"
56
 
57
  Finally, by using the -w flag you can watch a specified input file and have it
58
  compile as needed to the output file
59
 
60
+ $ plessc -w input-file output-file
61
 
62
  Errors from watch mode are written to standard out.
63
 
lib/vendor/lessphp/docs/docs.html DELETED
@@ -1,347 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
-
4
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
- <head>
6
- <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
7
- <link rel="stylesheet" type="text/css" href="style.css" media="screen" />
8
- <link rel="alternate" type="application/rss+xml" title="lessphp changelog feed" href="http://leafo.net/lessphp/feed/" />
9
- <title>Documentation - lessphp</title>
10
- </head>
11
- <body>
12
-
13
- <h1>Documentation - lessphp v0.2.0</h1>
14
- <div class="content">
15
-
16
- <ul id="nav">
17
- <li><a href="#start">Getting Started</a></li>
18
- <li><a href="#language">The Language</a>
19
- <ul><li><a href="#vars">Abstract Properties (Variables)</a></li></ul>
20
- <ul><li><a href="#pvalues">Property Values &amp; Expressions</a></li></ul>
21
- <ul><li><a href="#nested">Nested Blocks</a></li></ul>
22
- <ul><li><a href="#mixins">Mixins &amp; Namespace Access</a></li></ul>
23
- <ul><li><a href="#ablocks">Abstract Blocks</a></li></ul>
24
- <ul><li><a href="#args">Mixin Arguments</a></li></ul>
25
- <ul><li><a href="#import">Import Statement</a></li></ul>
26
- <ul><li><a href="#strings">String Mixins</a></li></ul>
27
- <ul><li><a href="#misc">Miscellaneous</a></li></ul>
28
- <ul><li><a href="#differences">Differences from Ruby LESS</a></li></ul>
29
- </li>
30
- <li><a href="#interface">The Interface</a></li>
31
- </ul>
32
-
33
- <p><strong>lessphp</strong> is a compiler that generates css from a small superset language that adds
34
- many additional features seen in other languages. It is based off an original Ruby implementation
35
- called <a href="http://lesscss.org/">LESS</a>. For the most part, <strong>lessphp</strong> is syntactically
36
- compatible with LESS, with the exception of a few things noted below.</p>
37
-
38
- <a name="start"></a>
39
- <h2>Getting Started</h2>
40
- <p>Download the latest version of <strong>lessphp</strong> <a href="http://leafo.net/lessphp/">here</a>.</p>
41
- <p>You can also find the latest development version in the <a href="http://github.com/leafo/lessphp">git repository</a>.</p>
42
-
43
- </div>
44
-
45
- <a name="language"></a>
46
- <h1>The Language</h1>
47
- <div class="content">
48
- <br />
49
- <p><strong>lessphp</strong> is a data description language built on top of CSS. The two major components of the language are
50
- blocks and property-value pairs. A block is a scope for a collection of property-value pairs.</p>
51
-
52
- <p>Blocks and properties have special characteristics depending on how they are named.</p>
53
-
54
- <p>It is important to realize that a block's state does not change over time. When a block is defined, all of its properties are constant. The best way to demonstrate this is to look at the following LESS snippet:</p>
55
-
56
- <pre class="code">
57
- body {
58
- color: @val;
59
- @val: blue;
60
- }</pre>
61
-
62
- <p>Because the state of the block is not changing over time, but constant after its creation,
63
- the color property is printed with the value <code>blue</code>.
64
-
65
- <a name="vars"></a>
66
- <h2>Abstract Properties (Variables)</h2>
67
- <p>Abstract properties are defined with a name starting with <code>@</code>. These types of properties are special in two ways: first, they are not included in the output of the compiler. Second, they can be easily accessed in the values of other properties just by writing their name. If a property is referenced but can not be found, a blank string is returned.</p>
68
- <p>As a LESS programmer, it means that you can define a collection of hidden values that can be referenced in other locations.</p>
69
-
70
- <pre class="code">
71
- @mycolor: #fff;
72
- body {
73
- color: @mycolor;
74
- }
75
- pre {
76
- color: @mycolor;
77
- }</pre>
78
-
79
- <p>Also take note that you can define abstract properties in the global scope.</p>
80
-
81
- <a name="pvalues"></a>
82
- <h2>Property Values & Expressions</h2>
83
- <p>All properties have at least one value. The value is a list of expressions separated by spaces or commas.
84
- An expression is any CSS value with optional mathematical operators applied to it. The operators only function
85
- with number and color value types.<p>
86
-
87
- <p>Operations on units will keep the unit of the rightmost value,
88
- unless it is unit-less, then the leftmost unit will be kept for the result. See the following examples below.<p>
89
-
90
- <pre class="code">body {
91
- color: #001 + #abc; // evaulates to #aabbdd:
92
- width: 3430px + 22; // evaluates to 3452px;
93
- margin: (1.5em / 2) + 2px; // evaluates to 2.85px;
94
- margin: 20 + 2px; // evaluates to 22px;
95
- font-family: "Some " + "Family"; // evaluates to "Some Family"
96
- }</pre>
97
-
98
- <p>It is important to notice that in the example above the output will print the margin property twice.
99
- A single property name can hold more than one value; older values are not overwritten.</p>
100
-
101
- <a name="nested"></a>
102
- <h2>Nested Blocks</h2>
103
- <p>Blocks can be nested inside of each other in order to achieve the same effect as listing out the
104
- path of identifiers in CSS. This can help to increase organization of your LESS code and reduce
105
- the amount of repeated tag names you have to type.</p>
106
-
107
- <pre class="code">body {
108
- a {
109
- color: green;
110
- :hover {
111
- color: blue;
112
- }
113
- }
114
- }</pre>
115
-
116
-
117
- <a name="mixins"></a>
118
- <h2>Mixins & Namespace Access</h2>
119
-
120
- <p>Any block can be "mixed" into the current block. This means that all properties and blocks
121
- in the target block are brought into the current block. It is possible to achieve the same effect
122
- with just CSS and HTML, but there are some additional features discussed below that make it worthwhile
123
- to utilize LESS-style mixing.</p>
124
- <p>The syntax is as follows:<p>
125
-
126
- <pre class="code">
127
- .myclass {
128
- @fonts: Helvetica, Arial;
129
- margin: 1.0em;
130
- line-spacing: 150%;
131
-
132
- a {
133
- background-color: black;
134
- }
135
- }
136
-
137
- pre {
138
- .myclass;
139
- font-family: @fonts; // uses the mixed in variable
140
- }
141
-
142
- div.notice {
143
- .myclass;
144
- }</pre>
145
-
146
- <p>If you want to mix in a specific block within another block you can use the <code>&gt;</code> namespace operator.
147
- Additionally you can pull out specific values of properties from blocks using the <code>[ ]</code> operator.
148
-
149
- <pre class="code">// using .myclass from above
150
- li {
151
- .myclass &gt; a; // just mix in properties from 'a' tag in .myclass
152
- fonts: .myclass[@fonts];
153
- padding: .myclass['margin'];
154
- }</pre>
155
-
156
-
157
- <a name="ablocks"></a>
158
- <h2>Abstract Blocks</h2>
159
-
160
- <p>Abstract blocks are like any other blocks, but their names start with a <code>@</code>. Like abstract properties, they are not
161
- included in the compiler's output. This allows you to utilize mixins without adding any unused blocks to the output.
162
- You can also use an abstract class to define a package of invisible, but extractable blocks and properties.<p>
163
-
164
- <pre class="code">@mypackage {
165
- .coolColors {
166
- color: pink;
167
- background-color: green;
168
- }
169
-
170
- .hotColors {
171
- color: red;
172
- background-color: orange;
173
- }
174
- }
175
-
176
- p {
177
- @mypackage &gt; .coolColors;
178
- }
179
-
180
- div {
181
- @mypackage; // inserts both classes into this block
182
- }</pre>
183
-
184
- <p>It is possible to give an abstract block the same name as an abstract property; their names will not collide.
185
- Block names and property names exist in different spaces. For example:</p>
186
-
187
- <pre class="code">@color(@color:red) { color: @color; } // this is valid
188
- </pre>
189
-
190
- <a name="args"></a>
191
- <h2>Mixin Arguments</h2>
192
- <p>All blocks have the option of taking argument lists, and the arguments can have default values.</p>
193
-
194
- <pre class="code">@some_mixin(@width: 200px;@radius) {
195
- border-radius: @radius;
196
- width: @width
197
- }
198
-
199
- .first {
200
- @some_mixin(300px; 2em);
201
- }
202
-
203
- .second {
204
- @some_mixin(;4px); // blank argument takes default value
205
- }</pre>
206
-
207
- <a name="import"></a>
208
- <h2>Import Statement</h2>
209
- <p>If you have multiple LESS files, you can combine them into a single CSS file during compilation using the
210
- <code>@import</code> directive. LESS import uses the same syntax as CSS import. If it can find the file specified
211
- then it will pull it into the compiler in place of the statement. If the file can't be found, the statement is
212
- printed to the output. The following are all valid:</p>
213
-
214
- <pre class="code">@import "file";
215
- @import 'file.less';
216
- @import url("file");
217
- @import url('file');
218
- @import url(file); </pre>
219
-
220
- <p>Note that if it fails to find a file it will append <code>.less</code> to the filename and try again.
221
- This means <code>@import 'somefile'</code> and <code>@import 'somefile.less'</code> will
222
- both import the file <code>somefile.less</code>.
223
-
224
-
225
- <a name="strings"></a>
226
- <h2>String Mixins</h2>
227
- <p>It is possible to access the value of an abstract property from a string using <code>{ }</code> operators.</p>
228
-
229
- <pre class="code">@image_folder: darktheme;
230
- .header {
231
- background-image: url(/images/{@image_folder}/header.png);
232
- }</pre>
233
-
234
- <p>The <code>{ }</code> syntax will also work in any string value type, which is any text
235
- wrapped in single or double quotes</p>
236
-
237
-
238
- <a name="misc"></a>
239
- <h2>Miscellaneous</h2>
240
- <p>As mentioned before, all properties hold constant data. This includes abstract values. While it may be convenient to
241
- think of them as variables, they don't have the ability to vary. For convenience, some tricks were implemented to
242
- make self referencing properties evaluate in order as if they had changing state. Consider the following statement:</p>
243
-
244
- <pre class="code">
245
- @what: 1;
246
- body {
247
- @what: @what + 1;
248
- @what: @what + 2;
249
- .class {
250
- @what: @what + 1;
251
- width: @what;
252
- }
253
- }
254
-
255
- #something {
256
- @what: 200;
257
- body > .class;
258
- }</pre>
259
-
260
- <p>In the output, <code>body .class</code> has width set to 5, and <code>#something</code> has width set to 201. It appears from that result that
261
- the property <code>@what</code> is being incremented. But, as mentioned above, the name <code>@what</code> stores a series of unchanging values.
262
- The values use delayed evaluation, so each value holds an equation.</p>
263
-
264
- <p>What this means is that the values of the properties don't change while the block is parsed, only additional property-value pairs are added
265
- to the block's definition.
266
- When the block's is compiled into CSS, the equations and property references are solved using the data in the scope. Technically, it is
267
- ambiguous what value to use for referencing a variable, because the single name can store multiple values.<p>
268
-
269
- <p>The approach taken in <strong>lessphp</strong> is to use the most recent value. This gives the appearance that the block is parsed line by line.
270
- In order to prevent infinite loops when a variable references itself, a single value in the set of all values for a given name can only be used once in
271
- the chain of dereferencing.</p>
272
-
273
-
274
- <a name="differences"></a>
275
- <h2>Differences from Ruby LESS</h2>
276
- <p class="important">Report missing ones <a href="http://github.com/leafo/lessphp/issues">here</a>.</p>
277
- <ul>
278
- <li>Arguments to mixins are separated by <code>;</code> instead of <code>,</code>.
279
- <p><b>Rationale</b>: the value of a css property can contain commas, so by using a comma as an argument separator you limit the kinds of input you can pass to a mixin.</p>
280
- </li>
281
- </ul>
282
-
283
- </div>
284
-
285
- <a name="interface"></a>
286
- <h1>The PHP Interface</h1><br />
287
- <div class="content">
288
- <p>There are a few ways to interface with the compiler. The easiest is to have it
289
- compile a LESS file when the page is requested. The static function
290
- <code>less::ccompile</code>, checked compile, will compile the inputed LESS file only when it
291
- is newer than the output file.<p>
292
-
293
- <pre class="code">
294
- <span class="PreProc">require</span> '<span class="String">lessc.inc.php</span>';
295
-
296
- <span class="Statement">try</span> <span class="Delimiter">{</span>
297
- lessc<span class="Operator">::</span>ccompile<span class="Delimiter">(</span>'<span class="String">input.less</span>', '<span class="String">out.css</span>'<span class="Delimiter">)</span>;
298
- <span class="Delimiter">}</span> <span class="Statement">catch</span> <span class="Delimiter">(</span><span class="Function">exception</span> <span class="Operator">$</span><span class="Identifier">ex</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
299
- <span class="Statement">exit</span><span class="Delimiter">(</span>'<span class="String">lessc fatal error:&lt;br /&gt;</span>'<span class="Operator">.</span><span class="Operator">$</span><span class="Identifier">ex</span><span class="Type">-&gt;</span>getMessage<span class="Delimiter">())</span>;
300
- <span class="Delimiter">}</span>
301
- </pre>
302
-
303
- <br />
304
- <p>Note that all failures with lessc are reported through exceptions.
305
- If you need more control then you can make your own instance of <code>lessc</code>.</p>
306
- <pre class="code">
307
- <span class="PreProc">require</span> '<span class="String">lessc.inc.php</span>';
308
-
309
- <span class="Operator">$</span><span class="Identifier">less</span> <span class="Operator">=</span> <span class="PreProc">new</span> lessc<span class="Delimiter">(</span>'<span class="String">path/to/style.less</span>'<span class="Delimiter">)</span>;
310
- <span class="Function">file_put_contents</span><span class="Delimiter">(</span>'<span class="String">path/to/style.css</span>', <span class="Operator">$</span><span class="Identifier">less</span><span class="Type">-&gt;</span>parse<span class="Delimiter">())</span>;
311
- </pre>
312
-
313
- <br />
314
- <p>In addition to loading from a file, you can also parse from a string like so:</p>
315
- <pre class="code">
316
- <span class="PreProc">require</span> '<span class="String">lessc.inc.php</span>';
317
-
318
- <span class="Operator">$</span><span class="Identifier">less</span> <span class="Operator">=</span> <span class="PreProc">new</span> lessc<span class="Delimiter">()</span>;
319
- <span class="Operator">$</span><span class="Identifier">style</span> <span class="Operator">=</span> '<span class="String">&lt;style type=&quot;text/css&quot;&gt;</span>'<span class="Operator">.</span>
320
- <span class="Operator">$</span><span class="Identifier">less</span><span class="Type">-&gt;</span>parse<span class="Delimiter">(</span>'<span class="String">.block { padding: 3 + 4px }</span>'<span class="Delimiter">)</span><span class="Operator">.</span>
321
- '<span class="String">&lt;/style&gt;</span>';
322
- </pre>
323
-
324
-
325
- <h2>Import Directoy</h2>
326
- <p>When using the <code>@import</code> directive, the compiler searches for files
327
- in the <code>$importDir</code> public property of <code>lessc</code>. If the compiler is loaded with a filename
328
- (either in the constructor or using <code>ccompile</code>) it will extract the directory and set that as the
329
- import directory</p>
330
-
331
-
332
- <h2>Library Functions</h2>
333
- <p>Functions within the compiler class that are prefixed with <code>lib_</code> are visible visible to the less
334
- code while it is being parsed. The easiest way to add your own functions is to subclass <code>lessc</code> and insert
335
- the implementations.</p>
336
-
337
- <br />
338
- <br />
339
- <hr />
340
- <p class="foot">
341
- <a href="http://leafo.net/lessphp/">http://leafo.net/lessphp</a> - Last updated March 9th 2010</p>
342
-
343
- </div>
344
-
345
- </body>
346
- </html>
347
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/vendor/lessphp/docs/docs.md CHANGED
@@ -1,4 +1,5 @@
1
- title: v0.3.0 documentation
 
2
  --
3
 
4
  <h2 skip="true">Documentation v0.3.0</h2>
@@ -320,6 +321,41 @@ you want to include. Optionally you can separate them by `>`.
320
  }
321
  ```
322
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  ### Import
324
 
325
  Multiple LESS files can be compiled into a single CSS file by using the
@@ -456,16 +492,33 @@ function that let's you unquote any value. It is called `e`.
456
  * `floor(number)` -- returns the floor of a numerical input
457
  * `round(number)` -- returns the rounded value of numerical input
458
 
459
- * `lighten(color, percent)` -- lightens color by percent and returns it
460
- * `darken(color, percent)` -- darkens color by percent and returns it
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
 
462
- * `saturate(color, percent)` -- saturates color by percent and returns it
463
- * `desaturate(color, percent)` -- desaturates color by percent and returns it
464
 
465
- * `fadein(color, percent)` -- makes color less transparent by percent and returns it
466
- * `fadeout(color, percent)` -- makes color more transparent by percent and returns it
467
 
468
- * `spin(color, amount)` -- returns a color with amount degrees added to hue
 
 
 
 
 
469
 
470
  * `rgbahex(color)` -- returns a string containing 4 part hex color.
471
 
@@ -506,14 +559,91 @@ To compile a string to a string:
506
  $css = $less->parse("body { a { color: red } }");
507
  ```
508
 
 
 
509
  Often, you want to write the compiled CSS to a file, and only recompile when
510
- the original LESS file has changed. The following function will check the
511
- modification date of the LESS file to see if a compile is required:
 
 
512
 
513
  ```php
514
  lessc::ccompile('myfile.less', 'mystyle.css');
515
  ```
516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  All of the following methods will throw an `Exception` if the parsing fails:
518
 
519
  ```php
@@ -524,8 +654,7 @@ All of the following methods will throw an `Exception` if the parsing fails:
524
  echo "lessphp fatal error: ".$ex->getMessage();
525
  }
526
  ```
527
-
528
- ### Setting Variables From PHP
529
 
530
  The `parse` function takes a second optional argument. If you want to
531
  initialize variables from outside the LESS file then you can pass in an
@@ -555,43 +684,58 @@ instead of the file:
555
  functions that will be exposed in LESS code during the compile. They can be a
556
  little tricky though because you need to work with the **lessphp** type system.
557
 
558
- By sub-classing `lessc`, and creating specially named methods we can extend
559
- **lessphp**. In order for a function to be visible in LESS, its name must
560
- start with `lib_`.
 
561
 
562
- Let's make a function that doubles any numeric argument.
 
563
 
564
  ```php
565
  <?php
566
  include "lessc.inc.php";
567
 
568
- class myless extends lessc {
569
- function lib_double($arg) {
570
- list($type, $value) = $arg;
571
- return array($type, $value*2);
572
- }
573
  }
574
 
575
  $myless = new myless();
 
 
 
576
  echo $myless->parse("div { width: double(400px); }");
577
  ```
578
 
579
- Although a little verbose, the implementation of `lib_double` gives us some
580
- insight on the type system. All values are stored in an array where the 0th
581
- element is a string representing the type, and the other elements make up the
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  associated data for that value.
583
 
584
- The best way to get an understanding of the system is to make a dummy `lib_`
585
  function which does a `vardump` on the argument. Try passing the function
586
  different values from LESS and see what the results are.
587
 
588
- The return value of the `lib_` function must also be a LESS type, but if it is
589
  a string or numeric value, it will automatically be coerced into an appropriate
590
  typed value. In our example, we reconstruct the value with our modifications
591
- while making sure that we preserve the type.
592
-
593
- All of the built in functions are implemented in this manner within the `lessc`
594
- class.
595
 
596
  ## Command Line Interface
597
 
1
+ title: v0.3.1 documentation
2
+ link_to_home: true
3
  --
4
 
5
  <h2 skip="true">Documentation v0.3.0</h2>
321
  }
322
  ```
323
 
324
+ #### `@arguments` Variable
325
+
326
+ Within an mixin there is a special variable named `@arguments` that contains
327
+ all the arguments passed to the mixin along with any remaining arguments that
328
+ have default values. The value of the variable has all the values separated by
329
+ spaces.
330
+
331
+ This useful for quickly assigning all the arguments:
332
+
333
+ ```less
334
+ .box-shadow(@inset, @x, @y, @blur, @spread, @color) {
335
+ box-shadow: @arguments;
336
+ -webkit-box-shadow: @arguments;
337
+ -moz-box-shadow: @arguments;
338
+ }
339
+ .menu {
340
+ .box-shadow(1px, 1px, 5px, #aaa);
341
+ }
342
+ ```
343
+
344
+ In addition to the arguments passed to the mixin, `@arguments` will also inlude
345
+ remaining default values assigned by the mixin:
346
+
347
+
348
+ ```less
349
+ .border-mixin(@width, @style: solid, @color: black) {
350
+ border: @arguments;
351
+ }
352
+
353
+ pre {
354
+ .border-mixin(4px, dotted);
355
+ }
356
+
357
+ ```
358
+
359
  ### Import
360
 
361
  Multiple LESS files can be compiled into a single CSS file by using the
492
  * `floor(number)` -- returns the floor of a numerical input
493
  * `round(number)` -- returns the rounded value of numerical input
494
 
495
+ * `lighten(color, percent)` -- lightens `color` by `percent` and returns it
496
+ * `darken(color, percent)` -- darkens `color` by `percent` and returns it
497
+
498
+ * `saturate(color, percent)` -- saturates `color` by `percent` and returns it
499
+ * `desaturate(color, percent)` -- desaturates `color` by `percent` and returns it
500
+
501
+ * `fadein(color, percent)` -- makes `color` less transparent by `percent` and returns it
502
+ * `fadeout(color, percent)` -- makes `color` more transparent by `percent` and returns it
503
+
504
+ * `spin(color, amount)` -- returns a color with `amount` degrees added to hue
505
+
506
+ * `fade(color, amount)` -- retuns a color with the alpha set to `amount`
507
+
508
+ * `hue(color)` -- retuns the hue of `color`
509
+
510
+ * `saturation(color)` -- retuns the saturation of `color`
511
 
512
+ * `lightness(color)` -- retuns the lightness of `color`
 
513
 
514
+ * `alpha(color)` -- retuns the alpha value of `color` or 1.0 if it doesn't have an alpha
 
515
 
516
+ * `percentage(number)` -- converts a floating point number to a percentage, eg. `0.65` -> `65%`
517
+
518
+ * `mix(color1, color1, percent)` -- mixes two colors by percentagle where 100%
519
+ keeps all of `color1`, and 0% keeps all of `color2`. Will take into account
520
+ the alpha of the colors if it exists. See
521
+ <http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method>.
522
 
523
  * `rgbahex(color)` -- returns a string containing 4 part hex color.
524
 
559
  $css = $less->parse("body { a { color: red } }");
560
  ```
561
 
562
+ ### Compiling Automatically
563
+
564
  Often, you want to write the compiled CSS to a file, and only recompile when
565
+ the original LESS file has changed. The following function will check if the
566
+ modification date of the LESS file is more recent than the CSS file. The LESS
567
+ file will be compiled if it is. If the CSS file doesn't exist yet, then it will
568
+ also compile the LESS file.
569
 
570
  ```php
571
  lessc::ccompile('myfile.less', 'mystyle.css');
572
  ```
573
 
574
+ `ccompile` is very basic, it only checks if the input file's modification time.
575
+ It is not of any files that are brought in using `@import`.
576
+
577
+ For this reason we also have `lessc::cexecute`. It functions slightly
578
+ differently, but gives us the ability to check changes to all files used during
579
+ the compile. It takes one argument, either the name of the file we want to
580
+ compile, or an existing *cache object*. Its return value is an updated cache
581
+ object.
582
+
583
+ If we don't have a cache object, then we call the function with the name of the
584
+ file to get the initial cache object. If we do have a cache object, then we
585
+ call the function with it. In both cases, an updated cache object is returned.
586
+
587
+ The cache object keeps track of all the files that must be checked in order to
588
+ determine if a rebuild is required.
589
+
590
+ The cache object is a plain PHP `array`. It stores the last time it compiled in
591
+ `$cache['updated']` and output of the compile in `$cache['compiled']`.
592
+
593
+ Here we demonstrate creating an new cache object, then using it to see if we
594
+ have a recompiled version available to be written:
595
+
596
+
597
+ ```php
598
+ $less_file = 'myfile.less';
599
+ $css_file = 'myfile.css';
600
+
601
+ // create a new cache object, and compile
602
+ $cache = lessc::cexecute('myfile.less');
603
+ file_put_contents($css_file, $cache['compiled']);
604
+
605
+ // the next time we run, write only if it has updated
606
+ $last_updated = $cache['updated'];
607
+ $cache = lessc::cexecute($cache);
608
+ if ($cache['updated'] > $last_updated) {
609
+ file_put_contents($css_file, $cache['compiled']);
610
+ }
611
+
612
+ ```
613
+
614
+ In order for the system to fully work, we must save cache object between
615
+ requests. Because it's a plain PHP `array`, it's sufficient to
616
+ [`serialize`](http://php.net/serialize) it and save it the string somewhere
617
+ like a file or in persistent memory.
618
+
619
+ An example with saving cache object to a file:
620
+
621
+ ```php
622
+ function auto_compile_less($less_fname, $css_fname) {
623
+ // load the cache
624
+ $cache_fname = $less_fname.".cache";
625
+ if (file_exists($cache_fname)) {
626
+ $cache = unserialize(file_get_contents($cache_fname));
627
+ } else {
628
+ $cache = $less_fname;
629
+ }
630
+
631
+ $new_cache = lessc::cexecute($cache);
632
+ if (!is_array($cache) || $new_cache['updated'] > $cache['updated']) {
633
+ file_put_contents($cache_fname, serialize($new_cache));
634
+ file_put_contents($css_fname, $new_cache['compiled']);
635
+ }
636
+ }
637
+
638
+ auto_compile_less('myfile.less', 'myfile.css')
639
+
640
+ ```
641
+
642
+ `lessc:cexecute` takes an optional second argument, `$force`. Passing in true
643
+ will cause the input to always be recompiled.
644
+
645
+ ### Error Handling
646
+
647
  All of the following methods will throw an `Exception` if the parsing fails:
648
 
649
  ```php
654
  echo "lessphp fatal error: ".$ex->getMessage();
655
  }
656
  ```
657
+ ### Setting Variables From PHP
 
658
 
659
  The `parse` function takes a second optional argument. If you want to
660
  initialize variables from outside the LESS file then you can pass in an
684
  functions that will be exposed in LESS code during the compile. They can be a
685
  little tricky though because you need to work with the **lessphp** type system.
686
 
687
+ An instance of `lessc`, the **lessphp** compiler has two relevant methods:
688
+ `registerFunction` and `unregisterFunction`. `registerFunction` takes two
689
+ arguments, a name and a callable value. `unregisterFunction` just takes the
690
+ name of an existing function to remove.
691
 
692
+ Here's an example that adds a function called `double` that doubles any numeric
693
+ argument:
694
 
695
  ```php
696
  <?php
697
  include "lessc.inc.php";
698
 
699
+ function lessphp_double($arg) {
700
+ list($type, $value) = $arg;
701
+ return array($type, $value*2);
 
 
702
  }
703
 
704
  $myless = new myless();
705
+ $myless->registerFunction("double", "lessphp_double");
706
+
707
+ // gives us a width of 800px
708
  echo $myless->parse("div { width: double(400px); }");
709
  ```
710
 
711
+ The second argument to `registerFunction` is any *callable value* that is
712
+ understood by [`call_user_func`](http://php.net/call_user_func).
713
+
714
+ If we are using PHP 5.3 or above then we are free to pass a function literal
715
+ like so:
716
+
717
+ ```php
718
+ $myless->registerFunction("double", function($arg) {
719
+ list($type, $value) = $arg;
720
+ return array($type, $value*2);
721
+ });
722
+ ```
723
+
724
+ Now let's talk about the `double` function itself.
725
+
726
+ Although a little verbose, the implementation gives us some insight on the type
727
+ system. All values in **lessphp** are stored in an array where the 0th element
728
+ is a string representing the type, and the other elements make up the
729
  associated data for that value.
730
 
731
+ The best way to get an understanding of the system is to register is dummy
732
  function which does a `vardump` on the argument. Try passing the function
733
  different values from LESS and see what the results are.
734
 
735
+ The return value of the registered function must also be a LESS type, but if it is
736
  a string or numeric value, it will automatically be coerced into an appropriate
737
  typed value. In our example, we reconstruct the value with our modifications
738
+ while making sure that we preserve the original type.
 
 
 
739
 
740
  ## Command Line Interface
741
 
lib/vendor/lessphp/docs/style.css DELETED
@@ -1,146 +0,0 @@
1
-
2
- body {
3
- margin: 0;
4
- padding: 0;
5
- font: 14px verdana, sans-serif;
6
- }
7
-
8
- #content, .content {
9
- width: 966px;
10
- margin-bottom: 1.0em;
11
- }
12
-
13
- h1,h2 {
14
- padding: 0.5em;
15
- font-family: calibri, helvetica, sans-serif;
16
- margin: 0;
17
- }
18
-
19
- h1 {
20
- background: #E7F3FB;
21
- color: #182F51;
22
- }
23
-
24
- h2 {
25
- color: #3AA6EE;
26
- color: #1C97E8;
27
- }
28
-
29
-
30
- p {
31
- margin: 0px;
32
- padding: 0px 1.0em 0.5em 1.0em;
33
- }
34
-
35
- a:link, a:visited {
36
- color: #4570B8;
37
- border-bottom: 1px solid #4570B8;
38
- text-decoration: none;
39
- }
40
-
41
- a:hover {
42
- background-color: #E7F3FB;
43
- }
44
-
45
- ul {
46
- margin: 0px;
47
- }
48
-
49
- ul#nav {
50
- margin: 1.0em 0.0em;
51
- }
52
-
53
- hr {
54
- border: 0;
55
- height: 1px;
56
- background-color: #afafaf;
57
- margin: 0px 1em;
58
- }
59
-
60
- .foot {
61
- color: #afafaf;
62
- font-size: 80%;
63
- text-align: center;
64
- margin: 1.0em 0em;
65
- }
66
-
67
- .foot a {
68
- text-decoration: none;
69
- color: #777777;
70
- border-bottom: 1px solid #777777;
71
- }
72
-
73
- .foot a:hover {
74
- color: #000000;
75
- background: none;
76
- }
77
-
78
-
79
- p.important {
80
- background-color: #FBE7E7;
81
- background-color: #FFD6D7;
82
- background-color: #FFDEE2;
83
- padding: 1em 0.5em;
84
- margin: 0.5em 0.0em 0.5em 0.5em;
85
- }
86
-
87
- .info {
88
- background: #ECFBE7;
89
- background: #E0FAD7;
90
- -moz-border-radius: 8px;
91
- -webkit-border-radius: 8px;
92
- padding: 1em;
93
- margin-left: 0.5em;
94
- float: right;
95
- width: 200px;
96
- }
97
-
98
- .info h3 {
99
- padding: 0.5em;
100
- margin: 0px;
101
- font-size: 18px;
102
- font-family: calibri, helvetica, sans-serif;
103
- }
104
-
105
- .info a:hover {
106
- background: none;
107
- }
108
-
109
-
110
- /* vim stuff */
111
- .Comment { color: #7c7c7c; }
112
- .Conditional { color: #6699cc; }
113
- .Statement { color: #6699cc; }
114
- .String { color: #a8ff60; }
115
- .Operator { color: #ffffff; }
116
- .Identifier { color: #c6c5fe; }
117
- .Function { color: #ffd2a7; }
118
- .Type { color: #ffffb6; }
119
- pre.code { font-family: monospace;
120
- color: #f6f3e8;
121
- background-color: #000000;
122
- background-color: #101010;
123
- padding: 1.0em 4.0em;
124
- margin: 1.0em;
125
- }
126
- pre.code b {
127
- color: #96cbfe;
128
- }
129
-
130
- pre.code u {
131
- color: #a8ff60;
132
- text-decoration: none;
133
- }
134
-
135
- code {
136
- background-color: #E7F3FB;
137
- color: #182F51;
138
- font-weight: bold;
139
- padding: 0px 2px;
140
- }
141
-
142
-
143
- .Delimiter { color: #00a0a0; }
144
- .PreProc { color: #96cbfe; }
145
-
146
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/vendor/lessphp/lessc.inc.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * lessphp v0.3.0
5
  * http://leafo.net/lessphp
6
  *
7
  * LESS css compiler, adapted from http://lesscss.org
@@ -36,6 +36,8 @@ class lessc {
36
  protected $buffer;
37
  protected $count;
38
  protected $line;
 
 
39
 
40
  public $indentLevel;
41
  public $indentChar = ' ';
@@ -65,7 +67,7 @@ class lessc {
65
  /**
66
  * @link http://www.w3.org/TR/css3-values/
67
  */
68
- static protected $units=array(
69
  'em', 'ex', 'px', 'gd', 'rem', 'vw', 'vh', 'vm', 'ch', // Relative length units
70
  'in', 'cm', 'mm', 'pt', 'pc', // Absolute length units
71
  '%', // Percentages
@@ -267,14 +269,16 @@ class lessc {
267
 
268
  if (!$hidden) $this->append(array('block', $block));
269
  foreach ($block->tags as $tag) {
 
 
 
270
  $this->env->children[$tag] = $block;
271
  }
272
 
273
  return true;
274
  }
275
 
276
-
277
- // mixin
278
  if ($this->mixinTags($tags) &&
279
  ($this->argumentValues($argv) || true) && $this->end())
280
  {
@@ -284,6 +288,7 @@ class lessc {
284
  } else {
285
  $this->seek($s);
286
  }
 
287
  // spare ;
288
  if ($this->literal(';')) return true;
289
 
@@ -738,9 +743,9 @@ class lessc {
738
  // a single tag
739
  function tag(&$tag, $simple = false) {
740
  if ($simple)
741
- $chars = '^,:;{}\][>\(\) ';
742
  else
743
- $chars = '^,;{}[';
744
 
745
  $tag = '';
746
  while ($this->tagBracket($first)) $tag .= $first;
@@ -837,6 +842,13 @@ class lessc {
837
  else return array('list', $delim, $items);
838
  }
839
 
 
 
 
 
 
 
 
840
  /**
841
  * Recursively compiles a block.
842
  * @param $block the block
@@ -958,8 +970,11 @@ class lessc {
958
  }
959
 
960
  // attempt to find block pointed at by path within search_in or its parent
961
- function findBlock($search_in, $path) {
962
  if ($search_in == null) return null;
 
 
 
963
  $name = $path[0];
964
 
965
  if (isset($search_in->children[$name])) {
@@ -967,10 +982,11 @@ class lessc {
967
  if (count($path) == 1) {
968
  return $block;
969
  } else {
970
- return $this->findBlock($block, array_slice($path, 1));
971
  }
972
  } else {
973
- return $this->findBlock($search_in->parent, $path);
 
974
  }
975
  }
976
 
@@ -978,6 +994,7 @@ class lessc {
978
  // or the one passed in through $values
979
  function zipSetArgs($args, $values) {
980
  $i = 0;
 
981
  foreach ($args as $a) {
982
  if ($i < count($values) && !is_null($values[$i])) {
983
  $value = $values[$i];
@@ -985,9 +1002,18 @@ class lessc {
985
  $value = $a[1];
986
  } else $value = null;
987
 
988
- $this->set($this->vPrefix.$a[0], $this->reduce($value));
 
 
989
  $i++;
990
  }
 
 
 
 
 
 
 
991
  }
992
 
993
  // compile a prop and update $lines or $blocks appropriately
@@ -1206,7 +1232,8 @@ class lessc {
1206
  return array(array('color', 0, 0, 0));
1207
  }
1208
  list($color, $delta) = $args[2];
1209
- if ($color[0] != 'color')
 
1210
  $color = array('color', 0, 0, 0);
1211
 
1212
  $delta = floatval($delta[1]);
@@ -1284,6 +1311,64 @@ class lessc {
1284
  return round($hsl[3]);
1285
  }
1286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1287
  function toHSL($color) {
1288
  if ($color[0] == 'hsl') return $color;
1289
 
@@ -1434,7 +1519,9 @@ class lessc {
1434
  else {
1435
  list($_, $name, $args) = $var;
1436
  if ($name == "%") $name = "_sprintf";
1437
- $f = array($this, 'lib_'.$name);
 
 
1438
  if (is_callable($f)) {
1439
  if ($args[0] == 'list')
1440
  $args = $this->compressList($args[2], $args[1]);
@@ -1462,11 +1549,32 @@ class lessc {
1462
  return $var;
1463
  }
1464
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1465
  // evaluate an expression
1466
  function evaluate($op, $left, $right) {
1467
  $left = $this->reduce($left);
1468
  $right = $this->reduce($right);
1469
 
 
 
 
 
 
 
 
 
1470
  if ($left[0] == 'color' && $right[0] == 'color') {
1471
  $out = $this->op_color_color($op, $left, $right);
1472
  return $out;
@@ -1599,6 +1707,7 @@ class lessc {
1599
  $b = new stdclass;
1600
  $b->parent = $this->env;
1601
 
 
1602
  $b->tags = $tags;
1603
  $b->props = array();
1604
  $b->children = array();
@@ -1645,7 +1754,13 @@ class lessc {
1645
  // get the highest occurrence entry for a name
1646
  function get($name) {
1647
  $current = $this->env;
 
 
1648
  while ($current) {
 
 
 
 
1649
  if (isset($current->store[$name]))
1650
  return $current->store[$name];
1651
  else
@@ -1662,7 +1777,7 @@ class lessc {
1662
  if ($this->count >= strlen($this->buffer)) return false;
1663
 
1664
  // shortcut on single letter
1665
- if (!$eatWhitespace and strlen($what) == 1) {
1666
  if ($this->buffer{$this->count} == $what) {
1667
  $this->count++;
1668
  return true;
@@ -1821,6 +1936,14 @@ class lessc {
1821
  }
1822
  }
1823
 
 
 
 
 
 
 
 
 
1824
  // remove comments from $text
1825
  // todo: make it work for all functions, not just url
1826
  function removeComments($text) {
@@ -1962,5 +2085,155 @@ class lessc {
1962
  }
1963
 
1964
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1965
  }
1966
 
1
  <?php
2
 
3
  /**
4
+ * lessphp v0.3.1
5
  * http://leafo.net/lessphp
6
  *
7
  * LESS css compiler, adapted from http://lesscss.org
36
  protected $buffer;
37
  protected $count;
38
  protected $line;
39
+ protected $libFunctions = array();
40
+ static protected $nextBlockId = 0;
41
 
42
  public $indentLevel;
43
  public $indentChar = ' ';
67
  /**
68
  * @link http://www.w3.org/TR/css3-values/
69
  */
70
+ static protected $units = array(
71
  'em', 'ex', 'px', 'gd', 'rem', 'vw', 'vh', 'vm', 'ch', // Relative length units
72
  'in', 'cm', 'mm', 'pt', 'pc', // Absolute length units
73
  '%', // Percentages
269
 
270
  if (!$hidden) $this->append(array('block', $block));
271
  foreach ($block->tags as $tag) {
272
+ if (isset($this->env->children[$tag])) {
273
+ $block = $this->mergeBlock($this->env->children[$tag], $block);
274
+ }
275
  $this->env->children[$tag] = $block;
276
  }
277
 
278
  return true;
279
  }
280
 
281
+ // mixin
 
282
  if ($this->mixinTags($tags) &&
283
  ($this->argumentValues($argv) || true) && $this->end())
284
  {
288
  } else {
289
  $this->seek($s);
290
  }
291
+
292
  // spare ;
293
  if ($this->literal(';')) return true;
294
 
743
  // a single tag
744
  function tag(&$tag, $simple = false) {
745
  if ($simple)
746
+ $chars = '^,:;{}\][>\(\) "\'';
747
  else
748
+ $chars = '^,;{}["\'';
749
 
750
  $tag = '';
751
  while ($this->tagBracket($first)) $tag .= $first;
842
  else return array('list', $delim, $items);
843
  }
844
 
845
+ // just do a shallow propety merge, seems to be what lessjs does
846
+ function mergeBlock($target, $from) {
847
+ $target = clone $target;
848
+ $target->props = array_merge($target->props, $from->props);
849
+ return $target;
850
+ }
851
+
852
  /**
853
  * Recursively compiles a block.
854
  * @param $block the block
970
  }
971
 
972
  // attempt to find block pointed at by path within search_in or its parent
973
+ function findBlock($search_in, $path, $seen=array()) {
974
  if ($search_in == null) return null;
975
+ if (isset($seen[$search_in->id])) return null;
976
+ $seen[$search_in->id] = true;
977
+
978
  $name = $path[0];
979
 
980
  if (isset($search_in->children[$name])) {
982
  if (count($path) == 1) {
983
  return $block;
984
  } else {
985
+ return $this->findBlock($block, array_slice($path, 1), $seen);
986
  }
987
  } else {
988
+ if ($search_in->parent === $search_in) return null;
989
+ return $this->findBlock($search_in->parent, $path, $seen);
990
  }
991
  }
992
 
994
  // or the one passed in through $values
995
  function zipSetArgs($args, $values) {
996
  $i = 0;
997
+ $assigned_values = array();
998
  foreach ($args as $a) {
999
  if ($i < count($values) && !is_null($values[$i])) {
1000
  $value = $values[$i];
1002
  $value = $a[1];
1003
  } else $value = null;
1004
 
1005
+ $value = $this->reduce($value);
1006
+ $this->set($this->vPrefix.$a[0], $value);
1007
+ $assigned_values[] = $value;
1008
  $i++;
1009
  }
1010
+
1011
+ // copy over any extra default args
1012
+ for ($i = count($values); $i < count($assigned_values); $i++) {
1013
+ $values[] = $assigned_values[$i];
1014
+ }
1015
+
1016
+ $this->env->arguments = $values;
1017
  }
1018
 
1019
  // compile a prop and update $lines or $blocks appropriately
1232
  return array(array('color', 0, 0, 0));
1233
  }
1234
  list($color, $delta) = $args[2];
1235
+ $color = $this->coerceColor($color);
1236
+ if (is_null($color))
1237
  $color = array('color', 0, 0, 0);
1238
 
1239
  $delta = floatval($delta[1]);
1311
  return round($hsl[3]);
1312
  }
1313
 
1314
+ // get the alpha of a color
1315
+ // defaults to 1 for non-colors or colors without an alpha
1316
+ function lib_alpha($color) {
1317
+ if ($color[0] != 'color') return 1;
1318
+ return isset($color[4]) ? $color[4] : 1;
1319
+ }
1320
+
1321
+ // set the alpha of the color
1322
+ function lib_fade($args) {
1323
+ list($color, $alpha) = $this->colorArgs($args);
1324
+ $color[4] = $this->clamp($alpha / 100.0);
1325
+ return $color;
1326
+ }
1327
+
1328
+ function lib_percentage($number) {
1329
+ return array('%', $number[1]*100);
1330
+ }
1331
+
1332
+ // mixes two colors by weight
1333
+ // mix(@color1, @color2, @weight);
1334
+ // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1335
+ function lib_mix($args) {
1336
+ if ($args[0] != "list")
1337
+ throw new exception("mix expects (color1, color2, weight)");
1338
+
1339
+ list($first, $second, $weight) = $args[2];
1340
+ $first = $this->assertColor($first);
1341
+ $second = $this->assertColor($second);
1342
+
1343
+ $first_a = $this->lib_alpha($first);
1344
+ $second_a = $this->lib_alpha($second);
1345
+ $weight = $weight[1] / 100.0;
1346
+
1347
+ $w = $weight * 2 - 1;
1348
+ $a = $first_a - $second_a;
1349
+
1350
+ $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
1351
+ $w2 = 1.0 - $w1;
1352
+
1353
+ $new = array('color',
1354
+ $w1 * $first[1] + $w2 * $second[1],
1355
+ $w1 * $first[2] + $w2 * $second[2],
1356
+ $w1 * $first[3] + $w2 * $second[3],
1357
+ );
1358
+
1359
+ if ($first_a != 1.0 || $second_a != 1.0) {
1360
+ $new[] = $first_a * $p + $second_a * ($p - 1);
1361
+ }
1362
+
1363
+ return $this->fixColor($new);
1364
+ }
1365
+
1366
+ function assertColor($value, $error = "expected color value") {
1367
+ $color = $this->coerceColor($value);
1368
+ if (is_null($color)) throw new exception($error);
1369
+ return $color;
1370
+ }
1371
+
1372
  function toHSL($color) {
1373
  if ($color[0] == 'hsl') return $color;
1374
 
1519
  else {
1520
  list($_, $name, $args) = $var;
1521
  if ($name == "%") $name = "_sprintf";
1522
+ $f = isset($this->libFunctions[$name]) ?
1523
+ $this->libFunctions[$name] : array($this, 'lib_'.$name);
1524
+
1525
  if (is_callable($f)) {
1526
  if ($args[0] == 'list')
1527
  $args = $this->compressList($args[2], $args[1]);
1549
  return $var;
1550
  }
1551
 
1552
+ function coerceColor($value) {
1553
+ switch($value[0]) {
1554
+ case 'color': return $value;
1555
+ case 'keyword':
1556
+ $name = $value[1];
1557
+ if (isset(self::$cssColors[$name])) {
1558
+ list($r, $g, $b) = explode(',', self::$cssColors[$name]);
1559
+ return array('color', $r, $g, $b);
1560
+ }
1561
+ return null;
1562
+ }
1563
+ }
1564
+
1565
  // evaluate an expression
1566
  function evaluate($op, $left, $right) {
1567
  $left = $this->reduce($left);
1568
  $right = $this->reduce($right);
1569
 
1570
+ if ($left_color = $this->coerceColor($left)) {
1571
+ $left = $left_color;
1572
+ }
1573
+
1574
+ if ($right_color = $this->coerceColor($right)) {
1575
+ $right = $right_color;
1576
+ }
1577
+
1578
  if ($left[0] == 'color' && $right[0] == 'color') {
1579
  $out = $this->op_color_color($op, $left, $right);
1580
  return $out;
1707
  $b = new stdclass;
1708
  $b->parent = $this->env;
1709
 
1710
+ $b->id = self::$nextBlockId++;
1711
  $b->tags = $tags;
1712
  $b->props = array();
1713
  $b->children = array();
1754
  // get the highest occurrence entry for a name
1755
  function get($name) {
1756
  $current = $this->env;
1757
+
1758
+ $is_arguments = $name == $this->vPrefix . 'arguments';
1759
  while ($current) {
1760
+ if ($is_arguments && isset($current->arguments)) {
1761
+ return array('list', ' ', $current->arguments);
1762
+ }
1763
+
1764
  if (isset($current->store[$name]))
1765
  return $current->store[$name];
1766
  else
1777
  if ($this->count >= strlen($this->buffer)) return false;
1778
 
1779
  // shortcut on single letter
1780
+ if (!$eatWhitespace && strlen($what) == 1) {
1781
  if ($this->buffer{$this->count} == $what) {
1782
  $this->count++;
1783
  return true;
1936
  }
1937
  }
1938
 
1939
+ public function registerFunction($name, $func) {
1940
+ $this->libFunctions[$name] = $func;
1941
+ }
1942
+
1943
+ public function unregisterFunction($name) {
1944
+ unset($this->libFunctions[$name]);
1945
+ }
1946
+
1947
  // remove comments from $text
1948
  // todo: make it work for all functions, not just url
1949
  function removeComments($text) {
2085
  }
2086
 
2087
  }
2088
+
2089
+ static protected $cssColors = array(
2090
+ 'aliceblue' => '240,248,255',
2091
+ 'antiquewhite' => '250,235,215',
2092
+ 'aqua' => '0,255,255',
2093
+ 'aquamarine' => '127,255,212',
2094
+ 'azure' => '240,255,255',
2095
+ 'beige' => '245,245,220',
2096
+ 'bisque' => '255,228,196',
2097
+ 'black' => '0,0,0',
2098
+ 'blanchedalmond' => '255,235,205',
2099
+ 'blue' => '0,0,255',
2100
+ 'blueviolet' => '138,43,226',
2101
+ 'brown' => '165,42,42',
2102
+ 'burlywood' => '222,184,135',
2103
+ 'cadetblue' => '95,158,160',
2104
+ 'chartreuse' => '127,255,0',
2105
+ 'chocolate' => '210,105,30',
2106
+ 'coral' => '255,127,80',
2107
+ 'cornflowerblue' => '100,149,237',
2108
+ 'cornsilk' => '255,248,220',
2109
+ 'crimson' => '220,20,60',
2110
+ 'cyan' => '0,255,255',
2111
+ 'darkblue' => '0,0,139',
2112
+ 'darkcyan' => '0,139,139',
2113
+ 'darkgoldenrod' => '184,134,11',
2114
+ 'darkgray' => '169,169,169',
2115
+ 'darkgreen' => '0,100,0',
2116
+ 'darkgrey' => '169,169,169',
2117
+ 'darkkhaki' => '189,183,107',
2118
+ 'darkmagenta' => '139,0,139',
2119
+ 'darkolivegreen' => '85,107,47',
2120
+ 'darkorange' => '255,140,0',
2121
+ 'darkorchid' => '153,50,204',
2122
+ 'darkred' => '139,0,0',
2123
+ 'darksalmon' => '233,150,122',
2124
+ 'darkseagreen' => '143,188,143',
2125
+ 'darkslateblue' => '72,61,139',
2126
+ 'darkslategray' => '47,79,79',
2127
+ 'darkslategrey' => '47,79,79',
2128
+ 'darkturquoise' => '0,206,209',
2129
+ 'darkviolet' => '148,0,211',
2130
+ 'deeppink' => '255,20,147',
2131
+ 'deepskyblue' => '0,191,255',
2132
+ 'dimgray' => '105,105,105',
2133
+ 'dimgrey' => '105,105,105',
2134
+ 'dodgerblue' => '30,144,255',
2135
+ 'firebrick' => '178,34,34',
2136
+ 'floralwhite' => '255,250,240',
2137
+ 'forestgreen' => '34,139,34',
2138
+ 'fuchsia' => '255,0,255',
2139
+ 'gainsboro' => '220,220,220',
2140
+ 'ghostwhite' => '248,248,255',
2141
+ 'gold' => '255,215,0',
2142
+ 'goldenrod' => '218,165,32',
2143
+ 'gray' => '128,128,128',
2144
+ 'green' => '0,128,0',
2145
+ 'greenyellow' => '173,255,47',
2146
+ 'grey' => '128,128,128',
2147
+ 'honeydew' => '240,255,240',
2148
+ 'hotpink' => '255,105,180',
2149
+ 'indianred' => '205,92,92',
2150
+ 'indigo' => '75,0,130',
2151
+ 'ivory' => '255,255,240',
2152
+ 'khaki' => '240,230,140',
2153
+ 'lavender' => '230,230,250',
2154
+ 'lavenderblush' => '255,240,245',
2155
+ 'lawngreen' => '124,252,0',
2156
+ 'lemonchiffon' => '255,250,205',
2157
+ 'lightblue' => '173,216,230',
2158
+ 'lightcoral' => '240,128,128',
2159
+ 'lightcyan' => '224,255,255',
2160
+ 'lightgoldenrodyellow' => '250,250,210',
2161
+ 'lightgray' => '211,211,211',
2162
+ 'lightgreen' => '144,238,144',
2163
+ 'lightgrey' => '211,211,211',
2164
+ 'lightpink' => '255,182,193',
2165
+ 'lightsalmon' => '255,160,122',
2166
+ 'lightseagreen' => '32,178,170',
2167
+ 'lightskyblue' => '135,206,250',
2168
+ 'lightslategray' => '119,136,153',
2169
+ 'lightslategrey' => '119,136,153',
2170
+ 'lightsteelblue' => '176,196,222',
2171
+ 'lightyellow' => '255,255,224',
2172
+ 'lime' => '0,255,0',
2173
+ 'limegreen' => '50,205,50',
2174
+ 'linen' => '250,240,230',
2175
+ 'magenta' => '255,0,255',
2176
+ 'maroon' => '128,0,0',
2177
+ 'mediumaquamarine' => '102,205,170',
2178
+ 'mediumblue' => '0,0,205',
2179
+ 'mediumorchid' => '186,85,211',
2180
+ 'mediumpurple' => '147,112,219',
2181
+ 'mediumseagreen' => '60,179,113',
2182
+ 'mediumslateblue' => '123,104,238',
2183
+ 'mediumspringgreen' => '0,250,154',
2184
+ 'mediumturquoise' => '72,209,204',
2185
+ 'mediumvioletred' => '199,21,133',
2186
+ 'midnightblue' => '25,25,112',
2187
+ 'mintcream' => '245,255,250',
2188
+ 'mistyrose' => '255,228,225',
2189
+ 'moccasin' => '255,228,181',
2190
+ 'navajowhite' => '255,222,173',
2191
+ 'navy' => '0,0,128',
2192
+ 'oldlace' => '253,245,230',
2193
+ 'olive' => '128,128,0',
2194
+ 'olivedrab' => '107,142,35',
2195
+ 'orange' => '255,165,0',
2196
+ 'orangered' => '255,69,0',
2197
+ 'orchid' => '218,112,214',
2198
+ 'palegoldenrod' => '238,232,170',
2199
+ 'palegreen' => '152,251,152',
2200
+ 'paleturquoise' => '175,238,238',
2201
+ 'palevioletred' => '219,112,147',
2202
+ 'papayawhip' => '255,239,213',
2203
+ 'peachpuff' => '255,218,185',
2204
+ 'peru' => '205,133,63',
2205
+ 'pink' => '255,192,203',
2206
+ 'plum' => '221,160,221',
2207
+ 'powderblue' => '176,224,230',
2208
+ 'purple' => '128,0,128',
2209
+ 'red' => '255,0,0',
2210
+ 'rosybrown' => '188,143,143',
2211
+ 'royalblue' => '65,105,225',
2212
+ 'saddlebrown' => '139,69,19',
2213
+ 'salmon' => '250,128,114',
2214
+ 'sandybrown' => '244,164,96',
2215
+ 'seagreen' => '46,139,87',
2216
+ 'seashell' => '255,245,238',
2217
+ 'sienna' => '160,82,45',
2218
+ 'silver' => '192,192,192',
2219
+ 'skyblue' => '135,206,235',
2220
+ 'slateblue' => '106,90,205',
2221
+ 'slategray' => '112,128,144',
2222
+ 'slategrey' => '112,128,144',
2223
+ 'snow' => '255,250,250',
2224
+ 'springgreen' => '0,255,127',
2225
+ 'steelblue' => '70,130,180',
2226
+ 'tan' => '210,180,140',
2227
+ 'teal' => '0,128,128',
2228
+ 'thistle' => '216,191,216',
2229
+ 'tomato' => '255,99,71',
2230
+ 'turquoise' => '64,224,208',
2231
+ 'violet' => '238,130,238',
2232
+ 'wheat' => '245,222,179',
2233
+ 'white' => '255,255,255',
2234
+ 'whitesmoke' => '245,245,245',
2235
+ 'yellow' => '255,255,0',
2236
+ 'yellowgreen' => '154,205,50'
2237
+ );
2238
  }
2239
 
lib/vendor/lessphp/tests/inputs/colors.less CHANGED
@@ -63,3 +63,36 @@ body {
63
  zero: spin(#000000, 100);
64
  zero: spin(#ffffff, 100);
65
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  zero: spin(#000000, 100);
64
  zero: spin(#ffffff, 100);
65
  }
66
+
67
+
68
+ alpha {
69
+ // g: alpha(red);
70
+ g: alpha(rgba(0,0,0,0));
71
+ g: alpha(rgb(155,55,0));
72
+ }
73
+
74
+ fade {
75
+ f: fade(red, 50%);
76
+ f: fade(#fff, 20%);
77
+ f: fade(rgba(34,23,64,0.4), 50%);
78
+ }
79
+
80
+ @a: rgb(255,255,255);
81
+ @b: rgb(0,0,0);
82
+
83
+ .mix {
84
+ color: mix(@a, @b, 50%);
85
+ }
86
+
87
+ .percent {
88
+ per: percentage(0.5);
89
+ }
90
+
91
+ // color keywords
92
+
93
+ .colorz {
94
+ color: whitesmoke - 10;
95
+ color: spin(red, 34);
96
+ }
97
+
98
+
lib/vendor/lessphp/tests/inputs/misc.less CHANGED
@@ -36,3 +36,36 @@ Here is a block comment
36
  background: url(/*no comment here*/);
37
  }
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  background: url(/*no comment here*/);
37
  }
38
 
39
+
40
+ .mix(@arg) { color: @arg; }
41
+ @aaa: aaa;
42
+ @bbb: bbb;
43
+ // make sure the opening selector isn't too greedy
44
+ .cool {.mix("@{aaa}, @{bbb}")}
45
+
46
+ .cool("{hello");
47
+ .cool('{hello');
48
+
49
+
50
+ // merging of mixins
51
+ .span-17 { float: left; }
52
+ .span-17 { width: 660px; }
53
+
54
+ .x {.span-17;}
55
+
56
+ .hi {
57
+ pre {
58
+ color: red;
59
+ }
60
+ }
61
+
62
+ .hi {
63
+ pre {
64
+ color: blue;
65
+ }
66
+ }
67
+
68
+ .rad {
69
+ .hi;
70
+ }
71
+
lib/vendor/lessphp/tests/inputs/mixins.less CHANGED
@@ -66,3 +66,57 @@ body {
66
  }
67
 
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
 
68
 
69
+ // arguments
70
+
71
+ .spam(@something: 100) {
72
+ @wow: 23434;
73
+ foo: @arguments;
74
+ bar: @arguments;
75
+ }
76
+
77
+ .eggs {
78
+ .spam(1px, 2px, 4px, 8px);
79
+ }
80
+
81
+ .first(@one, @two, @three, @four: cool) {
82
+ cool: @arguments;
83
+ }
84
+
85
+ #hello {
86
+ .first(one, two, three);
87
+ }
88
+
89
+
90
+ .rad() {
91
+ cool: @arguments;
92
+ }
93
+
94
+ #world {
95
+ @hello: "world";
96
+ .rad("@{hello}");
97
+ }
98
+
99
+ .second() {
100
+ things: @arguments;
101
+ }
102
+
103
+ #another {
104
+ .second(red, blue, green);
105
+ .second(red blue green);
106
+ }
107
+
108
+
109
+ .another() {
110
+ .cool {
111
+ color: @arguments;
112
+ }
113
+ }
114
+
115
+ #day {
116
+ .another(one,two, three);
117
+ .another(one two three);
118
+ }
119
+
120
+
121
+
122
+
lib/vendor/lessphp/tests/outputs/colors.css CHANGED
@@ -43,4 +43,15 @@ body {
43
  zero:#56124b;
44
  zero:#000000;
45
  zero:#ffffff;
46
- }
 
 
 
 
 
 
 
 
 
 
 
43
  zero:#56124b;
44
  zero:#000000;
45
  zero:#ffffff;
46
+ }
47
+ alpha {
48
+ g:0;
49
+ g:1;
50
+ }
51
+ fade {
52
+ f:rgba(0,0,0,0.5);
53
+ f:rgba(255,255,255,0.2);
54
+ f:rgba(34,23,64,0.5);
55
+ }
56
+ .mix { color:#7f7f7f; }
57
+ .percent { per:50%; }
lib/vendor/lessphp/tests/outputs/misc.css CHANGED
@@ -1,4 +1,6 @@
1
  @charset "utf-8";
 
 
2
  .topbar { background:url(/assets/images/test/topbar.png); }
3
  .hello { test:empty-function("/assets/images/test/",40%,to(#ffffff)); }
4
  .css3 { background-image:-webkit-gradient(linear,0% 0%,0% 90%,from(#e9a000),to(#a37000)); }
@@ -11,4 +13,15 @@
11
  world:'// neither is this';
12
  what-ever:100px;
13
  background:url(/*no comment here*/);
14
- }
 
 
 
 
 
 
 
 
 
 
 
1
  @charset "utf-8";
2
+ color:"aaa, bbb";
3
+ color:"aaa, bbb";
4
  .topbar { background:url(/assets/images/test/topbar.png); }
5
  .hello { test:empty-function("/assets/images/test/",40%,to(#ffffff)); }
6
  .css3 { background-image:-webkit-gradient(linear,0% 0%,0% 90%,from(#e9a000),to(#a37000)); }
13
  world:'// neither is this';
14
  what-ever:100px;
15
  background:url(/*no comment here*/);
16
+ }
17
+ .cool { color:"aaa, bbb"; }
18
+ .span-17 { float:left; }
19
+ .span-17 { width:660px; }
20
+ .x {
21
+ float:left;
22
+ width:660px;
23
+ }
24
+ .hi pre { color:red; }
25
+ .hi pre { color:blue; }
26
+ .rad pre { color:red; }
27
+ .rad pre { color:blue; }
lib/vendor/lessphp/tests/outputs/mixins.css CHANGED
@@ -32,4 +32,16 @@ body {
32
  }
33
  body b { color:blue; }
34
  .hello .world { color:blue; }
35
- .foobar { color:blue; }
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
  body b { color:blue; }
34
  .hello .world { color:blue; }
35
+ .foobar { color:blue; }
36
+ .eggs {
37
+ foo:1px 2px 4px 8px;
38
+ bar:1px 2px 4px 8px;
39
+ }
40
+ #hello { cool:one two three cool; }
41
+ #world { cool:"world"; }
42
+ #another {
43
+ things:red blue green;
44
+ things:red blue green;
45
+ }
46
+ #day .cool { color:one two three; }
47
+ #day .cool { color:one two three; }
lib/vendor/lessphp/tests/test.php CHANGED
@@ -78,16 +78,18 @@ $compiling = flag('C');
78
  $showDiff = flag('d', 'diff');
79
  echo ($compiling ? "Compiling" : "Running")." $count test".($count == 1 ? '' : 's').":\n";
80
 
81
- function dump($msgs, $depth = 1) {
82
  if (!is_array($msgs)) $msgs = array($msgs);
83
  foreach ($msgs as $m) {
84
- echo str_repeat("\t", $depth).' - '.$m."\n";
85
  }
86
  }
87
 
 
 
88
  $i = 1;
89
  foreach ($tests as $test) {
90
- printf("\t[Test %04d/%04d] %s -> %s\n", $i, $count, basename($test['in']), basename($test['out']));
91
 
92
  try {
93
  ob_start();
@@ -98,7 +100,7 @@ foreach ($tests as $test) {
98
  "Failed to compile input, reason:",
99
  $e->getMessage(),
100
  "Aborting"
101
- ));
102
  break;
103
  }
104
 
@@ -110,14 +112,14 @@ foreach ($tests as $test) {
110
  "Failed to find output file: $test[out]",
111
  "Maybe you forgot to compile tests?",
112
  "Aborting"
113
- ));
114
  break;
115
  }
116
  $expected = trim(file_get_contents($test['out']));
117
 
118
  if ($expected != $parsed) {
119
  if ($showDiff) {
120
- dump("Failed:");
121
  $tmp = $test['out'].".tmp";
122
  file_put_contents($tmp, $parsed);
123
  system($difftool.' '.$test['out'].' '.$tmp);
@@ -125,7 +127,7 @@ foreach ($tests as $test) {
125
 
126
  dump("Aborting");
127
  break;
128
- } else dump("Failed, run with -d flag to view diff");
129
  } else {
130
  dump("Passed");
131
  }
78
  $showDiff = flag('d', 'diff');
79
  echo ($compiling ? "Compiling" : "Running")." $count test".($count == 1 ? '' : 's').":\n";
80
 
81
+ function dump($msgs, $depth = 1, $prefix=" ") {
82
  if (!is_array($msgs)) $msgs = array($msgs);
83
  foreach ($msgs as $m) {
84
+ echo str_repeat($prefix, $depth).' - '.$m."\n";
85
  }
86
  }
87
 
88
+ $fail_prefix = " ** ";
89
+
90
  $i = 1;
91
  foreach ($tests as $test) {
92
+ printf(" [Test %04d/%04d] %s -> %s\n", $i, $count, basename($test['in']), basename($test['out']));
93
 
94
  try {
95
  ob_start();
100
  "Failed to compile input, reason:",
101
  $e->getMessage(),
102
  "Aborting"
103
+ ), 1, $fail_prefix);
104
  break;
105
  }
106
 
112
  "Failed to find output file: $test[out]",
113
  "Maybe you forgot to compile tests?",
114
  "Aborting"
115
+ ), 1, $fail_prefix);
116
  break;
117
  }
118
  $expected = trim(file_get_contents($test['out']));
119
 
120
  if ($expected != $parsed) {
121
  if ($showDiff) {
122
+ dump("Failed:", 1, $fail_prefix);
123
  $tmp = $test['out'].".tmp";
124
  file_put_contents($tmp, $parsed);
125
  system($difftool.' '.$test['out'].' '.$tmp);
127
 
128
  dump("Aborting");
129
  break;
130
+ } else dump("Failed, run with -d flag to view diff", 1, $fail_prefix);
131
  } else {
132
  dump("Passed");
133
  }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_i
4
  Tags: dev, theme, themes, toolkit, plugin-toolkit, less, lesscss, lessc, lessphp, productivity, style, stylesheet, api
5
  Requires at least: 2.8
6
  Tested up to: 3.3
7
- Stable tag: 1.4.1
8
 
9
  Implementation of LESS (Leaner CSS) in order to make themes development easier.
10
 
@@ -30,7 +30,7 @@ Seriously.
30
  The sole requirement is to use WordPress API and LESS convention: the `.less` extension.
31
 
32
  **Minimal Requirements**: PHP 5.1.2 and WordPress 2.8.
33
- **Relies on**: [LESSPHP 0.3.0](http://leafo.net/lessphp/), [plugin-toolkit](http://wordpress.org/extend/plugins/plugin-toolkit/).
34
 
35
  *Notice*: in case you'd like to drop the usage of this plugin, it's safe to do it. You will just need to convert back your stylesheets to CSS.
36
 
@@ -48,6 +48,13 @@ The sole requirement is to use WordPress API and LESS convention: the `.less` ex
48
 
49
  == Changelog ==
50
 
 
 
 
 
 
 
 
51
  = Version 1.4.1 =
52
 
53
  * bug: CSS `url()` are now properly resolved relative to the theme URL
@@ -147,6 +154,22 @@ And if you want to do that from a theme, with less code:
147
  1. include the `wp-less/lib/helper/ThemeHelper.php` file;
148
  1. call `less_add_variable('@default_color', '#fff')`
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  == Upgrade Notice ==
151
 
152
  = 1.4 =
4
  Tags: dev, theme, themes, toolkit, plugin-toolkit, less, lesscss, lessc, lessphp, productivity, style, stylesheet, api
5
  Requires at least: 2.8
6
  Tested up to: 3.3
7
+ Stable tag: 1.4.2
8
 
9
  Implementation of LESS (Leaner CSS) in order to make themes development easier.
10
 
30
  The sole requirement is to use WordPress API and LESS convention: the `.less` extension.
31
 
32
  **Minimal Requirements**: PHP 5.1.2 and WordPress 2.8.
33
+ **Relies on**: [LESSPHP 0.3.1](http://leafo.net/lessphp/), [plugin-toolkit](http://wordpress.org/extend/plugins/plugin-toolkit/).
34
 
35
  *Notice*: in case you'd like to drop the usage of this plugin, it's safe to do it. You will just need to convert back your stylesheets to CSS.
36
 
48
 
49
  == Changelog ==
50
 
51
+ = Version 1.4.2 =
52
+
53
+ * feature: if `WP_DEBUG` is set to true, compilation is done on every page
54
+ * feature: rebuild now takes care of LESS PHP variable
55
+ * feature: added support of [custom LESS functions](http://leafo.net/lessphp/docs/index.html#custom_functions)
56
+ * lessphp: updated to version 0.3.1
57
+
58
  = Version 1.4.1 =
59
 
60
  * bug: CSS `url()` are now properly resolved relative to the theme URL
154
  1. include the `wp-less/lib/helper/ThemeHelper.php` file;
155
  1. call `less_add_variable('@default_color', '#fff')`
156
 
157
+ = I want to create a new custom LESS function =
158
+ LESS PHP 0.3.1. introducted a new way to register functions without subclassing the compiler.
159
+
160
+ If you initialized the class by yourself, do it this way:
161
+ `$WPLessPlugin->registerFunction('double', 'lessphp_double');`
162
+
163
+ If you don't manage the plugin by yourself:
164
+ `WPPluginToolkitPlugin::getInstance('WPLess')->registerFunction('double', 'lessphp_double');`
165
+
166
+ And if you want to do that from a theme, with less code:
167
+
168
+ 1. include the `wp-less/lib/helper/ThemeHelper.php` file;
169
+ 1. call `less_register_function('double', 'lessphp_double')`
170
+
171
+ **Notice**: in this example, we assume `lessphp_double` is a valid [PHP callback](http://php.net/manual/en/language.pseudo-types.php#language.types.callback), as stated in `lessphp` documentation.
172
+
173
  == Upgrade Notice ==
174
 
175
  = 1.4 =