ILIAS  release_4-4 Revision
All Data Structures Namespaces Files Functions Variables Modules Pages
HTML5TreeConstructer Class Reference
+ Collaboration diagram for HTML5TreeConstructer:

Public Member Functions

 __construct ()
 
 emitToken ($token)
 
 save ()
 

Data Fields

 $stack = array()
 
const INIT_PHASE = 0
 
const ROOT_PHASE = 1
 
const MAIN_PHASE = 2
 
const END_PHASE = 3
 
const BEFOR_HEAD = 0
 
const IN_HEAD = 1
 
const AFTER_HEAD = 2
 
const IN_BODY = 3
 
const IN_TABLE = 4
 
const IN_CAPTION = 5
 
const IN_CGROUP = 6
 
const IN_TBODY = 7
 
const IN_ROW = 8
 
const IN_CELL = 9
 
const IN_SELECT = 10
 
const AFTER_BODY = 11
 
const IN_FRAME = 12
 
const AFTR_FRAME = 13
 
const SPECIAL = 0
 
const SCOPING = 1
 
const FORMATTING = 2
 
const PHRASING = 3
 
const MARKER = 0
 

Private Member Functions

 initPhase ($token)
 
 rootElementPhase ($token)
 
 mainPhase ($token)
 
 beforeHead ($token)
 
 inHead ($token)
 
 afterHead ($token)
 
 inBody ($token)
 
 inTable ($token)
 
 inCaption ($token)
 
 inColumnGroup ($token)
 
 inTableBody ($token)
 
 inRow ($token)
 
 inCell ($token)
 
 inSelect ($token)
 
 afterBody ($token)
 
 inFrameset ($token)
 
 afterFrameset ($token)
 
 trailingEndPhase ($token)
 
 insertElement ($token, $append=true, $check=false)
 
 insertText ($data)
 
 insertComment ($data)
 
 appendToRealParent ($node)
 
 elementInScope ($el, $table=false)
 
 reconstructActiveFormattingElements ()
 
 clearTheActiveFormattingElementsUpToTheLastMarker ()
 
 generateImpliedEndTags ($exclude=array())
 
 getElementCategory ($node)
 
 clearStackToTableContext ($elements)
 
 resetInsertionMode ()
 
 closeCell ()
 

Private Attributes

 $phase
 
 $mode
 
 $dom
 
 $foster_parent = null
 
 $a_formatting = array()
 
 $head_pointer = null
 
 $form_pointer = null
 
 $scoping = array('button','caption','html','marquee','object','table','td','th')
 
 $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u')
 
 $special
 

Detailed Description

Definition at line 1178 of file PH5P.php.

Constructor & Destructor Documentation

◆ __construct()

HTML5TreeConstructer::__construct ( )

Definition at line 1230 of file PH5P.php.

1230  {
1231  $this->phase = self::INIT_PHASE;
1232  $this->mode = self::BEFOR_HEAD;
1233  $this->dom = new DOMDocument;
1234 
1235  $this->dom->encoding = 'UTF-8';
1236  $this->dom->preserveWhiteSpace = true;
1237  $this->dom->substituteEntities = true;
1238  $this->dom->strictErrorChecking = false;
1239  }

Member Function Documentation

◆ afterBody()

HTML5TreeConstructer::afterBody (   $token)
private

Definition at line 3359 of file PH5P.php.

References $comment, HTML5\CHARACTR, HTML5\COMMENT, and HTML5\ENDTAG.

3359  {
3360  /* Handle the token as follows: */
3361 
3362  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3363  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3364  or U+0020 SPACE */
3365  if($token['type'] === HTML5::CHARACTR &&
3366  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3367  /* Process the token as it would be processed if the insertion mode
3368  was "in body". */
3369  $this->inBody($token);
3370 
3371  /* A comment token */
3372  } elseif($token['type'] === HTML5::COMMENT) {
3373  /* Append a Comment node to the first element in the stack of open
3374  elements (the html element), with the data attribute set to the
3375  data given in the comment token. */
3376  $comment = $this->dom->createComment($token['data']);
3377  $this->stack[0]->appendChild($comment);
3378 
3379  /* An end tag with the tag name "html" */
3380  } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') {
3381  /* If the parser was originally created in order to handle the
3382  setting of an element's innerHTML attribute, this is a parse error;
3383  ignore the token. (The element will be an html element in this
3384  case.) (innerHTML case) */
3385 
3386  /* Otherwise, switch to the trailing end phase. */
3387  $this->phase = self::END_PHASE;
3388 
3389  /* Anything else */
3390  } else {
3391  /* Parse error. Set the insertion mode to "in body" and reprocess
3392  the token. */
3393  $this->mode = self::IN_BODY;
3394  return $this->inBody($token);
3395  }
3396  }
const COMMENT
Definition: PH5P.php:123
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122

◆ afterFrameset()

HTML5TreeConstructer::afterFrameset (   $token)
private

Definition at line 3461 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

3461  {
3462  /* Handle the token as follows: */
3463 
3464  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3465  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3466  U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3467  if($token['type'] === HTML5::CHARACTR &&
3468  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3469  /* Append the character to the current node. */
3470  $this->insertText($token['data']);
3471 
3472  /* A comment token */
3473  } elseif($token['type'] === HTML5::COMMENT) {
3474  /* Append a Comment node to the current node with the data
3475  attribute set to the data given in the comment token. */
3476  $this->insertComment($token['data']);
3477 
3478  /* An end tag with the tag name "html" */
3479  } elseif($token['name'] === 'html' &&
3480  $token['type'] === HTML5::ENDTAG) {
3481  /* Switch to the trailing end phase. */
3482  $this->phase = self::END_PHASE;
3483 
3484  /* A start tag with the tag name "noframes" */
3485  } elseif($token['name'] === 'noframes' &&
3486  $token['type'] === HTML5::STARTTAG) {
3487  /* Process the token as if the insertion mode had been "in body". */
3488  $this->inBody($token);
3489 
3490  /* Anything else */
3491  } else {
3492  /* Parse error. Ignore the token. */
3493  }
3494  }
const COMMENT
Definition: PH5P.php:123
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ afterHead()

HTML5TreeConstructer::afterHead (   $token)
private

Definition at line 1576 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, and HTML5\STARTTAG.

1576  {
1577  /* Handle the token as follows: */
1578 
1579  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1580  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1581  or U+0020 SPACE */
1582  if($token['type'] === HTML5::CHARACTR &&
1583  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1584  /* Append the character to the current node. */
1585  $this->insertText($token['data']);
1586 
1587  /* A comment token */
1588  } elseif($token['type'] === HTML5::COMMENT) {
1589  /* Append a Comment node to the current node with the data attribute
1590  set to the data given in the comment token. */
1591  $this->insertComment($token['data']);
1592 
1593  /* A start tag token with the tag name "body" */
1594  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') {
1595  /* Insert a body element for the token. */
1596  $this->insertElement($token);
1597 
1598  /* Change the insertion mode to "in body". */
1599  $this->mode = self::IN_BODY;
1600 
1601  /* A start tag token with the tag name "frameset" */
1602  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') {
1603  /* Insert a frameset element for the token. */
1604  $this->insertElement($token);
1605 
1606  /* Change the insertion mode to "in frameset". */
1607  $this->mode = self::IN_FRAME;
1608 
1609  /* A start tag token whose tag name is one of: "base", "link", "meta",
1610  "script", "style", "title" */
1611  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
1612  array('base', 'link', 'meta', 'script', 'style', 'title'))) {
1613  /* Parse error. Switch the insertion mode back to "in head" and
1614  reprocess the token. */
1615  $this->mode = self::IN_HEAD;
1616  return $this->inHead($token);
1617 
1618  /* Anything else */
1619  } else {
1620  /* Act as if a start tag token with the tag name "body" and no
1621  attributes had been seen, and then reprocess the current token. */
1622  $this->afterHead(array(
1623  'name' => 'body',
1624  'type' => HTML5::STARTTAG,
1625  'attr' => array()
1626  ));
1627 
1628  return $this->inBody($token);
1629  }
1630  }
const COMMENT
Definition: PH5P.php:123
afterHead($token)
Definition: PH5P.php:1576
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const STARTTAG
Definition: PH5P.php:121

◆ appendToRealParent()

HTML5TreeConstructer::appendToRealParent (   $node)
private

Definition at line 3572 of file PH5P.php.

References $n.

3572  {
3573  if($this->foster_parent === null) {
3574  end($this->stack)->appendChild($node);
3575 
3576  } elseif($this->foster_parent !== null) {
3577  /* If the foster parent element is the parent element of the
3578  last table element in the stack of open elements, then the new
3579  node must be inserted immediately before the last table element
3580  in the stack of open elements in the foster parent element;
3581  otherwise, the new node must be appended to the foster parent
3582  element. */
3583  for($n = count($this->stack) - 1; $n >= 0; $n--) {
3584  if($this->stack[$n]->nodeName === 'table' &&
3585  $this->stack[$n]->parentNode !== null) {
3586  $table = $this->stack[$n];
3587  break;
3588  }
3589  }
3590 
3591  if(isset($table) && $this->foster_parent->isSameNode($table->parentNode))
3592  $this->foster_parent->insertBefore($node, $table);
3593  else
3594  $this->foster_parent->appendChild($node);
3595 
3596  $this->foster_parent = null;
3597  }
3598  }
$n
Definition: RandomTest.php:80

◆ beforeHead()

HTML5TreeConstructer::beforeHead (   $token)
private

Definition at line 1398 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

1398  {
1399  /* Handle the token as follows: */
1400 
1401  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1402  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1403  or U+0020 SPACE */
1404  if($token['type'] === HTML5::CHARACTR &&
1405  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1406  /* Append the character to the current node. */
1407  $this->insertText($token['data']);
1408 
1409  /* A comment token */
1410  } elseif($token['type'] === HTML5::COMMENT) {
1411  /* Append a Comment node to the current node with the data attribute
1412  set to the data given in the comment token. */
1413  $this->insertComment($token['data']);
1414 
1415  /* A start tag token with the tag name "head" */
1416  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') {
1417  /* Create an element for the token, append the new element to the
1418  current node and push it onto the stack of open elements. */
1419  $element = $this->insertElement($token);
1420 
1421  /* Set the head element pointer to this new element node. */
1422  $this->head_pointer = $element;
1423 
1424  /* Change the insertion mode to "in head". */
1425  $this->mode = self::IN_HEAD;
1426 
1427  /* A start tag token whose tag name is one of: "base", "link", "meta",
1428  "script", "style", "title". Or an end tag with the tag name "html".
1429  Or a character token that is not one of U+0009 CHARACTER TABULATION,
1430  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1431  or U+0020 SPACE. Or any other start tag token */
1432  } elseif($token['type'] === HTML5::STARTTAG ||
1433  ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') ||
1434  ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/',
1435  $token['data']))) {
1436  /* Act as if a start tag token with the tag name "head" and no
1437  attributes had been seen, then reprocess the current token. */
1438  $this->beforeHead(array(
1439  'name' => 'head',
1440  'type' => HTML5::STARTTAG,
1441  'attr' => array()
1442  ));
1443 
1444  return $this->inHead($token);
1445 
1446  /* Any other end tag */
1447  } elseif($token['type'] === HTML5::ENDTAG) {
1448  /* Parse error. Ignore the token. */
1449  }
1450  }
const COMMENT
Definition: PH5P.php:123
beforeHead($token)
Definition: PH5P.php:1398
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ clearStackToTableContext()

HTML5TreeConstructer::clearStackToTableContext (   $elements)
private

Definition at line 3770 of file PH5P.php.

3770  {
3771  /* When the steps above require the UA to clear the stack back to a
3772  table context, it means that the UA must, while the current node is not
3773  a table element or an html element, pop elements from the stack of open
3774  elements. If this causes any elements to be popped from the stack, then
3775  this is a parse error. */
3776  while(true) {
3777  $node = end($this->stack)->nodeName;
3778 
3779  if(in_array($node, $elements)) {
3780  break;
3781  } else {
3782  array_pop($this->stack);
3783  }
3784  }
3785  }

◆ clearTheActiveFormattingElementsUpToTheLastMarker()

HTML5TreeConstructer::clearTheActiveFormattingElementsUpToTheLastMarker ( )
private

Definition at line 3720 of file PH5P.php.

3720  {
3721  /* When the steps below require the UA to clear the list of active
3722  formatting elements up to the last marker, the UA must perform the
3723  following steps: */
3724 
3725  while(true) {
3726  /* 1. Let entry be the last (most recently added) entry in the list
3727  of active formatting elements. */
3728  $entry = end($this->a_formatting);
3729 
3730  /* 2. Remove entry from the list of active formatting elements. */
3731  array_pop($this->a_formatting);
3732 
3733  /* 3. If entry was a marker, then stop the algorithm at this point.
3734  The list has been cleared up to the last marker. */
3735  if($entry === self::MARKER) {
3736  break;
3737  }
3738  }
3739  }

◆ closeCell()

HTML5TreeConstructer::closeCell ( )
private

Definition at line 3885 of file PH5P.php.

References HTML5\ENDTAG.

3885  {
3886  /* If the stack of open elements has a td or th element in table scope,
3887  then act as if an end tag token with that tag name had been seen. */
3888  foreach(array('td', 'th') as $cell) {
3889  if($this->elementInScope($cell, true)) {
3890  $this->inCell(array(
3891  'name' => $cell,
3892  'type' => HTML5::ENDTAG
3893  ));
3894 
3895  break;
3896  }
3897  }
3898  }
elementInScope($el, $table=false)
Definition: PH5P.php:3600
const ENDTAG
Definition: PH5P.php:122

◆ elementInScope()

HTML5TreeConstructer::elementInScope (   $el,
  $table = false 
)
private

Definition at line 3600 of file PH5P.php.

References $n.

