下面列出了org.w3c.dom.stylesheets.MediaList#com.gargoylesoftware.htmlunit.html.DomNode 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Creates a new event instance.
* @param domNode the DOM node that triggered the event
* @param type the event type
* @param shiftKey true if SHIFT is pressed
* @param ctrlKey true if CTRL is pressed
* @param altKey true if ALT is pressed
* @param button the button code, must be {@link #BUTTON_LEFT}, {@link #BUTTON_MIDDLE} or {@link #BUTTON_RIGHT}
*/
public MouseEvent(final DomNode domNode, final String type, final boolean shiftKey,
final boolean ctrlKey, final boolean altKey, final int button) {
super(domNode, type);
setShiftKey(shiftKey);
setCtrlKey(ctrlKey);
setAltKey(altKey);
if (button != BUTTON_LEFT && button != BUTTON_MIDDLE && button != BUTTON_RIGHT) {
throw new IllegalArgumentException("Invalid button code: " + button);
}
button_ = button;
if (TYPE_DBL_CLICK.equals(type)) {
setDetail(2);
}
else {
setDetail(1);
}
}
/**
* Search for the prefix associated with specified namespace URI.
* @param element the element to start searching from
* @param namespace the namespace prefix
* @return the prefix bound to the namespace URI; or null if there is no such namespace
*/
public static String lookupPrefix(final DomElement element, final String namespace) {
final Map<String, DomAttr> attributes = element.getAttributesMap();
for (final Map.Entry<String, DomAttr> entry : attributes.entrySet()) {
final String name = entry.getKey();
final DomAttr value = entry.getValue();
if (name.startsWith("xmlns:") && value.getValue().equals(namespace)) {
return name.substring(6);
}
}
for (final DomNode child : element.getChildren()) {
if (child instanceof DomElement) {
final String prefix = lookupPrefix((DomElement) child, namespace);
if (prefix != null) {
return prefix;
}
}
}
return null;
}
/**
* Calls the {@code callback} given in parameter once for each value pair in the list, in insertion order.
* @param callback function to execute for each element
*/
@JsxFunction({CHROME, FF, FF68, FF60})
public void forEach(final Object callback) {
final List<DomNode> nodes = getElements();
final WebClient client = getWindow().getWebWindow().getWebClient();
final HtmlUnitContextFactory cf = ((JavaScriptEngine) client.getJavaScriptEngine()).getContextFactory();
final ContextAction<Object> contextAction = new ContextAction<Object>() {
@Override
public Object run(final Context cx) {
final Function function = (Function) callback;
final Scriptable scope = getParentScope();
for (int i = 0; i < nodes.size(); i++) {
function.call(cx, scope, NodeList.this, new Object[] {
nodes.get(i).getScriptableObject(), i, NodeList.this});
}
return null;
}
};
cf.call(contextAction);
}
/**
* Returns an {@link Iterator} allowing to go through all key/value pairs contained in this object.
* @return an {@link Iterator}
*/
@JsxFunction({CHROME, FF52})
public Iterator entries() {
final List<DomNode> elements = getElements();
final Context context = Context.getCurrentContext();
final Scriptable scope = getParentScope();
final List<Scriptable> list = new ArrayList<>();
for (int i = 0; i < elements.size(); i++) {
final Object[] array = new Object[] {i, elements.get(i).getScriptableObject()};
list.add(context.newArray(scope, array));
}
final Iterator object = new Iterator(ITERATOR_NAME, list.iterator());
object.setParentScope(scope);
setIteratorPrototype(object);
return object;
}
/**
* Creates a new keyboard event instance.
*
* @param domNode the DOM node that triggered the event
* @param type the event type
* @param keyCode the key code associated with the event
* @param shiftKey true if SHIFT is pressed
* @param ctrlKey true if CTRL is pressed
* @param altKey true if ALT is pressed
*/
public KeyboardEvent(final DomNode domNode, final String type, final int keyCode,
final boolean shiftKey, final boolean ctrlKey, final boolean altKey) {
super(domNode, type);
if (isAmbiguousKeyCode(keyCode)) {
throw new IllegalArgumentException("Please use the 'char' constructor instead of int");
}
setKeyCode(keyCode);
if (getType().equals(Event.TYPE_KEY_PRESS)) {
which_ = 0;
}
else {
which_ = keyCode;
}
setShiftKey(shiftKey);
setCtrlKey(ctrlKey);
setAltKey(altKey);
}
/**
* This is overridden instead of {@link #computeElements()} in order to prevent caching at all.
*
* {@inheritDoc}
*/
@Override
public List<DomNode> getElements() {
final List<DomNode> response = new ArrayList<>();
final DomElement domElement = (DomElement) getDomNodeOrDie();
for (DomNode parent = domElement.getParentNode(); parent != null; parent = parent.getParentNode()) {
if (parent instanceof HtmlLabel) {
response.add(parent);
}
}
final String id = domElement.getId();
if (id != DomElement.ATTRIBUTE_NOT_DEFINED) {
for (final DomElement label : domElement.getHtmlPageOrNull().getElementsByTagName("label")) {
if (id.equals(label.getAttributeDirect("for"))) {
response.add(label);
}
}
}
return response;
}
/**
* This is overridden instead of {@link #computeElements()} in order to prevent caching at all.
*
* {@inheritDoc}
*/
@Override
public List<DomNode> getElements() {
final List<DomNode> response = new ArrayList<>();
final DomElement domElement = (DomElement) getDomNodeOrDie();
for (DomNode parent = domElement.getParentNode(); parent != null; parent = parent.getParentNode()) {
if (parent instanceof HtmlLabel) {
response.add(parent);
}
}
final String id = domElement.getId();
if (id != DomElement.ATTRIBUTE_NOT_DEFINED) {
for (final DomElement label : domElement.getHtmlPageOrNull().getElementsByTagName("label")) {
if (id.equals(label.getAttributeDirect("for"))) {
response.add(label);
}
}
}
return response;
}
@Override
protected Object getWithPreemption(final String name) {
final List<DomNode> elements = getElements();
for (final Object next : elements) {
final BaseFrameElement frameElt = (BaseFrameElement) next;
final WebWindow window = frameElt.getEnclosedWindow();
if (name.equals(window.getName())) {
if (LOG.isDebugEnabled()) {
LOG.debug("Property \"" + name + "\" evaluated (by name) to " + window);
}
return getScriptableForElement(window);
}
if (getBrowserVersion().hasFeature(JS_WINDOW_FRAMES_ACCESSIBLE_BY_ID) && frameElt.getId().equals(name)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Property \"" + name + "\" evaluated (by id) to " + window);
}
return getScriptableForElement(window);
}
}
return NOT_FOUND;
}
private static void deleteBefore(final DomNode node, int offset) {
if (isOffsetChars(node)) {
String text = getText(node);
if (offset > -1 && offset < text.length()) {
text = text.substring(offset);
}
else {
text = "";
}
setText(node, text);
}
else {
final DomNodeList<DomNode> children = node.getChildNodes();
for (int i = 0; i < offset && i < children.getLength(); i++) {
final DomNode child = children.get(i);
child.remove();
i--;
offset--;
}
}
}
/**
* Creates an instance.
*
* @param domNode the {@link DomNode}
* @param attributeChangeSensitive indicates if the content of the collection may change when an attribute
* of a descendant node of parentScope changes (attribute added, modified or removed)
* @param initialElements the initial content for the cache
*/
private AbstractList(final DomNode domNode, final boolean attributeChangeSensitive,
final List<DomNode> initialElements) {
if (domNode != null) {
setDomNode(domNode, false);
final ScriptableObject parentScope = domNode.getScriptableObject();
if (parentScope != null) {
setParentScope(parentScope);
setPrototype(getPrototype(getClass()));
}
}
attributeChangeSensitive_ = attributeChangeSensitive;
cachedElements_ = initialElements;
if (initialElements != null) {
registerListener();
}
}
private List<HtmlElement> findElements(final String name) {
final List<HtmlElement> elements = new ArrayList<>();
addElements(name, getHtmlForm().getHtmlElementDescendants(), elements);
addElements(name, getHtmlForm().getLostChildren(), elements);
// If no form fields are found, browsers are able to find img elements by ID or name.
if (elements.isEmpty()) {
for (final DomNode node : getHtmlForm().getHtmlElementDescendants()) {
if (node instanceof HtmlImage) {
final HtmlImage img = (HtmlImage) node;
if (name.equals(img.getId()) || name.equals(img.getNameAttribute())) {
elements.add(img);
}
}
}
}
return elements;
}
/**
* Returns the value of the JavaScript attribute {@code areas}.
* @return the value of this attribute
*/
@JsxGetter
public HTMLCollection getAreas() {
if (areas_ == null) {
final HtmlMap map = (HtmlMap) getDomNodeOrDie();
areas_ = new HTMLCollection(map, false) {
@Override
protected List<DomNode> computeElements() {
final List<DomNode> list = new ArrayList<>();
for (final DomNode node : map.getChildElements()) {
if (node instanceof HtmlArea) {
list.add(node);
}
}
return list;
}
};
}
return areas_;
}
private void registerListener() {
if (!listenerRegistered_) {
final DomNode domNode = getDomNodeOrNull();
if (domNode != null) {
final DomHtmlAttributeChangeListenerImpl listener = new DomHtmlAttributeChangeListenerImpl(this);
domNode.addDomChangeListener(listener);
if (attributeChangeSensitive_) {
if (domNode instanceof HtmlElement) {
((HtmlElement) domNode).addHtmlAttributeChangeListener(listener);
}
else if (domNode instanceof HtmlPage) {
((HtmlPage) domNode).addHtmlAttributeChangeListener(listener);
}
}
listenerRegistered_ = true;
}
}
}
/**
* Overridden to allow the retrieval of certain form elements by ID or name.
*
* @param name {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
protected Object getWithPreemption(final String name) {
if (getDomNodeOrNull() == null) {
return NOT_FOUND;
}
final List<HtmlElement> elements = findElements(name);
if (elements.isEmpty()) {
return NOT_FOUND;
}
if (elements.size() == 1) {
return getScriptableFor(elements.get(0));
}
final List<DomNode> nodes = new ArrayList<>(elements);
return new HTMLCollection(getHtmlForm(), nodes) {
@Override
protected List<DomNode> computeElements() {
return new ArrayList<>(findElements(name));
}
};
}
/**
* Returns the value of the {@code embeds} property.
* @return the value of the {@code embeds} property
*/
@JsxGetter({CHROME, IE})
public Object getImages() {
return new HTMLCollection(getDomNodeOrDie(), false) {
@Override
protected boolean isMatching(final DomNode node) {
return node instanceof HtmlImage;
}
@Override
public Object call(final Context cx, final Scriptable scope,
final Scriptable thisObj, final Object[] args) {
if (getBrowserVersion().hasFeature(JS_DOCUMENT_FORMS_FUNCTION_SUPPORTED)) {
return super.call(cx, scope, thisObj, args);
}
throw Context.reportRuntimeError("TypeError: document.images is not a function");
}
};
}
/**
* Returns true if the element would be selected by the specified selector string; otherwise, returns false.
* @param context the JavaScript context
* @param thisObj the scriptable
* @param args the arguments passed into the method
* @param function the function
* @return the value
*/
@JsxFunction({CHROME, FF, EDGE})
public static boolean matches(
final Context context, final Scriptable thisObj, final Object[] args, final Function function) {
final String selectorString = (String) args[0];
if (!(thisObj instanceof Element)) {
throw ScriptRuntime.typeError("Illegal invocation");
}
try {
final DomNode domNode = ((Element) thisObj).getDomNodeOrNull();
return domNode != null && ((DomElement) domNode).matches(selectorString);
}
catch (final CSSException e) {
throw ScriptRuntime.constructError("SyntaxError",
"An invalid or illegal selector was specified (selector: '"
+ selectorString + "' error: " + e.getMessage() + ").");
}
}
/**
* Helper for {@link #getWithPreemption(String)} when finding by id doesn't get results.
* @param name the property name
* @param elements the children elements.
* @return {@link Scriptable#NOT_FOUND} if not found
*/
protected Object getWithPreemptionByName(final String name, final List<DomNode> elements) {
final List<DomNode> matchingElements = new ArrayList<>();
for (final DomNode next : elements) {
if (next instanceof DomElement) {
final String nodeName = ((DomElement) next).getAttributeDirect("name");
if (name.equals(nodeName)) {
matchingElements.add(next);
}
}
}
if (matchingElements.isEmpty()) {
return NOT_FOUND;
}
else if (matchingElements.size() == 1) {
return getScriptableForElement(matchingElements.get(0));
}
// many elements => build a sub collection
final DomNode domNode = getDomNodeOrNull();
final AbstractList collection = create(domNode, matchingElements);
collection.setAvoidObjectDetection(true);
return collection;
}
/**
* Returns the value of the {@code embeds} property.
* @return the value of the {@code embeds} property
*/
@JsxGetter({CHROME, IE})
public Object getImages() {
return new HTMLCollection(getDomNodeOrDie(), false) {
@Override
protected boolean isMatching(final DomNode node) {
return node instanceof HtmlImage;
}
@Override
public Object call(final Context cx, final Scriptable scope,
final Scriptable thisObj, final Object[] args) {
if (getBrowserVersion().hasFeature(JS_DOCUMENT_FORMS_FUNCTION_SUPPORTED)) {
return super.call(cx, scope, thisObj, args);
}
throw Context.reportRuntimeError("TypeError: document.images is not a function");
}
};
}
/**
* Gets the HTML elements from cache or retrieve them at first call.
* @return the list of {@link HtmlElement} contained in this collection
*/
public List<DomNode> getElements() {
// a bit strange but we like to avoid sync
List<DomNode> cachedElements = cachedElements_;
if (cachedElements == null) {
if (getParentScope() == null) {
cachedElements = new ArrayList<>();
}
else {
cachedElements = computeElements();
}
cachedElements_ = cachedElements;
}
registerListener();
// maybe the cache was cleared in between
// then this returns the old state and never null
return cachedElements;
}
private static org.w3c.dom.traversal.NodeFilter createFilterWrapper(final Scriptable filter,
final boolean filterFunctionOnly) {
org.w3c.dom.traversal.NodeFilter filterWrapper = null;
if (filter != null) {
filterWrapper = new org.w3c.dom.traversal.NodeFilter() {
@Override
public short acceptNode(final org.w3c.dom.Node n) {
final Object[] args = new Object[] {((DomNode) n).getScriptableObject()};
final Object response;
if (filter instanceof Callable) {
response = ((Callable) filter).call(Context.getCurrentContext(), filter, filter, args);
}
else {
if (filterFunctionOnly) {
throw Context.reportRuntimeError("only a function is allowed as filter");
}
response = ScriptableObject.callMethod(filter, "acceptNode", args);
}
return (short) Context.toNumber(response);
}
};
}
return filterWrapper;
}
/**
* {@inheritDoc}
*/
@Override
protected Object getWithPreemptionByName(final String name, final List<DomNode> elements) {
final List<DomNode> matchingElements = new ArrayList<>();
final boolean searchName = isGetWithPreemptionSearchName();
for (final DomNode next : elements) {
if (next instanceof DomElement
&& (searchName || next instanceof HtmlInput || next instanceof HtmlForm)) {
final String nodeName = ((DomElement) next).getAttributeDirect("name");
if (name.equals(nodeName)) {
matchingElements.add(next);
}
}
}
if (matchingElements.isEmpty()) {
if (getBrowserVersion().hasFeature(HTMLCOLLECTION_ITEM_SUPPORTS_DOUBLE_INDEX_ALSO)) {
final Double doubleValue = Context.toNumber(name);
if (!doubleValue.isNaN()) {
final Object object = get(doubleValue.intValue(), this);
if (object != NOT_FOUND) {
return object;
}
}
}
return NOT_FOUND;
}
else if (matchingElements.size() == 1) {
return getScriptableForElement(matchingElements.get(0));
}
// many elements => build a sub collection
final DomNode domNode = getDomNodeOrNull();
final HTMLCollection collection = new HTMLCollection(domNode, matchingElements);
collection.setAvoidObjectDetection(true);
return collection;
}
/**
* Copy all children from 'source' to 'dest', within the context of the specified page.
* @param page the page which the nodes belong to
* @param source the node to copy from
* @param dest the node to copy to
* @param handleXHTMLAsHTML if true elements from the XHTML namespace are handled as HTML elements instead of
* DOM elements
*/
private static void copy(final SgmlPage page, final Node source, final DomNode dest,
final boolean handleXHTMLAsHTML, final Map<Integer, List<String>> attributesOrderMap) {
final NodeList nodeChildren = source.getChildNodes();
for (int i = 0; i < nodeChildren.getLength(); i++) {
final Node child = nodeChildren.item(i);
switch (child.getNodeType()) {
case Node.ELEMENT_NODE:
final DomNode childXml = createFrom(page, child, handleXHTMLAsHTML, attributesOrderMap);
dest.appendChild(childXml);
copy(page, child, childXml, handleXHTMLAsHTML, attributesOrderMap);
break;
case Node.TEXT_NODE:
dest.appendChild(new DomText(page, child.getNodeValue()));
break;
case Node.CDATA_SECTION_NODE:
dest.appendChild(new DomCDataSection(page, child.getNodeValue()));
break;
case Node.COMMENT_NODE:
dest.appendChild(new DomComment(page, child.getNodeValue()));
break;
case Node.PROCESSING_INSTRUCTION_NODE:
dest.appendChild(new DomProcessingInstruction(page, child.getNodeName(), child.getNodeValue()));
break;
default:
LOG.warn("NodeType " + child.getNodeType()
+ " (" + child.getNodeName() + ") is not yet supported.");
}
}
}
/**
* Returns the DOM node that corresponds to this JavaScript object or throw
* an exception if one cannot be found.
* @return the DOM node
*/
public DomNode getDomNodeOrDie() {
if (domNode_ == null) {
final String clazz = getClass().getName();
throw new IllegalStateException("DomNode has not been set for this SimpleScriptable: " + clazz);
}
return domNode_;
}
/**
* Returns the value of the {@code defaultSelected} property.
* @return the text property
*/
@JsxGetter
public boolean isDefaultSelected() {
final DomNode dom = getDomNodeOrNull();
if (dom instanceof HtmlOption) {
return ((HtmlOption) dom).isDefaultSelected();
}
return false;
}
/**
* Builds a function that will execute the JavaScript code provided.
* @param node the element for which the event is build
* @param eventName the event for which this handler is created
* @param jsSnippet the JavaScript code
*/
public EventHandler(final DomNode node, final String eventName, final String jsSnippet) {
node_ = node;
eventName_ = eventName;
jsSnippet_ = "function on" + eventName + "(event) {" + jsSnippet + "\n}";
final ScriptableObject w = node.getPage().getEnclosingWindow().getScriptableObject();
final Scriptable function = (Scriptable) w.get("Function", w);
setPrototype(function.getPrototype());
}
/**
* Creates a new event instance.
*
* @param domNode the DOM node that triggered the event
* @param type the event type
* @param shiftKey true if SHIFT is pressed
* @param ctrlKey true if CTRL is pressed
* @param altKey true if ALT is pressed
* @param button the button code, must be {@link #BUTTON_LEFT}, {@link #BUTTON_MIDDLE} or {@link #BUTTON_RIGHT}
*/
public PointerEvent(final DomNode domNode, final String type, final boolean shiftKey,
final boolean ctrlKey, final boolean altKey, final int button) {
super(domNode, type, shiftKey, ctrlKey, altKey, button);
setDetail(0);
pointerId_ = 1;
width_ = 1;
height_ = 1;
pointerType_ = "mouse";
isPrimary_ = true;
}
/**
* Sets the DOM node that corresponds to this JavaScript object.
* @param domNode the DOM node
*/
@Override
public void setDomNode(final DomNode domNode) {
super.setDomNode(domNode);
if (getBrowserVersion().hasFeature(JS_XML_SUPPORT_VIA_ACTIVEXOBJECT)) {
if ((domNode instanceof HtmlAbbreviated && getBrowserVersion().hasFeature(HTMLABBREVIATED))
|| domNode instanceof HtmlAcronym
|| domNode instanceof HtmlBidirectionalOverride
|| domNode instanceof HtmlBig
|| domNode instanceof HtmlBlink
|| domNode instanceof HtmlBold
|| domNode instanceof HtmlCitation
|| domNode instanceof HtmlCode
|| domNode instanceof HtmlDefinition
|| domNode instanceof HtmlEmphasis
|| domNode instanceof HtmlItalic
|| domNode instanceof HtmlKeyboard
|| domNode instanceof HtmlNoBreak
|| domNode instanceof HtmlS
|| domNode instanceof HtmlSample
|| domNode instanceof HtmlSmall
|| domNode instanceof HtmlStrong
|| domNode instanceof HtmlStrike
|| domNode instanceof HtmlSubscript
|| domNode instanceof HtmlSuperscript
|| domNode instanceof HtmlTeletype
|| domNode instanceof HtmlUnderlined
|| domNode instanceof HtmlVariable
) {
ActiveXObject.addProperty(this, "cite", true, true);
ActiveXObject.addProperty(this, "dateTime", true, true);
}
}
}
/**
* Gets the browser version currently used.
* @return the browser version
*/
public BrowserVersion getBrowserVersion() {
final DomNode node = getDomNodeOrNull();
if (node != null) {
return node.getPage().getWebClient().getBrowserVersion();
}
return getWindow().getWebWindow().getWebClient().getBrowserVersion();
}
/**
* Returns the {@code text} property.
* @return the {@code text} property
*/
@JsxGetter
public String getText() {
final StringBuilder scriptCode = new StringBuilder();
for (final DomNode node : getDomNodeOrDie().getChildren()) {
if (node instanceof DomText) {
final DomText domText = (DomText) node;
scriptCode.append(domText.getData());
}
}
return scriptCode.toString();
}
private String asString() {
final Object resultObj = result_.get(0);
if (resultObj instanceof DomAttr) {
return ((DomAttr) resultObj).getValue();
}
if (resultObj instanceof DomNode) {
return ((DomNode) resultObj).asText();
}
return resultObj.toString();
}