diff --git a/src/ecmascript/spidermonkey/Makefile b/src/ecmascript/spidermonkey/Makefile index 340fccc49..5c8e9ba6a 100644 --- a/src/ecmascript/spidermonkey/Makefile +++ b/src/ecmascript/spidermonkey/Makefile @@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) OBJS = attr.o attributes.o console.o css2xpath.o document.o element.o form.o heartbeat.o implementation.o location.o \ - localstorage.o localstorage-db.o navigator.o screen.o unibar.o window.o + localstorage.o localstorage-db.o navigator.o nodelist.o screen.o unibar.o window.o include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/spidermonkey/document.c b/src/ecmascript/spidermonkey/document.c index 0738530ba..e97d92894 100644 --- a/src/ecmascript/spidermonkey/document.c +++ b/src/ecmascript/spidermonkey/document.c @@ -30,6 +30,7 @@ #include "ecmascript/spidermonkey/location.h" #include "ecmascript/spidermonkey/document.h" #include "ecmascript/spidermonkey/element.h" +#include "ecmascript/spidermonkey/nodelist.h" #include "ecmascript/spidermonkey/util.h" #include "ecmascript/spidermonkey/window.h" #include "intl/libintl.h" diff --git a/src/ecmascript/spidermonkey/element.c b/src/ecmascript/spidermonkey/element.c index 7320be3b6..c14a9bfc2 100644 --- a/src/ecmascript/spidermonkey/element.c +++ b/src/ecmascript/spidermonkey/element.c @@ -27,6 +27,7 @@ #include "ecmascript/spidermonkey/attributes.h" #include "ecmascript/spidermonkey/css2xpath.h" #include "ecmascript/spidermonkey/element.h" +#include "ecmascript/spidermonkey/nodelist.h" #include "ecmascript/spidermonkey/window.h" #include "intl/libintl.h" #include "main/select.h" @@ -60,7 +61,6 @@ static bool htmlCollection_set_items(JSContext *ctx, JS::HandleObject hobj, void *node); static bool nodeList_set_items(JSContext *ctx, JS::HandleObject hobj, void *node); -static bool attributes_set_items(JSContext *ctx, JS::HandleObject hobj, void *node); static bool element_get_property_attributes(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_children(JSContext *ctx, unsigned int argc, JS::Value *vp); @@ -3571,286 +3571,3 @@ getCollection(JSContext *ctx, void *node) return el; } - - -static bool nodeList_item(JSContext *ctx, unsigned int argc, JS::Value *rval); -static bool nodeList_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); -static bool nodeList_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp); - -static void nodeList_finalize(JSFreeOp *op, JSObject *obj) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif -} - -JSClassOps nodeList_ops = { - nullptr, // addProperty - nullptr, // deleteProperty - nullptr, // enumerate - nullptr, // newEnumerate - nullptr, // resolve - nullptr, // mayResolve - nodeList_finalize, // finalize - nullptr, // call - nullptr, // hasInstance - nullptr, // construct - JS_GlobalObjectTraceHook -}; - -JSClass nodeList_class = { - "nodeList", - JSCLASS_HAS_PRIVATE, - &nodeList_ops -}; - -static const spidermonkeyFunctionSpec nodeList_funcs[] = { - { "item", nodeList_item, 1 }, - { NULL } -}; - -static bool nodeList_get_property_length(JSContext *ctx, unsigned int argc, JS::Value *vp); - -static JSPropertySpec nodeList_props[] = { - JS_PSG("length", nodeList_get_property_length, JSPROP_ENUMERATE), - JS_PS_END -}; - -static bool -nodeList_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 = 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, &nodeList_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); - - if (!nl) { - args.rval().setInt32(0); - return true; - } - args.rval().setInt32(nl->size()); - - return true; -} - -static bool -nodeList_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); - - int index = args[0].toInt32(); - bool ret = nodeList_item2(ctx, hobj, index, &rval); - args.rval().set(rval); - - return ret; -} - -static bool -nodeList_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - 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 = JS::GetRealmPrivate(comp); - - if (!JS_InstanceOf(ctx, hobj, &nodeList_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - hvp.setUndefined(); - - xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); - - if (!nl) { - return true; - } - - xmlpp::Element *element = nullptr; - - auto it = nl->begin(); - auto end = nl->end(); - for (int i = 0; it != end; ++it, ++i) { - if (i == index) { - element = *it; - break; - } - } - - if (!element) { - return true; - } - - JSObject *obj = getElement(ctx, element); - hvp.setObject(*obj); - - return true; -} - -static bool -nodeList_set_items(JSContext *ctx, JS::HandleObject hobj, void *node) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - 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 = 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, &nodeList_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); - - if (!nl) { - return true; - } - - auto it = nl->begin(); - auto end = nl->end(); - for (int i = 0; it != end; ++it, ++i) { - xmlpp::Element *element = *it; - - if (element) { - JSObject *obj = getElement(ctx, element); - - if (!obj) { - continue; - } - - JS::RootedObject v(ctx, obj); - JS::RootedValue ro(ctx, JS::ObjectOrNullValue(v)); - JS_SetElement(ctx, hobj, i, ro); - } - } - - return true; -} - -static bool -nodeList_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - jsid id = hid.get(); - struct view_state *vs; - JS::Value idval; - - 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 = 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, &nodeList_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - if (JSID_IS_INT(id)) { - JS::RootedValue r_idval(ctx, idval); - JS_IdToValue(ctx, id, &r_idval); - int index = r_idval.toInt32(); - return nodeList_item2(ctx, hobj, index, hvp); - } - - return true; -} - -JSObject * -getNodeList(JSContext *ctx, void *node) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JSObject *el = JS_NewObject(ctx, &nodeList_class); - - if (!el) { - return NULL; - } - - JS::RootedObject r_el(ctx, el); - - JS_DefineProperties(ctx, r_el, (JSPropertySpec *) nodeList_props); - spidermonkey_DefineFunctions(ctx, el, nodeList_funcs); - - JS_SetPrivate(el, node); - nodeList_set_items(ctx, r_el, node); - - return el; -} - diff --git a/src/ecmascript/spidermonkey/element.h b/src/ecmascript/spidermonkey/element.h index 2fcffe492..0e9de0b3a 100644 --- a/src/ecmascript/spidermonkey/element.h +++ b/src/ecmascript/spidermonkey/element.h @@ -9,7 +9,6 @@ extern JSPropertySpec element_props[]; JSObject *getElement(JSContext *ctx, void *node); JSObject *getCollection(JSContext *ctx, void *node); -JSObject *getNodeList(JSContext *ctx, void *node); void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false); diff --git a/src/ecmascript/spidermonkey/meson.build b/src/ecmascript/spidermonkey/meson.build index 61296960f..70d933808 100644 --- a/src/ecmascript/spidermonkey/meson.build +++ b/src/ecmascript/spidermonkey/meson.build @@ -1,3 +1,3 @@ #INCLUDES += $(SPIDERMONKEY_CFLAGS) -srcs += files('attr.c', 'attributes.c', 'console.c', 'css2xpath.c', 'document.c', 'element.c', 'form.c', 'heartbeat.c', 'implementation.c', 'location.c', 'localstorage.c', 'localstorage-db.c', 'navigator.c', 'screen.c', 'unibar.c', 'window.c') +srcs += files('attr.c', 'attributes.c', 'console.c', 'css2xpath.c', 'document.c', 'element.c', 'form.c', 'heartbeat.c', 'implementation.c', 'location.c', 'localstorage.c', 'localstorage-db.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c') diff --git a/src/ecmascript/spidermonkey/nodelist.c b/src/ecmascript/spidermonkey/nodelist.c new file mode 100644 index 000000000..023a0ac82 --- /dev/null +++ b/src/ecmascript/spidermonkey/nodelist.c @@ -0,0 +1,339 @@ +/* The SpiderMonkey nodeList object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/spidermonkey/util.h" +#include + +#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/spidermonkey/element.h" +#include "ecmascript/spidermonkey/nodelist.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/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 +#include +#include +#include +#include + +#include +#include +#include + +static bool nodeList_item(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool nodeList_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +static bool nodeList_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp); + +static void nodeList_finalize(JSFreeOp *op, JSObject *obj) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif +} + +JSClassOps nodeList_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + nodeList_finalize, // finalize + nullptr, // call + nullptr, // hasInstance + nullptr, // construct + JS_GlobalObjectTraceHook +}; + +JSClass nodeList_class = { + "nodeList", + JSCLASS_HAS_PRIVATE, + &nodeList_ops +}; + +static const spidermonkeyFunctionSpec nodeList_funcs[] = { + { "item", nodeList_item, 1 }, + { NULL } +}; + +static bool nodeList_get_property_length(JSContext *ctx, unsigned int argc, JS::Value *vp); + +static JSPropertySpec nodeList_props[] = { + JS_PSG("length", nodeList_get_property_length, JSPROP_ENUMERATE), + JS_PS_END +}; + +static bool +nodeList_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 = 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, &nodeList_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); + + if (!nl) { + args.rval().setInt32(0); + return true; + } + args.rval().setInt32(nl->size()); + + return true; +} + +static bool +nodeList_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); + + int index = args[0].toInt32(); + bool ret = nodeList_item2(ctx, hobj, index, &rval); + args.rval().set(rval); + + return ret; +} + +static bool +nodeList_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + 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 = JS::GetRealmPrivate(comp); + + if (!JS_InstanceOf(ctx, hobj, &nodeList_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + hvp.setUndefined(); + + xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); + + if (!nl) { + return true; + } + + xmlpp::Element *element = nullptr; + + auto it = nl->begin(); + auto end = nl->end(); + for (int i = 0; it != end; ++it, ++i) { + if (i == index) { + element = *it; + break; + } + } + + if (!element) { + return true; + } + + JSObject *obj = getElement(ctx, element); + hvp.setObject(*obj); + + return true; +} + +static bool +nodeList_set_items(JSContext *ctx, JS::HandleObject hobj, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + 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 = 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, &nodeList_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + xmlpp::Node::NodeList *nl = JS_GetPrivate(hobj); + + if (!nl) { + return true; + } + + auto it = nl->begin(); + auto end = nl->end(); + for (int i = 0; it != end; ++it, ++i) { + xmlpp::Element *element = *it; + + if (element) { + JSObject *obj = getElement(ctx, element); + + if (!obj) { + continue; + } + + JS::RootedObject v(ctx, obj); + JS::RootedValue ro(ctx, JS::ObjectOrNullValue(v)); + JS_SetElement(ctx, hobj, i, ro); + } + } + + return true; +} + +static bool +nodeList_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + jsid id = hid.get(); + struct view_state *vs; + JS::Value idval; + + 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 = 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, &nodeList_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + if (JSID_IS_INT(id)) { + JS::RootedValue r_idval(ctx, idval); + JS_IdToValue(ctx, id, &r_idval); + int index = r_idval.toInt32(); + return nodeList_item2(ctx, hobj, index, hvp); + } + + return true; +} + +JSObject * +getNodeList(JSContext *ctx, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JSObject *el = JS_NewObject(ctx, &nodeList_class); + + if (!el) { + return NULL; + } + + JS::RootedObject r_el(ctx, el); + + JS_DefineProperties(ctx, r_el, (JSPropertySpec *) nodeList_props); + spidermonkey_DefineFunctions(ctx, el, nodeList_funcs); + + JS_SetPrivate(el, node); + nodeList_set_items(ctx, r_el, node); + + return el; +} + diff --git a/src/ecmascript/spidermonkey/nodelist.h b/src/ecmascript/spidermonkey/nodelist.h new file mode 100644 index 000000000..6612d2984 --- /dev/null +++ b/src/ecmascript/spidermonkey/nodelist.h @@ -0,0 +1,8 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_NODELIST_H +#define EL__ECMASCRIPT_SPIDERMONKEY_NODELIST_H + +#include "ecmascript/spidermonkey/util.h" + +JSObject *getNodeList(JSContext *ctx, void *node); + +#endif