Skip to content

Commit

Permalink
Add additional attributes to icon extension (#27)
Browse files Browse the repository at this point in the history
* Add default configuration for icon extension

* Add additional attributes to icon twig extension
  • Loading branch information
alexander-schranz committed Jul 14, 2020
1 parent 148310e commit d3892b2
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 11 deletions.
55 changes: 52 additions & 3 deletions docs/icon.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,36 @@ The icon extension gives you a simple way to render icomoon icons.

The twig extension need to be registered as [symfony service](http://symfony.com/doc/current/service_container.html).

```yaml
services:
Sulu\Twig\Extensions\IconExtension: ~
```

Or a more complex configuration example:

```yaml
services:
Sulu\Twig\Extensions\IconExtension:
arguments:
$iconSets:
# icon font:
default:
type: 'font' # or 'svg'
# for svg also a path to symbol-defs file is needed:
# path: '/website/fonts/icomoon-sulu/symbol-defs.svg'
type: 'font'
# the following options are optional but need to match your icomoon export settings:
# className: 'icon'
# classPrefix: 'icon-'
# classSuffix: ''
# svg icons:
other:
type: 'svg'
path: '/website/fonts/icomoon-sulu/symbol-defs.svg'

# the following options are optional but need to match your icomoon export settings:
# className: 'icon'
# classPrefix: 'icon-'
# classSuffix: ''
$defaultAttributes:
role: 'none'
```

## Usage
Expand All @@ -29,6 +45,7 @@ services:
```yaml
services:
Sulu\Twig\Extensions\IconExtension:
# the following configuration is default
arguments:
$iconSets:
default:
Expand Down Expand Up @@ -119,3 +136,35 @@ As you see above the format for the classes is the following:
```
{additionaClass} {className} {classPrefix}{icon}{classSuffix}
```

### Add additional attributes

Not only a class can be passed you can also add any other attributes:

```twig
<!-- Icon Font -->
{{ get_icon('test', { role: 'none'}) }}
<!-- SVG Icons -->
{{ get_icon('test', { role: 'none'}, 'other') }}
```

This will output:

```html
<!-- Icon Font -->
<span role="none" class="icon icon-test"></span>

<!-- SVG Icons -->
<svg role="none" class="icon icon-test"><use xlink:href="/path/to/symbol-defs.svg#test"></use></svg>
```

You can also configure default attributes in the service registration the following way:

```yaml
services:
Sulu\Twig\Extensions\IconExtension:
arguments:
$defaultAttributes:
role: 'none'
```
50 changes: 42 additions & 8 deletions src/IconExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,19 @@ class IconExtension extends AbstractExtension
*/
private $iconSets = [];

/**
* @var array<string, string|null>
*/
private $defaultAttributes = [];

/**
* @param string|mixed[] $iconSets
* @param array<string, string|null> $defaultAttributes
*/
public function __construct($iconSets)
public function __construct($iconSets = self::ICON_SET_TYPE_FONT, array $defaultAttributes = [])
{
$this->defaultAttributes = $defaultAttributes;

if (\is_string($iconSets)) {
$iconSets = [
'default' => $iconSets,
Expand Down Expand Up @@ -80,31 +88,39 @@ public function getFunctions()
* Get the an icomoon icon based on the configuration.
*
* @param string $icon
* @param string $className
* @param string|array<string, string|null>|null $attributes
* @param string $iconSetName
*
* @return string
*/
public function getIcon(string $icon, ?string $className = '', string $iconSetName = 'default'): string
public function getIcon(string $icon, $attributes = [], string $iconSetName = 'default'): string
{
$iconSet = $this->getIconSet($iconSetName);

$className = trim(sprintf(
if (!\is_array($attributes)) {
$attributes = [
'class' => $attributes,
];
}

$attributes = array_merge($this->defaultAttributes, $attributes);

$attributes['class'] = trim(sprintf(
'%s %s %s%s%s',
$className ?: '',
$attributes['class'] ?? '',
$iconSet['className'],
$iconSet['classPrefix'],
$icon,
$iconSet['classSuffix']
));

if (self::ICON_SET_TYPE_FONT === $iconSet['type']) {
return sprintf('<span class="%s"></span>', $className);
return sprintf('<span%s></span>', $this->renderAttributes($attributes));
}

return sprintf(
'<svg class="%s"><use xlink:href="%s#%s"></use></svg>',
$className,
'<svg%s><use xlink:href="%s#%s"></use></svg>',
$this->renderAttributes($attributes),
$iconSet['path'],
$icon
);
Expand All @@ -125,4 +141,22 @@ private function getIconSet(string $name): array

return $this->iconSets[$name];
}

/**
* @param array<string, string|null> $attributes
*/
private function renderAttributes(array $attributes): string
{
$output = '';

foreach ($attributes as $key => $value) {
if (null === $value) {
continue;
}

$output .= sprintf(' %s="%s"', $key, htmlentities($value));
}

return $output;
}
}
114 changes: 114 additions & 0 deletions tests/IconExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,36 @@ public function testFalseIconSet(): void
$iconExtension->getIcon('test', null, 'other');
}

public function testIconFontDefaultAttributes(): void
{
$iconExtension = new IconExtension('font', ['role' => 'none']);

$this->assertSame(
'<span role="none" class="icon icon-test"></span>',
$iconExtension->getIcon('test')
);
}

public function testIconFontRemoveDefaultAttributes(): void
{
$iconExtension = new IconExtension('font', ['role' => 'none']);

$this->assertSame(
'<span class="icon icon-test"></span>',
$iconExtension->getIcon('test', ['role' => null])
);
}

public function testIconFontAttributes(): void
{
$iconExtension = new IconExtension('font');

$this->assertSame(
'<span role="none" class="icon icon-test"></span>',
$iconExtension->getIcon('test', ['role' => 'none'])
);
}

public function testIconFontCustomSettings(): void
{
$iconExtension = new IconExtension([
Expand All @@ -58,6 +88,20 @@ public function testIconFontCustomSettings(): void
);
}

public function testIconFontOtherGroup(): void
{
$iconExtension = new IconExtension([
'other' => [
'type' => 'font',
],
]);

$this->assertSame(
'<span class="icon icon-test"></span>',
$iconExtension->getIcon('test', null, 'other')
);
}

public function testSvgIcon(): void
{
$iconExtension = new IconExtension([
Expand All @@ -73,6 +117,61 @@ public function testSvgIcon(): void
);
}

public function testSvgIconAttributes(): void
{
$iconExtension = new IconExtension([
'default' => [
'type' => 'svg',
'path' => '/path/to/symbol-defs.svg',
],
]);

$this->assertSame(
'<svg role="none" class="icon icon-test"><use xlink:href="/path/to/symbol-defs.svg#test"></use></svg>',
$iconExtension->getIcon('test', ['role' => 'none'])
);
}

public function testSvgIconDefaultAttributes(): void
{
$iconExtension = new IconExtension(
[
'default' => [
'type' => 'svg',
'path' => '/path/to/symbol-defs.svg',
],
],
[
'role' => 'none',
]
);

$this->assertSame(
'<svg role="none" class="icon icon-test"><use xlink:href="/path/to/symbol-defs.svg#test"></use></svg>',
$iconExtension->getIcon('test')
);
}

public function testSvgIconRemoveDefaultAttributes(): void
{
$iconExtension = new IconExtension(
[
'default' => [
'type' => 'svg',
'path' => '/path/to/symbol-defs.svg',
],
],
[
'role' => 'none',
]
);

$this->assertSame(
'<svg class="icon icon-test"><use xlink:href="/path/to/symbol-defs.svg#test"></use></svg>',
$iconExtension->getIcon('test', ['role' => null])
);
}

public function testSvgIconCustomSettings(): void
{
$iconExtension = new IconExtension([
Expand All @@ -90,4 +189,19 @@ public function testSvgIconCustomSettings(): void
$iconExtension->getIcon('test', 'add-class', 'other')
);
}

public function testSvgIconOtherGroup(): void
{
$iconExtension = new IconExtension([
'other' => [
'type' => 'svg',
'path' => '/path/to/symbol-defs.svg',
],
]);

$this->assertSame(
'<svg class="icon icon-test"><use xlink:href="/path/to/symbol-defs.svg#test"></use></svg>',
$iconExtension->getIcon('test', null, 'other')
);
}
}

0 comments on commit d3892b2

Please sign in to comment.