GithubHelp home page GithubHelp logo

kohana-less's Introduction

KO3 LESS Module v.1.1.1

LESS Module is a port of Leaf Corcoran's LESSPHP for Kohana 3 It adopts some of Alex Sancho's Kohana 2.3 Assets Module codes for CSS compression, credits goes to them Thanks to cheeaun for helping out! You might also want to check out another implementation from jeremeamia.

To Use

  1. Put the less module folder in your Modules directory
  2. Include less module in your application's bootstrap: 'less' => MODPATH.'less'
  3. Copy the less config file from /modules/less/config/less.php to your application's config directory
  4. From your less.php config file, put the 'path' to where you want the CSS files compiled / compressed, the folder must be writable
  5. You can set 'compress' to TRUE on your less.php config file if you want your CSS files to be combined in to one file and compressed (to lessen server calls)

Sample Code

Default less files extension is set in Less::$extension and is .less.

** MODPATH/baseModule/media/css/layout.less **

	@bodyBkgColor: #EEE;

	body {
		background: @bodyBkgColor;
		margin:0;
		padding:0;

		h1 { font-size: 3em; }
	}

** APPPATH/media/css/style.less **

	@divBkgColor: #DDD;

	.roundedCorners (@radius:8px) {
		-moz-border-radius:@radius;
		-webkit-border-radius:@radius;
		border-radius:@radius;
		zoom:1;
	}

	div {
		background: @divBkgColor;
		.roundedCorners;

		p { .roundedCorners(5px); }
	}

** APPPATH/config/less.php **

	return array(
		// relative PATH to a writable folder to store compiled / compressed css
		// path below will be treated as: DOCROOT . 'media/css/'
		'path'     => 'media/css/',
		'compress' => TRUE,
	);

** In your controller **

	class Controller_Sample extends Controller_Template {

		public $template = 'template';

		public function action_example1()
		{
			// no need to add .less extension
			// you can put your less files anywhere
			$less_files = array
			(
				MODPATH.'baseModule/media/css/layout.less',
				APPPATH.'media/css/style',
			);

			$this->template->stylesheet = Less::compile($less_files);
		}

		public function action_example2()
		{
			// you can pass just single file
			
			$this->template->stylesheet = Less::compile(APPPATH.'media/css/style');
		}
	}

** In your template **

	<html>
	<head>
		<title>LESS for Kohana</title>
		<?= $stylesheet; // will give me ONE compressed css file located in /media/css/ ?>
	</head>
	<body>
		<h1>LESS for Kohana or Kohana for LESS?</h1>
	</body>
	</html>

Issues

Please report it to the issues tracker..

kohana-less's People

Contributors

lkay avatar danhulton avatar oreolek avatar

Stargazers

Michaël Marinetti avatar felipe bastos avatar Nathan avatar Jonathan Reyes avatar  avatar Robbie Mackay avatar Radision avatar  avatar David Stutz avatar Michael Fielding avatar Dan avatar Joe Palala avatar Ronni Egeriis Persson avatar  avatar Adam Davis avatar Bartłomiej Kuleszewicz avatar Evgeny Kovalev avatar Jean Rodrigues avatar  avatar Mike Branderhorst avatar Tommy Johansen avatar Matt Oakley avatar Sam IT avatar Ralf Blumenthal avatar Martino di Filippo avatar Adam Liwski avatar Matthias avatar  avatar Shawn Sprehe avatar Ziopod avatar ÐΛИIΞL MΔCΞDѲ avatar  avatar Sergey Storchay avatar Joan P. avatar Choon Kee Oh avatar Mon Geslani avatar Brandon Summers avatar Paul (xobb) Chubatyy avatar Luiz Alberto S. Ribeiro avatar John Kramlich avatar Sebastián Cruz avatar Paul Dixon avatar Michael Lavers avatar Eric Winther avatar

Watchers

Mon Geslani avatar James Cloos avatar

kohana-less's Issues

Redundant variable

Variable on L100 in less/core.php is not required

    // create data holder
    $data = '';

Module should check if cache directory is writable on initialization

Much like Kohana does for cache and logs, this module should ensure the cache directory is writable on startup. To that end, init.php should read like so:

<?php defined('SYSPATH') OR die('No direct access allowed.');

$less_cache_path = DOCROOT . Kohana::config('less.path');

if ( ! is_writable($less_cache_path)) {
    throw new Kohana_Exception('Directory :dir must be writable',
        array(':dir' => Kohana::debug_path($less_cache_path)));
}

require_once 'vendor/lessphp/lessc.inc.php';

Using 'compress' breaks @import in the less files

By having

'compress' => TRUE

the function _combine() passes the generated, and relative path, to