3600  {
3601  if(is_array($el)) {
3602  foreach($el as $element) {
3603  if($this->elementInScope($element, $table)) {
3604  return true;
3605  }
3606  }
3607 
3608  return false;
3609  }
3610 
3611  $leng = count($this->stack);
3612 
3613  for($n = 0; $n < $leng; $n++) {
3614  /* 1. Initialise node to be the current node (the bottommost node of
3615  the stack). */
3616  $node = $this->stack[$leng - 1 - $n];
3617 
3618  if($node->tagName === $el) {
3619  /* 2. If node is the target node, terminate in a match state. */
3620  return true;
3621 
3622  } elseif($node->tagName === 'table') {
3623  /* 3. Otherwise, if node is a table element, terminate in a failure
3624  state. */
3625  return false;
3626 
3627  } elseif($table === true && in_array($node->tagName, array('caption', 'td',
3628  'th', 'button', 'marquee', 'object'))) {
3629  /* 4. Otherwise, if the algorithm is the "has an element in scope"
3630  variant (rather than the "has an element in table scope" variant),
3631  and node is one of the following, terminate in a failure state. */
3632  return false;
3633 
3634  } elseif($node === $node->ownerDocument->documentElement) {
3635  /* 5. Otherwise, if node is an html element (root element), terminate
3636  in a failure state. (This can only happen if the node is the topmost
3637  node of the stack of open elements, and prevents the next step from
3638  being invoked if there are no more elements in the stack.) */
3639  return false;
3640  }
3641 
3642  /* Otherwise, set node to the previous entry in the stack of open
3643  elements and return to step 2. (This will never fail, since the loop
3644  will always terminate in the previous step if the top of the stack
3645  is reached.) */
3646  }
3647  }
elementInScope($el, $table=false)
Definition: PH5P.php:3600
$n
Definition: RandomTest.php:80

◆ emitToken()

HTML5TreeConstructer::emitToken (   $token)

Definition at line 1242 of file PH5P.php.

1242  {
1243  switch($this->phase) {
1244  case self::INIT_PHASE: return $this->initPhase($token); break;
1245  case self::ROOT_PHASE: return $this->rootElementPhase($token); break;
1246  case self::MAIN_PHASE: return $this->mainPhase($token); break;
1247  case self::END_PHASE : return $this->trailingEndPhase($token); break;
1248  }
1249  }
rootElementPhase($token)
Definition: PH5P.php:1301
initPhase($token)
Definition: PH5P.php:1251
trailingEndPhase($token)
Definition: PH5P.php:3496
mainPhase($token)
Definition: PH5P.php:1348

◆ generateImpliedEndTags()

HTML5TreeConstructer::generateImpliedEndTags (   $exclude = array())
private

Definition at line 3741 of file PH5P.php.

References $exclude.

3741  {
3742  /* When the steps below require the UA to generate implied end tags,
3743  then, if the current node is a dd element, a dt element, an li element,
3744  a p element, a td element, a th element, or a tr element, the UA must
3745  act as if an end tag with the respective tag name had been seen and
3746  then generate implied end tags again. */
3747  $node = end($this->stack);
3748  $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
3749 
3750  while(in_array(end($this->stack)->nodeName, $elements)) {
3751  array_pop($this->stack);
3752  }
3753  }
if(! $in) $exclude

◆ getElementCategory()

HTML5TreeConstructer::getElementCategory (   $node)
private

Definition at line 3755 of file PH5P.php.

3755  {
3756  $name = $node->tagName;
3757  if(in_array($name, $this->special))
3758  return self::SPECIAL;
3759 
3760  elseif(in_array($name, $this->scoping))
3761  return self::SCOPING;
3762 
3763  elseif(in_array($name, $this->formatting))
3764  return self::FORMATTING;
3765 
3766  else
3767  return self::PHRASING;
3768  }

◆ inBody()

HTML5TreeConstructer::inBody (   $token)
private

Definition at line 1632 of file PH5P.php.

References $n, HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, HTML5\PLAINTEXT, HTML5\RCDATA, and HTML5\STARTTAG.

