diff --git a/src/ecmascript/mujs/Makefile b/src/ecmascript/mujs/Makefile index ac0f5a26..c86b49a3 100644 --- a/src/ecmascript/mujs/Makefile +++ b/src/ecmascript/mujs/Makefile @@ -3,7 +3,7 @@ include $(top_builddir)/Makefile.config INCLUDES += $(MUJS_CFLAGS) OBJS = attr.obj attributes.obj collection.obj console.obj document.obj element.obj form.obj \ - forms.obj history.obj implementation.obj input.obj location.obj \ + forms.obj history.obj implementation.obj input.obj keyboard.obj location.obj \ localstorage.obj navigator.obj nodelist.obj screen.obj unibar.obj window.obj xhr.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/mujs/element.cpp b/src/ecmascript/mujs/element.cpp index 6dd091df..9a8e286e 100644 --- a/src/ecmascript/mujs/element.cpp +++ b/src/ecmascript/mujs/element.cpp @@ -27,6 +27,7 @@ #include "ecmascript/mujs/collection.h" #include "ecmascript/mujs/document.h" #include "ecmascript/mujs/element.h" +#include "ecmascript/mujs/keyboard.h" #include "ecmascript/mujs/nodelist.h" #include "ecmascript/mujs/window.h" #include "intl/libintl.h" @@ -60,13 +61,38 @@ #include #include +struct listener { + LIST_HEAD(struct listener); + char *typ; + const char *fun; +}; + +struct mjs_element_private { + struct ecmascript_interpreter *interpreter; + const char *thisval; + LIST_OF(struct listener) listeners; + void *node; +}; + +static void * +mjs_getprivate(js_State *J, int idx) +{ + struct mjs_element_private *priv = (struct mjs_element_private *)js_touserdata(J, idx, "element"); + + if (!priv) { + return NULL; + } + + return priv->node; +} + static void mjs_element_get_property_attributes(js_State *J) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -90,7 +116,7 @@ mjs_element_get_property_children(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -138,7 +164,7 @@ mjs_element_get_property_childElementCount(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -156,7 +182,7 @@ mjs_element_get_property_childNodes(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -187,7 +213,7 @@ mjs_element_get_property_className(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -205,7 +231,7 @@ mjs_element_get_property_dir(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -226,7 +252,7 @@ mjs_element_get_property_firstChild(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -249,7 +275,7 @@ mjs_element_get_property_firstElementChild(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -283,7 +309,7 @@ mjs_element_get_property_id(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -299,7 +325,7 @@ mjs_element_get_property_lang(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -315,7 +341,7 @@ mjs_element_get_property_lastChild(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -336,7 +362,7 @@ mjs_element_get_property_lastElementChild(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -369,7 +395,7 @@ mjs_element_get_property_nextElementSibling(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -400,7 +426,7 @@ mjs_element_get_property_nodeName(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Node *node = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Node *node = static_cast(mjs_getprivate(J, 0)); xmlpp::ustring v; @@ -432,7 +458,7 @@ mjs_element_get_property_nodeType(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Node *node = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Node *node = static_cast(mjs_getprivate(J, 0)); if (!node) { js_pushnull(J); @@ -459,7 +485,7 @@ mjs_element_get_property_nodeValue(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Node *node = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Node *node = static_cast(mjs_getprivate(J, 0)); if (!node) { js_pushnull(J); @@ -503,7 +529,7 @@ mjs_element_get_property_nextSibling(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -536,7 +562,7 @@ mjs_element_get_property_parentElement(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -558,7 +584,7 @@ mjs_element_get_property_parentNode(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -579,7 +605,7 @@ mjs_element_get_property_previousElementSibling(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -610,7 +636,7 @@ mjs_element_get_property_previousSibling(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -631,7 +657,7 @@ mjs_element_get_property_tagName(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -648,7 +674,7 @@ mjs_element_get_property_title(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -747,7 +773,7 @@ mjs_element_get_property_innerHtml(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -769,7 +795,7 @@ mjs_element_get_property_outerHtml(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -791,7 +817,7 @@ mjs_element_get_property_textContent(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -816,7 +842,7 @@ mjs_element_set_property_className(js_State *J) const char *val = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); assert(interpreter); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -837,7 +863,7 @@ mjs_element_set_property_dir(js_State *J) const char *val = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); assert(interpreter); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -861,7 +887,7 @@ mjs_element_set_property_id(js_State *J) const char *val = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); assert(interpreter); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -881,7 +907,7 @@ mjs_element_set_property_innerHtml(js_State *J) #endif const char *val = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -923,7 +949,7 @@ mjs_element_set_property_innerText(js_State *J) #endif const char *val = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -950,7 +976,7 @@ mjs_element_set_property_lang(js_State *J) #endif const char *str = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -971,7 +997,7 @@ mjs_element_set_property_title(js_State *J) #endif const char *str = js_tostring(J, 1); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -1018,6 +1044,101 @@ check_contains(xmlpp::Node *node, xmlpp::Node *searched, bool *result_set, bool } } +static void +mjs_element_addEventListener(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct mjs_element_private *el_private = (struct mjs_element_private *)js_touserdata(J, 0, "element"); + + if (!el_private) { + js_pushnull(J); + return; + } + const char *str = js_tostring(J, 1); + + if (!str) { + js_pushnull(J); + return; + } + char *method = stracpy(str); + + if (!method) { + js_pushnull(J); + return; + } + js_copy(J, 2); + const char *fun = js_ref(J); + + struct listener *l; + + foreach(l, el_private->listeners) { + if (strcmp(l->typ, method)) { + continue; + } + if (!strcmp(l->fun, fun)) { + mem_free(method); + js_pushundefined(J); + return; + } + } + struct listener *n = (struct listener *)mem_calloc(1, sizeof(*n)); + + if (n) { + n->typ = method; + n->fun = fun; + add_to_list_end(el_private->listeners, n); + } + js_pushundefined(J); +} + +static void +mjs_element_removeEventListener(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct mjs_element_private *el_private = (struct mjs_element_private *)js_touserdata(J, 0, "element"); + + if (!el_private) { + js_pushnull(J); + return; + } + const char *str = js_tostring(J, 1); + + if (!str) { + js_pushnull(J); + return; + } + char *method = stracpy(str); + + if (!method) { + js_pushnull(J); + return; + } + js_copy(J, 2); + const char *fun = js_ref(J); + struct listener *l; + + foreach(l, el_private->listeners) { + if (strcmp(l->typ, method)) { + continue; + } + if (!strcmp(l->fun, fun)) { + del_from_list(l); + mem_free_set(&l->typ, NULL); + if (l->fun) js_unref(J, l->fun); + mem_free(l); + mem_free(method); + js_pushundefined(J); + return; + } + } + mem_free(method); + js_pushundefined(J); +} + static void mjs_element_appendChild(js_State *J) { @@ -1025,13 +1146,13 @@ mjs_element_appendChild(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); return; } - xmlpp::Node *el2 = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Node *el2 = static_cast(mjs_getprivate(J, 1)); el->import_node(el2); interpreter->changed = true; @@ -1045,7 +1166,7 @@ mjs_element_cloneNode(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -1104,7 +1225,7 @@ mjs_element_closest(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushnull(J); @@ -1149,13 +1270,13 @@ mjs_element_contains(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); return; } - xmlpp::Element *el2 = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Element *el2 = static_cast(mjs_getprivate(J, 1)); if (!el2) { js_pushboolean(J, 0); @@ -1176,7 +1297,7 @@ mjs_element_getAttribute(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1202,7 +1323,7 @@ mjs_element_getAttributeNode(js_State *J) #endif const char *str = js_tostring(J, 1); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -1225,7 +1346,7 @@ mjs_element_hasAttribute(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1244,7 +1365,7 @@ mjs_element_hasAttributes(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1261,7 +1382,7 @@ mjs_element_hasChildNodes(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1279,20 +1400,20 @@ mjs_element_insertBefore(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); return; } - xmlpp::Node *next_sibling = static_cast(js_touserdata(J, 2, "element")); + xmlpp::Node *next_sibling = static_cast(mjs_getprivate(J, 2)); if (!next_sibling) { js_pushnull(J); return; } - xmlpp::Node *child = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Node *child = static_cast(mjs_getprivate(J, 1)); auto node = xmlAddPrevSibling(next_sibling->cobj(), child->cobj()); auto res = el_add_child_element_common(child->cobj(), node); @@ -1307,14 +1428,14 @@ mjs_element_isEqualNode(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); return; } - xmlpp::Element *el2 = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Element *el2 = static_cast(mjs_getprivate(J, 1)); struct string first; struct string second; @@ -1346,13 +1467,13 @@ mjs_element_isSameNode(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); return; } - xmlpp::Element *el2 = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Element *el2 = static_cast(mjs_getprivate(J, 1)); js_pushboolean(J, (el == el2)); } @@ -1363,7 +1484,7 @@ mjs_element_matches(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1397,7 +1518,7 @@ mjs_element_querySelector(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1432,7 +1553,7 @@ mjs_element_querySelectorAll(js_State *J) #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushboolean(J, 0); @@ -1469,7 +1590,7 @@ mjs_element_remove(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -1488,8 +1609,8 @@ mjs_element_removeChild(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); - xmlpp::Element *el2 = static_cast(js_touserdata(J, 1, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); + xmlpp::Element *el2 = static_cast(mjs_getprivate(J, 1)); if (!el || !el2) { js_pushnull(J); @@ -1518,7 +1639,7 @@ mjs_element_setAttribute(js_State *J) fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); - xmlpp::Element *el = static_cast(js_touserdata(J, 0, "element")); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); if (!el) { js_pushundefined(J); @@ -1547,17 +1668,62 @@ mjs_element_toString(js_State *J) static std::map map_elements; static void -mjs_element_finalizer(js_State *J, void *node) +mjs_element_finalizer(js_State *J, void *priv) { - map_elements.erase(node); + struct mjs_element_private *el_private = (struct mjs_element_private *)priv; + + if (el_private) { + if (map_elements.find(el_private) != map_elements.end()) { + map_elements.erase(el_private); + + struct listener *l; + + foreach(l, el_private->listeners) { + mem_free_set(&l->typ, NULL); + if (l->fun) js_unref(J, l->fun); + } + free_list(el_private->listeners); + mem_free(el_private); + } + } } +static std::map map_privates; + void mjs_push_element(js_State *J, void *node) { + struct mjs_element_private *el_private = NULL; + auto node_find = map_privates.find(node); + + if (node_find != map_privates.end()) { + el_private = (struct mjs_element_private *)node_find->second; + if (map_elements.find(el_private) == map_elements.end()) { + el_private = NULL; + } + } + + if (!el_private) { + el_private = (struct mjs_element_private *)mem_calloc(1, sizeof(*el_private)); + + if (!el_private) { + js_pushnull(J); + return; + } + init_list(el_private->listeners); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); + el_private->interpreter = interpreter; + el_private->node = node; + map_privates[node] = el_private; + map_elements[el_private] = node; + } + js_newobject(J); { - js_newuserdata(J, "element", node, mjs_element_finalizer); + js_copy(J, 0); + el_private->thisval = js_ref(J); + js_newuserdata(J, "element", el_private, mjs_element_finalizer); + addmethod(J, "addEventListener", mjs_element_addEventListener, 3); addmethod(J, "appendChild",mjs_element_appendChild, 1); addmethod(J, "cloneNode", mjs_element_cloneNode, 1); addmethod(J, "closest", mjs_element_closest, 1); @@ -1575,6 +1741,7 @@ mjs_push_element(js_State *J, void *node) addmethod(J, "querySelectorAll", mjs_element_querySelectorAll, 1); addmethod(J, "remove", mjs_element_remove, 0); addmethod(J, "removeChild", mjs_element_removeChild, 1); + addmethod(J, "removeEventListener", mjs_element_removeEventListener, 3); addmethod(J, "setAttribute", mjs_element_setAttribute, 2); addmethod(J, "toString", mjs_element_toString, 0); @@ -1617,3 +1784,38 @@ mjs_element_init(js_State *J) return 0; } + +void +check_element_event(void *elem, const char *event_name, struct term_event *ev) +{ + auto el = map_privates.find(elem); + + if (el == map_privates.end()) { + return; + } + struct mjs_element_private *el_private = el->second; + struct ecmascript_interpreter *interpreter = el_private->interpreter; + js_State *J = (js_State *)interpreter->backend_data; + + struct listener *l; + + foreach(l, el_private->listeners) { + if (strcmp(l->typ, event_name)) { + continue; + } + if (ev && ev->ev == EVENT_KBD && (!strcmp(event_name, "keydown") || !strcmp(event_name, "keyup"))) { + js_getregistry(J, l->fun); /* retrieve the js function from the registry */ + js_getregistry(J, el_private->thisval); + mjs_push_keyboardEvent(J, ev); + js_pcall(J, 1); + js_pop(J, 1); + } else { + js_getregistry(J, l->fun); /* retrieve the js function from the registry */ + js_getregistry(J, el_private->thisval); + js_pushundefined(J); + js_pcall(J, 1); + js_pop(J, 1); + } + } + check_for_rerender(interpreter, event_name); +} diff --git a/src/ecmascript/mujs/element.h b/src/ecmascript/mujs/element.h index a1d14ea3..9c9255fa 100644 --- a/src/ecmascript/mujs/element.h +++ b/src/ecmascript/mujs/element.h @@ -3,8 +3,12 @@ #include +struct term_event; + int mjs_element_init(js_State *J); void mjs_push_element(js_State *J, void *node); void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false); +void check_element_event(void *elem, const char *event_name, struct term_event *ev); + #endif diff --git a/src/ecmascript/mujs/keyboard.cpp b/src/ecmascript/mujs/keyboard.cpp new file mode 100644 index 00000000..90a67230 --- /dev/null +++ b/src/ecmascript/mujs/keyboard.cpp @@ -0,0 +1,126 @@ +/* The MuJS KeyboardEvent object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.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/mujs.h" +#include "ecmascript/mujs/keyboard.h" +#include "ecmascript/timer.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "main/timer.h" +#include "network/connection.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/download.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 + + +static void mjs_keyboardEvent_get_property_key(js_State *J); +static void mjs_keyboardEvent_get_property_keyCode(js_State *J); + +static unicode_val_T keyCode; + +struct keyboard { + unicode_val_T keyCode; +}; + +static void +mjs_keyboardEvent_finalizer(js_State *J, void *val) +{ + struct keyboard *keyb = (struct keyboard *)val; + + if (keyb) { + mem_free(keyb); + } +} + +void +mjs_push_keyboardEvent(js_State *J, struct term_event *ev) +{ + struct keyboard *keyb = mem_calloc(1, sizeof(*keyb)); + + if (!keyb) { + js_pushnull(J); + return; + } + keyCode = keyb->keyCode = get_kbd_key(ev); + + js_newobject(J); + { + js_newuserdata(J, "event", keyb, mjs_keyboardEvent_finalizer); + addproperty(J, "key", mjs_keyboardEvent_get_property_key, NULL); + addproperty(J, "keyCode", mjs_keyboardEvent_get_property_keyCode, NULL); + } +} + +static void +mjs_keyboardEvent_get_property_key(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct keyboard *keyb = (struct keyboard *)js_touserdata(J, 0, "event"); + + if (!keyb) { + js_pushnull(J); + return; + } + char text[8] = {0}; + + *text = keyb->keyCode; + js_pushstring(J, text); +} + +static void +mjs_keyboardEvent_get_property_keyCode(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct keyboard *keyb = (struct keyboard *)js_touserdata(J, 0, "event"); + + if (!keyb) { + js_pushnull(J); + return; + } + js_pushnumber(J, keyb->keyCode); +} diff --git a/src/ecmascript/mujs/keyboard.h b/src/ecmascript/mujs/keyboard.h new file mode 100644 index 00000000..fd56b79f --- /dev/null +++ b/src/ecmascript/mujs/keyboard.h @@ -0,0 +1,10 @@ +#ifndef EL__ECMASCRIPT_MUJS_KEYBOARD_H +#define EL__ECMASCRIPT_MUJS_KEYBAORD_H + +#include + +struct term_event; + +void mjs_push_keyboardEvent(js_State *J, struct term_event *ev); + +#endif diff --git a/src/ecmascript/mujs/meson.build b/src/ecmascript/mujs/meson.build index ad70e96f..e8a56bf7 100644 --- a/src/ecmascript/mujs/meson.build +++ b/src/ecmascript/mujs/meson.build @@ -1,2 +1,2 @@ srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'document.cpp', 'element.cpp', 'form.cpp', 'forms.cpp', 'history.cpp', 'implementation.cpp', -'input.cpp', 'localstorage.cpp', 'location.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') +'input.cpp', 'keyboard.cpp', 'localstorage.cpp', 'location.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') diff --git a/src/viewer/text/link.cpp b/src/viewer/text/link.cpp index ab265930..42288ce9 100644 --- a/src/viewer/text/link.cpp +++ b/src/viewer/text/link.cpp @@ -29,6 +29,10 @@ #include "ecmascript/quickjs/element.h" #endif +#ifdef CONFIG_MUJS +#include "ecmascript/mujs/element.h" +#endif + #ifdef CONFIG_ECMASCRIPT #include #include @@ -75,7 +79,7 @@ current_link_evhook(struct document_view *doc_view, enum script_event_hook_type if (!link) return -1; if (!doc_view->vs->ecmascript) return -1; -#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) +#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS) std::map *mapa = (std::map *)doc_view->document->element_map; if (mapa) { diff --git a/src/viewer/text/view.cpp b/src/viewer/text/view.cpp index d0098caf..88c2ccb1 100644 --- a/src/viewer/text/view.cpp +++ b/src/viewer/text/view.cpp @@ -36,6 +36,10 @@ #include "ecmascript/quickjs/element.h" #endif +#ifdef CONFIG_MUJS +#include "ecmascript/mujs/element.h" +#endif + #ifdef CONFIG_ECMASCRIPT #include #include @@ -1298,7 +1302,7 @@ try_form_action(struct session *ses, struct document_view *doc_view, if (!link_is_textinput(link)) return FRAME_EVENT_IGNORED; -#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) +#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS) if (ses->insert_mode == INSERT_MODE_ON) { std::map *mapa = (std::map *)doc_view->document->element_map; diff --git a/test/ecmascript/clickListener2.html b/test/ecmascript/clickListener2.html index 5d55015b..fb1825c5 100644 --- a/test/ecmascript/clickListener2.html +++ b/test/ecmascript/clickListener2.html @@ -8,7 +8,7 @@ function cli() function loader() { - document.getElementById('c').addEventListener('click', function() { window.alert('aaaa'); }); + document.getElementById('c').addEventListener('click', function() { alert('aaaa'); }); document.getElementById('c').addEventListener('click', cli); }