Compare commits
7 Commits
issue/7-th
...
1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 761f02ff9b | |||
| ade021b8a6 | |||
| 5b13a21a82 | |||
| 1b917b4cac | |||
| 440053bf4f | |||
| a8af463c5c | |||
| 3f27e50c32 |
@@ -2,6 +2,11 @@
|
||||
|
||||
## [X.X.X] - XXXX-XX-XX
|
||||
- Allow passing in a space-separated string to the `classes` option
|
||||
- Add new exceptions and messages to make debugging a little bit faster
|
||||
- Set `aria-hidden` attribute depending on whether a `title` has been set
|
||||
|
||||
## [1.1.0] - 2024-08-05
|
||||
- Changing requirements to work with Symfony 7
|
||||
|
||||
## [1.0.0] - 2023-06-27
|
||||
- First major version release
|
||||
|
||||
@@ -1,42 +1,37 @@
|
||||
{
|
||||
"name": "pcm/icon-bundle",
|
||||
"description": "Twig icon bundle",
|
||||
|
||||
"type": "symfony-bundle",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bradley Goode",
|
||||
"email": "bg@pcmsystems.co.uk"
|
||||
},
|
||||
{
|
||||
"name": "Matt Feeney",
|
||||
"email": "mf@pcmsystems.co.uk"
|
||||
}
|
||||
],
|
||||
|
||||
"require": {
|
||||
"symfony/dependency-injection": "^6.1",
|
||||
"symfony/framework-bundle": "^6.1",
|
||||
"symfony/yaml": "^6.1",
|
||||
"symfony/http-client": "^6.1",
|
||||
"symfony/twig-bundle": "^6.1"
|
||||
"name": "pcm/icon-bundle",
|
||||
"description": "Twig icon bundle",
|
||||
"type": "symfony-bundle",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bradley Goode",
|
||||
"email": "bg@pcmsystems.co.uk"
|
||||
},
|
||||
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/phpunit-bridge": "^6.1"
|
||||
},
|
||||
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pcm\\IconBundle\\": "src/"
|
||||
}
|
||||
},
|
||||
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Pcm\\IconBundle\\Tests\\": "tests/"
|
||||
}
|
||||
{
|
||||
"name": "Matt Feeny",
|
||||
"email": "mf@pcmsystems.co.uk"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"symfony/dependency-injection": "^6.1 || ^7.0",
|
||||
"symfony/framework-bundle": "^6.1 || ^7.0",
|
||||
"symfony/yaml": "^6.1 || ^7.0",
|
||||
"symfony/http-client": "^6.1 || ^7.0",
|
||||
"symfony/twig-bundle": "^6.1 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/phpunit-bridge": "^6.1 || ^7.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pcm\\IconBundle\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Pcm\\IconBundle\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Exception/InvalidSvgException.php
Normal file
7
src/Exception/InvalidSvgException.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pcm\IconBundle\Exception;
|
||||
|
||||
class InvalidSvgException extends \Exception {};
|
||||
@@ -7,6 +7,7 @@ namespace Pcm\IconBundle\Twig\Runtime;
|
||||
use Pcm\IconBundle\Exception\ColourNotFound;
|
||||
use Pcm\IconBundle\Exception\EmptyFileException;
|
||||
use Pcm\IconBundle\Exception\IconNotFound;
|
||||
use Pcm\IconBundle\Exception\InvalidSvgException;
|
||||
use Twig\Extension\RuntimeExtensionInterface;
|
||||
|
||||
final class IconRuntime implements RuntimeExtensionInterface
|
||||
@@ -49,6 +50,10 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
throw new EmptyFileException(\sprintf("The file %s.svg was found, but it was empty!", $options['icon']));
|
||||
}
|
||||
|
||||
if (!$this->isValidXml($svg)) {
|
||||
throw new InvalidSvgException(\sprintf("The file %s.svg was found, but it does not contain valid SVG code!", $options['icon']));
|
||||
}
|
||||
|
||||
$this->sanitiseSvg($svg);
|
||||
|
||||
$colourClasses = $this->getColourClasses($options['colour'], $options['hover']);
|
||||
@@ -57,8 +62,11 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
$classes = trim($colourClasses.' '.$extraClasses);
|
||||
$this->addClassesToSvg($svg, $classes);
|
||||
|
||||
$svg = $this->addAttribute($svg, 'aria-hidden', 'true');
|
||||
|
||||
if (null !== $options['title']) {
|
||||
$this->addTitleToSvg($svg, $options['title']);
|
||||
$svg = $this->addAttribute($svg, 'aria-hidden', 'false');
|
||||
}
|
||||
|
||||
$this->setSvgHeightAndWidth($svg, $options['size']);
|
||||
@@ -211,4 +219,23 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
|
||||
$svg = $this->removeXMLDeclaration($svgAsXml->saveXML());
|
||||
}
|
||||
|
||||
private function addAttribute(string $svg, string $attribute, string $value): string
|
||||
{
|
||||
$xml = new \SimpleXMLElement($svg);
|
||||
$xml = $this->addAttributeToXmlElement($xml, $attribute, $value);
|
||||
|
||||
return $this->removeXMLDeclaration($xml->saveXML());
|
||||
}
|
||||
|
||||
private function isValidXml(string $input): bool
|
||||
{
|
||||
try {
|
||||
new \SimpleXMLElement($input);
|
||||
} catch (\Exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use Pcm\IconBundle\DependencyInjection\Configuration;
|
||||
use Pcm\IconBundle\Exception\ColourNotFound;
|
||||
use Pcm\IconBundle\Exception\EmptyFileException;
|
||||
use Pcm\IconBundle\Exception\IconNotFound;
|
||||
use Pcm\IconBundle\Exception\InvalidSvgException;
|
||||
use Pcm\IconBundle\Twig\Runtime\IconRuntime;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -57,6 +58,12 @@ class IconRuntimeTest extends TestCase
|
||||
$this->icon->renderIcon(['icon' => 'empty']);
|
||||
}
|
||||
|
||||
public function testThrowsIfContentsIsNotValidSvg(): void
|
||||
{
|
||||
$this->expectException(InvalidSvgException::class);
|
||||
$this->icon->renderIcon(['icon' => 'invalid']);
|
||||
}
|
||||
|
||||
public function testNoTitleExistsIfNotPassedIn(): void
|
||||
{
|
||||
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||
@@ -273,4 +280,23 @@ class IconRuntimeTest extends TestCase
|
||||
$this->assertStringNotContainsString($needleA, $contents);
|
||||
$this->assertStringNotContainsString($needleB, $contents);
|
||||
}
|
||||
|
||||
public function testAriaHiddenAttributeIsAdded(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||
$this->assertMatchesRegularExpression('/<svg.+aria-hidden="true".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testAriaHiddenAttributeIsSetToTrueIfAlreadyPresent(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => 'attr']);
|
||||
$this->assertMatchesRegularExpression('/<svg.+aria-hidden="true".*>/', $contents);
|
||||
$this->assertDoesNotMatchRegularExpression('/<svg.+aria-hidden="false".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testAriaHiddenAttributeIsSetToFalseIfATitleIsPassedIn(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'title' => 'something']);
|
||||
$this->assertMatchesRegularExpression('/<svg.+aria-hidden="false".*>/', $contents);
|
||||
}
|
||||
}
|
||||
|
||||
10
tests/icons/attr.svg
Normal file
10
tests/icons/attr.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg aria-hidden="false" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="96 96 320 320">
|
||||
<title>Some cross lol</title>
|
||||
<line fill="rgb(0, 0, 0)"></line>
|
||||
<line fill="#000"></line>
|
||||
<line fill="#000000"></line>
|
||||
<line stroke="currentColor" fill="black"></line>
|
||||
<line x1="256" y1="112" x2="256" y2="400" width="101" height="101" style="fill: none; stroke: rgb(0,0, 0); stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
||||
<line x1="400" y1="256" x2="112" y2="256" width="102" height="102" style="fill: none; stroke: #000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
||||
<polyline points="112 244 256 100 400 244" style="fill:#000;fill:#000000;fill: black;fill:rgb(0,0,0);stroke:#000;stroke:#000000;stroke:black;stroke:rgb(0, 0, 0);stroke-linecap:round;stroke-linejoin:round;stroke-width:48px" stroke='currentColor'/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 924 B |
1
tests/icons/invalid.svg
Normal file
1
tests/icons/invalid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg><svg>
|
||||
|
After Width: | Height: | Size: 11 B |
Reference in New Issue
Block a user