Permalink
Browse files

introduce php css-xfire handler

  • Loading branch information...
0 parents commit 49bce6fb926889fa8cadd12563a81d56d4734bea @docteurklein committed Dec 12, 2011
Showing with 458 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +15 −0 .gitmodules
  3. +161 −0 CssManipulator.php
  4. +26 −0 README.md
  5. +13 −0 autoload.php
  6. +5 −0 dirs.php.dist
  7. +54 −0 index.php
  8. +142 −0 tests/index.html
  9. +37 −0 tests/test.css
  10. +1 −0 vendor/Symfony/Component/ClassLoader
  11. +1 −0 vendor/Symfony/Component/Finder
  12. +1 −0 vendor/css-parser
@@ -0,0 +1,2 @@
+css.log
+dirs.php
@@ -0,0 +1,15 @@
+[submodule "vendor/css-parser"]
+ path = vendor/css-parser
+ url = https://github.com/sabberworm/PHP-CSS-Parser.git
+[submodule "vendor/Finder"]
+ path = vendor/Finder
+ url = https://github.com/symfony/Finder.git
+[submodule "vendor/class-loader"]
+ path = vendor/class-loader
+ url = https://github.com/symfony/ClassLoader.git
+[submodule "vendor/Symfony/Component/Finder"]
+ path = vendor/Symfony/Component/Finder
+ url = https://github.com/symfony/Finder.git
+[submodule "vendor/Symfony/Component/ClassLoader"]
+ path = vendor/Symfony/Component/ClassLoader
+ url = https://github.com/symfony/ClassLoader.git
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * CSS rules manipulator
+ *
+ * @author Florian Klein <florian.klein@free.fr>
+ */
+class CssManipulator
+{
+ /**
+ * __construct
+ *
+ * @param CSSDocument $css
+ */
+ public function __construct(CSSDocument $css, \Closure $logger = null)
+ {
+ $this->css = $css;
+ $this->logger = $logger;
+ }
+
+ private function log()
+ {
+ if(null !== $logger = $this->logger) {
+ $logger(print_r(func_get_args(), true));
+ }
+ }
+
+ /**
+ * createRule
+ *
+ * @param mixed $propery
+ * @param mixed $value
+ * @param mixed $important
+ * @return void
+ */
+ public function createRule($propery, $value = null, $important = false)
+ {
+ $rule = new CSSRule($property);
+ $rule->setValue($value);
+
+ return $rule;
+ }
+
+ /**
+ * createDeclarationBlock
+ *
+ * @param mixed $selector
+ * @return void
+ */
+ public function createDeclarationBlock($selector)
+ {
+ $declaration = new CSSDeclarationBlock();
+ $declaration->setSelectors($selector);
+
+ return $declaration;
+ }
+
+ /**
+ * addDeclarationBlock
+ *
+ * @param CSSDeclarationBlock $declaration
+ * @return void
+ */
+ public function addDeclarationBlock(CSSDeclarationBlock $declaration)
+ {
+ $this->log('adding ', $declaration);
+ $this->css->append($declaration);
+ }
+
+ /**
+ * removeDeclarationBlocks removes declaration blocks that match **exactly** the selector
+ *
+ * @param CSSSelector $selector
+ * @return void
+ */
+ public function removeDeclarationBlocks(CSSSelector $selector)
+ {
+ $this->log('remove ', $selector);
+ foreach($this->css->getAllDeclarationBlocks() as $declaration) {
+ $this->log('trying ', $selector, $declaration->getSelectors());
+ if($this->hasSelector($declaration, $selector)) {
+ $this->css->remove($declaration);
+ $this->log('removing ', $declaration);
+ }
+ }
+ }
+
+ /**
+ * addRules add rule to all blocks that match selector, or create one if no match
+ *
+ * @param CSSSelector $selector
+ * @param CSSRule $rule
+ * @return void
+ */
+ public function addRule(CSSSelector $selector, CSSRule $rule)
+ {
+ $this->log('add ', $rule, ' to ', $selector);
+ $found = false;
+ foreach($this->css->getAllDeclarationBlocks() as $declaration) {
+ if($this->hasSelector($declaration, $selector)) {
+ if ($rule->getValue()) {
+ $this->log('adding ', $rule, ' to ', $declaration);
+ $declaration->addRule($rule);
+ }
+ $found = true;
+ }
+ }
+
+ if (!$found) {
+ $declaration = $this->createDeclarationBlock((string)$selector);
+ if ($rule->getValue()) {
+ $this->log('adding ', $rule, ' to ', $declaration);
+ $declaration->addRule($rule);
+ }
+ $this->addDeclarationBlock($declaration);
+ }
+ }
+
+ /**
+ * removeRules
+ *
+ * @param CSSSelector $selector
+ * @param CSSRule $rule
+ * @return void
+ */
+ public function removeRule(CSSSelector $selector, CSSRule $rule)
+ {
+ $this->log('remove ', $rule);
+ foreach($this->css->getAllDeclarationBlocks() as $declaration) {
+ if($this->hasSelector($declaration, $selector)) {
+ $declaration->removeRule($rule->getRule());
+ $this->log('removing ', $rule);
+ }
+ }
+ }
+
+ private function hasSelector(CSSDeclarationBlock $declaration, CSSSelector $selector)
+ {
+ foreach($declaration->getSelectors() as $compare) {
+ if((string)$selector === (string)$compare) {
+ $this->log('found that ', (string)$selector, ' equals ', (string)$compare);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * save
+ *
+ * @param mixed $path
+ * @return boolean
+ */
+ public function save($path)
+ {
+ $this->log('saving to ', $path);
+ return @file_put_contents($path, (string)$this->css);
+ }
+}
+
@@ -0,0 +1,26 @@
+# PHP css-xfire handler
+
+## Handle live css manipulation from firebug to modify css source files.
+
+### how-to
+
+* clone the project
+
+ git clone http://github.com/docteurklein/css-manipulator.git css-manipulator
+ cd css-manipulator
+ git submodule update --init
+
+ echo "<?php $dirs = array(__DIR__.'/css');" > dirs.php
+
+* make the index.php file accessible at something like `http://css.local:8080`
+
+* configure css-xfire extension
+ * launch firefox
+ * install firebug
+ * [install css-xfire](http://code.google.com/p/css-x-fire/wiki/Installation#Details)
+ * open ``about:config``
+ * configure ``extensions.cssxfire@cssxfire.*`` keys to fit your config
+
+* relaunch firefox
+* edit your css live!
+* observe the diff of your css files located in ``__DIR__.'/css'`` (depending on what you put in ``dirs.php``)
@@ -0,0 +1,13 @@
+<?php
+
+require 'vendor/css-parser/CSSParser.php';
+require 'CssManipulator.php';
+require 'vendor/Symfony/Component/ClassLoader/UniversalClassLoader.php';
+
+use Symfony\Component\ClassLoader\UniversalClassLoader;
+
+$loader = new UniversalClassLoader();
+$loader->registerNamespaces(array(
+ 'Symfony\\Component' => __DIR__.'/vendor',
+));
+$loader->register();
@@ -0,0 +1,5 @@
+<?php
+
+$dirs = array(
+ __DIR__.'/tests',
+);
@@ -0,0 +1,54 @@
+<?php
+
+require 'autoload.php';
+require 'dirs.php';
+
+use Symfony\Component\Finder\Finder;
+
+$finder = new Finder;
+
+$finder
+ ->files()
+ ->name('*.css')
+ ->in($dirs); // coming from dirs.php
+;
+
+$rule= new CSSRule(@$_GET['property']);
+$rule->setValue(@$_GET['value']);
+
+// $params is coming from firebug's css-xfire extension
+$params = array(
+ 'selector' => new CSSSelector(@$_GET['selector']),
+ 'rule' => $rule,
+ 'property' => @$_GET['property'],
+ 'value' => @$_GET['value'],
+ 'deleted' => @$_GET['deleted'] === 'true',
+ 'href' => @$_GET['href'],
+ 'media' => @$_GET['media'],
+);
+
+$fd = fopen('css.log','a');
+$logger = function($log) use($fd) {
+ fwrite($fd, $log);
+};
+
+foreach($finder as $file) {
+ $parser = new CSSParser(file_get_contents((string)$file));
+ $css = $parser->parse();
+
+ $manipulator = new CssManipulator($css, $logger);
+
+ if($params['deleted']) {
+ if($params['value']) {
+ $manipulator->removeRule($params['selector'], $params['rule']);
+ }
+ else {
+ $manipulator->removeDeclarationBlocks($params['selector']);
+ }
+ }
+ else {
+ $manipulator->addRule($params['selector'], $params['rule']);
+ }
+
+ $manipulator->save((string)$file);
+}
Oops, something went wrong. Retry.

0 comments on commit 49bce6f

Please sign in to comment.