1632  {
1633  /* Handle the token as follows: */
1634 
1635  switch($token['type']) {
1636  /* A character token */
1637  case HTML5::CHARACTR:
1638  /* Reconstruct the active formatting elements, if any. */
1640 
1641  /* Append the token's character to the current node. */
1642  $this->insertText($token['data']);
1643  break;
1644 
1645  /* A comment token */
1646  case HTML5::COMMENT:
1647  /* Append a Comment node to the current node with the data
1648  attribute set to the data given in the comment token. */
1649  $this->insertComment($token['data']);
1650  break;
1651 
1652  case HTML5::STARTTAG:
1653  switch($token['name']) {
1654  /* A start tag token whose tag name is one of: "script",
1655  "style" */
1656  case 'script': case 'style':
1657  /* Process the token as if the insertion mode had been "in
1658  head". */
1659  return $this->inHead($token);
1660  break;
1661 
1662  /* A start tag token whose tag name is one of: "base", "link",
1663  "meta", "title" */
1664  case 'base': case 'link': case 'meta': case 'title':
1665  /* Parse error. Process the token as if the insertion mode
1666  had been "in head". */
1667  return $this->inHead($token);
1668  break;
1669 
1670  /* A start tag token with the tag name "body" */
1671  case 'body':
1672  /* Parse error. If the second element on the stack of open
1673  elements is not a body element, or, if the stack of open
1674  elements has only one node on it, then ignore the token.
1675  (innerHTML case) */
1676  if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') {
1677  // Ignore
1678 
1679  /* Otherwise, for each attribute on the token, check to see
1680  if the attribute is already present on the body element (the
1681  second element) on the stack of open elements. If it is not,
1682  add the attribute and its corresponding value to that
1683  element. */
1684  } else {
1685  foreach($token['attr'] as $attr) {
1686  if(!$this->stack[1]->hasAttribute($attr['name'])) {
1687  $this->stack[1]->setAttribute($attr['name'], $attr['value']);
1688  }
1689  }
1690  }
1691  break;
1692 
1693  /* A start tag whose tag name is one of: "address",
1694  "blockquote", "center", "dir", "div", "dl", "fieldset",
1695  "listing", "menu", "ol", "p", "ul" */
1696  case 'address': case 'blockquote': case 'center': case 'dir':
1697  case 'div': case 'dl': case 'fieldset': case 'listing':
1698  case 'menu': case 'ol': case 'p': case 'ul':
1699  /* If the stack of open elements has a p element in scope,
1700  then act as if an end tag with the tag name p had been
1701  seen. */
1702  if($this->elementInScope('p')) {
1703  $this->emitToken(array(
1704  'name' => 'p',
1705  'type' => HTML5::ENDTAG
1706  ));
1707  }
1708 
1709  /* Insert an HTML element for the token. */
1710  $this->insertElement($token);
1711  break;
1712 
1713  /* A start tag whose tag name is "form" */
1714  case 'form':
1715  /* If the form element pointer is not null, ignore the
1716  token with a parse error. */
1717  if($this->form_pointer !== null) {
1718  // Ignore.
1719 
1720  /* Otherwise: */
1721  } else {
1722  /* If the stack of open elements has a p element in
1723  scope, then act as if an end tag with the tag name p
1724  had been seen. */
1725  if($this->elementInScope('p')) {
1726  $this->emitToken(array(
1727  'name' => 'p',
1728  'type' => HTML5::ENDTAG
1729  ));
1730  }
1731 
1732  /* Insert an HTML element for the token, and set the
1733  form element pointer to point to the element created. */
1734  $element = $this->insertElement($token);
1735  $this->form_pointer = $element;
1736  }
1737  break;
1738 
1739  /* A start tag whose tag name is "li", "dd" or "dt" */
1740  case 'li': case 'dd': case 'dt':
1741  /* If the stack of open elements has a p element in scope,
1742  then act as if an end tag with the tag name p had been
1743  seen. */
1744  if($this->elementInScope('p')) {
1745  $this->emitToken(array(
1746  'name' => 'p',
1747  'type' => HTML5::ENDTAG
1748  ));
1749  }
1750 
1751  $stack_length = count($this->stack) - 1;
1752 
1753  for($n = $stack_length; 0 <= $n; $n--) {
1754  /* 1. Initialise node to be the current node (the
1755  bottommost node of the stack). */
1756  $stop = false;
1757  $node = $this->stack[$n];
1758  $cat = $this->getElementCategory($node->tagName);
1759 
1760  /* 2. If node is an li, dd or dt element, then pop all
1761  the nodes from the current node up to node, including
1762  node, then stop this algorithm. */
1763  if($token['name'] === $node->tagName || ($token['name'] !== 'li'
1764  && ($node->tagName === 'dd' || $node->tagName === 'dt'))) {
1765  for($x = $stack_length; $x >= $n ; $x--) {
1766  array_pop($this->stack);
1767  }
1768 
1769  break;
1770  }
1771 
1772  /* 3. If node is not in the formatting category, and is
1773  not in the phrasing category, and is not an address or
1774  div element, then stop this algorithm. */
1775  if($cat !== self::FORMATTING && $cat !== self::PHRASING &&
1776  $node->tagName !== 'address' && $node->tagName !== 'div') {
1777  break;
1778  }
1779  }
1780 
1781  /* Finally, insert an HTML element with the same tag
1782  name as the token's. */
1783  $this->insertElement($token);
1784  break;
1785 
1786  /* A start tag token whose tag name is "plaintext" */
1787  case 'plaintext':
1788  /* If the stack of open elements has a p element in scope,
1789  then act as if an end tag with the tag name p had been
1790  seen. */
1791  if($this->elementInScope('p')) {
1792  $this->emitToken(array(
1793  'name' => 'p',
1794  'type' => HTML5::ENDTAG
1795  ));
1796  }
1797 
1798  /* Insert an HTML element for the token. */
1799  $this->insertElement($token);
1800 
1801  return HTML5::PLAINTEXT;
1802  break;
1803 
1804  /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
1805  "h5", "h6" */
1806  case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
1807  /* If the stack of open elements has a p element in scope,
1808  then act as if an end tag with the tag name p had been seen. */
1809  if($this->elementInScope('p')) {
1810  $this->emitToken(array(
1811  'name' => 'p',
1812  'type' => HTML5::ENDTAG
1813  ));
1814  }
1815 
1816  /* If the stack of open elements has in scope an element whose
1817  tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
1818  this is a parse error; pop elements from the stack until an
1819  element with one of those tag names has been popped from the
1820  stack. */
1821  while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
1822  array_pop($this->stack);
1823  }
1824 
1825  /* Insert an HTML element for the token. */
1826  $this->insertElement($token);
1827  break;
1828 
1829  /* A start tag whose tag name is "a" */
1830  case 'a':
1831  /* If the list of active formatting elements contains
1832  an element whose tag name is "a" between the end of the
1833  list and the last marker on the list (or the start of
1834  the list if there is no marker on the list), then this
1835  is a parse error; act as if an end tag with the tag name
1836  "a" had been seen, then remove that element from the list
1837  of active formatting elements and the stack of open
1838  elements if the end tag didn't already remove it (it
1839  might not have if the element is not in table scope). */
1840  $leng = count($this->a_formatting);
1841 
1842  for($n = $leng - 1; $n >= 0; $n--) {
1843  if($this->a_formatting[$n] === self::MARKER) {
1844  break;
1845 
1846  } elseif($this->a_formatting[$n]->nodeName === 'a') {
1847  $this->emitToken(array(
1848  'name' => 'a',
1849  'type' => HTML5::ENDTAG
1850  ));
1851  break;
1852  }
1853  }
1854 
1855  /* Reconstruct the active formatting elements, if any. */
1857 
1858  /* Insert an HTML element for the token. */
1859  $el = $this->insertElement($token);
1860 
1861  /* Add that element to the list of active formatting
1862  elements. */
1863  $this->a_formatting[] = $el;
1864  break;
1865 
1866  /* A start tag whose tag name is one of: "b", "big", "em", "font",
1867  "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
1868  case 'b': case 'big': case 'em': case 'font': case 'i':
1869  case 'nobr': case 's': case 'small': case 'strike':
1870  case 'strong': case 'tt': case 'u':
1871  /* Reconstruct the active formatting elements, if any. */
1873 
1874  /* Insert an HTML element for the token. */
1875  $el = $this->insertElement($token);
1876 
1877  /* Add that element to the list of active formatting
1878  elements. */
1879  $this->a_formatting[] = $el;
1880  break;
1881 
1882  /* A start tag token whose tag name is "button" */
1883  case 'button':
1884  /* If the stack of open elements has a button element in scope,
1885  then this is a parse error; act as if an end tag with the tag
1886  name "button" had been seen, then reprocess the token. (We don't
1887  do that. Unnecessary.) */
1888  if($this->elementInScope('button')) {
1889  $this->inBody(array(
1890  'name' => 'button',
1891  'type' => HTML5::ENDTAG
1892  ));
1893  }
1894 
1895  /* Reconstruct the active formatting elements, if any. */
1897 
1898  /* Insert an HTML element for the token. */
1899  $this->insertElement($token);
1900 
1901  /* Insert a marker at the end of the list of active
1902  formatting elements. */
1903  $this->a_formatting[] = self::MARKER;
1904  break;
1905 
1906  /* A start tag token whose tag name is one of: "marquee", "object" */
1907  case 'marquee': case 'object':
1908  /* Reconstruct the active formatting elements, if any. */
1910 
1911  /* Insert an HTML element for the token. */
1912  $this->insertElement($token);
1913 
1914  /* Insert a marker at the end of the list of active
1915  formatting elements. */
1916  $this->a_formatting[] = self::MARKER;
1917  break;
1918 
1919  /* A start tag token whose tag name is "xmp" */
1920  case 'xmp':
1921  /* Reconstruct the active formatting elements, if any. */
1923 
1924  /* Insert an HTML element for the token. */
1925  $this->insertElement($token);
1926 
1927  /* Switch the content model flag to the CDATA state. */
1928  return HTML5::CDATA;
1929  break;
1930 
1931  /* A start tag whose tag name is "table" */
1932  case 'table':
1933  /* If the stack of open elements has a p element in scope,
1934  then act as if an end tag with the tag name p had been seen. */
1935  if($this->elementInScope('p')) {
1936  $this->emitToken(array(
1937  'name' => 'p',
1938  'type' => HTML5::ENDTAG
1939  ));
1940  }
1941 
1942  /* Insert an HTML element for the token. */
1943  $this->insertElement($token);
1944 
1945  /* Change the insertion mode to "in table". */
1946  $this->mode = self::IN_TABLE;
1947  break;
1948 
1949  /* A start tag whose tag name is one of: "area", "basefont",
1950  "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
1951  case 'area': case 'basefont': case 'bgsound': case 'br':
1952  case 'embed': case 'img': case 'param': case 'spacer':
1953  case 'wbr':
1954  /* Reconstruct the active formatting elements, if any. */
1956 
1957  /* Insert an HTML element for the token. */
1958  $this->insertElement($token);
1959 
1960  /* Immediately pop the current node off the stack of open elements. */
1961  array_pop($this->stack);
1962  break;
1963 
1964  /* A start tag whose tag name is "hr" */
1965  case 'hr':
1966  /* If the stack of open elements has a p element in scope,
1967  then act as if an end tag with the tag name p had been seen. */
1968  if($this->elementInScope('p')) {
1969  $this->emitToken(array(
1970  'name' => 'p',
1971  'type' => HTML5::ENDTAG
1972  ));
1973  }
1974 
1975  /* Insert an HTML element for the token. */
1976  $this->insertElement($token);
1977 
1978  /* Immediately pop the current node off the stack of open elements. */
1979  array_pop($this->stack);
1980  break;
1981 
1982  /* A start tag whose tag name is "image" */
1983  case 'image':
1984  /* Parse error. Change the token's tag name to "img" and
1985  reprocess it. (Don't ask.) */
1986  $token['name'] = 'img';
1987  return $this->inBody($token);
1988  break;
1989 
1990  /* A start tag whose tag name is "input" */
1991  case 'input':
1992  /* Reconstruct the active formatting elements, if any. */
1994 
1995  /* Insert an input element for the token. */
1996  $element = $this->insertElement($token, false);
1997 
1998  /* If the form element pointer is not null, then associate the
1999  input element with the form element pointed to by the form
2000  element pointer. */
2001  $this->form_pointer !== null
2002  ? $this->form_pointer->appendChild($element)
2003  : end($this->stack)->appendChild($element);
2004 
2005  /* Pop that input element off the stack of open elements. */
2006  array_pop($this->stack);
2007  break;
2008 
2009  /* A start tag whose tag name is "isindex" */
2010  case 'isindex':
2011  /* Parse error. */
2012  // w/e
2013 
2014  /* If the form element pointer is not null,
2015  then ignore the token. */
2016  if($this->form_pointer === null) {
2017  /* Act as if a start tag token with the tag name "form" had
2018  been seen. */
2019  $this->inBody(array(
2020  'name' => 'body',
2021  'type' => HTML5::STARTTAG,
2022  'attr' => array()
2023  ));
2024 
2025  /* Act as if a start tag token with the tag name "hr" had
2026  been seen. */
2027  $this->inBody(array(
2028  'name' => 'hr',
2029  'type' => HTML5::STARTTAG,
2030  'attr' => array()
2031  ));
2032 
2033  /* Act as if a start tag token with the tag name "p" had
2034  been seen. */
2035  $this->inBody(array(
2036  'name' => 'p',
2037  'type' => HTML5::STARTTAG,
2038  'attr' => array()
2039  ));
2040 
2041  /* Act as if a start tag token with the tag name "label"
2042  had been seen. */
2043  $this->inBody(array(
2044  'name' => 'label',
2045  'type' => HTML5::STARTTAG,
2046  'attr' => array()
2047  ));
2048 
2049  /* Act as if a stream of character tokens had been seen. */
2050  $this->insertText('This is a searchable index. '.
2051  'Insert your search keywords here: ');
2052 
2053  /* Act as if a start tag token with the tag name "input"
2054  had been seen, with all the attributes from the "isindex"
2055  token, except with the "name" attribute set to the value
2056  "isindex" (ignoring any explicit "name" attribute). */
2057  $attr = $token['attr'];
2058  $attr[] = array('name' => 'name', 'value' => 'isindex');
2059 
2060  $this->inBody(array(
2061  'name' => 'input',
2062  'type' => HTML5::STARTTAG,
2063  'attr' => $attr
2064  ));
2065 
2066  /* Act as if a stream of character tokens had been seen
2067  (see below for what they should say). */
2068  $this->insertText('This is a searchable index. '.
2069  'Insert your search keywords here: ');
2070 
2071  /* Act as if an end tag token with the tag name "label"
2072  had been seen. */
2073  $this->inBody(array(
2074  'name' => 'label',
2075  'type' => HTML5::ENDTAG
2076  ));
2077 
2078  /* Act as if an end tag token with the tag name "p" had
2079  been seen. */
2080  $this->inBody(array(
2081  'name' => 'p',
2082  'type' => HTML5::ENDTAG
2083  ));
2084 
2085  /* Act as if a start tag token with the tag name "hr" had
2086  been seen. */
2087  $this->inBody(array(
2088  'name' => 'hr',
2089  'type' => HTML5::ENDTAG
2090  ));
2091 
2092  /* Act as if an end tag token with the tag name "form" had
2093  been seen. */
2094  $this->inBody(array(
2095  'name' => 'form',
2096  'type' => HTML5::ENDTAG
2097  ));
2098  }
2099  break;
2100 
2101  /* A start tag whose tag name is "textarea" */
2102  case 'textarea':
2103  $this->insertElement($token);
2104 
2105  /* Switch the tokeniser's content model flag to the
2106  RCDATA state. */
2107  return HTML5::RCDATA;
2108  break;
2109 
2110  /* A start tag whose tag name is one of: "iframe", "noembed",
2111  "noframes" */
2112  case 'iframe': case 'noembed': case 'noframes':
2113  $this->insertElement($token);
2114 
2115  /* Switch the tokeniser's content model flag to the CDATA state. */
2116  return HTML5::CDATA;
2117  break;
2118 
2119  /* A start tag whose tag name is "select" */
2120  case 'select':
2121  /* Reconstruct the active formatting elements, if any. */
2123 
2124  /* Insert an HTML element for the token. */
2125  $this->insertElement($token);
2126 
2127  /* Change the insertion mode to "in select". */
2128  $this->mode = self::IN_SELECT;
2129  break;
2130 
2131  /* A start or end tag whose tag name is one of: "caption", "col",
2132  "colgroup", "frame", "frameset", "head", "option", "optgroup",
2133  "tbody", "td", "tfoot", "th", "thead", "tr". */
2134  case 'caption': case 'col': case 'colgroup': case 'frame':
2135  case 'frameset': case 'head': case 'option': case 'optgroup':
2136  case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead':
2137  case 'tr':
2138  // Parse error. Ignore the token.
2139  break;
2140 
2141  /* A start or end tag whose tag name is one of: "event-source",
2142  "section", "nav", "article", "aside", "header", "footer",
2143  "datagrid", "command" */
2144  case 'event-source': case 'section': case 'nav': case 'article':
2145  case 'aside': case 'header': case 'footer': case 'datagrid':
2146  case 'command':
2147  // Work in progress!
2148  break;
2149 
2150  /* A start tag token not covered by the previous entries */
2151  default:
2152  /* Reconstruct the active formatting elements, if any. */
2154 
2155  $this->insertElement($token, true, true);
2156  break;
2157  }
2158  break;
2159 
2160  case HTML5::ENDTAG:
2161  switch($token['name']) {
2162  /* An end tag with the tag name "body" */
2163  case 'body':
2164  /* If the second element in the stack of open elements is
2165  not a body element, this is a parse error. Ignore the token.
2166  (innerHTML case) */
2167  if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') {
2168  // Ignore.
2169 
2170  /* If the current node is not the body element, then this
2171  is a parse error. */
2172  } elseif(end($this->stack)->nodeName !== 'body') {
2173  // Parse error.
2174  }
2175 
2176  /* Change the insertion mode to "after body". */
2177  $this->mode = self::AFTER_BODY;
2178  break;
2179 
2180  /* An end tag with the tag name "html" */
2181  case 'html':
2182  /* Act as if an end tag with tag name "body" had been seen,
2183  then, if that token wasn't ignored, reprocess the current
2184  token. */
2185  $this->inBody(array(
2186  'name' => 'body',
2187  'type' => HTML5::ENDTAG
2188  ));
2189 
2190  return $this->afterBody($token);
2191  break;
2192 
2193  /* An end tag whose tag name is one of: "address", "blockquote",
2194  "center", "dir", "div", "dl", "fieldset", "listing", "menu",
2195  "ol", "pre", "ul" */
2196  case 'address': case 'blockquote': case 'center': case 'dir':
2197  case 'div': case 'dl': case 'fieldset': case 'listing':
2198  case 'menu': case 'ol': case 'pre': case 'ul':
2199  /* If the stack of open elements has an element in scope
2200  with the same tag name as that of the token, then generate
2201  implied end tags. */
2202  if($this->elementInScope($token['name'])) {
2203  $this->generateImpliedEndTags();
2204 
2205  /* Now, if the current node is not an element with
2206  the same tag name as that of the token, then this
2207  is a parse error. */
2208  // w/e
2209 
2210  /* If the stack of open elements has an element in
2211  scope with the same tag name as that of the token,
2212  then pop elements from this stack until an element
2213  with that tag name has been popped from the stack. */
2214  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2215  if($this->stack[$n]->nodeName === $token['name']) {
2216  $n = -1;
2217  }
2218 
2219  array_pop($this->stack);
2220  }
2221  }
2222  break;
2223 
2224  /* An end tag whose tag name is "form" */
2225  case 'form':
2226  /* If the stack of open elements has an element in scope
2227  with the same tag name as that of the token, then generate
2228  implied end tags. */
2229  if($this->elementInScope($token['name'])) {
2230  $this->generateImpliedEndTags();
2231 
2232  }
2233 
2234  if(end($this->stack)->nodeName !== $token['name']) {
2235  /* Now, if the current node is not an element with the
2236  same tag name as that of the token, then this is a parse
2237  error. */
2238  // w/e
2239 
2240  } else {
2241  /* Otherwise, if the current node is an element with
2242  the same tag name as that of the token pop that element
2243  from the stack. */
2244  array_pop($this->stack);
2245  }
2246 
2247  /* In any case, set the form element pointer to null. */
2248  $this->form_pointer = null;
2249  break;
2250 
2251  /* An end tag whose tag name is "p" */
2252  case 'p':
2253  /* If the stack of open elements has a p element in scope,
2254  then generate implied end tags, except for p elements. */
2255  if($this->elementInScope('p')) {
2256  $this->generateImpliedEndTags(array('p'));
2257 
2258  /* If the current node is not a p element, then this is
2259  a parse error. */
2260  // k
2261 
2262  /* If the stack of open elements has a p element in
2263  scope, then pop elements from this stack until the stack
2264  no longer has a p element in scope. */
2265  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2266  if($this->elementInScope('p')) {
2267  array_pop($this->stack);
2268 
2269  } else {
2270  break;
2271  }
2272  }
2273  }
2274  break;
2275 
2276  /* An end tag whose tag name is "dd", "dt", or "li" */
2277  case 'dd': case 'dt': case 'li':
2278  /* If the stack of open elements has an element in scope
2279  whose tag name matches the tag name of the token, then
2280  generate implied end tags, except for elements with the
2281  same tag name as the token. */
2282  if($this->elementInScope($token['name'])) {
2283  $this->generateImpliedEndTags(array($token['name']));
2284 
2285  /* If the current node is not an element with the same
2286  tag name as the token, then this is a parse error. */
2287  // w/e
2288 
2289  /* If the stack of open elements has an element in scope
2290  whose tag name matches the tag name of the token, then
2291  pop elements from this stack until an element with that
2292  tag name has been popped from the stack. */
2293  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2294  if($this->stack[$n]->nodeName === $token['name']) {
2295  $n = -1;
2296  }
2297 
2298  array_pop($this->stack);
2299  }
2300  }
2301  break;
2302 
2303  /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
2304  "h5", "h6" */
2305  case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
2306  $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
2307 
2308  /* If the stack of open elements has in scope an element whose
2309  tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
2310  generate implied end tags. */
2311  if($this->elementInScope($elements)) {
2312  $this->generateImpliedEndTags();
2313 
2314  /* Now, if the current node is not an element with the same
2315  tag name as that of the token, then this is a parse error. */
2316  // w/e
2317 
2318  /* If the stack of open elements has in scope an element
2319  whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
2320  "h6", then pop elements from the stack until an element
2321  with one of those tag names has been popped from the stack. */
2322  while($this->elementInScope($elements)) {
2323  array_pop($this->stack);
2324  }
2325  }
2326  break;
2327 
2328  /* An end tag whose tag name is one of: "a", "b", "big", "em",
2329  "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
2330  case 'a': case 'b': case 'big': case 'em': case 'font':
2331  case 'i': case 'nobr': case 's': case 'small': case 'strike':
2332  case 'strong': case 'tt': case 'u':
2333  /* 1. Let the formatting element be the last element in
2334  the list of active formatting elements that:
2335  * is between the end of the list and the last scope
2336  marker in the list, if any, or the start of the list
2337  otherwise, and
2338  * has the same tag name as the token.
2339  */
2340  while(true) {
2341  for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
2342  if($this->a_formatting[$a] === self::MARKER) {
2343  break;
2344 
2345  } elseif($this->a_formatting[$a]->tagName === $token['name']) {
2346  $formatting_element = $this->a_formatting[$a];
2347  $in_stack = in_array($formatting_element, $this->stack, true);
2348  $fe_af_pos = $a;
2349  break;
2350  }
2351  }
2352 
2353  /* If there is no such node, or, if that node is
2354  also in the stack of open elements but the element
2355  is not in scope, then this is a parse error. Abort
2356  these steps. The token is ignored. */
2357  if(!isset($formatting_element) || ($in_stack &&
2358  !$this->elementInScope($token['name']))) {
2359  break;
2360 
2361  /* Otherwise, if there is such a node, but that node
2362  is not in the stack of open elements, then this is a
2363  parse error; remove the element from the list, and
2364  abort these steps. */
2365  } elseif(isset($formatting_element) && !$in_stack) {
2366  unset($this->a_formatting[$fe_af_pos]);
2367  $this->a_formatting = array_merge($this->a_formatting);
2368  break;
2369  }
2370 
2371  /* 2. Let the furthest block be the topmost node in the
2372  stack of open elements that is lower in the stack
2373  than the formatting element, and is not an element in
2374  the phrasing or formatting categories. There might
2375  not be one. */
2376  $fe_s_pos = array_search($formatting_element, $this->stack, true);
2377  $length = count($this->stack);
2378 
2379  for($s = $fe_s_pos + 1; $s < $length; $s++) {
2380  $category = $this->getElementCategory($this->stack[$s]->nodeName);
2381 
2382  if($category !== self::PHRASING && $category !== self::FORMATTING) {
2383  $furthest_block = $this->stack[$s];
2384  }
2385  }
2386 
2387  /* 3. If there is no furthest block, then the UA must
2388  skip the subsequent steps and instead just pop all
2389  the nodes from the bottom of the stack of open
2390  elements, from the current node up to the formatting
2391  element, and remove the formatting element from the
2392  list of active formatting elements. */
2393  if(!isset($furthest_block)) {
2394  for($n = $length - 1; $n >= $fe_s_pos; $n--) {
2395  array_pop($this->stack);
2396  }
2397 
2398  unset($this->a_formatting[$fe_af_pos]);
2399  $this->a_formatting = array_merge($this->a_formatting);
2400  break;
2401  }
2402 
2403  /* 4. Let the common ancestor be the element
2404  immediately above the formatting element in the stack
2405  of open elements. */
2406  $common_ancestor = $this->stack[$fe_s_pos - 1];
2407 
2408  /* 5. If the furthest block has a parent node, then
2409  remove the furthest block from its parent node. */
2410  if($furthest_block->parentNode !== null) {
2411  $furthest_block->parentNode->removeChild($furthest_block);
2412  }
2413 
2414  /* 6. Let a bookmark note the position of the
2415  formatting element in the list of active formatting
2416  elements relative to the elements on either side
2417  of it in the list. */
2418  $bookmark = $fe_af_pos;
2419 
2420  /* 7. Let node and last node be the furthest block.
2421  Follow these steps: */
2422  $node = $furthest_block;
2423  $last_node = $furthest_block;
2424 
2425  while(true) {
2426  for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
2427  /* 7.1 Let node be the element immediately
2428  prior to node in the stack of open elements. */
2429  $node = $this->stack[$n];
2430 
2431  /* 7.2 If node is not in the list of active
2432  formatting elements, then remove node from
2433  the stack of open elements and then go back
2434  to step 1. */
2435  if(!in_array($node, $this->a_formatting, true)) {
2436  unset($this->stack[$n]);
2437  $this->stack = array_merge($this->stack);
2438 
2439  } else {
2440  break;
2441  }
2442  }
2443 
2444  /* 7.3 Otherwise, if node is the formatting
2445  element, then go to the next step in the overall
2446  algorithm. */
2447  if($node === $formatting_element) {
2448  break;
2449 
2450  /* 7.4 Otherwise, if last node is the furthest
2451  block, then move the aforementioned bookmark to
2452  be immediately after the node in the list of
2453  active formatting elements. */
2454  } elseif($last_node === $furthest_block) {
2455  $bookmark = array_search($node, $this->a_formatting, true) + 1;
2456  }
2457 
2458  /* 7.5 If node has any children, perform a
2459  shallow clone of node, replace the entry for
2460  node in the list of active formatting elements
2461  with an entry for the clone, replace the entry
2462  for node in the stack of open elements with an
2463  entry for the clone, and let node be the clone. */
2464  if($node->hasChildNodes()) {
2465  $clone = $node->cloneNode();
2466  $s_pos = array_search($node, $this->stack, true);
2467  $a_pos = array_search($node, $this->a_formatting, true);
2468 
2469  $this->stack[$s_pos] = $clone;
2470  $this->a_formatting[$a_pos] = $clone;
2471  $node = $clone;
2472  }
2473 
2474  /* 7.6 Insert last node into node, first removing
2475  it from its previous parent node if any. */
2476  if($last_node->parentNode !== null) {
2477  $last_node->parentNode->removeChild($last_node);
2478  }
2479 
2480  $node->appendChild($last_node);
2481 
2482  /* 7.7 Let last node be node. */
2483  $last_node = $node;
2484  }
2485 
2486  /* 8. Insert whatever last node ended up being in
2487  the previous step into the common ancestor node,
2488  first removing it from its previous parent node if
2489  any. */
2490  if($last_node->parentNode !== null) {
2491  $last_node->parentNode->removeChild($last_node);
2492  }
2493 
2494  $common_ancestor->appendChild($last_node);
2495 
2496  /* 9. Perform a shallow clone of the formatting
2497  element. */
2498  $clone = $formatting_element->cloneNode();
2499 
2500  /* 10. Take all of the child nodes of the furthest
2501  block and append them to the clone created in the
2502  last step. */
2503  while($furthest_block->hasChildNodes()) {
2504  $child = $furthest_block->firstChild;
2505  $furthest_block->removeChild($child);
2506  $clone->appendChild($child);
2507  }
2508 
2509  /* 11. Append that clone to the furthest block. */
2510  $furthest_block->appendChild($clone);
2511 
2512  /* 12. Remove the formatting element from the list
2513  of active formatting elements, and insert the clone
2514  into the list of active formatting elements at the
2515  position of the aforementioned bookmark. */
2516  $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
2517  unset($this->a_formatting[$fe_af_pos]);
2518  $this->a_formatting = array_merge($this->a_formatting);
2519 
2520  $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
2521  $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
2522  $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
2523 
2524  /* 13. Remove the formatting element from the stack
2525  of open elements, and insert the clone into the stack
2526  of open elements immediately after (i.e. in a more
2527  deeply nested position than) the position of the
2528  furthest block in that stack. */
2529  $fe_s_pos = array_search($formatting_element, $this->stack, true);
2530  $fb_s_pos = array_search($furthest_block, $this->stack, true);
2531  unset($this->stack[$fe_s_pos]);
2532 
2533  $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
2534  $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
2535  $this->stack = array_merge($s_part1, array($clone), $s_part2);
2536 
2537  /* 14. Jump back to step 1 in this series of steps. */
2538  unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
2539  }
2540  break;
2541 
2542  /* An end tag token whose tag name is one of: "button",
2543  "marquee", "object" */
2544  case 'button': case 'marquee': case 'object':
2545  /* If the stack of open elements has an element in scope whose
2546  tag name matches the tag name of the token, then generate implied
2547  tags. */
2548  if($this->elementInScope($token['name'])) {
2549  $this->generateImpliedEndTags();
2550 
2551  /* Now, if the current node is not an element with the same
2552  tag name as the token, then this is a parse error. */
2553  // k
2554 
2555  /* Now, if the stack of open elements has an element in scope
2556  whose tag name matches the tag name of the token, then pop
2557  elements from the stack until that element has been popped from
2558  the stack, and clear the list of active formatting elements up
2559  to the last marker. */
2560  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2561  if($this->stack[$n]->nodeName === $token['name']) {
2562  $n = -1;
2563  }
2564 
2565  array_pop($this->stack);
2566  }
2567 
2568  $marker = end(array_keys($this->a_formatting, self::MARKER, true));
2569 
2570  for($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
2571  array_pop($this->a_formatting);
2572  }
2573  }
2574  break;
2575 
2576  /* Or an end tag whose tag name is one of: "area", "basefont",
2577  "bgsound", "br", "embed", "hr", "iframe", "image", "img",
2578  "input", "isindex", "noembed", "noframes", "param", "select",
2579  "spacer", "table", "textarea", "wbr" */
2580  case 'area': case 'basefont': case 'bgsound': case 'br':
2581  case 'embed': case 'hr': case 'iframe': case 'image':
2582  case 'img': case 'input': case 'isindex': case 'noembed':
2583  case 'noframes': case 'param': case 'select': case 'spacer':
2584  case 'table': case 'textarea': case 'wbr':
2585  // Parse error. Ignore the token.
2586  break;
2587 
2588  /* An end tag token not covered by the previous entries */
2589  default:
2590  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2591  /* Initialise node to be the current node (the bottommost
2592  node of the stack). */
2593  $node = end($this->stack);
2594 
2595  /* If node has the same tag name as the end tag token,
2596  then: */
2597  if($token['name'] === $node->nodeName) {
2598  /* Generate implied end tags. */
2599  $this->generateImpliedEndTags();
2600 
2601  /* If the tag name of the end tag token does not
2602  match the tag name of the current node, this is a
2603  parse error. */
2604  // k
2605 
2606  /* Pop all the nodes from the current node up to
2607  node, including node, then stop this algorithm. */
2608  for($x = count($this->stack) - $n; $x >= $n; $x--) {
2609  array_pop($this->stack);
2610  }
2611 
2612  } else {
2613  $category = $this->getElementCategory($node);
2614 
2615  if($category !== self::SPECIAL && $category !== self::SCOPING) {
2616  /* Otherwise, if node is in neither the formatting
2617  category nor the phrasing category, then this is a
2618  parse error. Stop this algorithm. The end tag token
2619  is ignored. */
2620  return false;
2621  }
2622  }
2623  }
2624  break;
2625  }
2626  break;
2627  }
2628  }
emitToken($token)
Definition: PH5P.php:1242
const RCDATA
Definition: PH5P.php:116
getElementCategory($node)
Definition: PH5P.php:3755
const COMMENT
Definition: PH5P.php:123
afterBody($token)
Definition: PH5P.php:3359
const CDATA
Definition: PH5P.php:117
const PLAINTEXT
Definition: PH5P.php:118
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:3741
elementInScope($el, $table=false)
Definition: PH5P.php:3600
$n
Definition: RandomTest.php:80
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
reconstructActiveFormattingElements()
Definition: PH5P.php:3649

