From ed449aee6e32602fb34aed92c79cd8c553147267 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sun, 16 May 2021 15:42:01 +0200 Subject: [PATCH] [js] element.previousElementSibling --- src/ecmascript/spidermonkey/element.c | 57 +++++++++++++++++++++ test/ecmascript/previousElementSibling.html | 28 ++++++++++ 2 files changed, 85 insertions(+) create mode 100644 test/ecmascript/previousElementSibling.html diff --git a/src/ecmascript/spidermonkey/element.c b/src/ecmascript/spidermonkey/element.c index ad390d8d..47d39098 100644 --- a/src/ecmascript/spidermonkey/element.c +++ b/src/ecmascript/spidermonkey/element.c @@ -73,6 +73,7 @@ static bool element_get_property_nextElementSibling(JSContext *ctx, unsigned int static bool element_get_property_nextSibling(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_outerHtml(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_set_property_outerHtml(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool element_get_property_previousElementSibling(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_tagName(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_textContent(JSContext *ctx, unsigned int argc, JS::Value *vp); @@ -107,6 +108,7 @@ JSPropertySpec element_props[] = { JS_PSG("nextElementSibling", element_get_property_nextElementSibling, JSPROP_ENUMERATE), JS_PSG("nextSibling", element_get_property_nextSibling, JSPROP_ENUMERATE), JS_PSGS("outerHTML", element_get_property_outerHtml, element_set_property_outerHtml, JSPROP_ENUMERATE), + JS_PSG("previousElementSibling", element_get_property_previousElementSibling, JSPROP_ENUMERATE), JS_PSG("previousSibling", element_get_property_previousSibling, JSPROP_ENUMERATE), JS_PSG("tagName", element_get_property_tagName, JSPROP_ENUMERATE), JS_PSGS("textContent", element_get_property_textContent, element_set_property_textContent, JSPROP_ENUMERATE), @@ -662,6 +664,61 @@ element_get_property_nextSibling(JSContext *ctx, unsigned int argc, JS::Value *v return true; } +static bool +element_get_property_previousElementSibling(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + JSCompartment *comp = js::GetContextCompartment(ctx); + + if (!comp) { + return false; + } + + struct ecmascript_interpreter *interpreter = JS_GetCompartmentPrivate(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, &element_class, NULL)) + return false; + + vs = interpreter->vs; + if (!vs) { + return false; + } + + xmlpp::Element *el = JS_GetPrivate(hobj); + + if (!el) { + args.rval().setNull(); + return true; + } + + xmlpp::Node *node = el; + + while (true) { + node = node->get_previous_sibling(); + + if (!node) { + args.rval().setNull(); + return true; + } + xmlpp::Element *next = dynamic_cast(node); + + if (next) { + JSObject *elem = getElement(ctx, next); + args.rval().setObject(*elem); + return true; + } + } + + args.rval().setNull(); + return true; +} + static bool element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Value *vp) { diff --git a/test/ecmascript/previousElementSibling.html b/test/ecmascript/previousElementSibling.html new file mode 100644 index 00000000..f1460f63 --- /dev/null +++ b/test/ecmascript/previousElementSibling.html @@ -0,0 +1,28 @@ + + + + +

Example list:

+ + + +

Click the button to get the HTML content of the previous sibling of the second list item.

+ + + +

Note: The previousElementSibling property is not supported in IE8 and earlier versions.

+ +

+ + + + +