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.

102 lines
3.0KB

  1. <?php
  2. class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
  3. {
  4. /**
  5. * @type HTMLPurifier_Context
  6. */
  7. private $context;
  8. /**
  9. * @type HTMLPurifier_Config
  10. */
  11. private $config;
  12. /**
  13. * @type HTMLPurifier_AttrValidator
  14. */
  15. private $attrValidator;
  16. /**
  17. * @type bool
  18. */
  19. private $removeNbsp;
  20. /**
  21. * @type bool
  22. */
  23. private $removeNbspExceptions;
  24. /**
  25. * @type array
  26. * TODO: make me configurable
  27. */
  28. private $_exclude = array('colgroup' => 1, 'th' => 1, 'td' => 1, 'iframe' => 1);
  29. /**
  30. * @param HTMLPurifier_Config $config
  31. * @param HTMLPurifier_Context $context
  32. * @return void
  33. */
  34. public function prepare($config, $context)
  35. {
  36. parent::prepare($config, $context);
  37. $this->config = $config;
  38. $this->context = $context;
  39. $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp');
  40. $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions');
  41. $this->attrValidator = new HTMLPurifier_AttrValidator();
  42. }
  43. /**
  44. * @param HTMLPurifier_Token $token
  45. */
  46. public function handleElement(&$token)
  47. {
  48. if (!$token instanceof HTMLPurifier_Token_Start) {
  49. return;
  50. }
  51. $next = false;
  52. $deleted = 1; // the current tag
  53. for ($i = count($this->inputZipper->back) - 1; $i >= 0; $i--, $deleted++) {
  54. $next = $this->inputZipper->back[$i];
  55. if ($next instanceof HTMLPurifier_Token_Text) {
  56. if ($next->is_whitespace) {
  57. continue;
  58. }
  59. if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) {
  60. $plain = str_replace("\xC2\xA0", "", $next->data);
  61. $isWsOrNbsp = $plain === '' || ctype_space($plain);
  62. if ($isWsOrNbsp) {
  63. continue;
  64. }
  65. }
  66. }
  67. break;
  68. }
  69. if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) {
  70. if (isset($this->_exclude[$token->name])) {
  71. return;
  72. }
  73. $this->attrValidator->validateToken($token, $this->config, $this->context);
  74. $token->armor['ValidateAttributes'] = true;
  75. if (isset($token->attr['id']) || isset($token->attr['name'])) {
  76. return;
  77. }
  78. $token = $deleted + 1;
  79. for ($b = 0, $c = count($this->inputZipper->front); $b < $c; $b++) {
  80. $prev = $this->inputZipper->front[$b];
  81. if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) {
  82. continue;
  83. }
  84. break;
  85. }
  86. // This is safe because we removed the token that triggered this.
  87. $this->rewindOffset($b+$deleted);
  88. return;
  89. }
  90. }
  91. }
  92. // vim: et sw=4 sts=4