1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

[getElementById] small success. see test/ecmascript/element.html

Now memory leaks, etc. are not taken into account.
For the beginning I will implement read properties.
This commit is contained in:
Witold Filipczyk 2021-05-02 17:27:35 +02:00
parent ff78bd6a86
commit 63d892838c
7 changed files with 265 additions and 3 deletions

View File

@ -211,6 +211,7 @@ struct document {
/** used by setTimeout */
timer_id_T timeout;
int ecmascript_counter;
void *dom;
#endif
#ifdef CONFIG_CSS
/** @todo FIXME: We should externally maybe using cache_entry store the

View File

@ -2,6 +2,6 @@ top_builddir=../../..
include $(top_builddir)/Makefile.config
INCLUDES += $(SPIDERMONKEY_CFLAGS)
OBJS = console.o document.o form.o heartbeat.o location.o localstorage.o localstorage-db.o navigator.o unibar.o window.o
OBJS = console.o document.o element.c form.o heartbeat.o location.o localstorage.o localstorage-db.o navigator.o unibar.o window.o
include $(top_srcdir)/Makefile.lib

View File

@ -27,6 +27,7 @@
#include "ecmascript/spidermonkey/form.h"
#include "ecmascript/spidermonkey/location.h"
#include "ecmascript/spidermonkey/document.h"
#include "ecmascript/spidermonkey/element.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
@ -48,6 +49,10 @@
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
#include <htmlcxx/html/ParserDom.h>
using namespace htmlcxx;
#include <iostream>
static bool document_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp);
@ -678,6 +683,30 @@ document_replace(JSContext *ctx, unsigned int argc, JS::Value *vp)
return(true);
}
static void *
document_parse(struct document *document)
{
struct cache_entry *cached = document->cached;
struct fragment *f = get_cache_fragment(cached);
if (!f || !f->length) {
return NULL;
}
struct string str;
init_string(&str);
add_bytes_to_string(&str, f->data, f->length);
HTML::ParserDom parser;
tree<HTML::Node> *dom = new tree<HTML::Node>;
*dom = parser.parseTree(str.source);
done_string(&str);
return (void *)dom;
}
static bool
document_getElementById(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
@ -687,7 +716,51 @@ document_getElementById(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setBoolean(false);
return true;
}
args.rval().setNull();
JSCompartment *comp = js::GetContextCompartment(ctx);
struct ecmascript_interpreter *interpreter = JS_GetCompartmentPrivate(comp);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!document->dom) {
document->dom = document_parse(document);
}
if (!document->dom) {
args.rval().setNull();
return true;
}
tree<HTML::Node> *dom = document->dom;
tree<HTML::Node>::iterator it = dom->begin();
tree<HTML::Node>::iterator end = dom->end();
struct string idstr;
init_string(&idstr);
jshandle_value_to_char_string(&idstr, ctx, &args[0]);
std::string id = idstr.source;
JSObject *elem = nullptr;
for (; it != end; ++it) {
if (it->isTag()) {
it->parseAttributes();
if (it->attribute("id").first && it->attribute("id").second == id) {
tree<HTML::Node> *node = new tree<HTML::Node>;
*node = *it;
elem = getElement(ctx, node);
break;
}
}
}
done_string(&idstr);
if (elem) {
args.rval().setObject(*elem);
} else {
args.rval().setNull();
}
return true;
}

View File

@ -0,0 +1,159 @@
/* The SpiderMonkey html element objects implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "ecmascript/spidermonkey/util.h"
#include <jsfriendapi.h>
#include <htmlcxx/html/ParserDom.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/spidermonkey/element.h"
#include "ecmascript/spidermonkey/window.h"
#include "intl/gettext/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"
using namespace htmlcxx;
static bool element_get_property_id(JSContext *ctx, unsigned int argc, JS::Value *vp);
static bool element_set_property_id(JSContext *ctx, unsigned int argc, JS::Value *vp);
JSClassOps element_ops = {
JS_PropertyStub, nullptr,
JS_PropertyStub, JS_StrictPropertyStub,
nullptr, nullptr, nullptr, nullptr
};
JSClass element_class = {
"element",
JSCLASS_HAS_PRIVATE,
&element_ops
};
JSPropertySpec element_props[] = {
JS_PSGS("id", element_get_property_id, element_set_property_id, JSPROP_ENUMERATE),
JS_PS_END
};
static bool
element_get_property_id(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;
}
tree<HTML::Node> *el = JS_GetPrivate(hobj);
if (!el) {
args.rval().setNull();
return true;
}
tree<HTML::Node>::iterator it = el->begin();
it->parseAttributes();
std::string v = it->attribute("id").second;
args.rval().setString(JS_NewStringCopyZ(ctx, v.c_str()));
return true;
}
static bool
element_set_property_id(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
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;
struct view_state *vs = interpreter->vs;
if (!vs) {
return true;
}
return true;
}
JSObject *
getElement(JSContext *ctx, void *node)
{
JSObject *el = JS_NewObject(ctx, &element_class);
if (!el) {
return NULL;
}
JS::RootedObject r_el(ctx, el);
JS_DefineProperties(ctx, r_el, (JSPropertySpec *) element_props);
// spidermonkey_DefineFunctions(ctx, el, element_funcs);
JS_SetPrivate(el, node);
return el;
}

View File

@ -0,0 +1,14 @@
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
#define EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
#include "ecmascript/spidermonkey/util.h"
#include <htmlcxx/html/ParserDom.h>
using namespace htmlcxx;
extern JSClass element_class;
extern JSPropertySpec element_props[];
JSObject *getElement(JSContext *ctx, void *node);
#endif

View File

@ -1,3 +1,3 @@
#INCLUDES += $(SPIDERMONKEY_CFLAGS)
srcs += files('console.c', 'document.c', 'form.c', 'heartbeat.c', 'location.c', 'localstorage.c', 'localstorage-db.c', 'navigator.c', 'unibar.c', 'window.c')
srcs += files('console.c', 'document.c', 'element.c', 'form.c', 'heartbeat.c', 'location.c', 'localstorage.c', 'localstorage-db.c', 'navigator.c', 'unibar.c', 'window.c')

View File

@ -0,0 +1,15 @@
<html>
<body>
<a href="/home">BBB</a>
<b id="aaaa">bbb</b>
<a id="blabla" href="/">AAA</a>
<a id="bb" href="/">BB</a>
<script>
function aa()
{
alert(document.getElementById('blabla').id);
}
</script>
<button onclick="return aa()">Click me!</button>
</body>
</html>