Skip to content

Commit

Permalink
Merge branch 'master' of github.com:BrightFlair/PHP.Gt
Browse files Browse the repository at this point in the history
  • Loading branch information
g105b committed Feb 3, 2015
2 parents 0bd18b6 + 48cf076 commit a9500e2
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/Dom/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class Node {

public $domNode;
public $tagName;
public $classList;

/**
*
Expand Down Expand Up @@ -84,6 +85,9 @@ public function __construct($document, $node,
// Fix case, according to W3 spec
// http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-745549614
$this->tagName = strtoupper($this->domNode->tagName);

// Add classList property (only for Elements)
$this->classList = new TokenList($this, "class");
}

if(!is_null($nodeValue)) {
Expand Down
119 changes: 117 additions & 2 deletions src/Dom/TokenList.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,143 @@

class TokenList {

public function __construct($node, $attribute = "class") {
// var_dump($node);die();
private $list;
private $node;
private $attributeName;
private $attributeValue;
private $separator;

public function __construct($node, $attributeName = "class", $separator = " ") {
$this->node = $node;
$this->attributeName = $attributeName;
$this->separator = $separator;
$this->refreshAttribute();
}

/**
* Returns an item in the list by its index (or null if the number is
* greater than or equal to the length of the list)
*
* @param int $index Zero-based index of token in list
*
* @return string|null If set, the string token at the supplied index. If there
* is no token at that index, returns null
*/
public function item($index) {
$this->rebuildAttribute();

if(isset($list[$index])) {
return $list[$index];
}

return null;
}

/**
* Returns true if the underlying string contains token, otherwise false.
*
* @param string $token The token to search for
*
* @return bool true if the underlying string contains token, otherwise false
*/
public function contains($token) {
$this->rebuildAttribute();

return in_array($token, $this->list);
}

/**
* Adds token to the underlying string. If token is already part of the
* underlying string, ignore.
*
* @param string $token The token to add
*
* @return string The added token
*/
public function add($token) {
$this->rebuildAttribute();

if(!$this->contains($token)) {
$this->list []= $token;
}

$this->rebuildAttribute();
return $token;
}

/**
* Removes token from the underlying string. If token is not part of the
* underlying string, ignore.
*
* @param string $token The token to remove
*
* @return string The removed token
*/
public function remove($token) {
$this->rebuildAttribute();

if($this->contains($token)) {
$index = array_search($token, $this->list);
unset($this->list[$index]);
$this->list = array_values($this->list);
}

$this->rebuildAttribute();
return $token;
}

/**
* Removes token from string and returns false. If token doesn't exist it's
* added and the function returns true.
*
* @param string $token The token to toggle
*
* @return book True if the token is added, false if the token is removed
*/
public function toggle($token) {
$this->rebuildAttribute();

if($this->contains($token)) {
$this->remove($token);
return false;
}
else {
$this->add($token);
return true;
}
}

/**
* From the node's actual attribute value, refresh the underlying properties.
*
* @return void
*/
private function refreshAttribute() {
$attributeValue = "";
if($this->node->hasAttribute($this->attributeName)) {
$attributeValue = $this->node->getAttribute($this->attributeName);
}

$this->list = explode($this->separator, $attributeValue);
$this->attributeValue = $attributeValue;
}

/**
* From the underlying list in its given state, rebuild the attribute
* it represents by removing, then re-adding each token separately.
*
* @return void
*/
private function rebuildAttribute() {
$currentAttributeValue = $this->node->getAttribute($this->attributeName);
if($this->attributeValue !== $currentAttributeValue) {
$this->refreshAttribute();
}

$this->node->removeAttribute($this->attributeName);
$attributeValue = implode($this->separator, $this->list);

$this->node->setAttribute($this->attributeName, $attributeValue);
}

}#
104 changes: 104 additions & 0 deletions test/Unit/Dom/TokenList.test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php
/**
* PHP.Gt (http://php.gt)
* @copyright Copyright Ⓒ 2015 Bright Flair Ltd. (http://brightflair.com)
* @license http://www.opensource.org/licenses/mit-license.php MIT
*/
namespace Gt\Dom;

class DomTokenList_Test extends \PHPUnit_Framework_TestCase {

private $html = '<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Dom Test</title>
</head>
<body>
<h1>Dom Test!</h1>
</body>
</html>';

private $document;
private $classNameArray = [
"my-class",
"secondaryClass",
"and-another",
];

public function setUp() {
$this->document = new Document($this->html);
}

public function testClassListPropertyExists() {
$h1 = $this->document->getElementsByTagName("h1")[0];
$this->assertInstanceOf("\Gt\Dom\TokenList", $h1->classList);
}

public function testClassListContainsOneClass() {
$h1 = $this->document->getElementsByTagName("h1")[0];
$h1->setAttribute("class", $this->classNameArray[0]);

$this->assertTrue($h1->classList->contains($this->classNameArray[0]));
}

public function testClassListContainsMultipleClasses() {
$h1 = $this->document->getElementsByTagName("h1")[0];
$h1->setAttribute("class", implode(" ", $this->classNameArray));

foreach ($this->classNameArray as $className) {
$this->assertTrue($h1->classList->contains($className));
}
}

public function testClassListAdds() {
$h1 = $this->document->getElementsByTagName("h1")[0];

for($i = 0, $count = count($this->classNameArray); $i < $count; $i++) {
$className = $this->classNameArray[$i];
$this->assertFalse($h1->classList->contains($className));
$h1->classList->add($className);
$this->assertTrue($h1->classList->contains($className));
}

foreach ($this->classNameArray as $className) {
$this->assertTrue($h1->classList->contains($className));
}
}

public function testClassListRemoves() {
$h1 = $this->document->getElementsByTagName("h1")[0];

$h1->setAttribute("class", implode(" ", $this->classNameArray));

foreach ($this->classNameArray as $className) {
$this->assertTrue($h1->classList->contains($className));
$h1->classList->remove($className);
$this->assertFalse($h1->classList->contains($className));
}
}

public function testClassListToggle() {
$h1 = $this->document->getElementsByTagNAme("h1")[0];

$h1->setAttribute("class", implode(" ", $this->classNameArray));

for($i = 0; $i < 100; $i++) {
$classIndex = array_rand($this->classNameArray);
$className = $this->classNameArray[$classIndex];
$hasClass = $h1->classList->contains($className);
$toggled = $h1->classList->toggle($className);
$this->assertEquals(!$hasClass, $toggled);

if($hasClass) {
$this->assertFalse($h1->classList->contains($className));
}
else {
$this->assertTrue($h1->classList->contains($className));
}
}
}

}#

0 comments on commit a9500e2

Please sign in to comment.