List.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. /**
  3. * Definition for list containers ul and ol.
  4. */
  5. class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
  6. {
  7. public $type = 'list';
  8. // lying a little bit, so that we can handle ul and ol ourselves
  9. // XXX: This whole business with 'wrap' is all a bit unsatisfactory
  10. public $elements = array('li' => true, 'ul' => true, 'ol' => true);
  11. public function validateChildren($tokens_of_children, $config, $context) {
  12. // Flag for subclasses
  13. $this->whitespace = false;
  14. // if there are no tokens, delete parent node
  15. if (empty($tokens_of_children)) return false;
  16. // the new set of children
  17. $result = array();
  18. // current depth into the nest
  19. $nesting = 0;
  20. // a little sanity check to make sure it's not ALL whitespace
  21. $all_whitespace = true;
  22. $seen_li = false;
  23. $need_close_li = false;
  24. foreach ($tokens_of_children as $token) {
  25. if (!empty($token->is_whitespace)) {
  26. $result[] = $token;
  27. continue;
  28. }
  29. $all_whitespace = false; // phew, we're not talking about whitespace
  30. if ($nesting == 1 && $need_close_li) {
  31. $result[] = new HTMLPurifier_Token_End('li');
  32. $nesting--;
  33. $need_close_li = false;
  34. }
  35. $is_child = ($nesting == 0);
  36. if ($token instanceof HTMLPurifier_Token_Start) {
  37. $nesting++;
  38. } elseif ($token instanceof HTMLPurifier_Token_End) {
  39. $nesting--;
  40. }
  41. if ($is_child) {
  42. if ($token->name === 'li') {
  43. // good
  44. $seen_li = true;
  45. } elseif ($token->name === 'ul' || $token->name === 'ol') {
  46. // we want to tuck this into the previous li
  47. $need_close_li = true;
  48. $nesting++;
  49. if (!$seen_li) {
  50. // create a new li element
  51. $result[] = new HTMLPurifier_Token_Start('li');
  52. } else {
  53. // backtrack until </li> found
  54. while(true) {
  55. $t = array_pop($result);
  56. if ($t instanceof HTMLPurifier_Token_End) {
  57. // XXX actually, these invariants could very plausibly be violated
  58. // if we are doing silly things with modifying the set of allowed elements.
  59. // FORTUNATELY, it doesn't make a difference, since the allowed
  60. // elements are hard-coded here!
  61. if ($t->name !== 'li') {
  62. trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
  63. return false;
  64. }
  65. break;
  66. } elseif ($t instanceof HTMLPurifier_Token_Empty) { // bleagh
  67. if ($t->name !== 'li') {
  68. trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
  69. return false;
  70. }
  71. // XXX this should have a helper for it...
  72. $result[] = new HTMLPurifier_Token_Start('li', $t->attr, $t->line, $t->col, $t->armor);
  73. break;
  74. } else {
  75. if (!$t->is_whitespace) {
  76. trigger_error("Only whitespace present invariant violated in List ChildDef", E_USER_ERROR);
  77. return false;
  78. }
  79. }
  80. }
  81. }
  82. } else {
  83. // start wrapping (this doesn't precisely mimic
  84. // browser behavior, but what browsers do is kind of
  85. // hard to mimic in a standards compliant way
  86. // XXX Actually, this has no impact in practice,
  87. // because this gets handled earlier. Arguably,
  88. // we should rip out all of that processing
  89. $result[] = new HTMLPurifier_Token_Start('li');
  90. $nesting++;
  91. $seen_li = true;
  92. $need_close_li = true;
  93. }
  94. }
  95. $result[] = $token;
  96. }
  97. if ($need_close_li) {
  98. $result[] = new HTMLPurifier_Token_End('li');
  99. }
  100. if (empty($result)) return false;
  101. if ($all_whitespace) {
  102. return false;
  103. }
  104. if ($tokens_of_children == $result) return true;
  105. return $result;
  106. }
  107. }
  108. // vim: et sw=4 sts=4