◆ inCaption()

HTML5TreeConstructer::inCaption (   $token)
private

Definition at line 2807 of file PH5P.php.

References HTML5\ENDTAG, and HTML5\STARTTAG.

2807  {
2808  /* An end tag whose tag name is "caption" */
2809  if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') {
2810  /* If the stack of open elements does not have an element in table
2811  scope with the same tag name as the token, this is a parse error.
2812  Ignore the token. (innerHTML case) */
2813  if(!$this->elementInScope($token['name'], true)) {
2814  // Ignore
2815 
2816  /* Otherwise: */
2817  } else {
2818  /* Generate implied end tags. */
2819  $this->generateImpliedEndTags();
2820 
2821  /* Now, if the current node is not a caption element, then this
2822  is a parse error. */
2823  // w/e
2824 
2825  /* Pop elements from this stack until a caption element has
2826  been popped from the stack. */
2827  while(true) {
2828  $node = end($this->stack)->nodeName;
2829  array_pop($this->stack);
2830 
2831  if($node === 'caption') {
2832  break;
2833  }
2834  }
2835 
2836  /* Clear the list of active formatting elements up to the last
2837  marker. */
2839 
2840  /* Switch the insertion mode to "in table". */
2841  $this->mode = self::IN_TABLE;
2842  }
2843 
2844  /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2845  "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
2846  name is "table" */
2847  } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2848  array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
2849  'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG &&
2850  $token['name'] === 'table')) {
2851  /* Parse error. Act as if an end tag with the tag name "caption"
2852  had been seen, then, if that token wasn't ignored, reprocess the
2853  current token. */
2854  $this->inCaption(array(
2855  'name' => 'caption',
2856  'type' => HTML5::ENDTAG
2857  ));
2858 
2859  return $this->inTable($token);
2860 
2861  /* An end tag whose tag name is one of: "body", "col", "colgroup",
2862  "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2863  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
2864  array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
2865  'thead', 'tr'))) {
2866  // Parse error. Ignore the token.
2867 
2868  /* Anything else */
2869  } else {
2870  /* Process the token as if the insertion mode was "in body". */
2871  $this->inBody($token);
2872  }
2873  }
clearTheActiveFormattingElementsUpToTheLastMarker()
Definition: PH5P.php:3720
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:3741
inCaption($token)
Definition: PH5P.php:2807
elementInScope($el, $table=false)
Definition: PH5P.php:3600
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ inCell()

HTML5TreeConstructer::inCell (   $token)
private

Definition at line 3103 of file PH5P.php.

References HTML5\ENDTAG, and HTML5\STARTTAG.

3103  {
3104  /* An end tag whose tag name is one of: "td", "th" */
3105  if($token['type'] === HTML5::ENDTAG &&
3106  ($token['name'] === 'td' || $token['name'] === 'th')) {
3107  /* If the stack of open elements does not have an element in table
3108  scope with the same tag name as that of the token, then this is a
3109  parse error and the token must be ignored. */
3110  if(!$this->elementInScope($token['name'], true)) {
3111  // Ignore.
3112 
3113  /* Otherwise: */
3114  } else {
3115  /* Generate implied end tags, except for elements with the same
3116  tag name as the token. */
3117  $this->generateImpliedEndTags(array($token['name']));
3118 
3119  /* Now, if the current node is not an element with the same tag
3120  name as the token, then this is a parse error. */
3121  // k
3122 
3123  /* Pop elements from this stack until an element with the same
3124  tag name as the token has been popped from the stack. */
3125  while(true) {
3126  $node = end($this->stack)->nodeName;
3127  array_pop($this->stack);
3128 
3129  if($node === $token['name']) {
3130  break;
3131  }
3132  }
3133 
3134  /* Clear the list of active formatting elements up to the last
3135  marker. */
3137 
3138  /* Switch the insertion mode to "in row". (The current node
3139  will be a tr element at this point.) */
3140  $this->mode = self::IN_ROW;
3141  }
3142 
3143  /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3144  "tbody", "td", "tfoot", "th", "thead", "tr" */
3145  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3146  array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
3147  'thead', 'tr'))) {
3148  /* If the stack of open elements does not have a td or th element
3149  in table scope, then this is a parse error; ignore the token.
3150  (innerHTML case) */
3151  if(!$this->elementInScope(array('td', 'th'), true)) {
3152  // Ignore.
3153 
3154  /* Otherwise, close the cell (see below) and reprocess the current
3155  token. */
3156  } else {
3157  $this->closeCell();
3158  return $this->inRow($token);
3159  }
3160 
3161  /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3162  "tbody", "td", "tfoot", "th", "thead", "tr" */
3163  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3164  array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
3165  'thead', 'tr'))) {
3166  /* If the stack of open elements does not have a td or th element
3167  in table scope, then this is a parse error; ignore the token.
3168  (innerHTML case) */
3169  if(!$this->elementInScope(array('td', 'th'), true)) {
3170  // Ignore.
3171 
3172  /* Otherwise, close the cell (see below) and reprocess the current
3173  token. */
3174  } else {
3175  $this->closeCell();
3176  return $this->inRow($token);
3177  }
3178 
3179  /* An end tag whose tag name is one of: "body", "caption", "col",
3180  "colgroup", "html" */
3181  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3182  array('body', 'caption', 'col', 'colgroup', 'html'))) {
3183  /* Parse error. Ignore the token. */
3184 
3185  /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
3186  "thead", "tr" */
3187  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3188  array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
3189  /* If the stack of open elements does not have an element in table
3190  scope with the same tag name as that of the token (which can only
3191  happen for "tbody", "tfoot" and "thead", or, in the innerHTML case),
3192  then this is a parse error and the token must be ignored. */
3193  if(!$this->elementInScope($token['name'], true)) {
3194  // Ignore.
3195 
3196  /* Otherwise, close the cell (see below) and reprocess the current
3197  token. */
3198  } else {
3199  $this->closeCell();
3200  return $this->inRow($token);
3201  }
3202 
3203  /* Anything else */
3204  } else {
3205  /* Process the token as if the insertion mode was "in body". */
3206  $this->inBody($token);
3207  }
3208  }
clearTheActiveFormattingElementsUpToTheLastMarker()
Definition: PH5P.php:3720
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:3741
elementInScope($el, $table=false)
Definition: PH5P.php:3600
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ inColumnGroup()

HTML5TreeConstructer::inColumnGroup (   $token)
private

Definition at line 2875 of file PH5P.php.

References $comment, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

2875  {
2876  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2877  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2878  or U+0020 SPACE */
2879  if($token['type'] === HTML5::CHARACTR &&
2880  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
2881  /* Append the character to the current node. */
2882  $text = $this->dom->createTextNode($token['data']);
2883  end($this->stack)->appendChild($text);
2884 
2885  /* A comment token */
2886  } elseif($token['type'] === HTML5::COMMENT) {
2887  /* Append a Comment node to the current node with the data
2888  attribute set to the data given in the comment token. */
2889  $comment = $this->dom->createComment($token['data']);
2890  end($this->stack)->appendChild($comment);
2891 
2892  /* A start tag whose tag name is "col" */
2893  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') {
2894  /* Insert a col element for the token. Immediately pop the current
2895  node off the stack of open elements. */
2896  $this->insertElement($token);
2897  array_pop($this->stack);
2898 
2899  /* An end tag whose tag name is "colgroup" */
2900  } elseif($token['type'] === HTML5::ENDTAG &&
2901  $token['name'] === 'colgroup') {
2902  /* If the current node is the root html element, then this is a
2903  parse error, ignore the token. (innerHTML case) */
2904  if(end($this->stack)->nodeName === 'html') {
2905  // Ignore
2906 
2907  /* Otherwise, pop the current node (which will be a colgroup
2908  element) from the stack of open elements. Switch the insertion
2909  mode to "in table". */
2910  } else {
2911  array_pop($this->stack);
2912  $this->mode = self::IN_TABLE;
2913  }
2914 
2915  /* An end tag whose tag name is "col" */
2916  } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') {
2917  /* Parse error. Ignore the token. */
2918 
2919  /* Anything else */
2920  } else {
2921  /* Act as if an end tag with the tag name "colgroup" had been seen,
2922  and then, if that token wasn't ignored, reprocess the current token. */
2923  $this->inColumnGroup(array(
2924  'name' => 'colgroup',
2925  'type' => HTML5::ENDTAG
2926  ));
2927 
2928  return $this->inTable($token);
2929  }
2930  }
const COMMENT
Definition: PH5P.php:123
inColumnGroup($token)
Definition: PH5P.php:2875
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ inFrameset()

HTML5TreeConstructer::inFrameset (   $token)
private

Definition at line 3398 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

3398  {
3399  /* Handle the token as follows: */
3400 
3401  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3402  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3403  U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3404  if($token['type'] === HTML5::CHARACTR &&
3405  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3406  /* Append the character to the current node. */
3407  $this->insertText($token['data']);
3408 
3409  /* A comment token */
3410  } elseif($token['type'] === HTML5::COMMENT) {
3411  /* Append a Comment node to the current node with the data
3412  attribute set to the data given in the comment token. */
3413  $this->insertComment($token['data']);
3414 
3415  /* A start tag with the tag name "frameset" */
3416  } elseif($token['name'] === 'frameset' &&
3417  $token['type'] === HTML5::STARTTAG) {
3418  $this->insertElement($token);
3419 
3420  /* An end tag with the tag name "frameset" */
3421  } elseif($token['name'] === 'frameset' &&
3422  $token['type'] === HTML5::ENDTAG) {
3423  /* If the current node is the root html element, then this is a
3424  parse error; ignore the token. (innerHTML case) */
3425  if(end($this->stack)->nodeName === 'html') {
3426  // Ignore
3427 
3428  } else {
3429  /* Otherwise, pop the current node from the stack of open
3430  elements. */
3431  array_pop($this->stack);
3432 
3433  /* If the parser was not originally created in order to handle
3434  the setting of an element's innerHTML attribute (innerHTML case),
3435  and the current node is no longer a frameset element, then change
3436  the insertion mode to "after frameset". */
3437  $this->mode = self::AFTR_FRAME;
3438  }
3439 
3440  /* A start tag with the tag name "frame" */
3441  } elseif($token['name'] === 'frame' &&
3442  $token['type'] === HTML5::STARTTAG) {
3443  /* Insert an HTML element for the token. */
3444  $this->insertElement($token);
3445 
3446  /* Immediately pop the current node off the stack of open elements. */
3447  array_pop($this->stack);
3448 
3449  /* A start tag with the tag name "noframes" */
3450  } elseif($token['name'] === 'noframes' &&
3451  $token['type'] === HTML5::STARTTAG) {
3452  /* Process the token as if the insertion mode had been "in body". */
3453  $this->inBody($token);
3454 
3455  /* Anything else */
3456  } else {
3457  /* Parse error. Ignore the token. */
3458  }
3459  }
const COMMENT
Definition: PH5P.php:123
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ inHead()

HTML5TreeConstructer::inHead (   $token)
private

Definition at line 1452 of file PH5P.php.

References HTML5\CDATA, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, HTML5\PCDATA, HTML5\RCDATA, and HTML5\STARTTAG.

1452  {
1453  /* Handle the token as follows: */
1454 
1455  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1456  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1457  or U+0020 SPACE.
1458 
1459  THIS DIFFERS FROM THE SPEC: If the current node is either a title, style
1460  or script element, append the character to the current node regardless
1461  of its content. */
1462  if(($token['type'] === HTML5::CHARACTR &&
1463  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || (
1464  $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName,
1465  array('title', 'style', 'script')))) {
1466  /* Append the character to the current node. */
1467  $this->insertText($token['data']);
1468 
1469  /* A comment token */
1470  } elseif($token['type'] === HTML5::COMMENT) {
1471  /* Append a Comment node to the current node with the data attribute
1472  set to the data given in the comment token. */
1473  $this->insertComment($token['data']);
1474 
1475  } elseif($token['type'] === HTML5::ENDTAG &&
1476  in_array($token['name'], array('title', 'style', 'script'))) {
1477  array_pop($this->stack);
1478  return HTML5::PCDATA;
1479 
1480  /* A start tag with the tag name "title" */
1481  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') {
1482  /* Create an element for the token and append the new element to the
1483  node pointed to by the head element pointer, or, if that is null
1484  (innerHTML case), to the current node. */
1485  if($this->head_pointer !== null) {
1486  $element = $this->insertElement($token, false);
1487  $this->head_pointer->appendChild($element);
1488 
1489  } else {
1490  $element = $this->insertElement($token);
1491  }
1492 
1493  /* Switch the tokeniser's content model flag to the RCDATA state. */
1494  return HTML5::RCDATA;
1495 
1496  /* A start tag with the tag name "style" */
1497  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') {
1498  /* Create an element for the token and append the new element to the
1499  node pointed to by the head element pointer, or, if that is null
1500  (innerHTML case), to the current node. */
1501  if($this->head_pointer !== null) {
1502  $element = $this->insertElement($token, false);
1503  $this->head_pointer->appendChild($element);
1504 
1505  } else {
1506  $this->insertElement($token);
1507  }
1508 
1509  /* Switch the tokeniser's content model flag to the CDATA state. */
1510  return HTML5::CDATA;
1511 
1512  /* A start tag with the tag name "script" */
1513  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') {
1514  /* Create an element for the token. */
1515  $element = $this->insertElement($token, false);
1516  $this->head_pointer->appendChild($element);
1517 
1518  /* Switch the tokeniser's content model flag to the CDATA state. */
1519  return HTML5::CDATA;
1520 
1521  /* A start tag with the tag name "base", "link", or "meta" */
1522  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
1523  array('base', 'link', 'meta'))) {
1524  /* Create an element for the token and append the new element to the
1525  node pointed to by the head element pointer, or, if that is null
1526  (innerHTML case), to the current node. */
1527  if($this->head_pointer !== null) {
1528  $element = $this->insertElement($token, false);
1529  $this->head_pointer->appendChild($element);
1530  array_pop($this->stack);
1531 
1532  } else {
1533  $this->insertElement($token);
1534  }
1535 
1536  /* An end tag with the tag name "head" */
1537  } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') {
1538  /* If the current node is a head element, pop the current node off
1539  the stack of open elements. */
1540  if($this->head_pointer->isSameNode(end($this->stack))) {
1541  array_pop($this->stack);
1542 
1543  /* Otherwise, this is a parse error. */
1544  } else {
1545  // k
1546  }
1547 
1548  /* Change the insertion mode to "after head". */
1549  $this->mode = self::AFTER_HEAD;
1550 
1551  /* A start tag with the tag name "head" or an end tag except "html". */
1552  } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') ||
1553  ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) {
1554  // Parse error. Ignore the token.
1555 
1556  /* Anything else */
1557  } else {
1558  /* If the current node is a head element, act as if an end tag
1559  token with the tag name "head" had been seen. */
1560  if($this->head_pointer->isSameNode(end($this->stack))) {
1561  $this->inHead(array(
1562  'name' => 'head',
1563  'type' => HTML5::ENDTAG
1564  ));
1565 
1566  /* Otherwise, change the insertion mode to "after head". */
1567  } else {
1568  $this->mode = self::AFTER_HEAD;
1569  }
1570 
1571  /* Then, reprocess the current token. */
1572  return $this->afterHead($token);
1573  }
1574  }
const RCDATA
Definition: PH5P.php:116
const COMMENT
Definition: PH5P.php:123
const CDATA
Definition: PH5P.php:117
afterHead($token)
Definition: PH5P.php:1576
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const PCDATA
Definition: PH5P.php:115
const STARTTAG
Definition: PH5P.php:121

◆ initPhase()

HTML5TreeConstructer::initPhase (   $token)
private

Definition at line 1251 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, HTML5\EOF(), and HTML5\STARTTAG.

1251  {
1252  /* Initially, the tree construction stage must handle each token
1253  emitted from the tokenisation stage as follows: */
1254 
1255  /* A DOCTYPE token that is marked as being in error
1256  A comment token
1257  A start tag token
1258  An end tag token
1259  A character token that is not one of one of U+0009 CHARACTER TABULATION,
1260  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1261  or U+0020 SPACE
1262  An end-of-file token */
1263  if((isset($token['error']) && $token['error']) ||
1264  $token['type'] === HTML5::COMMENT ||
1265  $token['type'] === HTML5::STARTTAG ||
1266  $token['type'] === HTML5::ENDTAG ||
1267  $token['type'] === HTML5::EOF ||
1268  ($token['type'] === HTML5::CHARACTR && isset($token['data']) &&
1269  !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) {
1270  /* This specification does not define how to handle this case. In
1271  particular, user agents may ignore the entirety of this specification
1272  altogether for such documents, and instead invoke special parse modes
1273  with a greater emphasis on backwards compatibility. */
1274 
1275  $this->phase = self::ROOT_PHASE;
1276  return $this->rootElementPhase($token);
1277 
1278  /* A DOCTYPE token marked as being correct */
1279  } elseif(isset($token['error']) && !$token['error']) {
1280  /* Append a DocumentType node to the Document node, with the name
1281  attribute set to the name given in the DOCTYPE token (which will be
1282  "HTML"), and the other attributes specific to DocumentType objects
1283  set to null, empty lists, or the empty string as appropriate. */
1284  $doctype = new DOMDocumentType(null, null, 'HTML');
1285 
1286  /* Then, switch to the root element phase of the tree construction
1287  stage. */
1288  $this->phase = self::ROOT_PHASE;
1289 
1290  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1291  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1292  or U+0020 SPACE */
1293  } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/',
1294  $token['data'])) {
1295  /* Append that character to the Document node. */
1296  $text = $this->dom->createTextNode($token['data']);
1297  $this->dom->appendChild($text);
1298  }
1299  }
const COMMENT
Definition: PH5P.php:123
EOF()
Definition: PH5P.php:1170
rootElementPhase($token)
Definition: PH5P.php:1301
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
+ Here is the call graph for this function:

