PDF rausgenommen
This commit is contained in:
447
msd2/tracking/piwik/vendor/leafo/lessphp/lessify.inc.php
vendored
Normal file
447
msd2/tracking/piwik/vendor/leafo/lessphp/lessify.inc.php
vendored
Normal file
@ -0,0 +1,447 @@
|
||||
<?php
|
||||
/**
|
||||
* lessify
|
||||
* Convert a css file into a less file
|
||||
* http://leafo.net/lessphp
|
||||
* Copyright 2010, leaf corcoran <leafot@gmail.com>
|
||||
*
|
||||
* WARNING: THIS DOES NOT WORK ANYMORE. NEEDS TO BE UPDATED FOR
|
||||
* LATEST VERSION OF LESSPHP.
|
||||
*
|
||||
*/
|
||||
|
||||
require "lessc.inc.php";
|
||||
|
||||
//
|
||||
// check if the merge during mixin is overwriting values. should or should it not?
|
||||
//
|
||||
|
||||
//
|
||||
// 1. split apart class tags
|
||||
//
|
||||
|
||||
class easyparse {
|
||||
var $buffer;
|
||||
var $count;
|
||||
|
||||
function __construct($str) {
|
||||
$this->count = 0;
|
||||
$this->buffer = trim($str);
|
||||
}
|
||||
|
||||
function seek($where = null) {
|
||||
if ($where === null) return $this->count;
|
||||
else $this->count = $where;
|
||||
return true;
|
||||
}
|
||||
|
||||
function preg_quote($what) {
|
||||
return preg_quote($what, '/');
|
||||
}
|
||||
|
||||
function match($regex, &$out, $eatWhitespace = true) {
|
||||
$r = '/'.$regex.($eatWhitespace ? '\s*' : '').'/Ais';
|
||||
if (preg_match($r, $this->buffer, $out, null, $this->count)) {
|
||||
$this->count += strlen($out[0]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function literal($what, $eatWhitespace = true) {
|
||||
// this is here mainly prevent notice from { } string accessor
|
||||
if ($this->count >= strlen($this->buffer)) return false;
|
||||
|
||||
// shortcut on single letter
|
||||
if (!$eatWhitespace and strlen($what) == 1) {
|
||||
if ($this->buffer{$this->count} == $what) {
|
||||
$this->count++;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
return $this->match($this->preg_quote($what), $m, $eatWhitespace);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class tagparse extends easyparse {
|
||||
static private $combinators = null;
|
||||
static private $match_opts = null;
|
||||
|
||||
function parse() {
|
||||
if (empty(self::$combinators)) {
|
||||
self::$combinators = '('.implode('|', array_map(array($this, 'preg_quote'),
|
||||
array('+', '>', '~'))).')';
|
||||
self::$match_opts = '('.implode('|', array_map(array($this, 'preg_quote'),
|
||||
array('=', '~=', '|=', '$=', '*='))).')';
|
||||
}
|
||||
|
||||
// crush whitespace
|
||||
$this->buffer = preg_replace('/\s+/', ' ', $this->buffer).' ';
|
||||
|
||||
$tags = array();
|
||||
while ($this->tag($t)) $tags[] = $t;
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
static function compileString($string) {
|
||||
list(, $delim, $str) = $string;
|
||||
$str = str_replace($delim, "\\".$delim, $str);
|
||||
$str = str_replace("\n", "\\\n", $str);
|
||||
return $delim.$str.$delim;
|
||||
}
|
||||
|
||||
static function compilePaths($paths) {
|
||||
return implode(', ', array_map(array('self', 'compilePath'), $paths));
|
||||
}
|
||||
|
||||
// array of tags
|
||||
static function compilePath($path) {
|
||||
return implode(' ', array_map(array('self', 'compileTag'), $path));
|
||||
}
|
||||
|
||||
|
||||
static function compileTag($tag) {
|
||||
ob_start();
|
||||
if (isset($tag['comb'])) echo $tag['comb']." ";
|
||||
if (isset($tag['front'])) echo $tag['front'];
|
||||
if (isset($tag['attr'])) {
|
||||
echo '['.$tag['attr'];
|
||||
if (isset($tag['op'])) {
|
||||
echo $tag['op'].$tag['op_value'];
|
||||
}
|
||||
echo ']';
|
||||
}
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
function string(&$out) {
|
||||
$s = $this->seek();
|
||||
|
||||
if ($this->literal('"')) {
|
||||
$delim = '"';
|
||||
} elseif ($this->literal("'")) {
|
||||
$delim = "'";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// step through letters looking for either end or escape
|
||||
$buff = "";
|
||||
$escapeNext = false;
|
||||
$finished = false;
|
||||
for ($i = $this->count; $i < strlen($this->buffer); $i++) {
|
||||
$char = $this->buffer[$i];
|
||||
switch ($char) {
|
||||
case $delim:
|
||||
if ($escapeNext) {
|
||||
$buff .= $char;
|
||||
$escapeNext = false;
|
||||
break;
|
||||
}
|
||||
$finished = true;
|
||||
break 2;
|
||||
case "\\":
|
||||
if ($escapeNext) {
|
||||
$buff .= $char;
|
||||
$escapeNext = false;
|
||||
} else {
|
||||
$escapeNext = true;
|
||||
}
|
||||
break;
|
||||
case "\n":
|
||||
if (!$escapeNext) {
|
||||
break 3;
|
||||
}
|
||||
|
||||
$buff .= $char;
|
||||
$escapeNext = false;
|
||||
break;
|
||||
default:
|
||||
if ($escapeNext) {
|
||||
$buff .= "\\";
|
||||
$escapeNext = false;
|
||||
}
|
||||
$buff .= $char;
|
||||
}
|
||||
}
|
||||
if (!$finished) break;
|
||||
$out = array('string', $delim, $buff);
|
||||
$this->seek($i+1);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->seek($s);
|
||||
return false;
|
||||
}
|
||||
|
||||
function tag(&$out) {
|
||||
$s = $this->seek();
|
||||
$tag = array();
|
||||
if ($this->combinator($op)) $tag['comb'] = $op;
|
||||
|
||||
if (!$this->match('(.*?)( |$|\[|'.self::$combinators.')', $match)) {
|
||||
$this->seek($s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($match[3])) {
|
||||
// give back combinator
|
||||
$this->count-=strlen($match[3]);
|
||||
}
|
||||
|
||||
if (!empty($match[1])) $tag['front'] = $match[1];
|
||||
|
||||
if ($match[2] == '[') {
|
||||
if ($this->ident($i)) {
|
||||
$tag['attr'] = $i;
|
||||
|
||||
if ($this->match(self::$match_opts, $m) && $this->value($v)) {
|
||||
$tag['op'] = $m[1];
|
||||
$tag['op_value'] = $v;
|
||||
}
|
||||
|
||||
if ($this->literal(']')) {
|
||||
$out = $tag;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (isset($tag['front'])) {
|
||||
$out = $tag;
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->seek($s);
|
||||
return false;
|
||||
}
|
||||
|
||||
function ident(&$out) {
|
||||
// [-]?{nmstart}{nmchar}*
|
||||
// nmstart: [_a-z]|{nonascii}|{escape}
|
||||
// nmchar: [_a-z0-9-]|{nonascii}|{escape}
|
||||
if ($this->match('(-?[_a-z][_\w]*)', $m)) {
|
||||
$out = $m[1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function value(&$out) {
|
||||
if ($this->string($str)) {
|
||||
$out = $this->compileString($str);
|
||||
return true;
|
||||
} elseif ($this->ident($id)) {
|
||||
$out = $id;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function combinator(&$op) {
|
||||
if ($this->match(self::$combinators, $m)) {
|
||||
$op = $m[1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class nodecounter {
|
||||
var $count = 0;
|
||||
var $children = array();
|
||||
|
||||
var $name;
|
||||
var $child_blocks;
|
||||
var $the_block;
|
||||
|
||||
function __construct($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function dump($stack = null) {
|
||||
if (is_null($stack)) $stack = array();
|
||||
$stack[] = $this->getName();
|
||||
echo implode(' -> ', $stack)." ($this->count)\n";
|
||||
foreach ($this->children as $child) {
|
||||
$child->dump($stack);
|
||||
}
|
||||
}
|
||||
|
||||
static function compileProperties($c, $block) {
|
||||
foreach($block as $name => $value) {
|
||||
if ($c->isProperty($name, $value)) {
|
||||
echo $c->compileProperty($name, $value)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compile($c, $path = null) {
|
||||
if (is_null($path)) $path = array();
|
||||
$path[] = $this->name;
|
||||
|
||||
$isVisible = !is_null($this->the_block) || !is_null($this->child_blocks);
|
||||
|
||||
if ($isVisible) {
|
||||
echo $c->indent(implode(' ', $path).' {');
|
||||
$c->indentLevel++;
|
||||
$path = array();
|
||||
|
||||
if ($this->the_block) {
|
||||
$this->compileProperties($c, $this->the_block);
|
||||
}
|
||||
|
||||
if ($this->child_blocks) {
|
||||
foreach ($this->child_blocks as $block) {
|
||||
echo $c->indent(tagparse::compilePaths($block['__tags']).' {');
|
||||
$c->indentLevel++;
|
||||
$this->compileProperties($c, $block);
|
||||
$c->indentLevel--;
|
||||
echo $c->indent('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compile child nodes
|
||||
foreach($this->children as $node) {
|
||||
$node->compile($c, $path);
|
||||
}
|
||||
|
||||
if ($isVisible) {
|
||||
$c->indentLevel--;
|
||||
echo $c->indent('}');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getName() {
|
||||
if (is_null($this->name)) return "[root]";
|
||||
else return $this->name;
|
||||
}
|
||||
|
||||
function getNode($name) {
|
||||
if (!isset($this->children[$name])) {
|
||||
$this->children[$name] = new nodecounter($name);
|
||||
}
|
||||
|
||||
return $this->children[$name];
|
||||
}
|
||||
|
||||
function findNode($path) {
|
||||
$current = $this;
|
||||
for ($i = 0; $i < count($path); $i++) {
|
||||
$t = tagparse::compileTag($path[$i]);
|
||||
$current = $current->getNode($t);
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
function addBlock($path, $block) {
|
||||
$node = $this->findNode($path);
|
||||
if (!is_null($node->the_block)) throw new exception("can this happen?");
|
||||
|
||||
unset($block['__tags']);
|
||||
$node->the_block = $block;
|
||||
}
|
||||
|
||||
function addToNode($path, $block) {
|
||||
$node = $this->findNode($path);
|
||||
$node->child_blocks[] = $block;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a less file from a css file by combining blocks where appropriate
|
||||
*/
|
||||
class lessify extends lessc {
|
||||
public function dump() {
|
||||
print_r($this->env);
|
||||
}
|
||||
|
||||
public function parse($str = null) {
|
||||
$this->prepareParser($str ? $str : $this->buffer);
|
||||
while (false !== $this->parseChunk());
|
||||
|
||||
$root = new nodecounter(null);
|
||||
|
||||
// attempt to preserve some of the block order
|
||||
$order = array();
|
||||
|
||||
$visitedTags = array();
|
||||
foreach (end($this->env) as $name => $block) {
|
||||
if (!$this->isBlock($name, $block)) continue;
|
||||
if (isset($visitedTags[$name])) continue;
|
||||
|
||||
foreach ($block['__tags'] as $t) {
|
||||
$visitedTags[$t] = true;
|
||||
}
|
||||
|
||||
// skip those with more than 1
|
||||
if (count($block['__tags']) == 1) {
|
||||
$p = new tagparse(end($block['__tags']));
|
||||
$path = $p->parse();
|
||||
$root->addBlock($path, $block);
|
||||
$order[] = array('compressed', $path, $block);
|
||||
continue;
|
||||
} else {
|
||||
$common = null;
|
||||
$paths = array();
|
||||
foreach ($block['__tags'] as $rawtag) {
|
||||
$p = new tagparse($rawtag);
|
||||
$paths[] = $path = $p->parse();
|
||||
if (is_null($common)) $common = $path;
|
||||
else {
|
||||
$new_common = array();
|
||||
foreach ($path as $tag) {
|
||||
$head = array_shift($common);
|
||||
if ($tag == $head) {
|
||||
$new_common[] = $head;
|
||||
} else break;
|
||||
}
|
||||
$common = $new_common;
|
||||
if (empty($common)) {
|
||||
// nothing in common
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($common)) {
|
||||
$new_paths = array();
|
||||
foreach ($paths as $p) $new_paths[] = array_slice($p, count($common));
|
||||
$block['__tags'] = $new_paths;
|
||||
$root->addToNode($common, $block);
|
||||
$order[] = array('compressed', $common, $block);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$order[] = array('none', $block['__tags'], $block);
|
||||
}
|
||||
|
||||
|
||||
$compressed = $root->children;
|
||||
foreach ($order as $item) {
|
||||
list($type, $tags, $block) = $item;
|
||||
if ($type == 'compressed') {
|
||||
$top = tagparse::compileTag(reset($tags));
|
||||
if (isset($compressed[$top])) {
|
||||
$compressed[$top]->compile($this);
|
||||
unset($compressed[$top]);
|
||||
}
|
||||
} else {
|
||||
echo $this->indent(implode(', ', $tags).' {');
|
||||
$this->indentLevel++;
|
||||
nodecounter::compileProperties($this, $block);
|
||||
$this->indentLevel--;
|
||||
echo $this->indent('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user