/* 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; }