◆ inRow()

HTML5TreeConstructer::inRow (   $token)
private

Definition at line 3018 of file PH5P.php.

References HTML5\ENDTAG, and HTML5\STARTTAG.

3018  {
3019  $clear = array('tr', 'html');
3020 
3021  /* A start tag whose tag name is one of: "th", "td" */
3022  if($token['type'] === HTML5::STARTTAG &&
3023  ($token['name'] === 'th' || $token['name'] === 'td')) {
3024  /* Clear the stack back to a table row context. */
3025  $this->clearStackToTableContext($clear);
3026 
3027  /* Insert an HTML element for the token, then switch the insertion
3028  mode to "in cell". */
3029  $this->insertElement($token);
3030  $this->mode = self::IN_CELL;
3031 
3032  /* Insert a marker at the end of the list of active formatting
3033  elements. */
3034  $this->a_formatting[] = self::MARKER;
3035 
3036  /* An end tag whose tag name is "tr" */
3037  } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') {
3038  /* If the stack of open elements does not have an element in table
3039  scope with the same tag name as the token, this is a parse error.
3040  Ignore the token. (innerHTML case) */
3041  if(!$this->elementInScope($token['name'], true)) {
3042  // Ignore.
3043 
3044  /* Otherwise: */
3045  } else {
3046  /* Clear the stack back to a table row context. */
3047  $this->clearStackToTableContext($clear);
3048 
3049  /* Pop the current node (which will be a tr element) from the
3050  stack of open elements. Switch the insertion mode to "in table
3051  body". */
3052  array_pop($this->stack);
3053  $this->mode = self::IN_TBODY;
3054  }
3055 
3056  /* A start tag whose tag name is one of: "caption", "col", "colgroup",
3057  "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
3058  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
3059  array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) {
3060  /* Act as if an end tag with the tag name "tr" had been seen, then,
3061  if that token wasn't ignored, reprocess the current token. */
3062  $this->inRow(array(
3063  'name' => 'tr',
3064  'type' => HTML5::ENDTAG
3065  ));
3066 
3067  return $this->inCell($token);
3068 
3069  /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
3070  } elseif($token['type'] === HTML5::ENDTAG &&
3071  in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
3072  /* If the stack of open elements does not have an element in table
3073  scope with the same tag name as the token, this is a parse error.
3074  Ignore the token. */
3075  if(!$this->elementInScope($token['name'], true)) {
3076  // Ignore.
3077 
3078  /* Otherwise: */
3079  } else {
3080  /* Otherwise, act as if an end tag with the tag name "tr" had
3081  been seen, then reprocess the current token. */
3082  $this->inRow(array(
3083  'name' => 'tr',
3084  'type' => HTML5::ENDTAG
3085  ));
3086 
3087  return $this->inCell($token);
3088  }
3089 
3090  /* An end tag whose tag name is one of: "body", "caption", "col",
3091  "colgroup", "html", "td", "th" */
3092  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3093  array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
3094  /* Parse error. Ignore the token. */
3095 
3096  /* Anything else */
3097  } else {
3098  /* Process the token as if the insertion mode was "in table". */
3099  $this->inTable($token);
3100  }
3101  }
clearStackToTableContext($elements)
Definition: PH5P.php:3770
elementInScope($el, $table=false)
Definition: PH5P.php:3600
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121

◆ inSelect()

HTML5TreeConstructer::inSelect (   $token)
private

Definition at line 3210 of file PH5P.php.

References HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

3210  {
3211  /* Handle the token as follows: */
3212 
3213  /* A character token */
3214  if($token['type'] === HTML5::CHARACTR) {
3215  /* Append the token's character to the current node. */
3216  $this->insertText($token['data']);
3217 
3218  /* A comment token */
3219  } elseif($token['type'] === HTML5::COMMENT) {
3220  /* Append a Comment node to the current node with the data
3221  attribute set to the data given in the comment token. */
3222  $this->insertComment($token['data']);
3223 
3224  /* A start tag token whose tag name is "option" */
3225  } elseif($token['type'] === HTML5::STARTTAG &&
3226  $token['name'] === 'option') {
3227  /* If the current node is an option element, act as if an end tag
3228  with the tag name "option" had been seen. */
3229  if(end($this->stack)->nodeName === 'option') {
3230  $this->inSelect(array(
3231  'name' => 'option',
3232  'type' => HTML5::ENDTAG
3233  ));
3234  }
3235 
3236  /* Insert an HTML element for the token. */
3237  $this->insertElement($token);
3238 
3239  /* A start tag token whose tag name is "optgroup" */
3240  } elseif($token['type'] === HTML5::STARTTAG &&
3241  $token['name'] === 'optgroup') {
3242  /* If the current node is an option element, act as if an end tag
3243  with the tag name "option" had been seen. */
3244  if(end($this->stack)->nodeName === 'option') {
3245  $this->inSelect(array(
3246  'name' => 'option',
3247  'type' => HTML5::ENDTAG
3248  ));
3249  }
3250 
3251  /* If the current node is an optgroup element, act as if an end tag
3252  with the tag name "optgroup" had been seen. */
3253  if(end($this->stack)->nodeName === 'optgroup') {
3254  $this->inSelect(array(
3255  'name' => 'optgroup',
3256  'type' => HTML5::ENDTAG
3257  ));
3258  }
3259 
3260  /* Insert an HTML element for the token. */
3261  $this->insertElement($token);
3262 
3263  /* An end tag token whose tag name is "optgroup" */
3264  } elseif($token['type'] === HTML5::ENDTAG &&
3265  $token['name'] === 'optgroup') {
3266  /* First, if the current node is an option element, and the node
3267  immediately before it in the stack of open elements is an optgroup
3268  element, then act as if an end tag with the tag name "option" had
3269  been seen. */
3270  $elements_in_stack = count($this->stack);
3271 
3272  if($this->stack[$elements_in_stack - 1]->nodeName === 'option' &&
3273  $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') {
3274  $this->inSelect(array(
3275  'name' => 'option',
3276  'type' => HTML5::ENDTAG
3277  ));
3278  }
3279 
3280  /* If the current node is an optgroup element, then pop that node
3281  from the stack of open elements. Otherwise, this is a parse error,
3282  ignore the token. */
3283  if($this->stack[$elements_in_stack - 1] === 'optgroup') {
3284  array_pop($this->stack);
3285  }
3286 
3287  /* An end tag token whose tag name is "option" */
3288  } elseif($token['type'] === HTML5::ENDTAG &&
3289  $token['name'] === 'option') {
3290  /* If the current node is an option element, then pop that node
3291  from the stack of open elements. Otherwise, this is a parse error,
3292  ignore the token. */
3293  if(end($this->stack)->nodeName === 'option') {
3294  array_pop($this->stack);
3295  }
3296 
3297  /* An end tag whose tag name is "select" */
3298  } elseif($token['type'] === HTML5::ENDTAG &&
3299  $token['name'] === 'select') {
3300  /* If the stack of open elements does not have an element in table
3301  scope with the same tag name as the token, this is a parse error.
3302  Ignore the token. (innerHTML case) */
3303  if(!$this->elementInScope($token['name'], true)) {
3304  // w/e
3305 
3306  /* Otherwise: */
3307  } else {
3308  /* Pop elements from the stack of open elements until a select
3309  element has been popped from the stack. */
3310  while(true) {
3311  $current = end($this->stack)->nodeName;
3312  array_pop($this->stack);
3313 
3314  if($current === 'select') {
3315  break;
3316  }
3317  }
3318 
3319  /* Reset the insertion mode appropriately. */
3320  $this->resetInsertionMode();
3321  }
3322 
3323  /* A start tag whose tag name is "select" */
3324  } elseif($token['name'] === 'select' &&
3325  $token['type'] === HTML5::STARTTAG) {
3326  /* Parse error. Act as if the token had been an end tag with the
3327  tag name "select" instead. */
3328  $this->inSelect(array(
3329  'name' => 'select',
3330  'type' => HTML5::ENDTAG
3331  ));
3332 
3333  /* An end tag whose tag name is one of: "caption", "table", "tbody",
3334  "tfoot", "thead", "tr", "td", "th" */
3335  } elseif(in_array($token['name'], array('caption', 'table', 'tbody',
3336  'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) {
3337  /* Parse error. */
3338  // w/e
3339 
3340  /* If the stack of open elements has an element in table scope with
3341  the same tag name as that of the token, then act as if an end tag
3342  with the tag name "select" had been seen, and reprocess the token.
3343  Otherwise, ignore the token. */
3344  if($this->elementInScope($token['name'], true)) {
3345  $this->inSelect(array(
3346  'name' => 'select',
3347  'type' => HTML5::ENDTAG
3348  ));
3349 
3350  $this->mainPhase($token);
3351  }
3352 
3353  /* Anything else */
3354  } else {
3355  /* Parse error. Ignore the token. */
3356  }
3357  }
inSelect($token)
Definition: PH5P.php:3210
const COMMENT
Definition: PH5P.php:123
elementInScope($el, $table=false)
Definition: PH5P.php:3600
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
insertComment($data)
Definition: PH5P.php:3567
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
mainPhase($token)
Definition: PH5P.php:1348

◆ insertComment()

HTML5TreeConstructer::insertComment (   $data)
private

Definition at line 3567 of file PH5P.php.

References $comment, and $data.

3567  {
3568  $comment = $this->dom->createComment($data);
3569  $this->appendToRealParent($comment);
3570  }
$comment
Definition: buildRTE.php:83
appendToRealParent($node)
Definition: PH5P.php:3572
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data

◆ insertElement()

HTML5TreeConstructer::insertElement (   $token,
  $append = true,
  $check = false 
)
private

Definition at line 3536 of file PH5P.php.

3536  {
3537  // Proprietary workaround for libxml2's limitations with tag names
3538  if ($check) {
3539  // Slightly modified HTML5 tag-name modification,
3540  // removing anything that's not an ASCII letter, digit, or hyphen
3541  $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']);
3542  // Remove leading hyphens and numbers
3543  $token['name'] = ltrim($token['name'], '-0..9');
3544  // In theory, this should ever be needed, but just in case
3545  if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice
3546  }
3547 
3548  $el = $this->dom->createElement($token['name']);
3549 
3550  foreach($token['attr'] as $attr) {
3551  if(!$el->hasAttribute($attr['name'])) {
3552  $el->setAttribute($attr['name'], $attr['value']);
3553  }
3554  }
3555 
3556  $this->appendToRealParent($el);
3557  $this->stack[] = $el;
3558 
3559  return $el;
3560  }
appendToRealParent($node)
Definition: PH5P.php:3572

◆ insertText()

HTML5TreeConstructer::insertText (   $data)
private

Definition at line 3562 of file PH5P.php.

References $data.

3562  {
3563  $text = $this->dom->createTextNode($data);
3564  $this->appendToRealParent($text);
3565  }
appendToRealParent($node)
Definition: PH5P.php:3572
while($lm_rec=$ilDB->fetchAssoc($lm_set)) $data

◆ inTable()

HTML5TreeConstructer::inTable (   $token)
private

Definition at line 2630 of file PH5P.php.

References $comment, $n, HTML5\CHARACTR, HTML5\COMMENT, HTML5\ENDTAG, and HTML5\STARTTAG.

2630  {
2631  $clear = array('html', 'table');
2632 
2633  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2634  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2635  or U+0020 SPACE */
2636  if($token['type'] === HTML5::CHARACTR &&
2637  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
2638  /* Append the character to the current node. */
2639  $text = $this->dom->createTextNode($token['data']);
2640  end($this->stack)->appendChild($text);
2641 
2642  /* A comment token */
2643  } elseif($token['type'] === HTML5::COMMENT) {
2644  /* Append a Comment node to the current node with the data
2645  attribute set to the data given in the comment token. */
2646  $comment = $this->dom->createComment($token['data']);
2647  end($this->stack)->appendChild($comment);
2648 
2649  /* A start tag whose tag name is "caption" */
2650  } elseif($token['type'] === HTML5::STARTTAG &&
2651  $token['name'] === 'caption') {
2652  /* Clear the stack back to a table context. */
2653  $this->clearStackToTableContext($clear);
2654 
2655  /* Insert a marker at the end of the list of active
2656  formatting elements. */
2657  $this->a_formatting[] = self::MARKER;
2658 
2659  /* Insert an HTML element for the token, then switch the
2660  insertion mode to "in caption". */
2661  $this->insertElement($token);
2662  $this->mode = self::IN_CAPTION;
2663 
2664  /* A start tag whose tag name is "colgroup" */
2665  } elseif($token['type'] === HTML5::STARTTAG &&
2666  $token['name'] === 'colgroup') {
2667  /* Clear the stack back to a table context. */
2668  $this->clearStackToTableContext($clear);
2669 
2670  /* Insert an HTML element for the token, then switch the
2671  insertion mode to "in column group". */
2672  $this->insertElement($token);
2673  $this->mode = self::IN_CGROUP;
2674 
2675  /* A start tag whose tag name is "col" */
2676  } elseif($token['type'] === HTML5::STARTTAG &&
2677  $token['name'] === 'col') {
2678  $this->inTable(array(
2679  'name' => 'colgroup',
2680  'type' => HTML5::STARTTAG,
2681  'attr' => array()
2682  ));
2683 
2684  $this->inColumnGroup($token);
2685 
2686  /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
2687  } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2688  array('tbody', 'tfoot', 'thead'))) {
2689  /* Clear the stack back to a table context. */
2690  $this->clearStackToTableContext($clear);
2691 
2692  /* Insert an HTML element for the token, then switch the insertion
2693  mode to "in table body". */
2694  $this->insertElement($token);
2695  $this->mode = self::IN_TBODY;
2696 
2697  /* A start tag whose tag name is one of: "td", "th", "tr" */
2698  } elseif($token['type'] === HTML5::STARTTAG &&
2699  in_array($token['name'], array('td', 'th', 'tr'))) {
2700  /* Act as if a start tag token with the tag name "tbody" had been
2701  seen, then reprocess the current token. */
2702  $this->inTable(array(
2703  'name' => 'tbody',
2704  'type' => HTML5::STARTTAG,
2705  'attr' => array()
2706  ));
2707 
2708  return $this->inTableBody($token);
2709 
2710  /* A start tag whose tag name is "table" */
2711  } elseif($token['type'] === HTML5::STARTTAG &&
2712  $token['name'] === 'table') {
2713  /* Parse error. Act as if an end tag token with the tag name "table"
2714  had been seen, then, if that token wasn't ignored, reprocess the
2715  current token. */
2716  $this->inTable(array(
2717  'name' => 'table',
2718  'type' => HTML5::ENDTAG
2719  ));
2720 
2721  return $this->mainPhase($token);
2722 
2723  /* An end tag whose tag name is "table" */
2724  } elseif($token['type'] === HTML5::ENDTAG &&
2725  $token['name'] === 'table') {
2726  /* If the stack of open elements does not have an element in table
2727  scope with the same tag name as the token, this is a parse error.
2728  Ignore the token. (innerHTML case) */
2729  if(!$this->elementInScope($token['name'], true)) {
2730  return false;
2731 
2732  /* Otherwise: */
2733  } else {
2734  /* Generate implied end tags. */
2735  $this->generateImpliedEndTags();
2736 
2737  /* Now, if the current node is not a table element, then this
2738  is a parse error. */
2739  // w/e
2740 
2741  /* Pop elements from this stack until a table element has been
2742  popped from the stack. */
2743  while(true) {
2744  $current = end($this->stack)->nodeName;
2745  array_pop($this->stack);
2746 
2747  if($current === 'table') {
2748  break;
2749  }
2750  }
2751 
2752  /* Reset the insertion mode appropriately. */
2753  $this->resetInsertionMode();
2754  }
2755 
2756  /* An end tag whose tag name is one of: "body", "caption", "col",
2757  "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2758  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
2759  array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
2760  'tfoot', 'th', 'thead', 'tr'))) {
2761  // Parse error. Ignore the token.
2762 
2763  /* Anything else */
2764  } else {
2765  /* Parse error. Process the token as if the insertion mode was "in
2766  body", with the following exception: */
2767 
2768  /* If the current node is a table, tbody, tfoot, thead, or tr
2769  element, then, whenever a node would be inserted into the current
2770  node, it must instead be inserted into the foster parent element. */
2771  if(in_array(end($this->stack)->nodeName,
2772  array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
2773  /* The foster parent element is the parent element of the last
2774  table element in the stack of open elements, if there is a
2775  table element and it has such a parent element. If there is no
2776  table element in the stack of open elements (innerHTML case),
2777  then the foster parent element is the first element in the
2778  stack of open elements (the html element). Otherwise, if there
2779  is a table element in the stack of open elements, but the last
2780  table element in the stack of open elements has no parent, or
2781  its parent node is not an element, then the foster parent
2782  element is the element before the last table element in the
2783  stack of open elements. */
2784  for($n = count($this->stack) - 1; $n >= 0; $n--) {
2785  if($this->stack[$n]->nodeName === 'table') {
2786  $table = $this->stack[$n];
2787  break;
2788  }
2789  }
2790 
2791  if(isset($table) && $table->parentNode !== null) {
2792  $this->foster_parent = $table->parentNode;
2793 
2794  } elseif(!isset($table)) {
2795  $this->foster_parent = $this->stack[0];
2796 
2797  } elseif(isset($table) && ($table->parentNode === null ||
2798  $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
2799  $this->foster_parent = $this->stack[$n - 1];
2800  }
2801  }
2802 
2803  $this->inBody($token);
2804  }
2805  }
const COMMENT
Definition: PH5P.php:123
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:3741
clearStackToTableContext($elements)
Definition: PH5P.php:3770
inTableBody($token)
Definition: PH5P.php:2932
elementInScope($el, $table=false)
Definition: PH5P.php:3600
inColumnGroup($token)
Definition: PH5P.php:2875
$n
Definition: RandomTest.php:80
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
mainPhase($token)
Definition: PH5P.php:1348

◆ inTableBody()

HTML5TreeConstructer::inTableBody (   $token)
private

Definition at line 2932 of file PH5P.php.

References HTML5\ENDTAG, and HTML5\STARTTAG.

2932  {
2933  $clear = array('tbody', 'tfoot', 'thead', 'html');
2934 
2935  /* A start tag whose tag name is "tr" */
2936  if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') {
2937  /* Clear the stack back to a table body context. */
2938  $this->clearStackToTableContext($clear);
2939 
2940  /* Insert a tr element for the token, then switch the insertion
2941  mode to "in row". */
2942  $this->insertElement($token);
2943  $this->mode = self::IN_ROW;
2944 
2945  /* A start tag whose tag name is one of: "th", "td" */
2946  } elseif($token['type'] === HTML5::STARTTAG &&
2947  ($token['name'] === 'th' || $token['name'] === 'td')) {
2948  /* Parse error. Act as if a start tag with the tag name "tr" had
2949  been seen, then reprocess the current token. */
2950  $this->inTableBody(array(
2951  'name' => 'tr',
2952  'type' => HTML5::STARTTAG,
2953  'attr' => array()
2954  ));
2955 
2956  return $this->inRow($token);
2957 
2958  /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
2959  } elseif($token['type'] === HTML5::ENDTAG &&
2960  in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
2961  /* If the stack of open elements does not have an element in table
2962  scope with the same tag name as the token, this is a parse error.
2963  Ignore the token. */
2964  if(!$this->elementInScope($token['name'], true)) {
2965  // Ignore
2966 
2967  /* Otherwise: */
2968  } else {
2969  /* Clear the stack back to a table body context. */
2970  $this->clearStackToTableContext($clear);
2971 
2972  /* Pop the current node from the stack of open elements. Switch
2973  the insertion mode to "in table". */
2974  array_pop($this->stack);
2975  $this->mode = self::IN_TABLE;
2976  }
2977 
2978  /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2979  "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
2980  } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
2981  array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) ||
2982  ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) {
2983  /* If the stack of open elements does not have a tbody, thead, or
2984  tfoot element in table scope, this is a parse error. Ignore the
2985  token. (innerHTML case) */
2986  if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
2987  // Ignore.
2988 
2989  /* Otherwise: */
2990  } else {
2991  /* Clear the stack back to a table body context. */
2992  $this->clearStackToTableContext($clear);
2993 
2994  /* Act as if an end tag with the same tag name as the current
2995  node ("tbody", "tfoot", or "thead") had been seen, then
2996  reprocess the current token. */
2997  $this->inTableBody(array(
2998  'name' => end($this->stack)->nodeName,
2999  'type' => HTML5::ENDTAG
3000  ));
3001 
3002  return $this->mainPhase($token);
3003  }
3004 
3005  /* An end tag whose tag name is one of: "body", "caption", "col",
3006  "colgroup", "html", "td", "th", "tr" */
3007  } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
3008  array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
3009  /* Parse error. Ignore the token. */
3010 
3011  /* Anything else */
3012  } else {
3013  /* Process the token as if the insertion mode was "in table". */
3014  $this->inTable($token);
3015  }
3016  }
clearStackToTableContext($elements)
Definition: PH5P.php:3770
inTableBody($token)
Definition: PH5P.php:2932
elementInScope($el, $table=false)
Definition: PH5P.php:3600
insertElement($token, $append=true, $check=false)
Definition: PH5P.php:3536
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
mainPhase($token)
Definition: PH5P.php:1348

