Skip to content

Instantly share code, notes, and snippets.

@Zegnat
Last active April 3, 2018 09:52
Show Gist options
  • Save Zegnat/4fcfff20741a5f78a73bc7b717fd8396 to your computer and use it in GitHub Desktop.
Save Zegnat/4fcfff20741a5f78a73bc7b717fd8396 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace Zegnat;
final class PleaseNo
{
/**
* Returns a DOM element’s text content as if the DOM had been rendered through an
* approximate implementation of the HTML specification’s innerText getter.
*
* @see https://html.spec.whatwg.org/#dom-innertext
**/
public function innerText(\DOMElement $element): string
{
if ($this->isBeingRendered($element) === false) {
return $element->textContent;
}
$count = 0;
$output = '';
foreach ($this->innerTextCollectionSteps($element) as $item) {
if ($output !== '' && is_int($item) && $item > $count) {
$count = $item;
} elseif (is_string($item) && $item !== '') {
$output .= str_repeat("\n", $count) . $item;
$count = 0;
}
}
return $output;
}
/**
* Check if a DOM node should be rendered per section 14 Rendering of the HTML
* specification. If a node’s `display` value is none, it is not being rendered.
*
* For non-Element nodes it is assumed they use whatever value the closest Element
* parent is using.
*
* @TODO Decide if noscript elements are rendered.
* @TODO Decide if elements that represent nothing (e.g. template) are rendered.
* @TODO Check if any parent elements are not being rendered, as this cascades down.
*
* @see https://html.spec.whatwg.org/#hidden-elements 14.3.1 Hidden elements
* @see https://html.spec.whatwg.org/#tables-2 14.3.9 Tables
**/
private function isBeingRendered(\DOMNode $element): bool
{
// When this runs on a non-Element, walk up the tree to the closest element.
while (!$element instanceof \DOMElement) {
$element = $element->parentNode;
}
// List of elements that always have `display: none`.
$elements = ['area', 'base', 'basefont', 'datalist', 'head', 'link', 'meta',
'noembed', 'noframes', 'param', 'rp', 'script', 'source', 'style', 'template',
'track', 'title'];
// List of elements that are still rendered with the hidden attribute set.
$exceptions = ['embed', 'colgroup', 'col', 'thead', 'tbody', 'tfoot', 'tr', 'td',
'th'];
// List of parents that stop a form element from rendering.
$form = ['table', 'thead', 'tbody', 'tfoot', 'tr'];
// Figure it out!
$name = strtolower($element->tagName);
return !(in_array($name, $elements) ||
$element->hasAttribute('hidden') && !in_array($name, $exceptions) ||
$name === 'input' && strtolower($element->getAttribute('type')) === 'hidden' ||
$name === 'form' && in_array(strtolower($element->parentNode->tagName), $form));
}
/**
* @TODO Implement.
*
* @see https://html.spec.whatwg.org/#inner-text-collection-steps
**/
private function innerTextCollectionSteps(\DOMNode $node): array
{
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment