All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gargoylesoftware.htmlunit.javascript.host.dom.NodeList Maven / Gradle / Ivy

There is a newer version: 2.70.0
Show newest version
/*
 * Copyright (c) 2002-2018 Gargoyle Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gargoylesoftware.htmlunit.javascript.host.dom;

import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52;

import java.util.ArrayList;
import java.util.List;

import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.javascript.HtmlUnitScriptable;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
import com.gargoylesoftware.htmlunit.javascript.host.Iterator;

import net.sourceforge.htmlunit.corejs.javascript.Context;
import net.sourceforge.htmlunit.corejs.javascript.Function;
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;

/**
 * An array of elements. Used for the element arrays returned by document.all,
 * document.all.tags('x'), document.forms, window.frames, etc.
 * Note that this class must not be used for collections that can be modified, for example
 * map.areas and select.options.
 *
 * @author Daniel Gredler
 * @author Marc Guillemot
 * @author Chris Erskine
 * @author Ahmed Ashour
 * @author Frank Danek
 * @author Ronald Brill
 */
@JsxClass
public class NodeList extends AbstractList {

    private static final String ITERATOR_NAME = "Iterator";
    private static Iterator ITERATOR_PROTOTYPE_;

    /**
     * Creates an instance.
     */
    @JsxConstructor({CHROME, FF, EDGE})
    public NodeList() {
    }

    /**
     * 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)
     */
    public NodeList(final DomNode domNode, final boolean attributeChangeSensitive) {
        super(domNode, attributeChangeSensitive);
    }

    /**
     * Constructs an instance with an initial cache value.
     * @param domNode the parent scope, on which we listen for changes
     * @param initialElements the initial content for the cache
     */
    public NodeList(final DomNode domNode, final List initialElements) {
        super(domNode, initialElements);
    }

    /**
     * Creates an instance.
     * @param parentScope the parent scope
     */
    private NodeList(final ScriptableObject parentScope) {
        setParentScope(parentScope);
        setPrototype(getPrototype(getClass()));
    }

    /**
     * Gets a static NodeList.
     *
     * @param parentScope the parent scope
     * @param elements the elements
     * @return an empty collection
     */
    public static NodeList staticNodeList(final HtmlUnitScriptable parentScope, final List elements) {
        return new NodeList(parentScope) {
            @Override
            public List getElements() {
                return elements;
            }
        };
    }

    /**
     * Returns an {@link Iterator} allowing to go through all keys contained in this object.
     * @return an {@link Iterator}
     */
    @JsxFunction({CHROME, FF52})
    public Iterator keys() {
        final int length = getElements().size();
        final List list = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            list.add(i);
        }
        final Iterator object = new Iterator(ITERATOR_NAME, list.iterator());
        object.setParentScope(getParentScope());
        setIteratorPrototype(object);
        return object;
    }

    /**
     * Returns an {@link Iterator} allowing to go through all keys contained in this object.
     * @return an {@link Iterator}
     */
    @JsxFunction({CHROME, FF52})
    public Iterator values() {
        final List list = getElements();
        final Iterator object = new Iterator(ITERATOR_NAME, list.iterator());
        object.setParentScope(getParentScope());
        setIteratorPrototype(object);
        return object;
    }

    /**
     * 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 elements = getElements();
        final Context context = Context.getCurrentContext();
        final Scriptable scope = getParentScope();

        final List 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;
    }

    private static void setIteratorPrototype(final Scriptable scriptable) {
        if (ITERATOR_PROTOTYPE_ == null) {
            ITERATOR_PROTOTYPE_ = new Iterator(ITERATOR_NAME, null);
        }
        scriptable.setPrototype(ITERATOR_PROTOTYPE_);
    }

    /**
     * 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, FF52})
    public void forEach(final Object callback) {
        final List nodes = getElements();
        final Context context = Context.enter();
        try {
            final Function function = (Function) callback;
            final Scriptable scope = getParentScope();
            for (int i = 0; i < nodes.size(); i++) {
                function.call(context, scope, this, new Object[] {
                        nodes.get(i).getScriptableObject(), i, this});
            }
        }
        finally {
            Context.exit();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy