ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
Table.php
Go to the documentation of this file.
1 <?php
2 
33 {
37  public $allow_empty = false;
38 
42  public $type = 'table';
43 
47  public $elements = array(
48  'tr' => true,
49  'tbody' => true,
50  'thead' => true,
51  'tfoot' => true,
52  'caption' => true,
53  'colgroup' => true,
54  'col' => true
55  );
56 
57  public function __construct()
58  {
59  }
60 
67  public function validateChildren($children, $config, $context)
68  {
69  if (empty($children)) {
70  return false;
71  }
72 
73  // only one of these elements is allowed in a table
74  $caption = false;
75  $thead = false;
76  $tfoot = false;
77 
78  // whitespace
79  $initial_ws = array();
80  $after_caption_ws = array();
81  $after_thead_ws = array();
82  $after_tfoot_ws = array();
83 
84  // as many of these as you want
85  $cols = array();
86  $content = array();
87 
88  $tbody_mode = false; // if true, then we need to wrap any stray
89  // <tr>s with a <tbody>.
90 
91  $ws_accum =& $initial_ws;
92 
93  foreach ($children as $node) {
94  if ($node instanceof HTMLPurifier_Node_Comment) {
95  $ws_accum[] = $node;
96  continue;
97  }
98  switch ($node->name) {
99  case 'tbody':
100  $tbody_mode = true;
101  // fall through
102  case 'tr':
103  $content[] = $node;
104  $ws_accum =& $content;
105  break;
106  case 'caption':
107  // there can only be one caption!
108  if ($caption !== false) break;
109  $caption = $node;
110  $ws_accum =& $after_caption_ws;
111  break;
112  case 'thead':
113  $tbody_mode = true;
114  // XXX This breaks rendering properties with
115  // Firefox, which never floats a <thead> to
116  // the top. Ever. (Our scheme will float the
117  // first <thead> to the top.) So maybe
118  // <thead>s that are not first should be
119  // turned into <tbody>? Very tricky, indeed.
120  if ($thead === false) {
121  $thead = $node;
122  $ws_accum =& $after_thead_ws;
123  } else {
124  // Oops, there's a second one! What
125  // should we do? Current behavior is to
126  // transmutate the first and last entries into
127  // tbody tags, and then put into content.
128  // Maybe a better idea is to *attach
129  // it* to the existing thead or tfoot?
130  // We don't do this, because Firefox
131  // doesn't float an extra tfoot to the
132  // bottom like it does for the first one.
133  $node->name = 'tbody';
134  $content[] = $node;
135  $ws_accum =& $content;
136  }
137  break;
138  case 'tfoot':
139  // see above for some aveats
140  $tbody_mode = true;
141  if ($tfoot === false) {
142  $tfoot = $node;
143  $ws_accum =& $after_tfoot_ws;
144  } else {
145  $node->name = 'tbody';
146  $content[] = $node;
147  $ws_accum =& $content;
148  }
149  break;
150  case 'colgroup':
151  case 'col':
152  $cols[] = $node;
153  $ws_accum =& $cols;
154  break;
155  case '#PCDATA':
156  // How is whitespace handled? We treat is as sticky to
157  // the *end* of the previous element. So all of the
158  // nonsense we have worked on is to keep things
159  // together.
160  if (!empty($node->is_whitespace)) {
161  $ws_accum[] = $node;
162  }
163  break;
164  }
165  }
166 
167  if (empty($content)) {
168  return false;
169  }
170 
171  $ret = $initial_ws;
172  if ($caption !== false) {
173  $ret[] = $caption;
174  $ret = array_merge($ret, $after_caption_ws);
175  }
176  if ($cols !== false) {
177  $ret = array_merge($ret, $cols);
178  }
179  if ($thead !== false) {
180  $ret[] = $thead;
181  $ret = array_merge($ret, $after_thead_ws);
182  }
183  if ($tfoot !== false) {
184  $ret[] = $tfoot;
185  $ret = array_merge($ret, $after_tfoot_ws);
186  }
187 
188  if ($tbody_mode) {
189  // we have to shuffle tr into tbody
190  $current_tr_tbody = null;
191 
192  foreach($content as $node) {
193  switch ($node->name) {
194  case 'tbody':
195  $current_tr_tbody = null;
196  $ret[] = $node;
197  break;
198  case 'tr':
199  if ($current_tr_tbody === null) {
200  $current_tr_tbody = new HTMLPurifier_Node_Element('tbody');
201  $ret[] = $current_tr_tbody;
202  }
203  $current_tr_tbody->children[] = $node;
204  break;
205  case '#PCDATA':
206  assert($node->is_whitespace);
207  if ($current_tr_tbody === null) {
208  $ret[] = $node;
209  } else {
210  $current_tr_tbody->children[] = $node;
211  }
212  break;
213  }
214  }
215  } else {
216  $ret = array_merge($ret, $content);
217  }
218 
219  return $ret;
220 
221  }
222 }
223 
224 // vim: et sw=4 sts=4