/*
element is node created by the lexer
upon seeing the start tag, or by the
parser when the start tag is inferred
*/
public virtual void Parse(Lexer lexer, Node element, short mode)
{
Node node;
bool checkstack;
int istackbase = 0;
TagCollection tt = lexer.Options.TagTable;
checkstack = true;
if ((element.Tag.Model & ContentModel.EMPTY) != 0)
{
return;
}
if (element.Tag == tt.TagForm && element.IsDescendantOf(tt.TagForm))
{
Report.Warning(lexer, element, null, Report.ILLEGAL_NESTING);
}
/*
InlineDup() asks the lexer to insert inline emphasis tags
currently pushed on the istack, but take care to avoid
propagating inline emphasis inside OBJECT or APPLET.
For these elements a fresh inline stack context is created
and disposed of upon reaching the end of the element.
They thus behave like table cells in this respect.
*/
if ((element.Tag.Model & ContentModel.OBJECT) != 0)
{
istackbase = lexer.Istackbase;
lexer.Istackbase = lexer.Istack.Count;
}
if ((element.Tag.Model & ContentModel.MIXED) == 0)
{
lexer.InlineDup(null);
}
mode = Lexer.IGNORE_WHITESPACE;
while (true)
{
node = lexer.GetToken(mode);
if (node == null)
{
break;
}
/* end tag for this element */
if (node.Type == Node.END_TAG && node.Tag != null &&
(node.Tag == element.Tag || element.Was == node.Tag))
{
if ((element.Tag.Model & ContentModel.OBJECT) != 0)
{
/* pop inline stack */
while (lexer.Istack.Count > lexer.Istackbase)
{
lexer.PopInline(null);
}
lexer.Istackbase = istackbase;
}
element.Closed = true;
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
if (node.Tag == tt.TagHtml || node.Tag == tt.TagHead || node.Tag == tt.TagBody)
{
if (node.Type == Node.START_TAG || node.Type == Node.START_END_TAG)
{
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
}
continue;
}
if (node.Type == Node.END_TAG)
{
if (node.Tag == null)
{
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
continue;
}
if (node.Tag == tt.TagBr)
{
node.Type = Node.START_TAG;
}
else if (node.Tag == tt.TagP)
{
Node.CoerceNode(lexer, node, tt.TagBr);
Node.InsertNodeAtEnd(element, node);
node = lexer.InferredTag("br");
}
else
{
/*
if this is the end tag for an ancestor element
then infer end tag for this element
*/
Node parent;
for (parent = element.Parent; parent != null; parent = parent.Parent)
{
if (node.Tag != parent.Tag) continue;
if ((element.Tag.Model & ContentModel.OPT) == 0)
{
Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
}
lexer.UngetToken();
if ((element.Tag.Model & ContentModel.OBJECT) != 0)
{
/* pop inline stack */
while (lexer.Istack.Count > lexer.Istackbase)
{
lexer.PopInline(null);
}
lexer.Istackbase = istackbase;
}
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
/* special case </tr> etc. for stuff moved in front of table */
if (lexer.Exiled && node.Tag.Model != 0 && (node.Tag.Model & ContentModel.TABLE) != 0)
{
lexer.UngetToken();
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
}
}
/* mixed content model permits text */
if (node.Type == Node.TEXT_NODE)
{
bool iswhitenode = node.Type == Node.TEXT_NODE && node.End <= node.Start + 1 &&
lexer.Lexbuf[node.Start] == (sbyte) ' ';
if (lexer.Options.EncloseBlockText && !iswhitenode)
{
lexer.UngetToken();
node = lexer.InferredTag("p");
Node.InsertNodeAtEnd(element, node);
ParseTag(lexer, node, Lexer.MIXED_CONTENT);
continue;
}
if (checkstack)
{
checkstack = false;
if ((element.Tag.Model & ContentModel.MIXED) == 0)
{
if (lexer.InlineDup(node) > 0)
{
continue;
}
}
}
Node.InsertNodeAtEnd(element, node);
mode = Lexer.MIXED_CONTENT;
/*
HTML4 strict doesn't allow mixed content for
elements with %block; as their content model
*/
lexer.Versions &= ~ HtmlVersion.Html40Strict;
continue;
}
if (Node.InsertMisc(element, node))
{
continue;
}
/* allow PARAM elements? */
if (node.Tag == tt.TagParam)
{
if (((element.Tag.Model & ContentModel.PARAM) != 0) &&
(node.Type == Node.START_TAG || node.Type == Node.START_END_TAG))
{
Node.InsertNodeAtEnd(element, node);
continue;
}
/* otherwise discard it */
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
continue;
}
/* allow AREA elements? */
if (node.Tag == tt.TagArea)
{
if ((element.Tag == tt.TagMap) &&
(node.Type == Node.START_TAG || node.Type == Node.START_END_TAG))
{
Node.InsertNodeAtEnd(element, node);
continue;
}
/* otherwise discard it */
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
continue;
}
/* ignore unknown start/end tags */
if (node.Tag == null)
{
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
continue;
}
/*
Allow ContentModel.INLINE elements here.
Allow ContentModel.BLOCK elements here unless
lexer.excludeBlocks is yes.
LI and DD are special cased.
Otherwise infer end tag for this element.
*/
if ((node.Tag.Model & ContentModel.INLINE) == 0)
{
if (node.Type != Node.START_TAG && node.Type != Node.START_END_TAG)
{
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
continue;
}
if (element.Tag == tt.TagTd || element.Tag == tt.TagTh)
{
/* if parent is a table cell, avoid inferring the end of the cell */
if ((node.Tag.Model & ContentModel.HEAD) != 0)
{
MoveToHead(lexer, element, node);
continue;
}
if ((node.Tag.Model & ContentModel.LIST) != 0)
{
lexer.UngetToken();
node = lexer.InferredTag("ul");
Node.AddClass(node, "noindent");
lexer.ExcludeBlocks = true;
}
else if ((node.Tag.Model & ContentModel.DEFLIST) != 0)
{
lexer.UngetToken();
node = lexer.InferredTag("dl");
lexer.ExcludeBlocks = true;
}
/* infer end of current table cell */
if ((node.Tag.Model & ContentModel.BLOCK) == 0)
{
lexer.UngetToken();
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
}
else if ((node.Tag.Model & ContentModel.BLOCK) != 0)
{
if (lexer.ExcludeBlocks)
{
if ((element.Tag.Model & ContentModel.OPT) == 0)
Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
lexer.UngetToken();
if ((element.Tag.Model & ContentModel.OBJECT) != 0)
lexer.Istackbase = istackbase;
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
}
/* things like list items */
else
{
if ((element.Tag.Model & ContentModel.OPT) == 0 && !element.Isimplicit)
Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
if ((node.Tag.Model & ContentModel.HEAD) != 0)
{
MoveToHead(lexer, element, node);
continue;
}
lexer.UngetToken();
if ((node.Tag.Model & ContentModel.LIST) != 0)
{
if (element.Parent != null && element.Parent.Tag != null &&
element.Parent.Tag.Parser == ParseList)
{
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
node = lexer.InferredTag("ul");
Node.AddClass(node, "noindent");
}
else if ((node.Tag.Model & ContentModel.DEFLIST) != 0)
{
if (element.Parent.Tag == tt.TagDl)
{
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
node = lexer.InferredTag("dl");
}
else if ((node.Tag.Model & ContentModel.TABLE) != 0 ||
(node.Tag.Model & ContentModel.ROW) != 0)
{
node = lexer.InferredTag("table");
}
else if ((element.Tag.Model & ContentModel.OBJECT) != 0)
{
/* pop inline stack */
while (lexer.Istack.Count > lexer.Istackbase)
{
lexer.PopInline(null);
}
lexer.Istackbase = istackbase;
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
else
{
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
return;
}
}
}
/* parse known element */
if (node.Type == Node.START_TAG || node.Type == Node.START_END_TAG)
{
if ((node.Tag.Model & ContentModel.INLINE) != 0)
{
if (checkstack && !node.Isimplicit)
{
checkstack = false;
if (lexer.InlineDup(node) > 0)
continue;
}
mode = Lexer.MIXED_CONTENT;
}
else
{
checkstack = true;
mode = Lexer.IGNORE_WHITESPACE;
}
/* trim white space before <br> */
if (node.Tag == tt.TagBr)
{
Node.TrimSpaces(lexer, element);
}
Node.InsertNodeAtEnd(element, node);
if (node.Isimplicit)
{
Report.Warning(lexer, element, node, Report.INSERTING_TAG);
}
ParseTag(lexer, node, Lexer.IGNORE_WHITESPACE);
continue;
}
/* discard unexpected tags */
if (node.Type == Node.END_TAG)
lexer.PopInline(node);
/* if inline end tag */
Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
}
if ((element.Tag.Model & ContentModel.OPT) == 0)
{
Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_FOR);
}
if ((element.Tag.Model & ContentModel.OBJECT) != 0)
{
/* pop inline stack */
while (lexer.Istack.Count > lexer.Istackbase)
{
lexer.PopInline(null);
}
lexer.Istackbase = istackbase;
}
Node.TrimSpaces(lexer, element);
Node.TrimEmptyElement(lexer, element);
}