Browse Source
• ElementSet is now ElementMap again because it's now internally a map of a Document and an array of Elements, but it's public API is still that of a set. • Template elements are now only added as a reference in ElementMap when they're appended to a document. If they're removed, they're removed from ElementMap. If a template element's owner document is destructed then it and all of the other template elements in the document are removed from ElementMap.wrapper-classes
Dustin Wilson
3 years ago
8 changed files with 178 additions and 105 deletions
@ -0,0 +1,102 @@ |
|||
<?php |
|||
/** |
|||
* @license MIT |
|||
* Copyright 2017 Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML\DOM; |
|||
|
|||
// This is a set of elements which need to be kept in memory; it exists because |
|||
// of the peculiar way PHP works. Derived DOM classes (such as |
|||
// HTMLTemplateElement) won't remain as such in the DOM (meaning they will |
|||
// revert to being what is registered for elements in Document) unless at least |
|||
// one reference is kept for the element somewhere in userspace. This is that |
|||
// somewhere. |
|||
class ElementMap { |
|||
protected static $documents = []; |
|||
protected static $elements = []; |
|||
|
|||
|
|||
public static function add(Element $element): bool { |
|||
$document = $element->ownerDocument; |
|||
$index = self::index($document); |
|||
if ($index === -1) { |
|||
self::$documents[] = $document; |
|||
self::$elements[count(self::$documents) - 1][] = $element; |
|||
return true; |
|||
} else { |
|||
foreach (self::$elements[$index] as $v) { |
|||
if ($v->isSameNode($element)) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
self::$elements[$index][] = $element; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function delete(Element $element): bool { |
|||
$document = $element->ownerDocument; |
|||
$index = self::index($document); |
|||
if ($index !== -1) { |
|||
foreach (self::$elements[$index] as $k => $v) { |
|||
if ($v->isSameNode($element)) { |
|||
unset(self::$elements[$index][$k]); |
|||
self::$elements[$index] = array_values(self::$elements[$index]); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function destroy(Document $document): bool { |
|||
$index = self::index($document); |
|||
if ($index !== -1) { |
|||
unset(self::$documents[$index]); |
|||
unset(self::$elements[$index]); |
|||
self::$documents = array_values(self::$documents); |
|||
self::$elements = array_values(self::$elements); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function getIterator(Document $document): \Traversable { |
|||
$index = self::index($document); |
|||
foreach (self::$elements[$index] as $v) { |
|||
yield $v; |
|||
} |
|||
} |
|||
|
|||
public static function has(Element $element): bool { |
|||
$document = $element->ownerDocument; |
|||
$index = self::index($document); |
|||
if ($index !== -1) { |
|||
foreach (self::$elements[$index] as $v) { |
|||
if ($v->isSameNode($element)) { |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
protected static function index(Document $document): int { |
|||
foreach (self::$documents as $k => $d) { |
|||
if ($d->isSameNode($document)) { |
|||
return $k; |
|||
} |
|||
} |
|||
|
|||
return -1; |
|||
} |
|||
} |
@ -1,74 +0,0 @@ |
|||
<?php |
|||
/** |
|||
* @license MIT |
|||
* Copyright 2017 Dustin Wilson, J. King et al. |
|||
* See LICENSE and AUTHORS files for details |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
namespace MensBeam\HTML\DOM; |
|||
|
|||
// This is a set of elements which need to be kept in memory; it exists because |
|||
// of the peculiar way PHP works. Derived DOM classes (such as |
|||
// HTMLTemplateElement) won't remain as such in the DOM (meaning they will |
|||
// revert to being what is registered for elements in Document) unless at least |
|||
// one reference is kept for the element somewhere in userspace. This is that |
|||
// somewhere. |
|||
class ElementSet { |
|||
protected static $_storage = []; |
|||
|
|||
|
|||
public static function add(Element $element) { |
|||
if (!self::has($element)) { |
|||
self::$_storage[] = $element; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function delete(Element $element) { |
|||
foreach (self::$_storage as $k => $v) { |
|||
if ($v->isSameNode($element)) { |
|||
unset(self::$_storage[$k]); |
|||
self::$_storage = array_values(self::$_storage); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function destroy(Document $document) { |
|||
$changed = false; |
|||
foreach (self::$_storage as $k => $v) { |
|||
if ($v->ownerDocument->isSameNode($document)) { |
|||
unset(self::$_storage[$k]); |
|||
$changed = true; |
|||
} |
|||
} |
|||
|
|||
if ($changed) { |
|||
self::$_storage = array_values(self::$_storage); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function getIterator(): \Traversable { |
|||
foreach (self::$_storage as $v) { |
|||
yield $v; |
|||
} |
|||
} |
|||
|
|||
public static function has(Element $element) { |
|||
foreach (self::$_storage as $v) { |
|||
if ($v->isSameNode($element)) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
Loading…
Reference in new issue