HTMLPurifier 4.4.0
/home/ezyang/Dev/htmlpurifier/library/HTMLPurifier/ChildDef/List.php
Go to the documentation of this file.
00001 <?php
00002 
00006 class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
00007 {
00008     public $type = 'list';
00009     // lying a little bit, so that we can handle ul and ol ourselves
00010     // XXX: This whole business with 'wrap' is all a bit unsatisfactory
00011     public $elements = array('li' => true, 'ul' => true, 'ol' => true);
00012     public function validateChildren($tokens_of_children, $config, $context) {
00013         // Flag for subclasses
00014         $this->whitespace = false;
00015 
00016         // if there are no tokens, delete parent node
00017         if (empty($tokens_of_children)) return false;
00018 
00019         // the new set of children
00020         $result = array();
00021 
00022         // current depth into the nest
00023         $nesting = 0;
00024 
00025         // a little sanity check to make sure it's not ALL whitespace
00026         $all_whitespace = true;
00027 
00028         $seen_li = false;
00029         $need_close_li = false;
00030 
00031         foreach ($tokens_of_children as $token) {
00032             if (!empty($token->is_whitespace)) {
00033                 $result[] = $token;
00034                 continue;
00035             }
00036             $all_whitespace = false; // phew, we're not talking about whitespace
00037 
00038             if ($nesting == 1 && $need_close_li) {
00039                 $result[] = new HTMLPurifier_Token_End('li');
00040                 $nesting--;
00041                 $need_close_li = false;
00042             }
00043 
00044             $is_child = ($nesting == 0);
00045 
00046             if ($token instanceof HTMLPurifier_Token_Start) {
00047                 $nesting++;
00048             } elseif ($token instanceof HTMLPurifier_Token_End) {
00049                 $nesting--;
00050             }
00051 
00052             if ($is_child) {
00053                 if ($token->name === 'li') {
00054                     // good
00055                     $seen_li = true;
00056                 } elseif ($token->name === 'ul' || $token->name === 'ol') {
00057                     // we want to tuck this into the previous li
00058                     $need_close_li = true;
00059                     $nesting++;
00060                     if (!$seen_li) {
00061                         // create a new li element
00062                         $result[] = new HTMLPurifier_Token_Start('li');
00063                     } else {
00064                         // backtrack until </li> found
00065                         while(true) {
00066                             $t = array_pop($result);
00067                             if ($t instanceof HTMLPurifier_Token_End) {
00068                                 // XXX actually, these invariants could very plausibly be violated
00069                                 // if we are doing silly things with modifying the set of allowed elements.
00070                                 // FORTUNATELY, it doesn't make a difference, since the allowed
00071                                 // elements are hard-coded here!
00072                                 if ($t->name !== 'li') {
00073                                     trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
00074                                     return false;
00075                                 }
00076                                 break;
00077                             } elseif ($t instanceof HTMLPurifier_Token_Empty) { // bleagh
00078                                 if ($t->name !== 'li') {
00079                                     trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR);
00080                                     return false;
00081                                 }
00082                                 // XXX this should have a helper for it...
00083                                 $result[] = new HTMLPurifier_Token_Start('li', $t->attr, $t->line, $t->col, $t->armor);
00084                                 break;
00085                             } else {
00086                                 if (!$t->is_whitespace) {
00087                                     trigger_error("Only whitespace present invariant violated in List ChildDef", E_USER_ERROR);
00088                                     return false;
00089                                 }
00090                             }
00091                         }
00092                     }
00093                 } else {
00094                     // start wrapping (this doesn't precisely mimic
00095                     // browser behavior, but what browsers do is kind of
00096                     // hard to mimic in a standards compliant way
00097                     // XXX Actually, this has no impact in practice,
00098                     // because this gets handled earlier. Arguably,
00099                     // we should rip out all of that processing
00100                     $result[] = new HTMLPurifier_Token_Start('li');
00101                     $nesting++;
00102                     $seen_li = true;
00103                     $need_close_li = true;
00104                 }
00105             }
00106             $result[] = $token;
00107         }
00108         if ($need_close_li) {
00109             $result[] = new HTMLPurifier_Token_End('li');
00110         }
00111         if (empty($result)) return false;
00112         if ($all_whitespace) {
00113             return false;
00114         }
00115         if ($tokens_of_children == $result) return true;
00116         return $result;
00117     }
00118 }
00119 
00120 // vim: et sw=4 sts=4