From 5a107a466bb3153d0d6aea01f4574a907a921ed8 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 31 Oct 2015 14:52:37 +0100 Subject: Initial work toward JS event support --- javascript/duktape/dukky.c | 144 +++++++++++++++++++++++++++++++++++++++++++++ javascript/duktape/dukky.h | 3 + javascript/js.h | 20 +++++++ javascript/none/none.c | 8 +++ 4 files changed, 175 insertions(+) (limited to 'javascript') diff --git a/javascript/duktape/dukky.c b/javascript/duktape/dukky.c index a15ca387c..713f3d046 100644 --- a/javascript/duktape/dukky.c +++ b/javascript/duktape/dukky.c @@ -37,6 +37,9 @@ #include +#define EVENT_MAGIC MAGIC(EVENT_MAP) +#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP) + static duk_ret_t dukky_populate_object(duk_context *ctx) { /* ... obj args protoname nargs */ @@ -78,6 +81,10 @@ duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args) /* ... args */ duk_push_object(ctx); /* ... args obj */ + duk_push_object(ctx); + /* ... args obj handlers */ + duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC); + /* ... args obj */ duk_insert(ctx, -(args+1)); /* ... obj args */ duk_push_string(ctx, name); @@ -110,6 +117,10 @@ dukky_push_node_stacked(duk_context *ctx) /* ... nodeptr klass nodes */ duk_push_object(ctx); /* ... nodeptr klass nodes obj */ + duk_push_object(ctx); + /* ... nodeptr klass nodes obj handlers */ + duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC); + /* ... nodeptr klass nodes obj */ duk_dup(ctx, -4); /* ... nodeptr klass nodes obj nodeptr */ duk_dup(ctx, -4); @@ -350,6 +361,10 @@ jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv) duk_put_prop(CTX, -3); duk_put_global_string(CTX, NODE_MAGIC); + /* And now the event mapping table */ + duk_push_object(CTX); + duk_put_global_string(CTX, EVENT_MAGIC); + return (jsobject *)ctx; } @@ -390,3 +405,132 @@ bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, s LOG("Oh dear, an event: %s", type); return true; } + +/*** New style event handling ***/ + +static void dukky_generic_event_handler(dom_event *evt, void *pw) +{ + duk_context *ctx = (duk_context *)pw; + dom_string *name; + dom_exception exc; + /* ... */ + LOG("WOOP WOOP, An event:"); + exc = dom_event_get_type(evt, &name); + if (exc != DOM_NO_ERR) { + LOG("Unable to find the event name"); + return; + } + LOG("Event's name is %*s", + dom_string_length(name), dom_string_data(name)); + dom_string_unref(name); + LOG("TODO: Maybe do something with this?"); +} + +void dukky_register_event_listener_for(duk_context *ctx, + struct dom_element *ele, + dom_string *name) +{ + dom_event_listener *listen = NULL; + dom_exception exc; + + /* ... */ + if (dukky_push_node(ctx, (struct dom_node *)ele) == false) + return; + /* ... node */ + duk_get_prop_string(ctx, -1, HANDLER_LISTENER_MAGIC); + /* ... node handlers */ + duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name)); + /* ... node handlers name */ + if (duk_has_prop(ctx, -2)) { + /* ... node handlers */ + duk_pop_2(ctx); + /* ... */ + return; + } + /* ... node handlers */ + duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name)); + /* ... node handlers name */ + duk_push_boolean(ctx, true); + /* ... node handlers name true */ + duk_put_prop(ctx, -3); + /* ... node handlers */ + duk_pop_2(ctx); + /* ... */ + exc = dom_event_listener_create(dukky_generic_event_handler, ctx, + &listen); + if (exc != DOM_NO_ERR) return; + exc = dom_event_target_add_event_listener( + ele, name, listen, false); + if (exc != DOM_NO_ERR) { + LOG("Unable to register listener for %p.%*s", + ele, dom_string_length(name), dom_string_data(name)); + } + dom_event_listener_unref(listen); +} + + +void js_handle_new_element(jscontext *ctx, struct dom_element *node) +{ + assert(ctx); + assert(node); + dom_namednodemap *map; + dom_exception exc; + dom_ulong idx; + dom_ulong siz; + dom_attr *attr = NULL; + dom_string *key = NULL; + + exc = dom_node_get_attributes(node, &map); + if (exc != DOM_NO_ERR) return; + if (map == NULL) return; + + exc = dom_namednodemap_get_length(map, &siz); + if (exc != DOM_NO_ERR) goto out; + + for (idx = 0; idx < siz; idx++) { + exc = dom_namednodemap_item(map, idx, &attr); + if (exc != DOM_NO_ERR) goto out; + exc = dom_attr_get_name(attr, &key); + if (exc != DOM_NO_ERR) goto out; + if (dom_string_length(key) > 2) { + /* Can be on* */ + const uint8_t *data = (const uint8_t *)dom_string_data(key); + if (data[0] == 'o' && data[1] == 'n') { + dom_string *sub = NULL; + exc = dom_string_substr( + key, 2, dom_string_length(key) - 2, + &sub); + if (exc == DOM_NO_ERR) { + dukky_register_event_listener_for( + CTX, node, sub); + dom_string_unref(sub); + } + } + } + dom_string_unref(key); key = NULL; + dom_node_unref(attr); attr = NULL; + } + +out: + if (key != NULL) + dom_string_unref(key); + + if (attr != NULL) + dom_node_unref(attr); + + dom_namednodemap_unref(map); +} + +void js_event_cleanup(jscontext *ctx, struct dom_event *evt) +{ + assert(ctx); + /* ... */ + duk_get_global_string(CTX, EVENT_MAGIC); + /* ... EVENT_MAP */ + duk_push_pointer(CTX, evt); + /* ... EVENT_MAP eventptr */ + duk_del_prop(CTX, -2); + /* ... EVENT_MAP */ + duk_pop(CTX); + /* ... */ +} diff --git a/javascript/duktape/dukky.h b/javascript/duktape/dukky.h index abe21ba35..4ed462ea5 100644 --- a/javascript/duktape/dukky.h +++ b/javascript/duktape/dukky.h @@ -28,5 +28,8 @@ duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args); duk_bool_t dukky_push_node_stacked(duk_context *ctx); duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node); void dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name); +void dukky_register_event_listener_for(duk_context *ctx, + struct dom_element *ele, + dom_string *name); #endif diff --git a/javascript/js.h b/javascript/js.h index 6f7de920f..2929d0b5e 100644 --- a/javascript/js.h +++ b/javascript/js.h @@ -31,8 +31,10 @@ typedef struct jsobject jsobject; typedef bool(jscallback)(void *ctx); +struct dom_event; struct dom_document; struct dom_node; +struct dom_element; struct dom_string; /** Initialise javascript interpreter */ @@ -78,5 +80,23 @@ js_dom_event_add_listener(jscontext *ctx, struct dom_string *event_type_dom, void *js_funcval); +/*** New Events ***/ + +/** Handle a new element being created. + * + * This is called once an element is inserted into the DOM document handled + * by the context provided. The JS implementation must then scan the element + * for on* attributes and register appropriate listeners for those handlers. + */ +void js_handle_new_element(jscontext *ctx, struct dom_element *node); + +/** Handle an event propagation finished callback. + * + * This is called once an event finishes propagating, no matter how it + * finishes. The intent here is that the JS context can perform any cleanups + * it may need to perform before the DOM finishes and the event may end up + * freed. + */ +void js_event_cleanup(jscontext *ctx, struct dom_event *evt); #endif /* _NETSURF_JAVASCRIPT_JS_H_ */ diff --git a/javascript/none/none.c b/javascript/none/none.c index 3ae1f4f54..9a8b0a49d 100644 --- a/javascript/none/none.c +++ b/javascript/none/none.c @@ -60,3 +60,11 @@ bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, s { return true; } + +void js_handle_new_element(jscontext *ctx, struct dom_element *node) +{ +} + +void js_event_cleanup(jscontext *ctx, struct dom_event *evt) +{ +} -- cgit v1.2.3