Skip to content

Commit e1c8391

Browse files
authored
Merge pull request #17 from Paneon/feature/double-attribute-binding
Add support for double attribute binding
2 parents 681e03b + 2b59858 commit e1c8391

File tree

5 files changed

+88
-40
lines changed

5 files changed

+88
-40
lines changed

src/Compiler.php

Lines changed: 63 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public function convertNode(DOMNode $node): DOMNode
9494
switch ($node->nodeType) {
9595
case XML_TEXT_NODE:
9696
$this->logger->debug('Text node found', ['name' => $node->nodeName]);
97-
// fall through to next case, because we don't need to handle either of these node-types
97+
// fall through to next case, because we don't need to handle either of these node-types
9898
case XML_COMMENT_NODE:
9999
$this->logger->debug('Comment node found', ['name' => $node->nodeName]);
100100
return $node;
@@ -125,7 +125,7 @@ public function convertNode(DOMNode $node): DOMNode
125125

126126
$usedComponent->addProperty($name, $value, true);
127127
} else {
128-
$usedComponent->addProperty($attribute->name, '"'.$attribute->value.'"', false);
128+
$usedComponent->addProperty($attribute->name, '"' . $attribute->value . '"', false);
129129
}
130130
}
131131
}
@@ -166,61 +166,63 @@ private function handleAttributeBinding(DOMElement $node)
166166
foreach (iterator_to_array($node->attributes) as $attribute) {
167167

168168
if (strpos($attribute->name, 'v-bind:') !== 0 && strpos($attribute->name, ':') !== 0) {
169-
$this->logger->debug("- skip: ".$attribute->name);
169+
$this->logger->debug("- skip: " . $attribute->name);
170170
continue;
171171
}
172172

173173
$name = substr($attribute->name, strpos($attribute->name, ':') + 1);
174174
$value = $attribute->value;
175-
$this->logger->debug('- handle: '.$name.' = '.$value);
175+
$this->logger->debug('- handle: ' . $name . ' = ' . $value);
176176

177+
$staticValues = $node->hasAttribute($name) ? $node->getAttribute($name) : '';
178+
$dynamicValues = [];
179+
180+
// Remove originally bound attribute
181+
$this->logger->debug('- remove original ' . $attribute->name);
182+
$node->removeAttribute($attribute->name);
177183

178184
switch ($name) {
179185
case 'key':
180186
// Not necessary in twig
181-
break;
187+
$this->logger->debug('- skip: key');
188+
return;
182189
case 'style':
183190
break;
184191
case 'class':
185192
break;
186-
default:
187-
if ($value === 'true') {
188-
$this->logger->debug('- setAttribute '.$name);
189-
$node->setAttribute($name, $name);
190-
} else {
191-
$this->logger->debug('- setAttribute "'.$name.'" with value');
192-
$node->setAttribute(
193-
$name,
194-
Replacements::getSanitizedConstant('DOUBLE_CURLY_OPEN').
195-
$value.
196-
Replacements::getSanitizedConstant('DOUBLE_CURLY_CLOSE')
197-
);
198-
}
199193
}
200194

201-
if (is_array($value)) {
195+
if ($value === 'true') {
196+
$this->logger->debug('- setAttribute ' . $name);
197+
$node->setAttribute($name, $name);
198+
} elseif (preg_match('/^\[([^\]]+)\]$/', $value, $matches)) {
199+
$this->logger->debug('- is array '.$value);
200+
201+
if(preg_match_all('/((?:[\'"])(?<elements>[^\'"])[\'"])/', $value, $arrayMatch)){
202+
$value = $arrayMatch['elements'];
203+
$this->logger->debug('- ', ['match' => $arrayMatch]);
204+
}
205+
else {
206+
$value = [];
207+
}
208+
202209
if ($name === 'style') {
203-
$styles = [];
204210
foreach ($value as $prop => $setting) {
205211
if ($setting) {
206212
$prop = strtolower(preg_replace('/([A-Z])/', '-$1', $prop));
207-
$styles[] = sprintf('%s:%s', $prop, $setting);
213+
$dynamicValues[] = sprintf('%s:%s', $prop, $setting);
208214
}
209215
}
210-
$node->setAttribute($name, implode(';', $styles));
211216
} elseif ($name === 'class') {
212-
$classes = [];
213-
foreach ($value as $className => $setting) {
214-
if ($setting) {
215-
$classes[] = $className;
216-
}
217+
foreach ($value as $className) {
218+
$dynamicValues[] = $className;
217219
}
218-
$node->setAttribute($name, implode(' ', $classes));
219220
}
220-
} /*
221-
* <div :class="`abc ${someDynamicClass}`">
222-
*/
221+
}
223222
elseif (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
223+
/*
224+
* <div :class="`abc ${someDynamicClass}`">
225+
*/
224226
$templateStringContent = $matches['content'];
225227

226228
$templateStringContent = preg_replace(
@@ -229,13 +231,19 @@ private function handleAttributeBinding(DOMElement $node)
229231
$templateStringContent
230232
);
231233

232-
$node->setAttribute($name, $templateStringContent);
234+
$dynamicValues[] = $templateStringContent;
233235
} else {
234-
$this->logger->debug('- No Handling for: '.$value);
236+
$this->logger->debug('- setAttribute "' . $name . '" with value');
237+
$dynamicValues[] =
238+
Replacements::getSanitizedConstant('DOUBLE_CURLY_OPEN') .
239+
$value .
240+
Replacements::getSanitizedConstant('DOUBLE_CURLY_CLOSE');
235241
}
236242

237-
$this->logger->debug('=> remove original '.$attribute->name);
238-
$node->removeAttribute($attribute->name);
243+
$node->setAttribute(
244+
$name,
245+
$this->implodeAttributeValue($name, $dynamicValues, $staticValues)
246+
);
239247
}
240248
}
241249

