📄 node.java
字号:
element.parent.content != element)
{
prev = element.prev;
if (prev != null && prev.type == TextNode)
{
if (prev.textarray[prev.end - 1] != (byte)' ')
prev.textarray[prev.end++] = (byte)' ';
++element.start;
}
else /* create new node */
{
node = lexer.newNode();
node.start = element.start++;
node.end = element.start;
node.textarray = element.textarray;
node.textarray[node.start] = (byte)' ';
node.prev = prev;
if (prev != null)
prev.next = node;
node.next = element;
element.prev = node;
node.parent = element.parent;
}
}
/* discard the space in current node */
++text.start;
}
}
/*
Move initial and trailing space out.
This routine maps:
hello<em> world</em>
to
hello <em>world</em>
and
<em>hello </em><strong>world</strong>
to
<em>hello</em> <strong>world</strong>
*/
public static void trimSpaces(Lexer lexer, Node element)
{
Node text = element.content;
if (text != null && text.type == Node.TextNode &&
element.tag != TagTable.tagPre)
trimInitialSpace(lexer, element, text);
text = element.last;
if (text != null && text.type == Node.TextNode)
trimTrailingSpace(lexer, element, text);
}
public boolean isDescendantOf(Dict tag)
{
Node parent;
for (parent = this.parent;
parent != null; parent = parent.parent)
{
if (parent.tag == tag)
return true;
}
return false;
}
/*
the doctype has been found after other tags,
and needs moving to before the html element
*/
public static void insertDocType(Lexer lexer, Node element, Node doctype)
{
Report.warning(lexer, element, doctype, Report.DOCTYPE_AFTER_TAGS);
while (element.tag != TagTable.tagHtml)
element = element.parent;
insertNodeBeforeElement(element, doctype);
}
public static Node findHead(Node root)
{
Node node;
node = root.content;
while (node != null && node.tag != TagTable.tagHtml)
node = node.next;
if (node == null)
return null;
node = node.content;
while (node != null && node.tag != TagTable.tagHead)
node = node.next;
return node;
}
public static Node findBody(Node root)
{
Node node;
node = root.content;
while (node != null && node.tag != TagTable.tagHtml)
node = node.next;
if (node == null)
return null;
node = node.content;
while (node != null && node.tag != TagTable.tagBody)
node = node.next;
return node;
}
public boolean isElement()
{
return (this.type == StartTag || this.type == StartEndTag ? true : false);
}
/*
unexpected content in table row is moved to just before
the table in accordance with Netscape and IE. This code
assumes that node hasn't been inserted into the row.
*/
public static void moveBeforeTable(Node row, Node node)
{
Node table;
/* first find the table element */
for (table = row.parent; table != null; table = table.parent)
{
if (table.tag == TagTable.tagTable)
{
if (table.parent.content == table)
table.parent.content = node;
node.prev = table.prev;
node.next = table;
table.prev = node;
node.parent = table.parent;
if (node.prev != null)
node.prev.next = node;
break;
}
}
}
/*
if a table row is empty then insert an empty cell
this practice is consistent with browser behavior
and avoids potential problems with row spanning cells
*/
public static void fixEmptyRow(Lexer lexer, Node row)
{
Node cell;
if (row.content == null)
{
cell = lexer.inferredTag("td");
insertNodeAtEnd(row, cell);
Report.warning(lexer, row, cell, Report.MISSING_STARTTAG);
}
}
public static void coerceNode(Lexer lexer, Node node, Dict tag)
{
Node tmp = lexer.inferredTag(tag.name);
Report.warning(lexer, node, tmp, Report.OBSOLETE_ELEMENT);
node.was = node.tag;
node.tag = tag;
node.type = StartTag;
node.implicit = true;
node.element = new String(tag.name);
}
/* extract a node and its children from a markup tree */
public static void removeNode(Node node)
{
if (node.prev != null)
node.prev.next = node.next;
if (node.next != null)
node.next.prev = node.prev;
if (node.parent != null)
{
if (node.parent.content == node)
node.parent.content = node.next;
if (node.parent.last == node)
node.parent.last = node.prev;
}
node.parent = node.prev = node.next = null;
}
public static boolean insertMisc(Node element, Node node)
{
if (node.type == CommentTag ||
node.type == ProcInsTag ||
node.type == CDATATag ||
node.type == SectionTag ||
node.type == AspTag ||
node.type == JsteTag ||
node.type == PhpTag)
{
insertNodeAtEnd(element, node);
return true;
}
return false;
}
/*
used to determine how attributes
without values should be printed
this was introduced to deal with
user defined tags e.g. Cold Fusion
*/
public static boolean isNewNode(Node node)
{
if (node != null && node.tag != null)
{
return ((node.tag.model & Dict.CM_NEW) != 0);
}
return true;
}
public boolean hasOneChild()
{
return (this.content != null && this.content.next == null);
}
/* find html element */
public Node findHTML()
{
Node node;
for (node = this.content;
node != null && node.tag != TagTable.tagHtml; node = node.next);
return node;
}
public static Node findHEAD(Node root)
{
Node node;
node = root.findHTML();
if (node != null)
{
for (node = node.content;
node != null && node.tag != TagTable.tagHead;
node = node.next);
}
return node;
}
public boolean checkNodeIntegrity()
{
Node child;
boolean found = false;
if (this.prev != null)
{
if (this.prev.next != this)
return false;
}
if (this.next != null)
{
if (this.next.prev != this)
return false;
}
if (this.parent != null)
{
if (this.prev == null && this.parent.content != this)
return false;
if (this.next == null && this.parent.last != this)
return false;
for (child = this.parent.content; child != null; child = child.next)
if (child == this)
{
found = true;
break;
}
if (!found)
return false;
}
for (child = this.content; child != null; child = child.next)
if (!child.checkNodeIntegrity())
return false;
return true;
}
/*
Add class="foo" to node
*/
public static void addClass(Node node, String classname)
{
AttVal classattr = node.getAttrByName("class");
/*
if there already is a class attribute
then append class name after a space
*/
if (classattr != null)
{
classattr.value = classattr.value + " " + classname;
}
else /* create new class attribute */
node.addAttribute("class", classname);
}
/* --------------------- DEBUG -------------------------- */
private static final String[] nodeTypeString =
{
"RootNode",
"DocTypeTag",
"CommentTag",
"ProcInsTag",
"TextNode",
"StartTag",
"EndTag",
"StartEndTag",
"SectionTag",
"AspTag",
"PhpTag"
};
public String toString()
{
String s = "";
Node n = this;
while (n != null) {
s += "[Node type=";
s += nodeTypeString[n.type];
s += ",element=";
if (n.element != null)
s += n.element;
else
s += "null";
if (n.type == TextNode ||
n.type == CommentTag ||
n.type == ProcInsTag) {
s += ",text=";
if (n.textarray != null && n.start <= n.end) {
s += "\"";
s += Lexer.getString(n.textarray, n.start, n.end - n.start);
s += "\"";
} else {
s += "null";
}
}
s += ",content=";
if (n.content != null)
s += n.content.toString();
else
s += "null";
s += "]";
if (n.next != null)
s += ",";
n = n.next;
}
return s;
}
/* --------------------- END DEBUG ---------------------- */
/* --------------------- DOM ---------------------------- */
protected org.w3c.dom.Node adapter = null;
protected org.w3c.dom.Node getAdapter()
{
if (adapter == null)
{
switch (this.type)
{
case RootNode:
adapter = new DOMDocumentImpl(this);
break;
case StartTag:
case StartEndTag:
adapter = new DOMElementImpl(this);
break;
case DocTypeTag:
adapter = new DOMDocumentTypeImpl(this);
break;
case CommentTag:
adapter = new DOMCommentImpl(this);
break;
case TextNode:
adapter = new DOMTextImpl(this);
break;
case CDATATag:
adapter = new DOMCDATASectionImpl(this);
break;
case ProcInsTag:
adapter = new DOMProcessingInstructionImpl(this);
break;
default:
adapter = new DOMNodeImpl(this);
}
}
return adapter;
}
protected Node cloneNode(boolean deep)
{
Node node = (Node)this.clone();
if (deep)
{
Node child;
Node newChild;
for (child = this.content; child != null; child = child.next)
{
newChild = child.cloneNode(deep);
insertNodeAtEnd(node, newChild);
}
}
return node;
}
protected void setType(short newType)
{
this.type = newType;
}
/* --------------------- END DOM ------------------------ */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -