JSLikeHTMLElement.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. /**
  3. * JavaScript-like HTML DOM Element
  4. *
  5. * This class extends PHP's DOMElement to allow
  6. * users to get and set the innerHTML property of
  7. * HTML elements in the same way it's done in
  8. * JavaScript.
  9. *
  10. * Example usage:
  11. * @code
  12. * require_once 'JSLikeHTMLElement.php';
  13. * header('Content-Type: text/plain');
  14. * $doc = new DOMDocument();
  15. * $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
  16. * $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
  17. * $elem = $doc->getElementsByTagName('div')->item(0);
  18. *
  19. * // print innerHTML
  20. * echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
  21. * echo "\n\n";
  22. *
  23. * // set innerHTML
  24. * $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
  25. * echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
  26. * echo "\n\n";
  27. *
  28. * // print document (with our changes)
  29. * echo $doc->saveXML();
  30. * @endcode
  31. *
  32. * @author Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
  33. * @see http://fivefilters.org (the project this was written for)
  34. */
  35. class JSLikeHTMLElement extends DOMElement
  36. {
  37. /**
  38. * Used for setting innerHTML like it's done in JavaScript:
  39. * @code
  40. * $div->innerHTML = '<h2>Chapter 2</h2><p>The story begins...</p>';
  41. * @endcode
  42. */
  43. public function __set($name, $value) {
  44. if ($name == 'innerHTML') {
  45. // first, empty the element
  46. for ($x=$this->childNodes->length-1; $x>=0; $x--) {
  47. $this->removeChild($this->childNodes->item($x));
  48. }
  49. // $value holds our new inner HTML
  50. if ($value != '') {
  51. $f = $this->ownerDocument->createDocumentFragment();
  52. // appendXML() expects well-formed markup (XHTML)
  53. $result = @$f->appendXML($value); // @ to suppress PHP warnings
  54. if ($result) {
  55. if ($f->hasChildNodes()) $this->appendChild($f);
  56. } else {
  57. // $value is probably ill-formed
  58. $f = new DOMDocument();
  59. $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
  60. // Using <htmlfragment> will generate a warning, but so will bad HTML
  61. // (and by this point, bad HTML is what we've got).
  62. // We use it (and suppress the warning) because an HTML fragment will
  63. // be wrapped around <html><body> tags which we don't really want to keep.
  64. // Note: despite the warning, if loadHTML succeeds it will return true.
  65. $result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>');
  66. if ($result) {
  67. $import = $f->getElementsByTagName('htmlfragment')->item(0);
  68. foreach ($import->childNodes as $child) {
  69. $importedNode = $this->ownerDocument->importNode($child, true);
  70. $this->appendChild($importedNode);
  71. }
  72. } else {
  73. // oh well, we tried, we really did. :(
  74. // this element is now empty
  75. }
  76. }
  77. }
  78. } else {
  79. $trace = debug_backtrace();
  80. trigger_error('Undefined property via __set(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
  81. }
  82. }
  83. /**
  84. * Used for getting innerHTML like it's done in JavaScript:
  85. * @code
  86. * $string = $div->innerHTML;
  87. * @endcode
  88. */
  89. public function __get($name)
  90. {
  91. if ($name == 'innerHTML') {
  92. $inner = '';
  93. foreach ($this->childNodes as $child) {
  94. $inner .= $this->ownerDocument->saveXML($child);
  95. }
  96. return $inner;
  97. }
  98. $trace = debug_backtrace();
  99. trigger_error('Undefined property via __get(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
  100. return null;
  101. }
  102. public function __toString()
  103. {
  104. return '['.$this->tagName.']';
  105. }
  106. }
  107. ?>