1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-19 01:36:33 -04:00

[spidermonkey] document.getElementsByClassName

Memory leaks will be addressed later.
This commit is contained in:
Witold Filipczyk 2024-06-25 17:38:24 +02:00
parent 63590b0e05
commit 851c9c6f61
5 changed files with 184 additions and 9 deletions

View File

@ -609,3 +609,153 @@ walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int
} while (child != NULL); /* No more children */
}
}
static bool
node_has_classes(struct dom_node *node, void *ctx)
{
LIST_OF(struct class_string) *list = (LIST_OF(struct class_string) *)ctx;
struct class_string *st;
if (list_empty(*list)) {
return false;
}
foreach (st, *list) {
bool ret = false;
dom_exception exc = dom_element_has_class((struct dom_element *)node, st->name, &ret);
if (exc != DOM_NO_ERR || !ret) {
return false;
}
}
return true;
}
static LIST_OF(struct class_string) *
prepare_strings(char *text)
{
if (!text) {
return NULL;
}
LIST_OF(struct class_string) *list = (LIST_OF(struct class_string) *)mem_calloc(1, sizeof(*list));
if (!list) {
return NULL;
}
init_list(*list);
char *pos = text;
while (*pos) {
skip_space(pos);
if (*pos) {
char *begin = pos;
skip_nonspace(pos);
struct class_string *klass = (struct class_string *)mem_calloc(1, sizeof(*klass));
if (!klass) {
continue;
}
lwc_string *ls = NULL;
lwc_error err = lwc_intern_string(begin, pos - begin, &ls);
if (err == lwc_error_ok) {
klass->name = ls;
add_to_list_end(*list, klass);
} else {
mem_free(klass);
}
}
}
return list;
}
typedef bool (*dom_callback_is_in_collection)(struct dom_node *node, void *ctx);
/**
* The html_collection structure
*/
struct el_dom_html_collection {
dom_callback_is_in_collection ic;
/**< The function pointer used to test
* whether some node is an element of
* this collection
*/
void *ctx; /**< Context for the callback */
struct dom_html_document *doc; /**< The document created this
* collection
*/
dom_node *root; /**< The root node of this collection */
uint32_t refcnt; /**< Reference counting */
};
/**
* Intialiase a dom_html_collection
*
* \param doc The document
* \param col The collection object to be initialised
* \param root The root element of the collection
* \param ic The callback function used to determin whether certain node
* beint32_ts to the collection
* \return DOM_NO_ERR on success.
*/
static dom_exception
el_dom_html_collection_initialise(dom_html_document *doc,
struct el_dom_html_collection *col,
dom_node *root,
dom_callback_is_in_collection ic, void *ctx)
{
assert(doc != NULL);
assert(ic != NULL);
assert(root != NULL);
col->doc = doc;
dom_node_ref(doc);
col->root = root;
dom_node_ref(root);
col->ic = ic;
col->ctx = ctx;
col->refcnt = 1;
return DOM_NO_ERR;
}
static dom_exception
el_dom_html_collection_create(dom_html_document *doc,
dom_node *root,
dom_callback_is_in_collection ic,
void *ctx,
el_dom_html_collection **col)
{
*col = (el_dom_html_collection *)malloc(sizeof(struct el_dom_html_collection));
if (*col == NULL) {
return DOM_NO_MEM_ERR;
}
return el_dom_html_collection_initialise(doc, *col, root, ic, ctx);
}
void *
get_elements_by_class_name(dom_html_document *doc, dom_node *node, char *classes)
{
if (!node || !classes) {
return NULL;
}
LIST_OF(struct class_string) *list = prepare_strings(classes);
if (!list) {
return NULL;
}
el_dom_html_collection *col = NULL;
dom_exception exc = el_dom_html_collection_create(doc, node, node_has_classes, list, &col);
if (exc != DOM_NO_ERR || !col) {
return NULL;
}
return col;
}

View File

@ -29,6 +29,12 @@ struct selector_node {
void *node;
};
struct class_string {
LIST_HEAD_EL(struct class_string);
void *name;
};
int ecmascript_get_interpreter_count(void);
void ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter);
void toggle_ecmascript(struct session *ses);
@ -50,6 +56,7 @@ 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, LIST_OF(struct selector_node) *result_list);
void *get_elements_by_class_name(dom_html_document *doc, dom_node *node, char *classes);
extern struct module ecmascript_module;

View File

@ -1243,7 +1243,7 @@ const spidermonkeyFunctionSpec document_funcs[] = {
{ "writeln", document_writeln, 1 },
{ "replace", document_replace, 2 },
{ "getElementById", document_getElementById, 1 },
// { "getElementsByClassName", document_getElementsByClassName, 1 },
{ "getElementsByClassName", document_getElementsByClassName, 1 },
// { "getElementsByName", document_getElementsByName, 1 },
{ "getElementsByTagName", document_getElementsByTagName, 1 },
{ "querySelector", document_querySelector, 1 },
@ -1963,17 +1963,35 @@ document_getElementsByClassName(JSContext *ctx, unsigned int argc, JS::Value *vp
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JS::CallArgs args = CallArgsFromVp(argc, vp);
JS::RootedObject hobj(ctx, &args.thisv().toObject());
if (argc != 1) {
args.rval().setBoolean(false);
if (!JS_InstanceOf(ctx, hobj, &document_class, NULL)) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return false;
}
dom_html_document *doc = JS::GetMaybePtrFromReservedSlot<dom_html_document>(hobj, 0);
if (!doc) {
args.rval().setNull();
return true;
}
JS::Realm *comp = js::GetContextRealm(ctx);
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
if (argc != 1) {
args.rval().setNull();
return true;
}
char *classes = jsval_to_string(ctx, args[0]);
dom_html_collection *col = get_elements_by_class_name(doc, (dom_node *)doc, classes);
mem_free_if(classes);
// TODO
args.rval().setNull();
if (!col) {
args.rval().setNull();
return true;
}
JSObject *obj = getCollection(ctx, col);
args.rval().setObject(*obj);
return true;
}

View File

@ -13,7 +13,7 @@ First Name: <input name="fname" type="text" value="Doug">
<script>
function myFunction() {
var x = document.getElementsByClassName("test");//.item(1).outerHTML;
var x = document.getElementsByClassName("test").item(1).outerHTML;
console.assert(x === '<button onclick="myFunction()" class="test">Try it</button>', x);
}

View File

@ -1,6 +1,5 @@
tofail = [
'console.assert.html',
#'document.getElementsByClassName.html', // not implemented
#'document.getElementsByName.html', // not implemented
'document.head.html',
'element.namedItem.html'
@ -19,6 +18,7 @@ took = [
'document.documentElement.html',
'document.documentURI.html',
'document.domain.html',
'document.getElementsByClassName.html',
'document.getElementsByTagName.html',
'document.images.html',
'document.links.html',