Copie de Tumblr sur Shaarli
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.1KB

  1. <?php
  2. namespace League\HTMLToMarkdown;
  3. class Element implements ElementInterface
  4. {
  5. /**
  6. * @var \DOMNode
  7. */
  8. protected $node;
  9. /**
  10. * @var ElementInterface|null
  11. */
  12. private $nextCached;
  13. public function __construct(\DOMNode $node)
  14. {
  15. $this->node = $node;
  16. }
  17. /**
  18. * @return bool
  19. */
  20. public function isBlock()
  21. {
  22. switch ($this->getTagName()) {
  23. case 'blockquote':
  24. case 'body':
  25. case 'code':
  26. case 'div':
  27. case 'h1':
  28. case 'h2':
  29. case 'h3':
  30. case 'h4':
  31. case 'h5':
  32. case 'h6':
  33. case 'hr':
  34. case 'html':
  35. case 'li':
  36. case 'p':
  37. case 'ol':
  38. case 'ul':
  39. return true;
  40. default:
  41. return false;
  42. }
  43. }
  44. /**
  45. * @return bool
  46. */
  47. public function isText()
  48. {
  49. return $this->getTagName() === '#text';
  50. }
  51. /**
  52. * @return bool
  53. */
  54. public function isWhitespace()
  55. {
  56. return $this->getTagName() === '#text' && trim($this->getValue()) === '';
  57. }
  58. /**
  59. * @return string
  60. */
  61. public function getTagName()
  62. {
  63. return $this->node->nodeName;
  64. }
  65. /**
  66. * @return string
  67. */
  68. public function getValue()
  69. {
  70. return $this->node->nodeValue;
  71. }
  72. /**
  73. * @return ElementInterface|null
  74. */
  75. public function getParent()
  76. {
  77. return new static($this->node->parentNode) ?: null;
  78. }
  79. /**
  80. * @return bool
  81. */
  82. public function hasChildren()
  83. {
  84. return $this->node->hasChildNodes();
  85. }
  86. /**
  87. * @return ElementInterface[]
  88. */
  89. public function getChildren()
  90. {
  91. $ret = array();
  92. /** @var \DOMNode $node */
  93. foreach ($this->node->childNodes as $node) {
  94. $ret[] = new static($node);
  95. }
  96. return $ret;
  97. }
  98. /**
  99. * @return ElementInterface|null
  100. */
  101. public function getNext()
  102. {
  103. if ($this->nextCached === null) {
  104. $nextNode = $this->getNextNode($this->node);
  105. if ($nextNode !== null) {
  106. $this->nextCached = new static($nextNode);
  107. }
  108. }
  109. return $this->nextCached;
  110. }
  111. /**
  112. * @param \DomNode $node
  113. *
  114. * @return \DomNode|null
  115. */
  116. private function getNextNode($node, $checkChildren = true)
  117. {
  118. if ($checkChildren && $node->firstChild) {
  119. return $node->firstChild;
  120. } elseif ($node->nextSibling) {
  121. return $node->nextSibling;
  122. } elseif ($node->parentNode) {
  123. return $this->getNextNode($node->parentNode, false);
  124. }
  125. }
  126. /**
  127. * @param string[]|string $tagNames
  128. *
  129. * @return bool
  130. */
  131. public function isDescendantOf($tagNames)
  132. {
  133. if (!is_array($tagNames)) {
  134. $tagNames = array($tagNames);
  135. }
  136. for ($p = $this->node->parentNode; $p !== false; $p = $p->parentNode) {
  137. if (is_null($p)) {
  138. return false;
  139. }
  140. if (in_array($p->nodeName, $tagNames)) {
  141. return true;
  142. }
  143. }
  144. return false;
  145. }
  146. /**
  147. * @param string $markdown
  148. */
  149. public function setFinalMarkdown($markdown)
  150. {
  151. $markdown_node = $this->node->ownerDocument->createTextNode($markdown);
  152. $this->node->parentNode->replaceChild($markdown_node, $this->node);
  153. }
  154. /**
  155. * @return string
  156. */
  157. public function getChildrenAsString()
  158. {
  159. return $this->node->C14N();
  160. }
  161. /**
  162. * @return int
  163. */
  164. public function getSiblingPosition()
  165. {
  166. $position = 0;
  167. // Loop through all nodes and find the given $node
  168. foreach ($this->getParent()->getChildren() as $current_node) {
  169. if (!$current_node->isWhitespace()) {
  170. $position++;
  171. }
  172. // TODO: Need a less-buggy way of comparing these
  173. // Perhaps we can somehow ensure that we always have the exact same object and use === instead?
  174. if ($this->equals($current_node)) {
  175. break;
  176. }
  177. }
  178. return $position;
  179. }
  180. /**
  181. * @return int
  182. */
  183. public function getListItemLevel()
  184. {
  185. $level = 0;
  186. $parent = $this->getParent();
  187. while ($parent !== null && $parent->node->parentNode) {
  188. if ($parent->getTagName() === 'li') {
  189. $level++;
  190. }
  191. $parent = $parent->getParent();
  192. }
  193. return $level;
  194. }
  195. /**
  196. * @param string $name
  197. *
  198. * @return string
  199. */
  200. public function getAttribute($name)
  201. {
  202. if ($this->node instanceof \DOMElement) {
  203. return $this->node->getAttribute($name);
  204. }
  205. return '';
  206. }
  207. /**
  208. * @param ElementInterface $element
  209. *
  210. * @return bool
  211. */
  212. public function equals(ElementInterface $element)
  213. {
  214. if ($element instanceof self) {
  215. return $element->node === $this->node;
  216. }
  217. return $element === $this;
  218. }
  219. }