◆ mainPhase()

HTML5TreeConstructer::mainPhase (   $token)
private

Definition at line 1348 of file PH5P.php.

References HTML5\DOCTYPE, HTML5\EOF(), and HTML5\STARTTAG.

1348  {
1349  /* Tokens in the main phase must be handled as follows: */
1350 
1351  /* A DOCTYPE token */
1352  if($token['type'] === HTML5::DOCTYPE) {
1353  // Parse error. Ignore the token.
1354 
1355  /* A start tag token with the tag name "html" */
1356  } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') {
1357  /* If this start tag token was not the first start tag token, then
1358  it is a parse error. */
1359 
1360  /* For each attribute on the token, check to see if the attribute
1361  is already present on the top element of the stack of open elements.
1362  If it is not, add the attribute and its corresponding value to that
1363  element. */
1364  foreach($token['attr'] as $attr) {
1365  if(!$this->stack[0]->hasAttribute($attr['name'])) {
1366  $this->stack[0]->setAttribute($attr['name'], $attr['value']);
1367  }
1368  }
1369 
1370  /* An end-of-file token */
1371  } elseif($token['type'] === HTML5::EOF) {
1372  /* Generate implied end tags. */
1373  $this->generateImpliedEndTags();
1374 
1375  /* Anything else. */
1376  } else {
1377  /* Depends on the insertion mode: */
1378  switch($this->mode) {
1379  case self::BEFOR_HEAD: return $this->beforeHead($token); break;
1380  case self::IN_HEAD: return $this->inHead($token); break;
1381  case self::AFTER_HEAD: return $this->afterHead($token); break;
1382  case self::IN_BODY: return $this->inBody($token); break;
1383  case self::IN_TABLE: return $this->inTable($token); break;
1384  case self::IN_CAPTION: return $this->inCaption($token); break;
1385  case self::IN_CGROUP: return $this->inColumnGroup($token); break;
1386  case self::IN_TBODY: return $this->inTableBody($token); break;
1387  case self::IN_ROW: return $this->inRow($token); break;
1388  case self::IN_CELL: return $this->inCell($token); break;
1389  case self::IN_SELECT: return $this->inSelect($token); break;
1390  case self::AFTER_BODY: return $this->afterBody($token); break;
1391  case self::IN_FRAME: return $this->inFrameset($token); break;
1392  case self::AFTR_FRAME: return $this->afterFrameset($token); break;
1393  case self::END_PHASE: return $this->trailingEndPhase($token); break;
1394  }
1395  }
1396  }
inSelect($token)
Definition: PH5P.php:3210
EOF()
Definition: PH5P.php:1170
afterBody($token)
Definition: PH5P.php:3359
generateImpliedEndTags($exclude=array())
Definition: PH5P.php:3741
beforeHead($token)
Definition: PH5P.php:1398
afterHead($token)
Definition: PH5P.php:1576
inCaption($token)
Definition: PH5P.php:2807
afterFrameset($token)
Definition: PH5P.php:3461
inFrameset($token)
Definition: PH5P.php:3398
inTableBody($token)
Definition: PH5P.php:2932
const DOCTYPE
Definition: PH5P.php:120
inColumnGroup($token)
Definition: PH5P.php:2875
trailingEndPhase($token)
Definition: PH5P.php:3496
const STARTTAG
Definition: PH5P.php:121
+ Here is the call graph for this function:

◆ reconstructActiveFormattingElements()

HTML5TreeConstructer::reconstructActiveFormattingElements ( )
private

Definition at line 3649 of file PH5P.php.

3649  {
3650  /* 1. If there are no entries in the list of active formatting elements,
3651  then there is nothing to reconstruct; stop this algorithm. */
3652  $formatting_elements = count($this->a_formatting);
3653 
3654  if($formatting_elements === 0) {
3655  return false;
3656  }
3657 
3658  /* 3. Let entry be the last (most recently added) element in the list
3659  of active formatting elements. */
3660  $entry = end($this->a_formatting);
3661 
3662  /* 2. If the last (most recently added) entry in the list of active
3663  formatting elements is a marker, or if it is an element that is in the
3664  stack of open elements, then there is nothing to reconstruct; stop this
3665  algorithm. */
3666  if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3667  return false;
3668  }
3669 
3670  for($a = $formatting_elements - 1; $a >= 0; true) {
3671  /* 4. If there are no entries before entry in the list of active
3672  formatting elements, then jump to step 8. */
3673  if($a === 0) {
3674  $step_seven = false;
3675  break;
3676  }
3677 
3678  /* 5. Let entry be the entry one earlier than entry in the list of
3679  active formatting elements. */
3680  $a--;
3681  $entry = $this->a_formatting[$a];
3682 
3683  /* 6. If entry is neither a marker nor an element that is also in
3684  thetack of open elements, go to step 4. */
3685  if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3686  break;
3687  }
3688  }
3689 
3690  while(true) {
3691  /* 7. Let entry be the element one later than entry in the list of
3692  active formatting elements. */
3693  if(isset($step_seven) && $step_seven === true) {
3694  $a++;
3695  $entry = $this->a_formatting[$a];
3696  }
3697 
3698  /* 8. Perform a shallow clone of the element entry to obtain clone. */
3699  $clone = $entry->cloneNode();
3700 
3701  /* 9. Append clone to the current node and push it onto the stack
3702  of open elements so that it is the new current node. */
3703  end($this->stack)->appendChild($clone);
3704  $this->stack[] = $clone;
3705 
3706  /* 10. Replace the entry for entry in the list with an entry for
3707  clone. */
3708  $this->a_formatting[$a] = $clone;
3709 
3710  /* 11. If the entry for clone in the list of active formatting
3711  elements is not the last entry in the list, return to step 7. */
3712  if(end($this->a_formatting) !== $clone) {
3713  $step_seven = true;
3714  } else {
3715  break;
3716  }
3717  }
3718  }

