Skip to content

Commit ec18aff

Browse files
authored
Merge pull request #29 from Paneon/master
Update master
2 parents d87b210 + 8d94673 commit ec18aff

18 files changed

+203
-51
lines changed

src/Compiler.php

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ public function convert(): string
167167
}
168168

169169
if ($styleBlocks->length) {
170+
$this->styleBuilder->setScopedAttribute('data-v-' . md5($this->document->textContent));
170171
foreach ($styleBlocks as $styleBlock) {
171172
/* @var DOMElement $styleBlock */
172173
$this->rawBlocks[] = $this->styleBuilder->compile($styleBlock);
@@ -190,6 +191,7 @@ public function convert(): string
190191

191192
$html = $this->addVariableBlocks($html);
192193
$html = $this->replacePlaceholders($html);
194+
$html = $this->replaceScopedPlaceholders($html);
193195

194196
$html = preg_replace('/<template>\s*(.*)\s*<\/template>/ism', '$1', $html);
195197
$html = preg_replace('/<\/?template[^>]*?>/i', '', $html);
@@ -241,7 +243,7 @@ public function convertNode(DOMNode $node, int $level = 0): DOMNode
241243
$this->stripEventHandlers($node);
242244
$this->handleSlots($node);
243245
$this->cleanupAttributes($node);
244-
$this->addScopedAttribute($node);
246+
$this->addScopedAttribute($node, $level);
245247
}
246248

247249
// Registered Component
@@ -362,6 +364,20 @@ private function preparePropertiesForInclude(array $variables): array
362364
$values[$name][] = $value;
363365
}
364366
unset($variables[$key]);
367+
} elseif (strpos($name, 'dataV') === 0 && strlen($name) === 37) {
368+
unset($variables[$key]);
369+
$variables[] = new Property(
370+
'dataScopedStyleAttribute',
371+
'"data-v-' . strtolower(substr($name, 5)) . '"',
372+
false
373+
);
374+
} elseif ($name === '__DATA_SCOPED_STYLE_ATTRIBUTE__') {
375+
unset($variables[$key]);
376+
$variables[] = new Property(
377+
'dataScopedStyleAttribute',
378+
'dataScopedStyleAttribute|default(\'\')',
379+
false
380+
);
365381
}
366382
}
367383

@@ -1068,6 +1084,13 @@ public function setStyleBlockOutputType(int $outputType): Compiler
10681084
return $this;
10691085
}
10701086

1087+
public function setStyleBlockScssData(string $scssData): Compiler
1088+
{
1089+
$this->styleBuilder->setScssData($scssData);
1090+
1091+
return $this;
1092+
}
1093+
10711094
/**
10721095
* @param mixed $value
10731096
*/
@@ -1217,12 +1240,27 @@ private function twigRemove(DOMElement $node): bool
12171240
return false;
12181241
}
12191242

1220-
private function addScopedAttribute(DOMElement $node): void
1243+
private function addScopedAttribute(DOMElement $node, int $level): void
12211244
{
1222-
if (!$this->styleBuilder->hasScoped()) {
1223-
return;
1245+
if ($this->styleBuilder->hasScoped()) {
1246+
$scopedAttribute = $this->styleBuilder->getScopedAttribute();
1247+
$node->setAttributeNode(new DOMAttr($scopedAttribute, ''));
1248+
1249+
if ($level !== 1) {
1250+
return;
1251+
}
12241252
}
1225-
$scopedAttribute = $this->styleBuilder->getScopedAttribute();
1226-
$node->setAttributeNode(new DOMAttr($scopedAttribute, ''));
1253+
1254+
if ($this->styleBuilder->getOutputType() & StyleBuilder::STYLE_SCOPED) {
1255+
$node->setAttributeNode(new DOMAttr('__DATA_SCOPED_STYLE_ATTRIBUTE__', ''));
1256+
}
1257+
}
1258+
1259+
private function replaceScopedPlaceholders(string $html): string
1260+
{
1261+
$html = str_replace('__DATA_SCOPED_STYLE_ATTRIBUTE__=""', '{{ dataScopedStyleAttribute|default(\'\') }}', $html);
1262+
$html = preg_replace('/(data-v-[0-9a-f]{32})=""/', '$1', $html);
1263+
1264+
return $html;
12271265
}
12281266
}

src/Utils/StyleBuilder.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use DOMElement;
88
use Exception;
9-
use Ramsey\Uuid\Uuid;
109
use ScssPhp\ScssPhp\Compiler as ScssCompiler;
1110

1211
class StyleBuilder
@@ -21,6 +20,11 @@ class StyleBuilder
2120
*/
2221
private $outputType;
2322

23+
/**
24+
* @var string
25+
*/
26+
private $scssData;
27+
2428
/**
2529
* @var ScssCompiler|null
2630
*/
@@ -44,16 +48,27 @@ class StyleBuilder
4448
public function __construct()
4549
{
4650
$this->outputType = self::STYLE_ALL;
51+
$this->scssData = '';
4752
$this->scssCompiler = null;
4853
$this->hasScoped = false;
49-
$this->scopedAttribute = 'data-v-' . substr(md5(Uuid::uuid4()->toString()), 0, 8);
54+
$this->scopedAttribute = '';
5055
}
5156

5257
public function setOutputType(int $outputType): void
5358
{
5459
$this->outputType = $outputType;
5560
}
5661

62+
public function getOutputType(): int
63+
{
64+
return $this->outputType;
65+
}
66+
67+
public function setScssData(string $data): void
68+
{
69+
$this->scssData = $data;
70+
}
71+
5772
public function compile(?DOMElement $styleElement): ?string
5873
{
5974
if (!$styleElement instanceof DOMElement
@@ -68,7 +83,7 @@ public function compile(?DOMElement $styleElement): ?string
6883
if ($this->scssCompiler === null) {
6984
$this->scssCompiler = new ScssCompiler();
7085
}
71-
$style = $this->scssCompiler->compile($style);
86+
$style = $this->scssCompiler->compile($this->scssData . ' ' . $style);
7287
}
7388

7489
if ($styleElement->hasAttribute('scoped')) {
@@ -84,6 +99,11 @@ public function hasScoped(): ?bool
8499
return $this->hasScoped;
85100
}
86101

102+
public function setScopedAttribute(string $scopedAttribute): void
103+
{
104+
$this->scopedAttribute = $scopedAttribute;
105+
}
106+
87107
public function getScopedAttribute(): string
88108
{
89109
return $this->scopedAttribute;

tests/AbstractTestCase.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Monolog\Handler\StreamHandler;
1111
use Monolog\Logger;
1212
use Paneon\VueToTwig\Compiler;
13+
use Paneon\VueToTwig\Utils\StyleBuilder;
1314
use PHPUnit\Framework\TestCase;
1415

1516
abstract class AbstractTestCase extends TestCase
@@ -21,6 +22,7 @@ protected function createCompiler(string $template): Compiler
2122
{
2223
$document = $this->createDocumentWithHtml($template);
2324
$compiler = new Compiler($document, $this->createLogger());
25+
$compiler->setStyleBlockOutputType(StyleBuilder::STYLE_NO);
2426

2527
return $compiler;
2628
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Paneon\VueToTwig\Tests;
4+
5+
use Exception;
6+
use Paneon\VueToTwig\Utils\StyleBuilder;
7+
8+
class CompilerStyleBlockScopedTest extends AbstractTestCase
9+
{
10+
/**
11+
* @dataProvider dataProvider
12+
*
13+
* @param mixed $html
14+
* @param mixed $expected
15+
*
16+
* @throws Exception
17+
*/
18+
public function testStyleBlock($html, $expected)
19+
{
20+
$compiler = $this->createCompiler($html);
21+
$compiler->setStyleBlockOutputType(StyleBuilder::STYLE_ALL);
22+
$compiler->registerComponent('ChildComponent', '/templates/ChildComponent.twig');
23+
24+
$actual = $compiler->convert();
25+
26+
$this->assertEqualHtml($expected, $actual);
27+
}
28+
29+
/**
30+
* @return array
31+
*/
32+
public function dataProvider()
33+
{
34+
return $this->loadFixturesFromDir('style-block-scoped');
35+
}
36+
}

tests/CompilerStyleBlockTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Paneon\VueToTwig\Tests;
44

55
use Exception;
6+
use Paneon\VueToTwig\Utils\StyleBuilder;
67

78
class CompilerStyleBlockTest extends AbstractTestCase
89
{
@@ -17,11 +18,10 @@ class CompilerStyleBlockTest extends AbstractTestCase
1718
public function testStyleBlock($html, $expected)
1819
{
1920
$compiler = $this->createCompiler($html);
21+
$compiler->setStyleBlockOutputType(StyleBuilder::STYLE);
2022

2123
$actual = $compiler->convert();
2224

23-
$actual = preg_replace('/data-v-[0-9a-z]{8}/', 'data-v-12345678', $actual);
24-
2525
$this->assertEqualHtml($expected, $actual);
2626
}
2727

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<style>
2+
.foo[data-v-a2116698cabca27b45a4db453446b8d2] {
3+
color: red;
4+
}
5+
</style>
6+
<div class="root {{ class|default('') }}" data-v-a2116698cabca27b45a4db453446b8d2 {{ dataScopedStyleAttribute|default('') }} style="{{ style|default('') }}">
7+
<div class="foo" data-v-a2116698cabca27b45a4db453446b8d2>
8+
{% include "/templates/ChildComponent.twig" with { 'dataScopedStyleAttribute': "data-v-a2116698cabca27b45a4db453446b8d2", 'class': "", 'style': "" } %}
9+
</div>
10+
</div>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<div class="root">
3+
<div class="foo">
4+
<ChildComponent />
5+
</div>
6+
</div>
7+
</template>
8+
9+
<script>
10+
export default {
11+
name: 'cstyle-block-scoped-with-child-binding.vue',
12+
component: {
13+
ChildComponent,
14+
}
15+
};
16+
</script>
17+
18+
<style scoped>
19+
.foo {
20+
color: red;
21+
}
22+
</style>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<style>
2+
.foo[data-v-6737f06d5bb113335593e128322855f1] {
3+
color: red;
4+
}
5+
.bar[data-v-6737f06d5bb113335593e128322855f1],
6+
.baz[data-v-6737f06d5bb113335593e128322855f1] {
7+
color: blue;
8+
}
9+
.foo:after[data-v-6737f06d5bb113335593e128322855f1] {
10+
display: none;
11+
}
12+
.root .bar[data-v-6737f06d5bb113335593e128322855f1] {
13+
text-decoration: underline;
14+
}
15+
</style>
16+
<div class="root {{ class|default('') }}" data-v-6737f06d5bb113335593e128322855f1 {{ dataScopedStyleAttribute|default('') }} style="{{ style|default('') }}">
17+
<div class="foo" data-v-6737f06d5bb113335593e128322855f1>
18+
foo
19+
</div>
20+
<div class="bar" data-v-6737f06d5bb113335593e128322855f1>
21+
bar
22+
</div>
23+
<div class="baz" data-v-6737f06d5bb113335593e128322855f1>
24+
baz
25+
</div>
26+
</div>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<style>.foo[data-v-eb50964453fb1d39d2d2f020c6639c00] { color: red; } .foo__bar[data-v-eb50964453fb1d39d2d2f020c6639c00] { color: blue; } .foo__baz[data-v-eb50964453fb1d39d2d2f020c6639c00] { color: #00FF00; }</style>
2+
<div data-v-eb50964453fb1d39d2d2f020c6639c00 {{ dataScopedStyleAttribute|default('') }} class="{{ class|default('') }}" style="{{ style|default('') }}">
3+
<div class="foo__bar" data-v-eb50964453fb1d39d2d2f020c6639c00>
4+
baz
5+
</div>
6+
</div>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<style> .foo { color: red; }</style>
2+
<div {{ dataScopedStyleAttribute|default('') }} class="{{ class|default('') }}" style="{{ style|default('') }}">
3+
<div class="foo" {{ dataScopedStyleAttribute|default('') }}>
4+
foo
5+
</div>
6+
</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<div>
3+
<div class="foo">
4+
foo
5+
</div>
6+
</div>
7+
</template>
8+
9+
<style>
10+
.foo {
11+
color: red;
12+
}
13+
</style>
14+
15+
<script>
16+
export default {
17+
}
18+
</script>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<style> .foo { color: red; }</style>
2+
<style> .bar[data-v-9d8ac5d70d06b0f0d2a21f893932dffe] { color: blue; }</style>
3+
<style>.baz { color: #00FF00; }</style>
4+
<div data-v-9d8ac5d70d06b0f0d2a21f893932dffe {{ dataScopedStyleAttribute|default('') }} class="{{ class|default('') }}" style="{{ style|default('') }}">
5+
<div class="foo bar baz" data-v-9d8ac5d70d06b0f0d2a21f893932dffe>
6+
42
7+
</div>
8+
</div>

tests/fixtures/style-block/style-block-scoped.twig

Lines changed: 0 additions & 26 deletions
This file was deleted.

tests/fixtures/style-block/style-block-scss-scoped.twig

Lines changed: 0 additions & 6 deletions
This file was deleted.

tests/fixtures/style-block/style-blocks.twig

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)