1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-29 01:45:34 +00:00

[spidermonkey] own implementation of nodeList for querySelectorAll

This commit is contained in:
Witold Filipczyk 2024-06-24 16:50:08 +02:00
parent 5329a84cb5
commit 89dde0e0b6
9 changed files with 249 additions and 34 deletions

View File

@ -559,7 +559,7 @@ walk_tree_query(dom_node *node, const char *selector, int depth)
}
void
walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth)
walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth, LIST_OF(struct selector_node) *result_list)
{
dom_exception exc;
dom_node *child;
@ -574,17 +574,11 @@ walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int
}
if (res = el_match_selector(selector, node)) {
dom_node *clone = NULL;
exc = dom_node_clone_node(res, false, &clone);
struct selector_node *sn = (struct selector_node *)mem_calloc(1, sizeof(*sn));
if (exc != DOM_NO_ERR || !clone) {
} else {
dom_node *result = NULL;
exc = dom_node_append_child(root, clone, &result);
}
if (exc != DOM_NO_ERR) {
return;
if (sn) {
sn->node = res;
add_to_list_end(*result_list, sn);
}
}
/* Get the node's first child */
@ -601,7 +595,7 @@ walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int
dom_node *next_child;
/* Visit node's descendents */
walk_tree_query_append(root, child, selector, depth);
walk_tree_query_append(root, child, selector, depth, result_list);
/* Go to next sibling */
exc = dom_node_get_next_sibling(child, &next_child);
@ -615,4 +609,3 @@ walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int
} while (child != NULL); /* No more children */
}
}

View File

@ -5,6 +5,7 @@
#include "ecmascript/libdom/dom.h"
#include "main/module.h"
#include "terminal/kbd.h"
#include "util/lists.h"
#ifdef __cplusplus
extern "C" {
@ -22,6 +23,12 @@ struct term_event;
struct uri;
struct view_state;
struct selector_node {
LIST_HEAD_EL(struct selector_node);
void *node;
};
int ecmascript_get_interpreter_count(void);
void ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter);
void toggle_ecmascript(struct session *ses);
@ -42,7 +49,7 @@ void ecmascript_detach_form_state(struct form_state *fs);
void ecmascript_moved_form_state(struct form_state *fs);
void *walk_tree_query(dom_node *node, const char *selector, int depth);
void walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth);
void walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth, LIST_OF(struct selector_node) *result_list);
extern struct module ecmascript_module;

View File

@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config
INCLUDES += $(SPIDERMONKEY_CFLAGS)
OBJS = attr.obj attributes.obj collection.obj console.obj css.obj customevent.obj document.obj domrect.obj element.obj event.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \
keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj style.obj unibar.obj url.obj urlsearchparams.obj window.obj xhr.obj
keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj nodelist2.obj screen.obj style.obj unibar.obj url.obj urlsearchparams.obj window.obj xhr.obj
include $(top_srcdir)/Makefile.lib

View File

@ -41,6 +41,7 @@
#include "ecmascript/spidermonkey/event.h"
#include "ecmascript/spidermonkey/heartbeat.h"
#include "ecmascript/spidermonkey/nodelist.h"
#include "ecmascript/spidermonkey/nodelist2.h"
#include "ecmascript/spidermonkey/util.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/libintl.h"
@ -2181,19 +2182,21 @@ document_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setNull();
return true;
}
walk_tree_query_append((dom_node *)element, doc_root, selector, 0);
dom_node_unref(doc_root);
mem_free(selector);
LIST_OF(struct selector_node) *result_list = (LIST_OF(struct selector_node) *)mem_calloc(1, sizeof(*result_list));
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
if (!result_list) {
dom_node_unref(doc_root);
mem_free(selector);
args.rval().setNull();
return true;
}
JSObject *obj = getNodeList(ctx, nodes);
init_list(*result_list);
walk_tree_query_append((dom_node *)element, doc_root, selector, 0, result_list);
dom_node_unref(doc_root);
mem_free(selector);
JSObject *obj = getNodeList2(ctx, result_list);
args.rval().setObject(*obj);
return true;

View File

@ -39,6 +39,7 @@
#include "ecmascript/spidermonkey/heartbeat.h"
#include "ecmascript/spidermonkey/keyboard.h"
#include "ecmascript/spidermonkey/nodelist.h"
#include "ecmascript/spidermonkey/nodelist2.h"
#include "ecmascript/spidermonkey/style.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/libintl.h"
@ -5058,18 +5059,17 @@ element_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setNull();
return true;
}
walk_tree_query_append((dom_node *)element, el, selector, 0);
mem_free(selector);
LIST_OF(struct selector_node) *result_list = (LIST_OF(struct selector_node) *)mem_calloc(1, sizeof(*result_list));
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
if (!result_list) {
mem_free(selector);
args.rval().setNull();
return true;
}
JSObject *obj = getNodeList(ctx, nodes);
init_list(*result_list);
walk_tree_query_append((dom_node *)element, el, selector, 0, result_list);
mem_free(selector);
JSObject *obj = getNodeList2(ctx, result_list);
args.rval().setObject(*obj);
return true;