@@ -319,7 +327,7 @@ private function handleFor(DOMElement $node)
319327

320328
// (2)
321329
if (preg_match('/(\d+)/', $listName)) {
322-
$listName = '1..'.$listName;
330+
$listName = '1..' . $listName;
323331
}
324332

325333
// (1)
@@ -408,6 +416,21 @@ protected function sanitizeCondition(string $condition)
408416
return $condition;
409417
}
410418

419+
protected function implodeAttributeValue(string $attribute, array $values, string $oldValue): string
420+
{
421+
$glue = ' ';
422+
423+
if($attribute === 'style') {
424+
$glue = '; ';
425+
}
426+
427+
if(!empty($oldValue)) {
428+
$values = array_merge([$oldValue], $values);
429+
}
430+
431+
return implode($glue, $values);
432+
}
433+
411434
protected function replacePlaceholders(string $string)
412435
{
413436
foreach (Replacements::getConstants() as $constant => $value) {
@@ -424,7 +447,7 @@ public function registerComponent(string $componentName, string $componentPath)
424447

425448
protected function addSingleLineBanner(string $html)
426449
{
427-
return $this->builder->createComment(implode('', $this->banner))."\n".$html;
450+
return $this->builder->createComment(implode('', $this->banner)) . "\n" . $html;
428451
}
429452

430453
protected function addBanner(string $html)
@@ -436,20 +459,20 @@ protected function addBanner(string $html)
436459
$bannerLines = ['{#'];
437460

438461
foreach ($this->banner as $line) {
439-
$bannerLines[] = ' # '.$line;
462+
$bannerLines[] = ' # ' . $line;
440463
}
441464

442465
$bannerLines[] = ' #}';
443466

444-
$html = implode(PHP_EOL, $bannerLines).PHP_EOL.$html;
467+
$html = implode(PHP_EOL, $bannerLines) . PHP_EOL . $html;
445468

446469
return $html;
447470
}
448471

449472
public function refactorTemplateString($value)
450473
{
451474
if (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
452-
$templateStringContent = '"'.$matches['content'].'"';
475+
$templateStringContent = '"' . $matches['content'] . '"';
453476
$value = preg_replace(
454477
'/\$\{(.+)\}/',
455478
'{{ $1 }}',

tests/fixtures/vue-bind/bindings.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
<div>
33
<input type="radio" checked>
44
<img src="{{imageSrc}}">
5+
<div class="a b c"></div>
56
</div>
67
</div>

tests/fixtures/vue-bind/bindings.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<div>
44
<input type="radio" :checked="true">
55
<img :src="imageSrc">
6+
<div :class="['a', 'b', 'c']"></div>
67
</div>
78
</div>
89
</template>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="block">
2+
<div class="static1 static2 dynamic dynamic--{{ modifier }}">
3+
Hello World
4+
</div>
5+
</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<div class="block">
3+
<div :class="`dynamic dynamic--${modifier}`" class="static1 static2">
4+
Hello World
5+
</div>
6+
</div>
7+
</template>
8+
9+
<script>
10+
export default {
11+
props: {
12+
modifier: {
13+
type: String,
14+
required: true,
15+
},
16+
},
17+
};
18+
</script>

0 commit comments

Comments
 (0)