public static function _compile($filename)
{
    $less = new lessc($filename);
    try {
        $compiled = $less->parse();
    ...

whereas a path to the less file is expected.

Of course the compressed file can be made up of several files, from any number of directories, but we can only choose one directory for any less @imports to be made from.

I solved this by setting a 'compressed_import_dir' in the config file and adding these lines;

    $less = new lessc();
    $less->importDir = self::$config['compressed_import_dir'];

Hope that helps.

Issues with Windows system?

Don't know if it is because I am using Windows but using your readme as an example I am having issues.

Config is...
return array
(
'compress' => FALSE,
'path' => 'public/less/',
)

Your example had
$stylesheets = array('/media/css/reset.less', '/media/css/style.less');
but apparently it seems it auto-adds the $config->path and the .less extension so it seems it should of been
$stylesheets = array('reset', 'style');

And I don't know if it is because I am on Windows but it couldn't find the files. So I modified the code where mainly it says $config->path.$filename or similar to add the DOCROOT so basically it becomes DOCROOT.$config->path.$filename.

Can't include CSS files

I've found one of the real useful bits of this module is including separate files and having it compile them all down into one CSS file. However, I have a lot of existing CSS files being updated by third parties, and renaming them isn't an attractive option.

Instead, it would be nice if raw CSS files were allowed to be compiled as well. The nice thing about LESS is that it EXTENDS CSS, so raw CSS files should compile just as well as LESS files.

To that end, I modified a few functions:

<?php defined('SYSPATH') or die('No direct script access.');

/**
 * Modification of Less_Core to allow for CSS files to be "compiled" as well.
 */
class Less extends Less_Core {
    /**
     * Get the link tag of less paths
     *
     * @param   array     array of css paths
     * @param   string    value of media css type
     * @param   boolean   allow compression
     * @return  string    link tag pointing to the css paths
     */
    public static function compile($array = array(), $media = 'screen')
    {
        // return comment if array is empty
        if (empty($array)) return self::_html_comment('no less files');

        $stylesheets = array();
        $assets = array();

        // validate
        foreach ($array as $file)
        {
            // remove extension if its present
            $file = preg_replace('/\.less/', '', $file);
            if (file_exists($file.'.less'))
            {
                array_push($stylesheets, $file . '.less');
            }
            else
            {
                // Might be a CSS file
                $file = preg_replace('/\.css/', '', $file);
                if (file_exists($file . '.css')) {
                    array_push($stylesheets, $file . '.css');
                }
                // Welp, couldn't find it
                else {
                    Kohana::$log->add("ERROR", "Could not find LESS/CSS file: $file");
                    array_push($assets, self::_html_comment('could not find '.Kohana::debug_path($file).'.less'));
                }
            }
        }

        // all stylesheets are invalid
        if ( ! count($stylesheets)) return self::_html_comment('all less files are invalid');

        // get less config
        $config = Kohana::config('less');

        // if compression is allowed
        if ($config['compress'])
        {
            return html::style(self::_combine($stylesheets), array('media' => $media));
        }

        // if no compression
        foreach ($stylesheets as $file)
        {
            $filename = self::_get_filename($file, $config['path']);
            array_push($assets, html::style($filename, array('media' => $media)));
        }

        return implode("\n", $assets);
    }

    /**
     * Check if the asset exists already, if not generate an asset
     *
     * @param   string   path of the css file
     * @return  string   path to the asset file
     */
    protected static function _get_filename($file, $path)
    {
        // get the filename
        $filename = preg_replace('/^.+\//', '', $file);

        // get the last modified date
        $last_modified = self::_get_last_modified(array($file));

        // compose the expected filename to store in /media/css
        $compiled = $filename.'-'.$last_modified.'.css';

        // compose the expected file path
        $filename = $path.$compiled;

        // if the file exists no need to generate
        if ( ! file_exists($filename))
        {
            // create data holder
            $data = '';

            touch($filename, filemtime($file) - 3600);

            lessc::ccompile($file, $filename);
        }

        return $filename;
    }

    /**
     * Combine the files
     *
     * @param   array    array of asset files
     * @return  string   path to the asset file
     */
    protected static function _combine($files)
    {
        // get assets' css config
        $config = Kohana::config('less');

        // get the most recent modified time of any of the files
        $last_modified = self::_get_last_modified($files);

        // compose the asset filename
        $compiled = md5(implode('|', $files)).'-'.$last_modified.'.css';

        // compose the path to the asset file
        $filename = $config['path'].$compiled;

        // if the file exists no need to generate
        if ( ! file_exists($filename))
        {
            self::_generate_assets($filename, $files);
        }

        return $filename;
    }

    /**
     * Generate an asset file
     *
     * @param   string   filename of the asset file
     * @param   array    array of source files
     */
    protected static function _generate_assets($filename, $files)
    {
        // create data holder
        $data = '';

        touch($filename);

        ob_start();

        foreach($files as $file)
        {
            $data .= file_get_contents($file);
        }

        echo $data;

        file_put_contents($filename, ob_get_clean(), LOCK_EX);

        self::_compile($filename);
    }

    /**
     * Get the most recent modified date of files
     *
     * @param   array    array of asset files
     * @return  string   path to the asset file
     */
    protected static function _get_last_modified($files)
    {
        $last_modified = 0;

        foreach ($files as $file) 
        {
            $modified = filemtime($file);
            if ($modified !== false and $modified > $last_modified) $last_modified = $modified;
        }

        return $last_modified;
    }
}

In short, in the compile() function, I check for less files, and if they exist, add them to the $stylesheets array with the ".less" extension appended here instead of every other time throughout the file. Then I do the same thing with CSS files.

The other functions I included because a) I removed the ".less" extension append, or b) they were part of Less_Core and called self::somefunction(), which called the un-fixed variant in Less_Core, not the fixed one in Less.

public static function _compile($filename) is redundant

The _generate_assets() method writes the concatenated less file which is then overwritten by the _compile() method with the compiled and compressed css file.

The contents of the concatenation ($data) could simply be passed to parse

$less->parse($data);

(Note $less->importDir will need to be set for @import 'lessfile' to work.)

I rewrote it as a single function and can post the code or create a pull request if you like,.
Cheers and thanks for all of your work.

Imported stylesheets does not trigger new compilations

Hi!

I'm currently testing out Twitter Bootstrap for Less, and at the core is the single file that ties all the stylesheets together with regular css imports:

 // CSS Reset
 @import "reset.less";

 // Core variables and mixins
 @import "variables.less"; // Modify this for custom colors, font-sizes, etc
 @import "mixins.less";

// ...

And this compiles just fine, but if I e.g. modify mixins.less it won't trigger a recompile as it seems only the files specified to the module directly will do so.

Of couse, one can just tell the Less module about the imports directly, but it would be nice if it were supported directly.

Any thoughts on this? :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.