/* Node binding for browser using duktape and libdom * * Copyright 2015 Vincent Sanders * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * Released under the terms of the MIT License, * http://www.opensource.org/licenses/mit-license */ class Node { private dom_node *node; prologue %{ %}; }; init Node(struct dom_node *node) %{ priv->node = node; dom_node_ref(node); priv->parent.is_node = true; %} fini Node() %{ dom_node_unref(priv->node); %} getter Node::nodeType() %{ dom_exception exc; dom_node_type ntype; exc = dom_node_get_node_type(priv->node, &ntype); if (exc != DOM_NO_ERR) return 0; duk_push_uint(ctx, (duk_uint_t)ntype); return 1; %} getter Node::nodeName() %{ dom_exception exc; dom_string *str = NULL; exc = dom_node_get_node_name(priv->node, &str); if (exc != DOM_NO_ERR) return 0; duk_push_lstring(ctx, dom_string_data(str), dom_string_length(str)); dom_string_unref(str); return 1; %} getter Node::baseURI() %{ dom_exception exc; dom_string *base = NULL; exc = dom_node_get_base(priv->node, &base); if (exc != DOM_NO_ERR) return 0; assert(base != NULL); duk_push_lstring(ctx, dom_string_data(base), dom_string_length(base)); dom_string_unref(base); return 1; %} getter Node::ownerDocument() %{ dom_exception exc; dom_node *doc; exc = dom_node_get_owner_document(priv->node, &doc); if (exc != DOM_NO_ERR) return 0; if (doc == NULL) return 0; dukky_push_node(ctx, doc); dom_node_unref(doc); return 1; %} getter Node::parentNode() %{ dom_exception exc; dom_node *pnode = NULL; exc = dom_node_get_parent_node(priv->node, &pnode); if (exc != DOM_NO_ERR) return 0; dukky_push_node(ctx, pnode); dom_node_unref(pnode); return 1; %} getter Node::parentElement() %{ dom_exception exc; dom_node *pnode = NULL; dom_node_type ntype = DOM_NODE_TYPE_COUNT + 1; exc = dom_node_get_parent_node(priv->node, &pnode); if (exc != DOM_NO_ERR) return 0; if (pnode != NULL) { exc = dom_node_get_node_type(pnode, &ntype); if (exc != DOM_NO_ERR) { dom_node_unref(pnode); return 0; } } dukky_push_node(ctx, (ntype == DOM_ELEMENT_NODE) ? pnode : NULL); dom_node_unref(pnode); return 1; %} method Node::hasChildNodes() %{ dom_exception exc; bool res; exc = dom_node_has_child_nodes(priv->node, &res); if (exc != DOM_NO_ERR) return 0; duk_push_boolean(ctx, res); return 1; %} getter Node::childNodes() %{ dom_exception exc; dom_nodelist *nlist = NULL; duk_set_top(ctx, 0); duk_push_this(ctx); duk_get_prop_string(ctx, 0, MAGIC(childNodes)); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); exc = dom_node_get_child_nodes(priv->node, &nlist); if (exc != DOM_NO_ERR) return 0; dukky_push_generics(ctx, "makeListProxy"); duk_push_pointer(ctx, nlist); if (dukky_create_object(ctx, PROTO_NAME(NODELIST), 1) != DUK_EXEC_SUCCESS) { dom_nodelist_unref(nlist); return 0; } dom_nodelist_unref(nlist); if (dukky_pcall(ctx, 1, false) != 0) { NSLOG(dukky, DEBUG, "Unable to construct nodelist?"); return 0; /* coerced to undefined */ } duk_dup(ctx, -1); duk_put_prop_string(ctx, 0, MAGIC(childNodes)); } return 1; %} getter Node::firstChild() %{ dom_exception exc; dom_node *n; exc = dom_node_get_first_child(priv->node, &n); if (exc != DOM_NO_ERR) return 0; if (dukky_push_node(ctx, n) == false) { dom_node_unref(n); return 0; } dom_node_unref(n); return 1; %} getter Node::lastChild() %{ dom_exception exc; dom_node *n; exc = dom_node_get_last_child(priv->node, &n); if (exc != DOM_NO_ERR) return 0; if (dukky_push_node(ctx, n) == false) { dom_node_unref(n); return 0; } dom_node_unref(n); return 1; %} getter Node::previousSibling() %{ dom_exception exc; dom_node *n; exc = dom_node_get_previous_sibling(priv->node, &n); if (exc != DOM_NO_ERR) return 0; if (dukky_push_node(ctx, n) == false) { dom_node_unref(n); return 0; } dom_node_unref(n); return 1; %} getter Node::nextSibling() %{ dom_exception exc; dom_node *n; exc = dom_node_get_next_sibling(priv->node, &n); if (exc != DOM_NO_ERR) return 0; if (dukky_push_node(ctx, n) == false) { dom_node_unref(n); return 0; } dom_node_unref(n); return 1; %} getter Node::nodeValue() %{ dom_exception exc; dom_string *content; exc = dom_node_get_node_value(priv->node, &content); if (exc != DOM_NO_ERR) { return 0; } if (content != NULL) { duk_push_lstring(ctx, dom_string_data(content), dom_string_length(content)); dom_string_unref(content); return 1; } return 0; %} setter Node::nodeValue() %{ dom_exception exc; dom_string *content; duk_size_t slen; const char *s = duk_safe_to_lstring(ctx, 0, &slen); exc = dom_string_create((const uint8_t *)s, slen, &content); if (exc != DOM_NO_ERR) return 0; exc = dom_node_set_node_value(priv->node, content); dom_string_unref(content); return 0; %} getter Node::textContent() %{ dom_exception exc; dom_string *content; exc = dom_node_get_text_content(priv->node, &content); if (exc != DOM_NO_ERR) { return 0; } if (content != NULL) { duk_push_lstring(ctx, dom_string_data(content), dom_string_length(content)); dom_string_unref(content); return 1; } return 0; %} setter Node::textContent() %{ dom_exception exc; dom_string *content; duk_size_t slen; const char *s = duk_safe_to_lstring(ctx, 0, &slen); exc = dom_string_create((const uint8_t *)s, slen, &content); if (exc != DOM_NO_ERR) return 0; exc = dom_node_set_text_content(priv->node, content); dom_string_unref(content); return 0; %} method Node::normalize() %{ dom_exception exc; exc = dom_node_normalize(priv->node); if (exc != DOM_NO_ERR) return 0; return 0; %} method Node::cloneNode() %{ dom_exception exc; bool deep; dom_node *clone; deep = duk_to_boolean(ctx, 0); exc = dom_node_clone_node(priv->node, deep, &clone); if (exc != DOM_NO_ERR) return 0; duk_set_top(ctx, 0); dukky_push_node(ctx, clone); dom_node_unref(clone); return 1; %} method Node::isEqualNode() %{ dom_exception exc; bool result; if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); exc = dom_node_is_equal(priv->node, other->node, &result); if (exc != DOM_NO_ERR) return 0; duk_push_boolean(ctx, result); return 1; %} method Node::compareDocumentPosition() %{ dom_exception exc; uint16_t ret; if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); exc = dom_node_compare_document_position(priv->node, other->node, &ret); if (exc != DOM_NO_ERR) return 0; duk_push_uint(ctx, ret); return 1; %} method Node::contains() %{ dom_exception exc; uint16_t ret; if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); /* Note that inclusive descendant says *IS* or *CONTAINED_BY* */ if (priv->node == other->node) { duk_push_boolean(ctx, true); return 1; } exc = dom_node_compare_document_position(priv->node, other->node, &ret); if (exc != DOM_NO_ERR) return 0; duk_push_boolean(ctx, ret == DOM_DOCUMENT_POSITION_CONTAINED_BY); return 1; %} method Node::lookupPrefix() %{ dom_exception exc; dom_string *ns, *pfx; duk_size_t size; const char *s = duk_safe_to_lstring(ctx, 0, &size); exc = dom_string_create((const uint8_t *)s, size, &ns); if (exc != DOM_NO_ERR) return 0; exc = dom_node_lookup_prefix(priv->node, ns, &pfx); dom_string_unref(ns); if (exc != DOM_NO_ERR) return 0; if (pfx == NULL) return 0; duk_push_lstring(ctx, dom_string_data(pfx), dom_string_length(pfx)); dom_string_unref(pfx); return 0; %} method Node::lookupNamespaceURI() %{ dom_exception exc; dom_string *ns, *pfx; duk_size_t size; const char *s = duk_safe_to_lstring(ctx, 0, &size); exc = dom_string_create((const uint8_t *)s, size, &pfx); if (exc != DOM_NO_ERR) return 0; exc = dom_node_lookup_namespace(priv->node, pfx, &ns); dom_string_unref(pfx); if (exc != DOM_NO_ERR) return 0; if (ns == NULL) return 0; duk_push_lstring(ctx, dom_string_data(ns), dom_string_length(ns)); dom_string_unref(ns); return 0; %} method Node::isDefaultNamespace() %{ dom_exception exc; dom_string *ns; duk_size_t size; const char *s = duk_safe_to_lstring(ctx, 0, &size); bool ret; exc = dom_string_create((const uint8_t *)s, size, &ns); if (exc != DOM_NO_ERR) return 0; exc = dom_node_is_default_namespace(priv->node, ns, &ret); dom_string_unref(ns); if (exc != DOM_NO_ERR) return 0; duk_push_boolean(ctx, ret); return 1; %} method Node::insertBefore() %{ if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); dom_node *before = NULL; if (duk_get_top(ctx) == 2) { if (!dukky_instanceof(ctx, 1, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 1, PRIVATE_MAGIC); node_private_t *another = duk_get_pointer(ctx, -1); before = another->node; duk_pop(ctx); } dom_exception err; dom_node *spare; err = dom_node_insert_before(priv->node, other->node, before, &spare); if (err != DOM_NO_ERR) return 0; dukky_push_node(ctx, spare); dom_node_unref(spare); return 1; %} method Node::appendChild() %{ if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); dom_exception err; dom_node *spare; NSLOG(dukky, DEEPDEBUG, "About to append %p to %p", other->node, priv->node); err = dom_node_append_child(priv->node, other->node, &spare); if (err != DOM_NO_ERR) return 0; dukky_push_node(ctx, spare); dom_node_unref(spare); return 1; %} method Node::replaceChild() %{ if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); if (!dukky_instanceof(ctx, 1, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 1, PRIVATE_MAGIC); node_private_t *old = duk_get_pointer(ctx, -1); duk_pop(ctx); dom_exception err; dom_node *spare; err = dom_node_replace_child(priv->node, other->node, old->node, &spare); if (err != DOM_NO_ERR) return 0; dukky_push_node(ctx, spare); dom_node_unref(spare); return 1; %} method Node::removeChild() %{ if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0; duk_get_prop_string(ctx, 0, PRIVATE_MAGIC); node_private_t *other = duk_get_pointer(ctx, -1); duk_pop(ctx); dom_exception err; dom_node *spare; err = dom_node_remove_child(priv->node, other->node, &spare); if (err != DOM_NO_ERR) return 0; dukky_push_node(ctx, spare); dom_node_unref(spare); return 1; %}