Skip to content

Commit

Permalink
[Experimental/HtmlAttributes] Adds HTML attributes support
Browse files Browse the repository at this point in the history
* Emmet style HTML attributes inside a curly braces
* Related Ticket is #16

See test/Ciconia/Resources/html/* to get the usage
  • Loading branch information
kzykhys committed Jan 24, 2014
1 parent bf77eb2 commit d36db85
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 0 deletions.
110 changes: 110 additions & 0 deletions src/Ciconia/Extension/Html/AttributesExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace Ciconia\Extension\Html;

use Ciconia\Common\Tag;
use Ciconia\Common\Text;
use Ciconia\Extension\ExtensionInterface;
use Ciconia\Markdown;

class AttributesExtension implements ExtensionInterface
{

/**
* {@inheritdoc}
*/
public function register(Markdown $markdown)
{
$markdown->on('tag', array($this, 'processBlockTags'));
}

/**
* Parse emmet style attributes
*
* @param Tag $tag
*/
public function processBlockTags(Tag $tag)
{
if ($tag->isInline()) {
return;
}

$text = null;
$tag->getText()->replace('/(^{([^:\(\)]+)}[ \t]*\n?|(?:[ \t]*|\n?){([^:\(\)]+)}\n*$)/', function (Text $w) use (&$text) {
$text = $w->trim()->trim('{}');

return '';
});

if ($text) {
$tag->setAttributes($this->parseAttributes($text));
}
}

/**
* {@inheritdoc}
*/
public function getName()
{
return 'htmlAttributes';
}

/**
* @param Text $text
*
* @return array
*/
protected function parseAttributes(Text $text)
{
$patterns = [
'id' => '/^#([a-zA-Z0-9_-]+)/',
'class' => '/^\.([a-zA-Z0-9_-]+)/',
'attr' => '/^\[([^\]]+)\]/',
'ident' => '/^(.)/'
];

$tokens = [
'id' => [], 'class' => [], 'attr' => [], 'ident' => []
];

while (!$text->isEmpty()) {
foreach ($patterns as $name => $pattern) {
if ($text->match($pattern, $matches)) {
$tokens[$name][] = $matches[1];
$text->setString(
substr($text->getString(), strlen($matches[0]))
);

break;
}
}
}

$attributes = array();

if (count($tokens['id'])) {
$attributes['id'] = array_pop($tokens['id']);
}

if (count($tokens['class'])) {
$attributes['class'] = implode(' ', $tokens['class']);
}

if (count($tokens['attr'])) {
foreach ($tokens['attr'] as $raw) {
$items = explode(' ', $raw);
foreach ($items as $item) {
if (strpos($item, '=') !== false) {
list ($key, $value) = explode('=', $item);
$attributes[$key] = trim($value, '"');
} else {
$attributes[$item] = $item;
}
}
}
}

return $attributes;
}

}
68 changes: 68 additions & 0 deletions test/Ciconia/Extension/HtmlExtensionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

use Ciconia\Ciconia;
use Ciconia\Renderer\XhtmlRenderer;
use Symfony\Component\Finder\Finder;

/**
* Tests Ciconia\Extensions\Html\*
*
* @group Html
*
* @author Kazuyuki Hayashi <[email protected]>
*/
class HtmlExtensionsTest extends PHPUnit_Framework_TestCase
{

/**
* @dataProvider htmlProvider
*/
public function testHtmlPatterns($name, $textile, $expected)
{
$ciconia = new Ciconia(new XhtmlRenderer());
$ciconia->addExtensions([
new \Ciconia\Extension\Html\AttributesExtension()
]);

$expected = str_replace("\r\n", "\n", $expected);
$expected = str_replace("\r", "\n", $expected);
$html = $ciconia->render($textile);

$this->assertEquals($expected, $html, sprintf('%s failed', $name));
}

/**
* @return array
*/
public function htmlProvider()
{
$finder = Finder::create()
->in([__DIR__.'/../Resources/html', __DIR__.'/../Resources/core'])
->files()
->name('*.md')
->notName('link-automatic-email.md');

return $this->processPatterns($finder);
}

/**
* @param Finder|\Symfony\Component\Finder\SplFileInfo[] $finder
*
* @return array
*/
protected function processPatterns(Finder $finder)
{
$patterns = [];

foreach ($finder as $file) {
$name = preg_replace('/\.(md|out)$/', '', $file->getFilename());
$expected = trim(file_get_contents(preg_replace('/\.md$/', '.out', $file->getPathname())));
$expected = str_replace("\r\n", "\n", $expected);
$expected = str_replace("\r", "\n", $expected);
$patterns[] = [$name, $file->getContents(), $expected];
}

return $patterns;
}

}
11 changes: 11 additions & 0 deletions test/Ciconia/Resources/html/html-attributes-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Header {#id.class1.class2[role="main" align=right]}
======

### Header {#id}

### Header {.class}

{[aria-hidden=true]} Header
-----------

###### {[aria-hidden=true]} Header
9 changes: 9 additions & 0 deletions test/Ciconia/Resources/html/html-attributes-headers.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h1 id="id" class="class1 class2" role="main" align="right">Header</h1>

<h3 id="id">Header</h3>

<h3 class="class">Header</h3>

<h2 aria-hidden="true">Header</h2>

<h6 aria-hidden="true">Header</h6>
23 changes: 23 additions & 0 deletions test/Ciconia/Resources/html/html-attributes-paragraph.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{#id} Lorem ipsum dolor sit amet

{#id} Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus

{#id}
Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus

Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus {#id}

Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus
{#id}
21 changes: 21 additions & 0 deletions test/Ciconia/Resources/html/html-attributes-paragraph.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<p id="id">Lorem ipsum dolor sit amet</p>

<p id="id">Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus</p>

<p id="id">Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus</p>

<p id="id">Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus</p>

<p id="id">Lorem ipsum dolor sit amet,
consectetur adipisicing elit.
Qui dicta minus molestiae vel
beatae natus eveniet ratione temporibus</p>

0 comments on commit d36db85

Please sign in to comment.