Combining:

When you get down to the code there is a lot of cross-over between these two pieces of requested functionality.

The latest dev version as of 2012-09-17 has the functionality of both of these issues.

There is a new less_demo module included that provides an example of how the new functionality works, and while the demo is not complete yet, it should give you a good idea of what is now possible.

One of the big changes is that you can now have settings for modules as well as themes. Settings for modules are also edited from the theme configuration page and are specific to that theme. So you can have styles from a module appear differently depending on your settings for each theme.

To allow for settings per arbitrary value, files now have a hash added to the generated filename which boils down to:

md5(json_encode($less_settings));

I know that some people feel that md5 is a little heavyweight for this situation so I am also testing using CRC32 instead. CRC32 is also much shorter character count and will be easier on the eyes when viewing html source.

The requested 'tag' functionality from #1543276: Support passing/defining LESS variables/functions via drupal_add_css() and theme.info can be accomplished by passing in an LESS variable to drupal_add_css() that is not used in the .less file. Any future changes to this variable will create a new hash and cause the file to be rebuilt.

When using drupal_add_css() the second argument, $options, can now contain an index of 'less', which should be an array like:


$less_settings = array(
  'variables' => array(
    '@header_to' => 'red',
  ),
  'functions' => array(
    'tolower' => 'strtolower',
    'tolowerlambda' => function ($args, $less) {
      return strtolower($args[2][0]);
    }
  ),
);

There are two new hooks: hook_less_variables() and hook_less_functions(). Both should return an array like their respective parts of the above code sample.

There is a new function: less_get_settings($system_name). This allows you to get the less settings for a module or theme.

This could be used if you have a module package, where you have several modules that should all use the same styling. You can set the styling in one module and the other modules can pull those settings in.

Any .less file that is specified in a module/theme's .info file will automatically have the settings from that module/theme included.

Comments

jay.dansand’s picture

Looks awesome, thanks for the work! I haven't had a chance to test it yet, but just a note regarding CRC32: there's a lot of room for collisions in that tiny 32-bit space (75,000 discrete inputs have 50% chance of colliding, but it converges near 100% every 175,000 inputs, roughly). For example, these two hilarious variables collide:

// Assuming @plumless and @buckeroo were somehow defined elsewhere in the .less file or something.
// This is very much a toy example.
dechex(crc32('@color: @plumless')); // a6bfe545
dechex(crc32('@color: @buckeroo')); // also a6bfe545

That would be more frustrating than a performance hit from using SHA1 or (better yet SHA-256). If that's the choice, I'll gladly drop any objections in favor of SHA. As you pointed out in #1543276: Support passing/defining LESS variables/functions via drupal_add_css() and theme.info, drupal_build_css_cache() uses SHA-256, so I'd say if you're going the hash route, use that. The output space is huge and will probably never collide under normal use. That said, SHA1 is faster and rsync/etc. content-based-addressing systems use SHA1 with the assumption that collisions are nonexistent, so that's arguably a good option too, though not as collision-resistant.

corey.aufang’s picture

Looking through the code, core uses drupal_hash_base64(), which I agree should be the go-to standard for hashing of this nature.

On the performance front, when a file exists the entire process is taking less than 1ms to complete, but that is a limited test on my machine which is a bit overkill, so results from others would be most useful.

Also, if anyone has a good idea for the demo HTML page, something that's prettier and more demonstrative of what's possible with LESS, please post.

corey.aufang’s picture

Right now only settings from .info files are included on the theme configuration page.

Should we also include the data from hook_less_variables()?

If we include hook_less_variables() it makes it a little easier and "prettier" to have many settings bundled with your theme/module without adding to .info bloat. We would also have to specify that it functions similar to how hook_menu works in that this information is cached. They could include their definitions in another file and specify a hook_hook_info() to only include when rebuild cache.

Also, hook_less_functions() could not be cached due to the possibility of lambda functions being used.

Should we also have a drupal_alter() call on the variables and functions? This would allow users to alter other theme/module's defaults.

I would also appreciate any feedback or questions that people have on this new functionality.

jay.dansand’s picture

I'm always in favor of adding more hooks to let modules extend each other, so drupal_alter() sounds perfect.

I don't know about configuring what feels like code-derived settings (from hook_less_variables) via the theme configuration page; it feels like any potential for configuration should be left to the hook_less_variables-implementing module to provide via theme configuration form alter, or the module's own settings pages. If you do end up allowing a generic settings form to override module code, you'd probably want to do what Views does and clearly mark such settings as "database overriding code", with the option to "revert".

corey.aufang’s picture

I was thinking hook_less_variables is purely to described static defaults. Keep in mind that all settings are grouped by the theme/module system name as to avoid variable name collisions.

Sorta like this:

.info
hook_less_variables
theme configuration

Those 3 in order providing static content, with the resultant merged data cached for speed.

For dynamic content you would then have:

hook_less_variables_alter
drupal_add_css

The alter would have the static data passed in.
Settings from drupal_add_css would trump all other values, and if used, would be up to the user to make sure to merge in defaults using less_get_setting.

Functions would be similar, but only static caching:

hook_less_functions
hook_less_functions_alter

corey.aufang’s picture

Status: Active » Needs review

Please check out the latest beta.

If you are still finding problems, please retag this issue with the new version as all future development for D7 will be on the 7.x-3.x branch.

corey.aufang’s picture

Version: 7.x-2.x-dev » 7.x-3.x-dev
Category: feature » task

Functionality is pretty well solidified.

Check out the latest 7.x-3.x dev.

refaktor’s picture

Please delete this comment.

corey.aufang’s picture

The less_demo module contained within the 7.x-3.0 release of LESS contains working examples of both variables and functions.

There is also the less.api.php in the main module folder has more detailed hook documentation.

Also, you can't just pass in native php functions since they will not match the arguments profile that lessphp is expecting.

corey.aufang’s picture

Status: Needs review » Fixed

This should be resolved in 7.x-3.0.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.