Skip to content

Commit

Permalink
feature: allow binding directly to data-element
Browse files Browse the repository at this point in the history
  • Loading branch information
g105b committed Nov 21, 2024
1 parent 1db4484 commit 459836d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 6 deletions.
14 changes: 10 additions & 4 deletions src/DocumentBinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,23 +160,29 @@ public function bindListCallback(

public function cleanupDocument():void {
$xpathResult = $this->document->evaluate(
"//*/@*[starts-with(name(), 'data-bind')] | //*/@*[starts-with(name(), 'data-list')] | //*/@*[starts-with(name(), 'data-template')] | //*/@*[starts-with(name(), 'data-table-key')]"
"//*/@*[starts-with(name(), 'data-bind')] | //*/@*[starts-with(name(), 'data-list')] | //*/@*[starts-with(name(), 'data-template')] | //*/@*[starts-with(name(), 'data-table-key')] | //*/@*[starts-with(name(), 'data-element')]"
);

$elementsToRemove = [];
/** @var Attr $item */
foreach($xpathResult as $item) {

Check failure on line 168 in src/DocumentBinder.php

View workflow job for this annotation

GitHub Actions / phpstan

PHPDoc tag @var with type Gt\Dom\Attr is not subtype of native type Gt\Dom\Element|Gt\Dom\Node.
if($item->ownerElement->hasAttribute("data-element")) {
array_push($elementsToRemove, $item->ownerElement);
$ownerElement = $item->ownerElement;
if($ownerElement->hasAttribute("data-element")) {
if(!$ownerElement->hasAttribute("data-bound")) {
array_push($elementsToRemove, $ownerElement);
}
continue;
}

$item->ownerElement->removeAttribute($item->name);
$ownerElement->removeAttribute($item->name);
}

foreach($this->document->querySelectorAll("[data-element]") as $dataElement) {
$dataElement->removeAttribute("data-element");
}
foreach($this->document->querySelectorAll("[data-bound]") as $dataBound) {
$dataBound->removeAttribute("data-bound");
}

foreach($elementsToRemove as $element) {
$element->remove();
Expand Down
7 changes: 7 additions & 0 deletions src/HTMLAttributeBinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public function bind(
foreach($element->attributes as $attrName => $attr) {
$attrValue = $attr->value;

if($attrName === "data-element") {
if($attr->value === $key && $value) {
$element->setAttribute("data-bound", true);

Check failure on line 46 in src/HTMLAttributeBinder.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #2 $value of method DOMElement::setAttribute() expects string, true given.
}
}

if(!str_starts_with($attrName, "data-bind")) {
continue;
}
Expand Down Expand Up @@ -81,6 +87,7 @@ public function bind(
$value,
$modifier
);
$element->setAttribute("data-bound", true);

Check failure on line 90 in src/HTMLAttributeBinder.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #2 $value of method DOMElement::setAttribute() expects string, true given.

if(!$attr->ownerElement->hasAttribute("data-rebind")) {
array_push($attributesToRemove, $attrName);
Expand Down
2 changes: 1 addition & 1 deletion src/HTMLAttributeCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class HTMLAttributeCollection {
public function find(Element $context):XPathResult {
return $context->ownerDocument->evaluate(
"descendant-or-self::*[@*[starts-with(name(), 'data-bind')]]",
"descendant-or-self::*[@*[starts-with(name(), 'data-bind')] or (@data-element and @data-element != '')]",
$context
);
}
Expand Down
24 changes: 23 additions & 1 deletion test/phpunit/DocumentBinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,29 @@ public function test_keepsElementWhenBound():void {
$sut->setDependencies(...$this->documentBinderDependencies($document));
$sut->bindKeyValue("error", "Example error!");
$sut->cleanupDocument();
self::assertStringContainsStringIgnoringCase("error", (string)$document);
$errorDiv = $document->querySelector("form>div");
self::assertNotNull($errorDiv);
self::assertSame("Example error!", $errorDiv->textContent);
}

public function test_bindElementWithBindValue():void {
$document = new HTMLDocument(HTMLPageContent::HTML_REMOVE_UNBOUND_BIND_VALUE);
$sut = new DocumentBinder($document);
$sut->setDependencies(...$this->documentBinderDependencies($document));
$sut->bindKeyValue("error", true);
$sut->cleanupDocument();
$errorDiv = $document->querySelector("form>div");
self::assertNotNull($errorDiv);
self::assertSame("There has been an error!", $errorDiv->textContent);
}

public function test_bindElementIsRemovedWhenNotBound():void {
$document = new HTMLDocument(HTMLPageContent::HTML_REMOVE_UNBOUND_BIND_VALUE);
$sut = new DocumentBinder($document);
$sut->setDependencies(...$this->documentBinderDependencies($document));
$sut->cleanupDocument();
$errorDiv = $document->querySelector("form>div");
self::assertNull($errorDiv);
}

public function test_bindData_withList_dataBindList():void {
Expand Down
19 changes: 19 additions & 0 deletions test/phpunit/TestHelper/HTMLPageContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,25 @@ class HTMLPageContent {
<button name="do" value="login">Log in!</button>
</form>
HTML;

const HTML_REMOVE_UNBOUND_BIND_VALUE = <<<HTML
<!doctype html>
<h1>Log in to the system</h1>
<form method="post">
<div data-element="error">There has been an error!</div>
<label>
<span>Your email address:</span>
<input name="email" type="email" required />
</label>
<label>
<span>Your password:</span>
<input name="password" type="password" required />
</label>
<button name="do" value="login">Log in!</button>
</form>
HTML;

const HTML_DATA_BIND_LIST = <<<HTML
Expand Down

0 comments on commit 459836d

Please sign in to comment.