View File

@ -1,4 +1,4 @@
srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'css.cpp', 'customevent.cpp', 'document.cpp', 'domrect.cpp', 'element.cpp', 'event.cpp',
'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', 'keyboard.cpp',
'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'style.cpp', 'unibar.cpp', 'url.cpp',
'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'nodelist2.cpp', 'screen.cpp', 'style.cpp', 'unibar.cpp', 'url.cpp',
'urlsearchparams.cpp', 'window.cpp', 'xhr.cpp')

View File

@ -0,0 +1,204 @@
/* The SpiderMonkey nodeList2 object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "ecmascript/libdom/dom.h"
#include "ecmascript/spidermonkey/util.h"
#include <jsfriendapi.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/spidermonkey/element.h"
#include "ecmascript/spidermonkey/nodelist2.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/lists.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
#include <iostream>
#include <algorithm>
#include <string>
static bool nodeList2_item(JSContext *ctx, unsigned int argc, JS::Value *rval);
static bool nodeList2_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp);
static void nodeList2_finalize(JS::GCContext *op, JSObject *obj)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
LIST_OF(struct selector_node) *sni = JS::GetMaybePtrFromReservedSlot<LIST_OF(struct selector_node)>(obj, 0);
if (sni) {
free_list(*sni);
}
}
JSClassOps nodeList2_ops = {
nullptr, // addProperty
nullptr, // deleteProperty
nullptr, // enumerate
nullptr, // newEnumerate
nullptr, // resolve
nullptr, // mayResolve
nodeList2_finalize, // finalize
nullptr, // call
nullptr, // construct
JS_GlobalObjectTraceHook
};
JSClass nodeList2_class = {
"nodeList2",
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
&nodeList2_ops
};
static const spidermonkeyFunctionSpec nodeList2_funcs[] = {
{ "item", nodeList2_item, 1 },
{ NULL }
};
static bool nodeList2_get_property_length(JSContext *ctx, unsigned int argc, JS::Value *vp);
static JSPropertySpec nodeList2_props[] = {
JS_PSG("length", nodeList2_get_property_length, JSPROP_ENUMERATE),
JS_PS_END
};
static bool
nodeList2_get_property_length(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
struct view_state *vs;
JS::Realm *comp = js::GetContextRealm(ctx);
if (!comp) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
/* This can be called if @obj if not itself an instance of the
* appropriate class but has one in its prototype chain. Fail
* such calls. */
if (!JS_InstanceOf(ctx, hobj, &nodeList2_class, NULL)) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
LIST_OF(struct selector_node) *sni = JS::GetMaybePtrFromReservedSlot<LIST_OF(struct selector_node)>(hobj, 0);
args.rval().setInt32(list_size(sni));
return true;
}
static bool
nodeList2_item(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JS::Value val;
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
JS::RootedValue rval(ctx, val);
LIST_OF(struct selector_node) *sni = JS::GetMaybePtrFromReservedSlot<LIST_OF(struct selector_node)>(hobj, 0);
int index = args[0].toInt32();
int counter = 0;
struct selector_node *sn = NULL;
foreach (sn, *sni) {
if (counter == index) {
break;
}
counter++;
}
if (!sn || !sn->node) {
args.rval().setNull();
return true;
}
JSObject *res = getElement(ctx, sn->node);
args.rval().setObject(*res);
return true;
}
JSObject *
getNodeList2(JSContext *ctx, void *res)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
LIST_OF(struct selector_node) *sni = (LIST_OF(struct selector_node) *)res;
JSObject *el = JS_NewObject(ctx, &nodeList2_class);
if (!el) {
return NULL;
}
JS::RootedObject r_el(ctx, el);
JS_DefineProperties(ctx, r_el, (JSPropertySpec *) nodeList2_props);
spidermonkey_DefineFunctions(ctx, el, nodeList2_funcs);
struct selector_node *sn = NULL;
int i = 0;
foreach (sn, *sni) {
JSObject *obj = getElement(ctx, sn->node);
if (obj) {
JS::RootedObject v(ctx, obj);
JS::RootedValue ro(ctx, JS::ObjectOrNullValue(v));
JS_SetElement(ctx, r_el, i, ro);
}
i++;
}
JS::SetReservedSlot(el, 0, JS::PrivateValue(res));
return el;
}

View File

@ -0,0 +1,8 @@
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_NODELIST2_H
#define EL__ECMASCRIPT_SPIDERMONKEY_NODELIST2_H
#include "ecmascript/spidermonkey/util.h"
JSObject *getNodeList2(JSContext *ctx, void *result_list);
#endif

View File

@ -9,7 +9,7 @@
console.error('nodelist.forEach.html');
var birds = document.querySelectorAll('li');
console.assert(birds.length === 3, birds.length);
console.assert(birds.length === 3, 'birds.length');
var counter = 0;
birds.forEach(function(b) {