◆ resetInsertionMode()

HTML5TreeConstructer::resetInsertionMode ( )
private

Definition at line 3787 of file PH5P.php.

References $n.

3787  {
3788  /* 1. Let last be false. */
3789  $last = false;
3790  $leng = count($this->stack);
3791 
3792  for($n = $leng - 1; $n >= 0; $n--) {
3793  /* 2. Let node be the last node in the stack of open elements. */
3794  $node = $this->stack[$n];
3795 
3796  /* 3. If node is the first node in the stack of open elements, then
3797  set last to true. If the element whose innerHTML attribute is being
3798  set is neither a td element nor a th element, then set node to the
3799  element whose innerHTML attribute is being set. (innerHTML case) */
3800  if($this->stack[0]->isSameNode($node)) {
3801  $last = true;
3802  }
3803 
3804  /* 4. If node is a select element, then switch the insertion mode to
3805  "in select" and abort these steps. (innerHTML case) */
3806  if($node->nodeName === 'select') {
3807  $this->mode = self::IN_SELECT;
3808  break;
3809 
3810  /* 5. If node is a td or th element, then switch the insertion mode
3811  to "in cell" and abort these steps. */
3812  } elseif($node->nodeName === 'td' || $node->nodeName === 'th') {
3813  $this->mode = self::IN_CELL;
3814  break;
3815 
3816  /* 6. If node is a tr element, then switch the insertion mode to
3817  "in row" and abort these steps. */
3818  } elseif($node->nodeName === 'tr') {
3819  $this->mode = self::IN_ROW;
3820  break;
3821 
3822  /* 7. If node is a tbody, thead, or tfoot element, then switch the
3823  insertion mode to "in table body" and abort these steps. */
3824  } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) {
3825  $this->mode = self::IN_TBODY;
3826  break;
3827 
3828  /* 8. If node is a caption element, then switch the insertion mode
3829  to "in caption" and abort these steps. */
3830  } elseif($node->nodeName === 'caption') {
3831  $this->mode = self::IN_CAPTION;
3832  break;
3833 
3834  /* 9. If node is a colgroup element, then switch the insertion mode
3835  to "in column group" and abort these steps. (innerHTML case) */
3836  } elseif($node->nodeName === 'colgroup') {
3837  $this->mode = self::IN_CGROUP;
3838  break;
3839 
3840  /* 10. If node is a table element, then switch the insertion mode
3841  to "in table" and abort these steps. */
3842  } elseif($node->nodeName === 'table') {
3843  $this->mode = self::IN_TABLE;
3844  break;
3845 
3846  /* 11. If node is a head element, then switch the insertion mode
3847  to "in body" ("in body"! not "in head"!) and abort these steps.
3848  (innerHTML case) */
3849  } elseif($node->nodeName === 'head') {
3850  $this->mode = self::IN_BODY;
3851  break;
3852 
3853  /* 12. If node is a body element, then switch the insertion mode to
3854  "in body" and abort these steps. */
3855  } elseif($node->nodeName === 'body') {
3856  $this->mode = self::IN_BODY;
3857  break;
3858 
3859  /* 13. If node is a frameset element, then switch the insertion
3860  mode to "in frameset" and abort these steps. (innerHTML case) */
3861  } elseif($node->nodeName === 'frameset') {
3862  $this->mode = self::IN_FRAME;
3863  break;
3864 
3865  /* 14. If node is an html element, then: if the head element
3866  pointer is null, switch the insertion mode to "before head",
3867  otherwise, switch the insertion mode to "after head". In either
3868  case, abort these steps. (innerHTML case) */
3869  } elseif($node->nodeName === 'html') {
3870  $this->mode = ($this->head_pointer === null)
3871  ? self::BEFOR_HEAD
3872  : self::AFTER_HEAD;
3873 
3874  break;
3875 
3876  /* 15. If last is true, then set the insertion mode to "in body"
3877  and abort these steps. (innerHTML case) */
3878  } elseif($last) {
3879  $this->mode = self::IN_BODY;
3880  break;
3881  }
3882  }
3883  }
$n
Definition: RandomTest.php:80

◆ rootElementPhase()

HTML5TreeConstructer::rootElementPhase (   $token)
private

Definition at line 1301 of file PH5P.php.

References $comment, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF(), and HTML5\STARTTAG.

1301  {
1302  /* After the initial phase, as each token is emitted from the tokenisation
1303  stage, it must be processed as described in this section. */
1304 
1305  /* A DOCTYPE token */
1306  if($token['type'] === HTML5::DOCTYPE) {
1307  // Parse error. Ignore the token.
1308 
1309  /* A comment token */
1310  } elseif($token['type'] === HTML5::COMMENT) {
1311  /* Append a Comment node to the Document object with the data
1312  attribute set to the data given in the comment token. */
1313  $comment = $this->dom->createComment($token['data']);
1314  $this->dom->appendChild($comment);
1315 
1316  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
1317  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
1318  or U+0020 SPACE */
1319  } elseif($token['type'] === HTML5::CHARACTR &&
1320  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
1321  /* Append that character to the Document node. */
1322  $text = $this->dom->createTextNode($token['data']);
1323  $this->dom->appendChild($text);
1324 
1325  /* A character token that is not one of U+0009 CHARACTER TABULATION,
1326  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED
1327  (FF), or U+0020 SPACE
1328  A start tag token
1329  An end tag token
1330  An end-of-file token */
1331  } elseif(($token['type'] === HTML5::CHARACTR &&
1332  !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
1333  $token['type'] === HTML5::STARTTAG ||
1334  $token['type'] === HTML5::ENDTAG ||
1335  $token['type'] === HTML5::EOF) {
1336  /* Create an HTMLElement node with the tag name html, in the HTML
1337  namespace. Append it to the Document object. Switch to the main
1338  phase and reprocess the current token. */
1339  $html = $this->dom->createElement('html');
1340  $this->dom->appendChild($html);
1341  $this->stack[] = $html;
1342 
1343  $this->phase = self::MAIN_PHASE;
1344  return $this->mainPhase($token);
1345  }
1346  }
const COMMENT
Definition: PH5P.php:123
EOF()
Definition: PH5P.php:1170
const DOCTYPE
Definition: PH5P.php:120
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
mainPhase($token)
Definition: PH5P.php:1348
+ Here is the call graph for this function:

◆ save()

HTML5TreeConstructer::save ( )

Definition at line 3900 of file PH5P.php.

3900  {
3901  return $this->dom;
3902  }

◆ trailingEndPhase()

HTML5TreeConstructer::trailingEndPhase (   $token)
private

Definition at line 3496 of file PH5P.php.

References $comment, HTML5\CHARACTR, HTML5\COMMENT, HTML5\DOCTYPE, HTML5\ENDTAG, HTML5\EOF(), and HTML5\STARTTAG.

3496  {
3497  /* After the main phase, as each token is emitted from the tokenisation
3498  stage, it must be processed as described in this section. */
3499 
3500  /* A DOCTYPE token */
3501  if($token['type'] === HTML5::DOCTYPE) {
3502  // Parse error. Ignore the token.
3503 
3504  /* A comment token */
3505  } elseif($token['type'] === HTML5::COMMENT) {
3506  /* Append a Comment node to the Document object with the data
3507  attribute set to the data given in the comment token. */
3508  $comment = $this->dom->createComment($token['data']);
3509  $this->dom->appendChild($comment);
3510 
3511  /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3512  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3513  or U+0020 SPACE */
3514  } elseif($token['type'] === HTML5::CHARACTR &&
3515  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
3516  /* Process the token as it would be processed in the main phase. */
3517  $this->mainPhase($token);
3518 
3519  /* A character token that is not one of U+0009 CHARACTER TABULATION,
3520  U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3521  or U+0020 SPACE. Or a start tag token. Or an end tag token. */
3522  } elseif(($token['type'] === HTML5::CHARACTR &&
3523  preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
3524  $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) {
3525  /* Parse error. Switch back to the main phase and reprocess the
3526  token. */
3527  $this->phase = self::MAIN_PHASE;
3528  return $this->mainPhase($token);
3529 
3530  /* An end-of-file token */
3531  } elseif($token['type'] === HTML5::EOF) {
3532  /* OMG DONE!! */
3533  }
3534  }
const COMMENT
Definition: PH5P.php:123
EOF()
Definition: PH5P.php:1170
const DOCTYPE
Definition: PH5P.php:120
$comment
Definition: buildRTE.php:83
const CHARACTR
Definition: PH5P.php:124
const ENDTAG
Definition: PH5P.php:122
const STARTTAG
Definition: PH5P.php:121
mainPhase($token)
Definition: PH5P.php:1348
+ Here is the call graph for this function:

Field Documentation

◆ $a_formatting

HTML5TreeConstructer::$a_formatting = array()
private

Definition at line 1185 of file PH5P.php.

◆ $dom

HTML5TreeConstructer::$dom
private

Definition at line 1183 of file PH5P.php.

◆ $form_pointer

HTML5TreeConstructer::$form_pointer = null
private

Definition at line 1188 of file PH5P.php.

◆ $formatting

HTML5TreeConstructer::$formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u')
private

Definition at line 1191 of file PH5P.php.

◆ $foster_parent

HTML5TreeConstructer::$foster_parent = null
private

Definition at line 1184 of file PH5P.php.

◆ $head_pointer

HTML5TreeConstructer::$head_pointer = null
private

Definition at line 1187 of file PH5P.php.

◆ $mode

HTML5TreeConstructer::$mode
private

Definition at line 1182 of file PH5P.php.

◆ $phase

HTML5TreeConstructer::$phase
private

Definition at line 1181 of file PH5P.php.

◆ $scoping

HTML5TreeConstructer::$scoping = array('button','caption','html','marquee','object','table','td','th')
private

Definition at line 1190 of file PH5P.php.

◆ $special

HTML5TreeConstructer::$special
private
Initial value:
= array('address','area','base','basefont','bgsound',
'blockquote','body','br','center','col','colgroup','dd','dir','div','dl',
'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5',
'h6','head','hr','iframe','image','img','input','isindex','li','link',
'listing','menu','meta','noembed','noframes','noscript','ol','optgroup',
'option','p','param','plaintext','pre','script','select','spacer','style',
'tbody','textarea','tfoot','thead','title','tr','ul','wbr')

Definition at line 1192 of file PH5P.php.

◆ $stack

HTML5TreeConstructer::$stack = array()

Definition at line 1179 of file PH5P.php.

◆ AFTER_BODY

const HTML5TreeConstructer::AFTER_BODY = 11

Definition at line 1218 of file PH5P.php.

◆ AFTER_HEAD

const HTML5TreeConstructer::AFTER_HEAD = 2

Definition at line 1209 of file PH5P.php.

◆ AFTR_FRAME

const HTML5TreeConstructer::AFTR_FRAME = 13

Definition at line 1220 of file PH5P.php.

◆ BEFOR_HEAD

const HTML5TreeConstructer::BEFOR_HEAD = 0

Definition at line 1207 of file PH5P.php.

◆ END_PHASE

const HTML5TreeConstructer::END_PHASE = 3

Definition at line 1204 of file PH5P.php.

◆ FORMATTING

const HTML5TreeConstructer::FORMATTING = 2

Definition at line 1225 of file PH5P.php.

◆ IN_BODY

const HTML5TreeConstructer::IN_BODY = 3

Definition at line 1210 of file PH5P.php.

◆ IN_CAPTION

const HTML5TreeConstructer::IN_CAPTION = 5

Definition at line 1212 of file PH5P.php.

◆ IN_CELL

const HTML5TreeConstructer::IN_CELL = 9

Definition at line 1216 of file PH5P.php.

◆ IN_CGROUP

const HTML5TreeConstructer::IN_CGROUP = 6

Definition at line 1213 of file PH5P.php.

◆ IN_FRAME

const HTML5TreeConstructer::IN_FRAME = 12

Definition at line 1219 of file PH5P.php.

◆ IN_HEAD

const HTML5TreeConstructer::IN_HEAD = 1

Definition at line 1208 of file PH5P.php.

◆ IN_ROW

const HTML5TreeConstructer::IN_ROW = 8

Definition at line 1215 of file PH5P.php.

◆ IN_SELECT

const HTML5TreeConstructer::IN_SELECT = 10

Definition at line 1217 of file PH5P.php.

◆ IN_TABLE

const HTML5TreeConstructer::IN_TABLE = 4

Definition at line 1211 of file PH5P.php.

◆ IN_TBODY

const HTML5TreeConstructer::IN_TBODY = 7

Definition at line 1214 of file PH5P.php.

◆ INIT_PHASE

const HTML5TreeConstructer::INIT_PHASE = 0

Definition at line 1201 of file PH5P.php.

◆ MAIN_PHASE

const HTML5TreeConstructer::MAIN_PHASE = 2

Definition at line 1203 of file PH5P.php.

◆ MARKER

const HTML5TreeConstructer::MARKER = 0

Definition at line 1228 of file PH5P.php.

◆ PHRASING

const HTML5TreeConstructer::PHRASING = 3

Definition at line 1226 of file PH5P.php.

◆ ROOT_PHASE

const HTML5TreeConstructer::ROOT_PHASE = 1

Definition at line 1202 of file PH5P.php.

◆ SCOPING

const HTML5TreeConstructer::SCOPING = 1

Definition at line 1224 of file PH5P.php.

◆ SPECIAL

const HTML5TreeConstructer::SPECIAL = 0

Definition at line 1223 of file PH5P.php.


The documentation for this class was generated from the following file: