Skip to content

Commit 6005b2c

Browse files
committed
fixed generation of bbcode for uppercased tags
1 parent ca659ac commit 6005b2c

File tree

6 files changed

+262
-7
lines changed

6 files changed

+262
-7
lines changed

JBBCode/CodeDefinition.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class CodeDefinition
1414
/** @var string NOTE: THIS PROPERTY SHOULD ALWAYS BE LOWERCASE; USE setTagName() TO ENSURE THIS */
1515
protected $tagName;
1616

17+
/** @var string The original defined tag name. Needed for uppercased tags */
18+
protected $originalTagName;
19+
1720
/** @var boolean Whether or not this CodeDefinition uses an option parameter. */
1821
protected $useOption;
1922

@@ -188,6 +191,16 @@ public function getTagName()
188191
return $this->tagName;
189192
}
190193

194+
/**
195+
* Returns the original and not normalized tag name of this code definition
196+
*
197+
* @return string this definition's associated original tag name
198+
*/
199+
public function getOriginalTagName()
200+
{
201+
return $this->originalTagName;
202+
}
203+
191204
/**
192205
* Returns the replacement text of this code definition. This usually has little, if any meaning if the
193206
* CodeDefinition class was extended. For default, html replacement CodeDefinitions this returns the html
@@ -243,6 +256,7 @@ public function getNestLimit()
243256
*/
244257
public function setTagName($tagName)
245258
{
259+
$this->originalTagName = $tagName;
246260
$this->tagName = strtolower($tagName);
247261
}
248262

JBBCode/ElementNode.php

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ class ElementNode extends Node
1616
/** @var string The tagname of this element, for i.e. "b" in [b]bold[/b] */
1717
protected $tagName;
1818

19+
/**
20+
* The original defined tag name of this element, for i.e. "b" in [b]bold[/b]
21+
* or [B]bold[/B]
22+
* @var string
23+
*/
24+
protected $originalTagName;
25+
1926
/** @var string[] The attributes, if any, of this element node */
2027
protected $attribute;
2128

@@ -61,6 +68,7 @@ public function setCodeDefinition(CodeDefinition $codeDef)
6168
{
6269
$this->codeDefinition = $codeDef;
6370
$this->setTagName($codeDef->getTagName());
71+
$this->originalTagName = $codeDef->getOriginalTagName();
6472
}
6573

6674
/**
@@ -83,6 +91,16 @@ public function getAttribute()
8391
return $this->attribute;
8492
}
8593

94+
/**
95+
* Returns if element has any children.
96+
*
97+
* @return bool
98+
*/
99+
public function hasChildren()
100+
{
101+
return (bool) $this->children;
102+
}
103+
86104
/**
87105
* Returns all the children of this element.
88106
*
@@ -123,14 +141,17 @@ public function getAsText()
123141
*/
124142
public function getAsBBCode()
125143
{
126-
$str = "[".$this->tagName;
144+
$str = "[".$this->originalTagName;
127145
if (!empty($this->attribute)) {
128-
if(isset($this->attribute[$this->tagName])) {
129-
$str .= "=".$this->attribute[$this->tagName];
146+
if (isset($this->attribute[$this->originalTagName])) {
147+
// avoid to generate something like [FOO= bar=baz]...[/FOO]
148+
if (!empty($this->attribute[$this->originalTagName]) || !$this->hasChildren()) {
149+
$str .= "=".$this->attribute[$this->originalTagName];
150+
}
130151
}
131152

132-
foreach($this->attribute as $key => $value){
133-
if($key == $this->tagName){
153+
foreach ($this->attribute as $key => $value) {
154+
if ($this->normalize($key) == $this->normalize($this->originalTagName)) {
134155
continue;
135156
}
136157
else{
@@ -142,7 +163,7 @@ public function getAsBBCode()
142163
foreach ($this->getChildren() as $child) {
143164
$str .= $child->getAsBBCode();
144165
}
145-
$str .= "[/".$this->tagName."]";
166+
$str .= "[/".$this->originalTagName."]";
146167

147168
return $str;
148169
}
@@ -210,6 +231,18 @@ public function setAttribute($attribute)
210231
$this->attribute = $attribute;
211232
}
212233

234+
/**
235+
* Normalizes incoming string for better comparison possibilities.
236+
*
237+
* @param string $str
238+
*
239+
* @return string
240+
*/
241+
private function normalize($str)
242+
{
243+
return strtolower($str);
244+
}
245+
213246
/**
214247
* Traverses the parse tree upwards, going from parent to parent, until it finds a
215248
* parent who has the given tag name. Returns the parent with the matching tag name
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace JBBCode;
4+
5+
require_once 'CodeDefinition.php';
6+
require_once 'CodeDefinitionBuilder.php';
7+
require_once 'CodeDefinitionSet.php';
8+
require_once 'validators/CssColorValidator.php';
9+
require_once 'validators/UrlValidator.php';
10+
11+
/**
12+
* Provides a uppercased default set of common bbcode definitions.
13+
*
14+
* @author jbowens|frastel
15+
*/
16+
class UppercasedCodeDefinitionSet implements CodeDefinitionSet
17+
{
18+
19+
/** @var CodeDefinition[] The default code definitions in this set. */
20+
protected $definitions = array();
21+
22+
/**
23+
* Constructs the default code definitions.
24+
*/
25+
public function __construct()
26+
{
27+
/* [B] bold tag */
28+
$builder = new CodeDefinitionBuilder('B', '<strong>{param}</strong>');
29+
$this->definitions[] = $builder->build();
30+
31+
/* [I] italics tag */
32+
$builder = new CodeDefinitionBuilder('I', '<em>{param}</em>');
33+
$this->definitions[] = $builder->build();
34+
35+
/* [U] underline tag */
36+
$builder = new CodeDefinitionBuilder('U', '<u>{param}</u>');
37+
$this->definitions[] = $builder->build();
38+
39+
$urlValidator = new \JBBCode\validators\UrlValidator();
40+
41+
/* [URL] link tag */
42+
$builder = new CodeDefinitionBuilder('URL', '<a href="{param}">{param}</a>');
43+
$builder->setParseContent(false)->setBodyValidator($urlValidator);
44+
$this->definitions[] = $builder->build();
45+
46+
/* [URL=http://example.com] link tag */
47+
$builder = new CodeDefinitionBuilder('URL', '<a href="{option}">{param}</a>');
48+
$builder->setUseOption(true)->setParseContent(true)->setOptionValidator($urlValidator);
49+
$this->definitions[] = $builder->build();
50+
51+
/* [IMG] image tag */
52+
$builder = new CodeDefinitionBuilder('IMG', '<img src="{param}" />');
53+
$builder->setUseOption(false)->setParseContent(false)->setBodyValidator($urlValidator);
54+
$this->definitions[] = $builder->build();
55+
56+
/* [IMG=alt text] image tag */
57+
$builder = new CodeDefinitionBuilder('IMG', '<img src="{param}" alt="{option}" />');
58+
$builder->setUseOption(true)->setParseContent(false)->setBodyValidator($urlValidator);
59+
$this->definitions[] = $builder->build();
60+
61+
/* [COLOR] color tag */
62+
$builder = new CodeDefinitionBuilder('COLOR', '<span style="color: {option}">{param}</span>');
63+
$builder->setUseOption(true)->setOptionValidator(new \JBBCode\validators\CssColorValidator());
64+
$this->definitions[] = $builder->build();
65+
}
66+
67+
/**
68+
* Returns an array of the default code definitions.
69+
*
70+
* @return CodeDefinition[]
71+
*/
72+
public function getCodeDefinitions()
73+
{
74+
return $this->definitions;
75+
}
76+
}

JBBCode/tests/ElementNodeTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,22 @@ public function testGetAsBBCode()
7676
));
7777
$this->assertEquals('[foo=bar bar=baz][/foo]', $this->_elementNode->getAsBBCode());
7878
}
79+
80+
public function testGetAsBBCodeUppercased()
81+
{
82+
$builder = new JBBCode\CodeDefinitionBuilder('FOO', 'bar');
83+
$codeDefinition = $builder->build();
84+
$this->_elementNode->setCodeDefinition($codeDefinition);
85+
$this->assertEquals('[FOO][/FOO]', $this->_elementNode->getAsBBCode());
86+
87+
$this->_elementNode->setAttribute(array('bar' => 'baz'));
88+
$this->assertEquals('[FOO bar=baz][/FOO]', $this->_elementNode->getAsBBCode());
89+
90+
/** @ticket 55 */
91+
$this->_elementNode->setAttribute(array(
92+
'bar' => 'baz',
93+
'FOO' => 'bar'
94+
));
95+
$this->assertEquals('[FOO=bar bar=baz][/FOO]', $this->_elementNode->getAsBBCode());
96+
}
7997
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
4+
class ParsingUpperCaseTest extends PHPUnit_Framework_TestCase
5+
{
6+
/**
7+
* @var JBBCode\Parser
8+
*/
9+
private $_parser;
10+
11+
protected function setUp()
12+
{
13+
$this->_parser = new JBBCode\Parser();
14+
$this->_parser->addCodeDefinitionSet(new JBBCode\UppercasedCodeDefinitionSet());
15+
}
16+
17+
/**
18+
* @param string $code
19+
* @param string[] $expected
20+
* @dataProvider textCodeProvider
21+
*/
22+
public function testParse($code, $expected)
23+
{
24+
$parser = $this->_parser->parse($code);
25+
$this->assertEquals($expected['text'], $parser->getAsText());
26+
$this->assertEquals($expected['html'], $parser->getAsHTML());
27+
$this->assertEquals($expected['bbcode'], $parser->getAsBBCode());
28+
}
29+
30+
public function textCodeProvider()
31+
{
32+
return array(
33+
array(
34+
'foo',
35+
array(
36+
'text' => 'foo',
37+
'html' => 'foo',
38+
'bbcode' => 'foo',
39+
)
40+
),
41+
array(
42+
'[B]this is bold[/B]',
43+
array(
44+
'text' => 'this is bold',
45+
'html' => '<strong>this is bold</strong>',
46+
'bbcode' => '[B]this is bold[/B]',
47+
)
48+
),
49+
array(
50+
'[B]this is bold',
51+
array(
52+
'text' => 'this is bold',
53+
'html' => '<strong>this is bold</strong>',
54+
'bbcode' => '[B]this is bold[/B]',
55+
)
56+
),
57+
array(
58+
'buffer text [B]this is bold[/B] buffer text',
59+
array(
60+
'text' => 'buffer text this is bold buffer text',
61+
'html' => 'buffer text <strong>this is bold</strong> buffer text',
62+
'bbcode' => 'buffer text [B]this is bold[/B] buffer text',
63+
)
64+
),
65+
array(
66+
'this is some text with [B]bold tags[/B] and [I]italics[/I] and things like [U]that[/U].',
67+
array(
68+
'text' => 'this is some text with bold tags and italics and things like that.',
69+
'html' => 'this is some text with <strong>bold tags</strong> and <em>italics</em> and things like <u>that</u>.',
70+
'bbcode' => 'this is some text with [B]bold tags[/B] and [I]italics[/I] and things like [U]that[/U].',
71+
)
72+
),
73+
array(
74+
'This contains a [URL=http://jbbcode.com]url[/URL] which uses an option.',
75+
array(
76+
'text' => 'This contains a url which uses an option.',
77+
'html' => 'This contains a <a href="http://jbbcode.com">url</a> which uses an option.',
78+
'bbcode' => 'This contains a [URL=http://jbbcode.com]url[/URL] which uses an option.',
79+
)
80+
),
81+
array(
82+
'This doesn\'t use the url option [URL]http://jbbcode.com[/URL].',
83+
array(
84+
'text' => 'This doesn\'t use the url option http://jbbcode.com.',
85+
'html' => 'This doesn\'t use the url option <a href="http://jbbcode.com">http://jbbcode.com</a>.',
86+
'bbcode' => 'This doesn\'t use the url option [URL]http://jbbcode.com[/URL].',
87+
)
88+
),
89+
);
90+
}
91+
92+
/**
93+
* @param string $code
94+
*
95+
* @dataProvider textCodeProviderWithInvalidCode
96+
*/
97+
public function testParseInvalidCode($code)
98+
{
99+
$parser = $this->_parser->parse($code);
100+
$this->assertEquals($code, $parser->getAsText());
101+
$this->assertEquals($code, $parser->getAsHTML());
102+
$this->assertEquals($code, $parser->getAsBBCode());
103+
}
104+
105+
public function textCodeProviderWithInvalidCode()
106+
{
107+
return array(
108+
array('This is some text with an [URL]I N V A L I D[/URL] URL tag.'),
109+
array('This is some text with an [URL foo=bar]INVALID[/URL] URL tag.'),
110+
array('This is some text with an invalid [URL=INVALID]URL[/URL] tag.')
111+
);
112+
}
113+
}

JBBCode/tests/bootstrap.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
<?php
2-
require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Parser.php';
2+
require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Parser.php';
3+
require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'UppercasedCodeDefinitionSet.php';

0 commit comments

Comments
 (0)