Skip to content

Instantly share code, notes, and snippets.

@mturjak
Last active August 29, 2015 13:57
Show Gist options
  • Save mturjak/9684082 to your computer and use it in GitHub Desktop.
Save mturjak/9684082 to your computer and use it in GitHub Desktop.
lessphp lessc_invert class for inverting colors, except for 'shadow' properties
<?php
/* extends lessphp's lessc class */
class lessc_invert extends lessc {
private $f = 1;
protected function invert_color($c, $f){
if($f)
return abs($c - 255);
return $c;
}
protected function compileProp($prop, $block, $out) {
$this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
switch ($prop[0]) {
case 'assign':
list(, $name, $value) = $prop;
if ($name[0] == $this->vPrefix) {
$this->set($name, $value);
} else {
$this->f = preg_match('/shadow/',$name) ? 0 : 1;
$out->lines[] = $this->formatter->property($name,
$this->compileValue($this->reduce($value)));
}
break;
case 'block':
list(, $child) = $prop;
$this->compileBlock($child);
break;
case 'mixin':
list(, $path, $args, $suffix) = $prop;
$orderedArgs = array();
$keywordArgs = array();
foreach ((array)$args as $arg) {
$argval = null;
switch ($arg[0]) {
case "arg":
if (!isset($arg[2])) {
$orderedArgs[] = $this->reduce(array("variable", $arg[1]));
} else {
$keywordArgs[$arg[1]] = $this->reduce($arg[2]);
}
break;
case "lit":
$orderedArgs[] = $this->reduce($arg[1]);
break;
default:
$this->throwError("Unknown arg type: " . $arg[0]);
}
}
$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
if ($mixins === null) {
$this->throwError("{$prop[1][0]} is undefined");
}
foreach ($mixins as $mixin) {
if ($mixin === $block && !$orderedArgs) {
continue;
}
$haveScope = false;
if (isset($mixin->parent->scope)) {
$haveScope = true;
$mixinParentEnv = $this->pushEnv();
$mixinParentEnv->storeParent = $mixin->parent->scope;
}
$haveArgs = false;
if (isset($mixin->args)) {
$haveArgs = true;
$this->pushEnv();
$this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
}
$oldParent = $mixin->parent;
if ($mixin != $block) $mixin->parent = $block;
foreach ($this->sortProps($mixin->props) as $subProp) {
if ($suffix !== null &&
$subProp[0] == "assign" &&
is_string($subProp[1]) &&
$subProp[1]{0} != $this->vPrefix)
{
$subProp[2] = array(
'list', ' ',
array($subProp[2], array('keyword', $suffix))
);
}
$this->compileProp($subProp, $mixin, $out);
}
$mixin->parent = $oldParent;
if ($haveArgs) $this->popEnv();
if ($haveScope) $this->popEnv();
}
break;
case 'raw':
$out->lines[] = $prop[1];
break;
case "directive":
list(, $name, $value) = $prop;
$out->lines[] = "@$name " . $this->compileValue($this->reduce($value)).';';
break;
case "comment":
$out->lines[] = $prop[1];
break;
case "import";
list(, $importPath, $importId) = $prop;
$importPath = $this->reduce($importPath);
if (!isset($this->env->imports)) {
$this->env->imports = array();
}
$result = $this->tryImport($importPath, $block, $out);
$this->env->imports[$importId] = $result === false ?
array(false, "@import " . $this->compileValue($importPath).";") :
$result;
break;
case "import_mixin":
list(,$importId) = $prop;
$import = $this->env->imports[$importId];
if ($import[0] === false) {
if (isset($import[1])) {
$out->lines[] = $import[1];
}
} else {
list(, $bottom, $parser, $importDir) = $import;
$this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
}
break;
default:
$this->throwError("unknown op: {$prop[0]}\n");
}
}
protected function compileValue($value) {
$f = $this->f;
switch ($value[0]) {
case 'list':
return implode($value[1], array_map(array($this, 'compileValue'), $value[2]));
case 'raw_color':
return $this->compileValue($this->coerceColor($value));
case 'keyword':
if (isset(self::$cssColors[$value[1]])) {
return $this->compileValue($this->coerceColor($value));
}
return $value[1];
case 'number':
list(, $num, $unit) = $value;
if ($this->numberPrecision !== null) {
$num = round($num, $this->numberPrecision);
}
return $num . $unit;
case 'string':
list(, $delim, $content) = $value;
foreach ($content as &$part) {
if (is_array($part)) {
$part = $this->compileValue($part);
}
}
return $delim . implode($content) . $delim;
case 'color':
list(, $r, $g, $b) = $value;
$r = $this->invert_color(round($r),$f);
$g = $this->invert_color(round($g),$f);
$b = $this->invert_color(round($b),$f);
if (count($value) == 5 && $value[4] != 1) {
return 'rgba('.$r.','.$g.','.$b.','.$value[4].')';
}
$h = sprintf("#%02x%02x%02x", $r, $g, $b);
if (!empty($this->formatter->compressColors)) {
if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
$h = '#' . $h[1] . $h[3] . $h[5];
}
}
return $h;
case 'function':
list(, $name, $args) = $value;
return $name.'('.$this->compileValue($args).')';
default:
$this->throwError("unknown value type: $value[0]");
}
}
}
/* example */
$less = new lessc_invert;
$less->setFormatter("compressed");
echo $less->compile("
a {
color: red;
text-shadow: 1px 1px #005;
}
");
a{color:#0ff;text-shadow:1px 1px #005;}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment