netsurf: branch master updated. release/3.6-225-gf1c98cc
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/f1c98ccfa404f1890fa62...
...commit http://git.netsurf-browser.org/netsurf.git/commit/f1c98ccfa404f1890fa6299...
...tree http://git.netsurf-browser.org/netsurf.git/tree/f1c98ccfa404f1890fa6299a6...
The branch, master has been updated
via f1c98ccfa404f1890fa6299a69b165a226dc4d35 (commit)
via 57fec3504f29753128204bbf03cc92767f501fd4 (commit)
via 8e9751d3b6cd555119ca195e6751c2675beb3b7d (commit)
via 2858aec1c2bf32d0793cbafff6849cf91625b31b (commit)
from 51062e55b00b8b307d9f45cb150dcefa4d710cfc (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
Docs/UnimplementedJavascript.txt | 3 -
.../handlers/javascript/duktape/EventTarget.bnd | 277 ++++++++++++++++++++
content/handlers/javascript/duktape/Node.bnd | 1 +
content/handlers/javascript/duktape/dukky.c | 184 ++++++++++++-
content/handlers/javascript/duktape/dukky.h | 10 +
content/handlers/javascript/duktape/netsurf.bnd | 1 +
test/js/dom-change-event.html | 17 ++
test/js/index.html | 1 +
8 files changed, 484 insertions(+), 10 deletions(-)
create mode 100644 content/handlers/javascript/duktape/EventTarget.bnd
create mode 100644 test/js/dom-change-event.html
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..92e2ac8
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_ONCE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 66d1b05..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -46,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -809,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -840,6 +843,12 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
return;
}
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -850,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -882,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -890,7 +895,107 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index 1d6baee..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -42,5 +42,15 @@ void dukky_register_event_listener_for(duk_context *ctx,
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
--
NetSurf Browser
5 years, 11 months
netsurf-wiki: branch master updated. a2f6d19e7e68c4c731c20e971bda08e5057e3d40
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-wiki.git/shortlog/a2f6d19e7e68c4c7...
...commit http://git.netsurf-browser.org/netsurf-wiki.git/commit/a2f6d19e7e68c4c731...
...tree http://git.netsurf-browser.org/netsurf-wiki.git/tree/a2f6d19e7e68c4c731c2...
The branch, master has been updated
via a2f6d19e7e68c4c731c20e971bda08e5057e3d40 (commit)
from d2c753abe09c53d441b8ad7298608f24fa906958 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-wiki.git/commit/?id=a2f6d19e7e68c4...
commit a2f6d19e7e68c4c731c20e971bda08e5057e3d40
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Update my progress in developer weekend
diff --git a/developer-weekend/feb-2017.mdwn b/developer-weekend/feb-2017.mdwn
index 8e2f4ba..861acd7 100644
--- a/developer-weekend/feb-2017.mdwn
+++ b/developer-weekend/feb-2017.mdwn
@@ -54,7 +54,10 @@ plot context through everything, for widgetery (or however you spell that)
Actions:
-> **TODO:** Vince to fill out.
+* define plotetr API which passes context to each call (done)
+* update all core uses of API to match changes (in progress)
+* update core plotters (knockout and print) to meet new API
+* update each frontend plotters to provide API
`libnslayout`
-------------
@@ -64,7 +67,9 @@ Actions:
Cookies
-------
-> **TODO**: Vince will fill this out. (RFC6265)
+netsurf cookies currently adheres to RFC2109 (kinda) and we should implement RFC6265
+
+Vince has investigated and this is necessary for using cookies at least partially safely with javascript. without this implementation javascript acess is not secure.
JavaScript and Events
---------------------
@@ -90,3 +95,10 @@ Daniel found and corrected some hiccoughs in the `test/` tree:
**MERGED**
* We were at risk of going over-time on some hash table tests.
**MERGED**
+
+Frontends
+---------
+
+cocoa - to be put on notice. noone is maintaining it. if noone responds on developer or user list then CI will stop building and updating to build will not be required. If the frontend does not build at teh next developer weekend it will be removed from git.
+
+atari - toolchains are badly in need of a refresh. will be removed if noone wants to maintain it.
\ No newline at end of file
-----------------------------------------------------------------------
Summary of changes:
developer-weekend/feb-2017.mdwn | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/developer-weekend/feb-2017.mdwn b/developer-weekend/feb-2017.mdwn
index 8e2f4ba..861acd7 100644
--- a/developer-weekend/feb-2017.mdwn
+++ b/developer-weekend/feb-2017.mdwn
@@ -54,7 +54,10 @@ plot context through everything, for widgetery (or however you spell that)
Actions:
-> **TODO:** Vince to fill out.
+* define plotetr API which passes context to each call (done)
+* update all core uses of API to match changes (in progress)
+* update core plotters (knockout and print) to meet new API
+* update each frontend plotters to provide API
`libnslayout`
-------------
@@ -64,7 +67,9 @@ Actions:
Cookies
-------
-> **TODO**: Vince will fill this out. (RFC6265)
+netsurf cookies currently adheres to RFC2109 (kinda) and we should implement RFC6265
+
+Vince has investigated and this is necessary for using cookies at least partially safely with javascript. without this implementation javascript acess is not secure.
JavaScript and Events
---------------------
@@ -90,3 +95,10 @@ Daniel found and corrected some hiccoughs in the `test/` tree:
**MERGED**
* We were at risk of going over-time on some hash table tests.
**MERGED**
+
+Frontends
+---------
+
+cocoa - to be put on notice. noone is maintaining it. if noone responds on developer or user list then CI will stop building and updating to build will not be required. If the frontend does not build at teh next developer weekend it will be removed from git.
+
+atari - toolchains are badly in need of a refresh. will be removed if noone wants to maintain it.
\ No newline at end of file
--
NetSurf Developer Wiki Backing Store
5 years, 11 months
netsurf: branch dsilvers/eventtarget updated. release/3.6-225-gf1c98cc
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/f1c98ccfa404f1890fa62...
...commit http://git.netsurf-browser.org/netsurf.git/commit/f1c98ccfa404f1890fa6299...
...tree http://git.netsurf-browser.org/netsurf.git/tree/f1c98ccfa404f1890fa6299a6...
The branch, dsilvers/eventtarget has been updated
discards 34d5d69e5db7a9dce3e1f1bcc92a681ae5d48083 (commit)
discards 49b60d247fd060bf621f3518dba60eb7fd9679fc (commit)
discards 5185c5fc974b70e7cafb26a15db63fd57f8bd173 (commit)
via f1c98ccfa404f1890fa6299a69b165a226dc4d35 (commit)
via 57fec3504f29753128204bbf03cc92767f501fd4 (commit)
via 8e9751d3b6cd555119ca195e6751c2675beb3b7d (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (34d5d69e5db7a9dce3e1f1bcc92a681ae5d48083)
\
N -- N -- N (f1c98ccfa404f1890fa6299a69b165a226dc4d35)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=f1c98ccfa404f1890fa...
commit f1c98ccfa404f1890fa6299a69b165a226dc4d35
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Record that we have implemented EventTarget
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=57fec3504f297531282...
commit 57fec3504f29753128204bbf03cc92767f501fd4
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add dom change event test
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=8e9751d3b6cd555119c...
commit 8e9751d3b6cd555119ca195e6751c2675beb3b7d
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add EventTarget binding
This adds the binding for EventTarget along with implementations for
addEventListener() removeEventListener() and dispatchEvent()
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..92e2ac8
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_ONCE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
-----------------------------------------------------------------------
Summary of changes:
content/handlers/javascript/duktape/EventTarget.bnd | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
index 4e168b9..92e2ac8 100644
--- a/content/handlers/javascript/duktape/EventTarget.bnd
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -31,7 +31,7 @@ static event_listener_flags event_listener_pop_options(duk_context *ctx)
duk_pop(ctx);
duk_get_prop_string(ctx, -1, "once");
if (duk_to_boolean(ctx, -1))
- ret |= ELF_CAPTURE;
+ ret |= ELF_ONCE;
duk_pop_2(ctx);
/* ... */
return ret;
--
NetSurf Browser
5 years, 11 months
libcss: branch jmb/mq updated. release/0.6.1-30-gca72aef
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libcss.git/shortlog/ca72aeff08e5d596f2da13...
...commit http://git.netsurf-browser.org/libcss.git/commit/ca72aeff08e5d596f2da13ee...
...tree http://git.netsurf-browser.org/libcss.git/tree/ca72aeff08e5d596f2da13eeab...
The branch, jmb/mq has been updated
via ca72aeff08e5d596f2da13eeab00433f566431ba (commit)
via f83915d4fe8b6cba8b52422dd2a6240cae712c6b (commit)
from 7d759aba6639709b23b92f9fb6cb29099ff612d3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/libcss.git/commit/?id=ca72aeff08e5d596f2da...
commit ca72aeff08e5d596f2da13eeab00433f566431ba
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Media Queries: remainder of parser
diff --git a/src/parse/mq.c b/src/parse/mq.c
index 96f70df..c557996 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -333,6 +333,8 @@ static css_error mq_parse_media_feature(css_language *c,
/* ( already consumed */
+ consumeWhitespace(vector, ctx);
+
name_or_value = parserutils_vector_iterate(vector, ctx);
if (name_or_value == NULL)
return CSS_INVALID;
@@ -423,42 +425,359 @@ static css_error mq_parse_media_feature(css_language *c,
return CSS_OK;
}
-static css_error mq_parse_media_in_parens()
+static css_error mq_parse_general_enclosed(css_language *c,
+ const parserutils_vector *vector, int *ctx)
{
+ /* <general-enclosed> = [ <function-token> <any-value> ) ]
+ * | ( <ident> <any-value> )
+ */
+
+ /* TODO: implement */
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_cond_or_feature **cond_or_feature)
+{
+ const css_token *token;
+ bool match;
+ int old_ctx;
+ cond_or_feature *result = NULL;
+ css_error error = CSS_OK;
+
/* <media-in-parens> = ( <media-condition> ) | <media-feature> | <general-enclosed>
- * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident> <any-value> )
*/
//LPAREN -> condition-or-feature
// "not" or LPAREN -> condition
// IDENT | NUMBER | DIMENSION | RATIO -> feature
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL) {
+ return CSS_INVALID;
+ }
+
+ old_ctx = *ctx;
+
+ if (tokenIsChar(token, '(') || (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match)) {
+ css_mq_cond *cond;
+ error = mq_parse_condition(c, vector, ctx, true, &cond);
+ if (error == CSS_OK) {
+ token = parserutils_vector_iterate(vector, ctx);
+ if (tokenIsChar(token, ')') == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up cond */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_COND;
+ result->data.cond = cond;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ } else if (token->type == CSS_TOKEN_IDENT ||
+ token->type == CSS_TOKEN_NUMBER ||
+ token->type == CSS_TOKEN_DIMENSION) {
+ css_mq_feature *feature;
+ error = mq_parse_media_feature(c, vector, ctx, &feature);
+ if (error == CSS_OK) {
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up feature */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_FEATURE;
+ result->data.feat = feature;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ }
+
+ *ctx = old_ctx;
+ error = mq_parse_general_enclosed(c, vector, ctx);
+
+ return error;
}
-static css_error mq_parse_condition()
+static css_error mq_parse_condition(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ bool permit_or, css_mq_cond **cond)
{
+ const css_token *token;
+ bool match;
+ int op = 0; /* Will be AND | OR once we've had one */
+ css_mq_cond_or_feature *cond_or_feature, **parts;
+ css_mq_cond *result;
+ css_error error;
+
/* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* | <media-or>* ]
* <media-condition-without-or> = <media-not> | <media-in-parens> <media-and>*
* <media-not> = not <media-in-parens>
* <media-and> = and <media-in-parens>
* <media-or> = or <media-in-parens>
*/
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false ||
+ token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) != lwc_error_ok ||
+ match == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->parts = malloc(sizeof(*result->parts));
+ if (result->parts == NULL) {
+ free(result);
+ return CSS_NOMEM;
+ }
+ memset(result->parts, 0, sizeof(*result->parts));
+
+ if (tokenIsChar(token, '(') == false) {
+ /* Must be "not" */
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_media_in_parens(c, vector, ctx, &cond_or_feature);
+ if (error != CSS_OK) {
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->negate = 1;
+ result->parts->nparts = 1;
+ result->parts->parts = malloc(sizeof(*result->parts->parts));
+ if (result->parts->parts == NULL) {
+ /* TODO: clean up cond_or_feature */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ result->parts->parts[0] = cond_or_feature;
+
+ *cond = result;
+
+ return CSS_OK;
+ }
+
+ /* FOLLOW(media-condition) := RPAREN | COMMA | EOF */
+ while (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ error = mq_parse_media_in_parens(c, vector, ctx, &cond_or_feature);
+ if (error != CSS_OK) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parts = realloc(result->parts->parts,
+ (result->parts->nparts+1)*sizeof(*result->parts->parts));
+ if (parts == NULL) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ parts[result->parts->nparts] = cond_or_feature;
+ result->parts->parts = parts;
+ result->parts->nparts++;
+
+ consumeWhitespace(vector, token);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ if (token->type != CSS_TOKEN_IDENT) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) == lwc_error_ok &&
+ match) {
+ if (op != 0 && op != AND) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = AND;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[OR], &match) == lwc_error_ok &&
+ match) {
+ if (permit_or == false || (op != 0 && op != OR)) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = OR;
+ } else {
+ /* Neither AND nor OR */
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+ }
+ }
+
+ if (op == OR) {
+ result->op = 1;
+ }
+
+ *cond = result;
+
+ return CSS_OK;
}
-css_error css__mq_parse_media_list(css_language *c,
+static css_error mq_parse_media_query(css_language *c,
const parserutils_vector *vector, int *ctx,
- css_mq_query **media)
+ css_mq_query **query)
{
- css_mq_query *ret = NULL;
const css_token *token;
+ bool match, is_condition = false;
+ css_mq_query *result;
+ css_error error;
- /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
- * <media-query> = <media-condition>
+ /* <media-query> = <media-condition>
* | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?
* <media-type> = <ident> (except "not", "and", "or", "only")
- *
*/
+ // LPAREN -> media-condition
+ // not LPAREN -> media-condition
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ } else if (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ int old_ctx = *ctx;
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ }
+
+ *ctx = old_ctx;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+
+ if (is_condition) {
+ /* media-condition */
+ error = mq_parse_condition(c, vector, ctx, true, &result->cond);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+
+ *query = result;
+ return CSS_OK;
+ }
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ if (lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ result->negate_type = 1;
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[ONLY], &match) == lwc_error_ok &&
+ match) {
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ }
+
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->type = lwc_string_ref(token->idata);
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token != NULL) {
+ if (token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) != lwc_error_ok ||
+ match == false) {
+ lwc_string_unref(result->type);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_condition(c, vector, ctx, false, &result->cond);
+ if (error != CSS_OK) {
+ lwc_string_unref(result->type);
+ free(result);
+ return error;
+ }
+ }
+
+ *query = result;
+ return CSS_OK;
+}
+
+css_error css__mq_parse_media_list(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_query **media)
+{
+ css_mq_query *result = NULL, *last;
+ const css_token *token;
+ css_error error;
+
+ /* <media-query-list> = <media-query> [ COMMA <media-query> ]* */
+
/* if {[(, push }]) to stack
* if func, push ) to stack
* on error, scan forward until stack is empty (or EOF), popping matching tokens off stack
@@ -466,78 +785,32 @@ css_error css__mq_parse_media_list(css_language *c,
* if comma, consume, and start again from the next input token
*/
- UNUSED(c);
-
- token = parserutils_vector_iterate(vector, ctx);
-
+ token = parserutils_vector_peek(vector, *ctx);
while (token != NULL) {
- if (token->type != CSS_TOKEN_IDENT)
- return CSS_INVALID;
+ css_mq_query *query;
+
+ error = mq_parse_media_query(c, vector, ctx, &query);
+ if (error != CSS_OK) {
+ /* TODO: error recovery (see above) */
+ } else {
+ if (result == NULL) {
+ result = last = query;
+ } else {
+ last->next = query;
+ last = query;
+ }
+ }
-#if 0
- if (lwc_string_caseless_isequal(token->idata, c->strings[AURAL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_AURAL;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[BRAILLE],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_BRAILLE;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[EMBOSSED],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_EMBOSSED;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[HANDHELD],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_HANDHELD;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PRINT],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PRINT;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PROJECTION],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PROJECTION;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SCREEN],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SCREEN;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SPEECH],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SPEECH;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TTY],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TTY;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TV],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TV;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[ALL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_ALL;
- } else
- return CSS_INVALID;
-#endif
consumeWhitespace(vector, ctx);
token = parserutils_vector_iterate(vector, ctx);
- if (token != NULL && tokenIsChar(token, ',') == false)
- return CSS_INVALID;
-
- consumeWhitespace(vector, ctx);
+ if (token != NULL && tokenIsChar(token, ',') == false) {
+ /* Give up */
+ break;
+ }
}
-#if 0
- /* If, after parsing the media list, we still have no media,
- * then it must be ALL. */
- if (ret == 0)
- ret = CSS_MEDIA_ALL;
-#endif
-
- *media = ret;
+ *media = result;
return CSS_OK;
}
diff --git a/src/parse/mq.h b/src/parse/mq.h
index c5268c7..ae0110b 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -73,20 +73,18 @@ struct css_mq_cond_or_feature {
CSS_MQ_COND
} type;
union {
- css_mq_cond cond;
- css_mq_feature feat;
+ css_mq_cond *cond;
+ css_mq_feature *feat;
} data;
};
typedef struct css_mq_query {
struct css_mq_query *next;
- uint32_t negate_type : 1, /* set if "not type" */
- cond_op : 1; /* clear if "and", set if "or" */
+ uint32_t negate_type : 1; /* set if "not type" */
lwc_string *type; /* or NULL */
- uint32_t nconds;
- css_mq_cond **conds;
+ css_mq_cond *cond;
} css_mq_query;
css_error css__mq_parse_media_list(css_language *c,
commitdiff http://git.netsurf-browser.org/libcss.git/commit/?id=f83915d4fe8b6cba8b52...
commit f83915d4fe8b6cba8b52422dd2a6240cae712c6b
Author: John-Mark Bell <jmb(a)netsurf-browser.org>
Commit: John-Mark Bell <jmb(a)netsurf-browser.org>
Propstrings: add AND, ONLY, OR
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index 2c166a0..5a59a7e 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -412,6 +412,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "horizontal-tb", SLEN("horizontal-tb") },
{ "vertical-rl", SLEN("vertical-rl") },
{ "vertical-lr", SLEN("vertical-lr") },
+ { "and", SLEN("and") },
+ { "or", SLEN("or") },
+ { "only", SLEN("only") },
{ "aliceblue", SLEN("aliceblue") },
{ "antiquewhite", SLEN("antiquewhite") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index c686a91..3d4753f 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -98,6 +98,7 @@ enum {
LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL,
FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG, COLUMN,
AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL, VERTICAL_LR,
+ AND, OR, ONLY,
/* Named colours */
FIRST_COLOUR,
-----------------------------------------------------------------------
Summary of changes:
src/parse/mq.c | 421 ++++++++++++++++++++++++++++++++++++++---------
src/parse/mq.h | 10 +-
src/parse/propstrings.c | 3 +
src/parse/propstrings.h | 1 +
4 files changed, 355 insertions(+), 80 deletions(-)
diff --git a/src/parse/mq.c b/src/parse/mq.c
index 96f70df..c557996 100644
--- a/src/parse/mq.c
+++ b/src/parse/mq.c
@@ -333,6 +333,8 @@ static css_error mq_parse_media_feature(css_language *c,
/* ( already consumed */
+ consumeWhitespace(vector, ctx);
+
name_or_value = parserutils_vector_iterate(vector, ctx);
if (name_or_value == NULL)
return CSS_INVALID;
@@ -423,42 +425,359 @@ static css_error mq_parse_media_feature(css_language *c,
return CSS_OK;
}
-static css_error mq_parse_media_in_parens()
+static css_error mq_parse_general_enclosed(css_language *c,
+ const parserutils_vector *vector, int *ctx)
{
+ /* <general-enclosed> = [ <function-token> <any-value> ) ]
+ * | ( <ident> <any-value> )
+ */
+
+ /* TODO: implement */
+
+ return CSS_OK;
+}
+
+static css_error mq_parse_media_in_parens(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_cond_or_feature **cond_or_feature)
+{
+ const css_token *token;
+ bool match;
+ int old_ctx;
+ cond_or_feature *result = NULL;
+ css_error error = CSS_OK;
+
/* <media-in-parens> = ( <media-condition> ) | <media-feature> | <general-enclosed>
- * <general-enclosed> = [ <function-token> <any-value> ) ] | ( <ident> <any-value> )
*/
//LPAREN -> condition-or-feature
// "not" or LPAREN -> condition
// IDENT | NUMBER | DIMENSION | RATIO -> feature
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false) {
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL) {
+ return CSS_INVALID;
+ }
+
+ old_ctx = *ctx;
+
+ if (tokenIsChar(token, '(') || (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match)) {
+ css_mq_cond *cond;
+ error = mq_parse_condition(c, vector, ctx, true, &cond);
+ if (error == CSS_OK) {
+ token = parserutils_vector_iterate(vector, ctx);
+ if (tokenIsChar(token, ')') == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up cond */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_COND;
+ result->data.cond = cond;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ } else if (token->type == CSS_TOKEN_IDENT ||
+ token->type == CSS_TOKEN_NUMBER ||
+ token->type == CSS_TOKEN_DIMENSION) {
+ css_mq_feature *feature;
+ error = mq_parse_media_feature(c, vector, ctx, &feature);
+ if (error == CSS_OK) {
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ /* TODO: clean up feature */
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->type = CSS_MQ_FEATURE;
+ result->data.feat = feature;
+ *cond_or_feature = result;
+ return CSS_OK;
+ }
+ }
+
+ *ctx = old_ctx;
+ error = mq_parse_general_enclosed(c, vector, ctx);
+
+ return error;
}
-static css_error mq_parse_condition()
+static css_error mq_parse_condition(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ bool permit_or, css_mq_cond **cond)
{
+ const css_token *token;
+ bool match;
+ int op = 0; /* Will be AND | OR once we've had one */
+ css_mq_cond_or_feature *cond_or_feature, **parts;
+ css_mq_cond *result;
+ css_error error;
+
/* <media-condition> = <media-not> | <media-in-parens> [ <media-and>* | <media-or>* ]
* <media-condition-without-or> = <media-not> | <media-in-parens> <media-and>*
* <media-not> = not <media-in-parens>
* <media-and> = and <media-in-parens>
* <media-or> = or <media-in-parens>
*/
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token == NULL || tokenIsChar(token, '(') == false ||
+ token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) != lwc_error_ok ||
+ match == false) {
+ return CSS_INVALID;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+ result->parts = malloc(sizeof(*result->parts));
+ if (result->parts == NULL) {
+ free(result);
+ return CSS_NOMEM;
+ }
+ memset(result->parts, 0, sizeof(*result->parts));
+
+ if (tokenIsChar(token, '(') == false) {
+ /* Must be "not" */
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_media_in_parens(c, vector, ctx, &cond_or_feature);
+ if (error != CSS_OK) {
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->negate = 1;
+ result->parts->nparts = 1;
+ result->parts->parts = malloc(sizeof(*result->parts->parts));
+ if (result->parts->parts == NULL) {
+ /* TODO: clean up cond_or_feature */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ result->parts->parts[0] = cond_or_feature;
+
+ *cond = result;
+
+ return CSS_OK;
+ }
+
+ /* FOLLOW(media-condition) := RPAREN | COMMA | EOF */
+ while (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ error = mq_parse_media_in_parens(c, vector, ctx, &cond_or_feature);
+ if (error != CSS_OK) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parts = realloc(result->parts->parts,
+ (result->parts->nparts+1)*sizeof(*result->parts->parts));
+ if (parts == NULL) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_NOMEM;
+ }
+ parts[result->parts->nparts] = cond_or_feature;
+ result->parts->parts = parts;
+ result->parts->nparts++;
+
+ consumeWhitespace(vector, token);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (token != NULL && tokenIsChar(token, ')') == false &&
+ tokenIsChar(token, ',') == false) {
+ if (token->type != CSS_TOKEN_IDENT) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) == lwc_error_ok &&
+ match) {
+ if (op != 0 && op != AND) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = AND;
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[OR], &match) == lwc_error_ok &&
+ match) {
+ if (permit_or == false || (op != 0 && op != OR)) {
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+ op = OR;
+ } else {
+ /* Neither AND nor OR */
+ /* TODO: clean up result->parts->parts */
+ free(result->parts);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+ }
+ }
+
+ if (op == OR) {
+ result->op = 1;
+ }
+
+ *cond = result;
+
+ return CSS_OK;
}
-css_error css__mq_parse_media_list(css_language *c,
+static css_error mq_parse_media_query(css_language *c,
const parserutils_vector *vector, int *ctx,
- css_mq_query **media)
+ css_mq_query **query)
{
- css_mq_query *ret = NULL;
const css_token *token;
+ bool match, is_condition = false;
+ css_mq_query *result;
+ css_error error;
- /* <media-query-list> = <media-query> [ COMMA <media-query> ]*
- * <media-query> = <media-condition>
+ /* <media-query> = <media-condition>
* | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?
* <media-type> = <ident> (except "not", "and", "or", "only")
- *
*/
+ // LPAREN -> media-condition
+ // not LPAREN -> media-condition
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ } else if (token->type == CSS_TOKEN_IDENT &&
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ int old_ctx = *ctx;
+
+ parserutils_vector_iterate(vector, ctx);
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_peek(vector, *ctx);
+ if (tokenIsChar(token, '(')) {
+ is_condition = true;
+ }
+
+ *ctx = old_ctx;
+ }
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) {
+ return CSS_NOMEM;
+ }
+ memset(result, 0, sizeof(*result));
+
+ if (is_condition) {
+ /* media-condition */
+ error = mq_parse_condition(c, vector, ctx, true, &result->cond);
+ if (error != CSS_OK) {
+ free(result);
+ return error;
+ }
+
+ *query = result;
+ return CSS_OK;
+ }
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ if (lwc_string_caseless_isequal(token->idata,
+ c->strings[NOT], &match) == lwc_error_ok &&
+ match) {
+ result->negate_type = 1;
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ } else if (lwc_string_caseless_isequal(token->idata,
+ c->strings[ONLY], &match) == lwc_error_ok &&
+ match) {
+ consumeWhitespace(vector, ctx);
+ token = parserutils_vector_iterate(vector, ctx);
+ }
+
+ if (token == NULL || token->type != CSS_TOKEN_IDENT) {
+ free(result);
+ return CSS_INVALID;
+ }
+
+ result->type = lwc_string_ref(token->idata);
+
+ consumeWhitespace(vector, ctx);
+
+ token = parserutils_vector_iterate(vector, ctx);
+ if (token != NULL) {
+ if (token->type != CSS_TOKEN_IDENT ||
+ lwc_string_caseless_isequal(token->idata,
+ c->strings[AND], &match) != lwc_error_ok ||
+ match == false) {
+ lwc_string_unref(result->type);
+ free(result);
+ return CSS_INVALID;
+ }
+
+ consumeWhitespace(vector, ctx);
+
+ error = mq_parse_condition(c, vector, ctx, false, &result->cond);
+ if (error != CSS_OK) {
+ lwc_string_unref(result->type);
+ free(result);
+ return error;
+ }
+ }
+
+ *query = result;
+ return CSS_OK;
+}
+
+css_error css__mq_parse_media_list(css_language *c,
+ const parserutils_vector *vector, int *ctx,
+ css_mq_query **media)
+{
+ css_mq_query *result = NULL, *last;
+ const css_token *token;
+ css_error error;
+
+ /* <media-query-list> = <media-query> [ COMMA <media-query> ]* */
+
/* if {[(, push }]) to stack
* if func, push ) to stack
* on error, scan forward until stack is empty (or EOF), popping matching tokens off stack
@@ -466,78 +785,32 @@ css_error css__mq_parse_media_list(css_language *c,
* if comma, consume, and start again from the next input token
*/
- UNUSED(c);
-
- token = parserutils_vector_iterate(vector, ctx);
-
+ token = parserutils_vector_peek(vector, *ctx);
while (token != NULL) {
- if (token->type != CSS_TOKEN_IDENT)
- return CSS_INVALID;
+ css_mq_query *query;
+
+ error = mq_parse_media_query(c, vector, ctx, &query);
+ if (error != CSS_OK) {
+ /* TODO: error recovery (see above) */
+ } else {
+ if (result == NULL) {
+ result = last = query;
+ } else {
+ last->next = query;
+ last = query;
+ }
+ }
-#if 0
- if (lwc_string_caseless_isequal(token->idata, c->strings[AURAL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_AURAL;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[BRAILLE],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_BRAILLE;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[EMBOSSED],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_EMBOSSED;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[HANDHELD],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_HANDHELD;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PRINT],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PRINT;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[PROJECTION],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_PROJECTION;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SCREEN],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SCREEN;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[SPEECH],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_SPEECH;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TTY],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TTY;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[TV],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_TV;
- } else if (lwc_string_caseless_isequal(
- token->idata, c->strings[ALL],
- &match) == lwc_error_ok && match) {
- ret |= CSS_MEDIA_ALL;
- } else
- return CSS_INVALID;
-#endif
consumeWhitespace(vector, ctx);
token = parserutils_vector_iterate(vector, ctx);
- if (token != NULL && tokenIsChar(token, ',') == false)
- return CSS_INVALID;
-
- consumeWhitespace(vector, ctx);
+ if (token != NULL && tokenIsChar(token, ',') == false) {
+ /* Give up */
+ break;
+ }
}
-#if 0
- /* If, after parsing the media list, we still have no media,
- * then it must be ALL. */
- if (ret == 0)
- ret = CSS_MEDIA_ALL;
-#endif
-
- *media = ret;
+ *media = result;
return CSS_OK;
}
diff --git a/src/parse/mq.h b/src/parse/mq.h
index c5268c7..ae0110b 100644
--- a/src/parse/mq.h
+++ b/src/parse/mq.h
@@ -73,20 +73,18 @@ struct css_mq_cond_or_feature {
CSS_MQ_COND
} type;
union {
- css_mq_cond cond;
- css_mq_feature feat;
+ css_mq_cond *cond;
+ css_mq_feature *feat;
} data;
};
typedef struct css_mq_query {
struct css_mq_query *next;
- uint32_t negate_type : 1, /* set if "not type" */
- cond_op : 1; /* clear if "and", set if "or" */
+ uint32_t negate_type : 1; /* set if "not type" */
lwc_string *type; /* or NULL */
- uint32_t nconds;
- css_mq_cond **conds;
+ css_mq_cond *cond;
} css_mq_query;
css_error css__mq_parse_media_list(css_language *c,
diff --git a/src/parse/propstrings.c b/src/parse/propstrings.c
index 2c166a0..5a59a7e 100644
--- a/src/parse/propstrings.c
+++ b/src/parse/propstrings.c
@@ -412,6 +412,9 @@ const stringmap_entry stringmap[LAST_KNOWN] = {
{ "horizontal-tb", SLEN("horizontal-tb") },
{ "vertical-rl", SLEN("vertical-rl") },
{ "vertical-lr", SLEN("vertical-lr") },
+ { "and", SLEN("and") },
+ { "or", SLEN("or") },
+ { "only", SLEN("only") },
{ "aliceblue", SLEN("aliceblue") },
{ "antiquewhite", SLEN("antiquewhite") },
diff --git a/src/parse/propstrings.h b/src/parse/propstrings.h
index c686a91..3d4753f 100644
--- a/src/parse/propstrings.h
+++ b/src/parse/propstrings.h
@@ -98,6 +98,7 @@ enum {
LIBCSS_RIGHT, CURRENTCOLOR, ODD, EVEN, SRC, LOCAL, INITIAL,
FORMAT, WOFF, TRUETYPE, OPENTYPE, EMBEDDED_OPENTYPE, SVG, COLUMN,
AVOID_PAGE, AVOID_COLUMN, BALANCE, HORIZONTAL_TB, VERTICAL_RL, VERTICAL_LR,
+ AND, OR, ONLY,
/* Named colours */
FIRST_COLOUR,
--
Cascading Style Sheets library
5 years, 11 months
netsurf: branch dsilvers/eventtarget updated. release/3.6-225-g34d5d69
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/34d5d69e5db7a9dce3e1f...
...commit http://git.netsurf-browser.org/netsurf.git/commit/34d5d69e5db7a9dce3e1f1b...
...tree http://git.netsurf-browser.org/netsurf.git/tree/34d5d69e5db7a9dce3e1f1bcc...
The branch, dsilvers/eventtarget has been updated
discards c98b7d3ad46eb3b7c4f3691391668e89c222a0a0 (commit)
discards c14b5a3c9227e588e48da38d3862a7d6d40f5a35 (commit)
discards e4a339f82a72b055c027f42a9f8e5e0a5e47ec71 (commit)
discards ed3bef9ac2ade3adb3d281a245f9591e74a3c082 (commit)
via 34d5d69e5db7a9dce3e1f1bcc92a681ae5d48083 (commit)
via 49b60d247fd060bf621f3518dba60eb7fd9679fc (commit)
via 5185c5fc974b70e7cafb26a15db63fd57f8bd173 (commit)
via 2858aec1c2bf32d0793cbafff6849cf91625b31b (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (c98b7d3ad46eb3b7c4f3691391668e89c222a0a0)
\
N -- N -- N (34d5d69e5db7a9dce3e1f1bcc92a681ae5d48083)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=34d5d69e5db7a9dce3e...
commit 34d5d69e5db7a9dce3e1f1bcc92a681ae5d48083
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Record that we have implemented EventTarget
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=49b60d247fd060bf621...
commit 49b60d247fd060bf621f3518dba60eb7fd9679fc
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add dom change event test
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=5185c5fc974b70e7caf...
commit 5185c5fc974b70e7cafb26a15db63fd57f8bd173
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add EventTarget binding
This adds the binding for EventTarget along with implementations for
addEventListener() removeEventListener() and dispatchEvent()
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..4e168b9
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=2858aec1c2bf32d0793...
commit 2858aec1c2bf32d0793cbafff6849cf91625b31b
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add EventListener support to duktape binding.
This paves the way for EventTarget and its associated event listener support.
In particular it ensures the generic event handling we do supports the
semantics of the addEventListener() and removeEventListener() managed lists of
callbacks.
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 66d1b05..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -46,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -809,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -840,6 +843,12 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
return;
}
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -850,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -882,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -890,7 +895,107 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index 1d6baee..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -42,5 +42,15 @@ void dukky_register_event_listener_for(duk_context *ctx,
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
-----------------------------------------------------------------------
Summary of changes:
--
NetSurf Browser
5 years, 11 months
netsurf-wiki: branch master updated. d2c753abe09c53d441b8ad7298608f24fa906958
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-wiki.git/shortlog/d2c753abe09c53d4...
...commit http://git.netsurf-browser.org/netsurf-wiki.git/commit/d2c753abe09c53d441...
...tree http://git.netsurf-browser.org/netsurf-wiki.git/tree/d2c753abe09c53d441b8...
The branch, master has been updated
via d2c753abe09c53d441b8ad7298608f24fa906958 (commit)
from d81cbe93cb7c348bcf0c7093c8df389698c4eb0c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-wiki.git/commit/?id=d2c753abe09c53...
commit d2c753abe09c53d441b8ad7298608f24fa906958
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Update notes for dev weekend
diff --git a/developer-weekend/feb-2017.mdwn b/developer-weekend/feb-2017.mdwn
index c3a0412..8e2f4ba 100644
--- a/developer-weekend/feb-2017.mdwn
+++ b/developer-weekend/feb-2017.mdwn
@@ -42,11 +42,19 @@ CSS Media Queries
John-Mark is getting on with these
+Actions:
+
+> **TODO** jmb to fill out
+
Plotter API work
----------------
-After discussion, Vince is working on updating the plotter API to
-thread the plot context through everything, for widgetery (or however you spell that)
+After discussion, Vince is working on updating the plotter API to thread the
+plot context through everything, for widgetery (or however you spell that)
+
+Actions:
+
+> **TODO:** Vince to fill out.
`libnslayout`
-------------
@@ -63,3 +71,22 @@ JavaScript and Events
Daniel continues his epic horror-party into `addEventListener()` and friends.
+Activity:
+
+* Fixed bug in nsgenbind which meant generic onFOO handlers were always being
+ registered for 'click'. **MERGED**
+* Added support for event listeners to duktape binding
+* Added `EventTarget` IDL implementation to duktape binding
+* Added test case for `DOMNodeInserted` which sadly doesn't work on modern
+ browsers due to them switching to mutation observers.
+* Updated `Docs/UnimplementedJavascript.txt` for `EventTarget`
+
+Tests
+-----
+
+Daniel found and corrected some hiccoughs in the `test/` tree:
+
+* We were linking the system libidn rather than using `utils/punycode.c`
+ **MERGED**
+* We were at risk of going over-time on some hash table tests.
+ **MERGED**
-----------------------------------------------------------------------
Summary of changes:
developer-weekend/feb-2017.mdwn | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/developer-weekend/feb-2017.mdwn b/developer-weekend/feb-2017.mdwn
index c3a0412..8e2f4ba 100644
--- a/developer-weekend/feb-2017.mdwn
+++ b/developer-weekend/feb-2017.mdwn
@@ -42,11 +42,19 @@ CSS Media Queries
John-Mark is getting on with these
+Actions:
+
+> **TODO** jmb to fill out
+
Plotter API work
----------------
-After discussion, Vince is working on updating the plotter API to
-thread the plot context through everything, for widgetery (or however you spell that)
+After discussion, Vince is working on updating the plotter API to thread the
+plot context through everything, for widgetery (or however you spell that)
+
+Actions:
+
+> **TODO:** Vince to fill out.
`libnslayout`
-------------
@@ -63,3 +71,22 @@ JavaScript and Events
Daniel continues his epic horror-party into `addEventListener()` and friends.
+Activity:
+
+* Fixed bug in nsgenbind which meant generic onFOO handlers were always being
+ registered for 'click'. **MERGED**
+* Added support for event listeners to duktape binding
+* Added `EventTarget` IDL implementation to duktape binding
+* Added test case for `DOMNodeInserted` which sadly doesn't work on modern
+ browsers due to them switching to mutation observers.
+* Updated `Docs/UnimplementedJavascript.txt` for `EventTarget`
+
+Tests
+-----
+
+Daniel found and corrected some hiccoughs in the `test/` tree:
+
+* We were linking the system libidn rather than using `utils/punycode.c`
+ **MERGED**
+* We were at risk of going over-time on some hash table tests.
+ **MERGED**
--
NetSurf Developer Wiki Backing Store
5 years, 11 months
netsurf: branch dsilvers/eventtarget updated. release/3.6-225-gc98b7d3
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/c98b7d3ad46eb3b7c4f36...
...commit http://git.netsurf-browser.org/netsurf.git/commit/c98b7d3ad46eb3b7c4f3691...
...tree http://git.netsurf-browser.org/netsurf.git/tree/c98b7d3ad46eb3b7c4f369139...
The branch, dsilvers/eventtarget has been updated
discards 0a71be2d486f4911cd5f84f59b0134b39c945925 (commit)
discards e92298ab273128516d52def52adbe6f7a5da2063 (commit)
discards 3691a643bf9e964a7f4d621a4a26a06dcd08a482 (commit)
discards 512b568c24f3fdadd38e9a7874489729acde9055 (commit)
via c98b7d3ad46eb3b7c4f3691391668e89c222a0a0 (commit)
via c14b5a3c9227e588e48da38d3862a7d6d40f5a35 (commit)
via e4a339f82a72b055c027f42a9f8e5e0a5e47ec71 (commit)
via ed3bef9ac2ade3adb3d281a245f9591e74a3c082 (commit)
via 51062e55b00b8b307d9f45cb150dcefa4d710cfc (commit)
via 4b3f2bb946ad201f99a20ddaff980ecea05e5ebc (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (0a71be2d486f4911cd5f84f59b0134b39c945925)
\
N -- N -- N (c98b7d3ad46eb3b7c4f3691391668e89c222a0a0)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=c98b7d3ad46eb3b7c4f...
commit c98b7d3ad46eb3b7c4f3691391668e89c222a0a0
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Record that we have implemented EventTarget
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=c14b5a3c9227e588e48...
commit c14b5a3c9227e588e48da38d3862a7d6d40f5a35
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add dom change event test
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=e4a339f82a72b055c02...
commit e4a339f82a72b055c027f42a9f8e5e0a5e47ec71
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
rework: Add EventTarget binding
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..4e168b9
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=ed3bef9ac2ade3adb3d...
commit ed3bef9ac2ade3adb3d281a245f9591e74a3c082
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
rework: Add the support for event target handlers to dukky
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 66d1b05..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -46,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -809,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -840,6 +843,12 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
return;
}
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -850,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -882,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -890,7 +895,107 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index 1d6baee..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -42,5 +42,15 @@ void dukky_register_event_listener_for(duk_context *ctx,
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
-----------------------------------------------------------------------
Summary of changes:
test/Makefile | 10 +++++-----
test/hashtable.c | 7 +++++++
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/test/Makefile b/test/Makefile
index fd54fb9..d5e9d00 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -13,13 +13,13 @@ TESTS := \
time #llcache
# nsurl sources
-nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
+nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/nsurl.c
# url database test sources
urldbtest_SRCS := content/urldb.c \
utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
- utils/corestrings.c \
+ utils/corestrings.c utils/punycode.c \
utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
test/log.c test/urldbtest.c
@@ -51,7 +51,7 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/nsurl.c utils/idna.c \
+ utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/utils.c
# time test sources
@@ -113,11 +113,11 @@ TESTCFLAGS := -std=c99 -g \
-D_XOPEN_SOURCE=600 \
-Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
-Dnsgtk \
- $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) \
+ $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
$(LIB_CFLAGS) \
$(COV_CFLAGS)
-TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) -lz \
+TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) -lz \
$(LIB_LDFLAGS)\
$(COV_LDFLAGS)
diff --git a/test/hashtable.c b/test/hashtable.c
index 9f46e4c..11c58c6 100644
--- a/test/hashtable.c
+++ b/test/hashtable.c
@@ -32,6 +32,9 @@
#include "utils/hashtable.h"
+/* Limit for hash table tests which use /usr/share/dict/words */
+#define DICT_TEST_WORD_COUNT 100000
+
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
struct test_pairs {
@@ -91,6 +94,7 @@ static void dict_hashtable_create(int dict_hash_size)
{
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -102,6 +106,7 @@ static void dict_hashtable_create(int dict_hash_size)
fscanf(dictf, "%s", keybuf);
fscanf(dictf, "%s", valbuf);
hash_add(dict_hash, keybuf, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
@@ -227,6 +232,7 @@ START_TEST(hashtable_dict_test)
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
const char *res;
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -238,6 +244,7 @@ START_TEST(hashtable_dict_test)
res = hash_get(dict_hash, keybuf);
ck_assert(res != NULL);
ck_assert_str_eq(res, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
--
NetSurf Browser
5 years, 11 months
netsurf: branch master updated. release/3.6-221-g51062e5
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/51062e55b00b8b307d9f4...
...commit http://git.netsurf-browser.org/netsurf.git/commit/51062e55b00b8b307d9f45c...
...tree http://git.netsurf-browser.org/netsurf.git/tree/51062e55b00b8b307d9f45cb1...
The branch, master has been updated
via 51062e55b00b8b307d9f45cb150dcefa4d710cfc (commit)
via 4b3f2bb946ad201f99a20ddaff980ecea05e5ebc (commit)
from 108cc0cebdca9a3300c9b524d3409eb10fa09b05 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=51062e55b00b8b307d9...
commit 51062e55b00b8b307d9f45cb150dcefa4d710cfc
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Ensure hash table test doesn't go over-time
diff --git a/test/hashtable.c b/test/hashtable.c
index 9f46e4c..11c58c6 100644
--- a/test/hashtable.c
+++ b/test/hashtable.c
@@ -32,6 +32,9 @@
#include "utils/hashtable.h"
+/* Limit for hash table tests which use /usr/share/dict/words */
+#define DICT_TEST_WORD_COUNT 100000
+
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
struct test_pairs {
@@ -91,6 +94,7 @@ static void dict_hashtable_create(int dict_hash_size)
{
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -102,6 +106,7 @@ static void dict_hashtable_create(int dict_hash_size)
fscanf(dictf, "%s", keybuf);
fscanf(dictf, "%s", valbuf);
hash_add(dict_hash, keybuf, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
@@ -227,6 +232,7 @@ START_TEST(hashtable_dict_test)
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
const char *res;
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -238,6 +244,7 @@ START_TEST(hashtable_dict_test)
res = hash_get(dict_hash, keybuf);
ck_assert(res != NULL);
ck_assert_str_eq(res, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=4b3f2bb946ad201f99a...
commit 4b3f2bb946ad201f99a20ddaff980ecea05e5ebc
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Fix up tests to not use system libidn
diff --git a/test/Makefile b/test/Makefile
index fd54fb9..d5e9d00 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -13,13 +13,13 @@ TESTS := \
time #llcache
# nsurl sources
-nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
+nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/nsurl.c
# url database test sources
urldbtest_SRCS := content/urldb.c \
utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
- utils/corestrings.c \
+ utils/corestrings.c utils/punycode.c \
utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
test/log.c test/urldbtest.c
@@ -51,7 +51,7 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/nsurl.c utils/idna.c \
+ utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/utils.c
# time test sources
@@ -113,11 +113,11 @@ TESTCFLAGS := -std=c99 -g \
-D_XOPEN_SOURCE=600 \
-Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
-Dnsgtk \
- $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) \
+ $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
$(LIB_CFLAGS) \
$(COV_CFLAGS)
-TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) -lz \
+TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) -lz \
$(LIB_LDFLAGS)\
$(COV_LDFLAGS)
-----------------------------------------------------------------------
Summary of changes:
test/Makefile | 10 +++++-----
test/hashtable.c | 7 +++++++
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/test/Makefile b/test/Makefile
index fd54fb9..d5e9d00 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -13,13 +13,13 @@ TESTS := \
time #llcache
# nsurl sources
-nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
+nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/nsurl.c
# url database test sources
urldbtest_SRCS := content/urldb.c \
utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
- utils/corestrings.c \
+ utils/corestrings.c utils/punycode.c \
utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
test/log.c test/urldbtest.c
@@ -51,7 +51,7 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/nsurl.c utils/idna.c \
+ utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
test/log.c test/utils.c
# time test sources
@@ -113,11 +113,11 @@ TESTCFLAGS := -std=c99 -g \
-D_XOPEN_SOURCE=600 \
-Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
-Dnsgtk \
- $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) \
+ $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
$(LIB_CFLAGS) \
$(COV_CFLAGS)
-TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc libidn) -lz \
+TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) -lz \
$(LIB_LDFLAGS)\
$(COV_LDFLAGS)
diff --git a/test/hashtable.c b/test/hashtable.c
index 9f46e4c..11c58c6 100644
--- a/test/hashtable.c
+++ b/test/hashtable.c
@@ -32,6 +32,9 @@
#include "utils/hashtable.h"
+/* Limit for hash table tests which use /usr/share/dict/words */
+#define DICT_TEST_WORD_COUNT 100000
+
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
struct test_pairs {
@@ -91,6 +94,7 @@ static void dict_hashtable_create(int dict_hash_size)
{
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -102,6 +106,7 @@ static void dict_hashtable_create(int dict_hash_size)
fscanf(dictf, "%s", keybuf);
fscanf(dictf, "%s", valbuf);
hash_add(dict_hash, keybuf, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
@@ -227,6 +232,7 @@ START_TEST(hashtable_dict_test)
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
const char *res;
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -238,6 +244,7 @@ START_TEST(hashtable_dict_test)
res = hash_get(dict_hash, keybuf);
ck_assert(res != NULL);
ck_assert_str_eq(res, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
--
NetSurf Browser
5 years, 11 months
netsurf: branch dsilvers/eventtarget updated. release/3.6-223-g0a71be2
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/0a71be2d486f4911cd5f8...
...commit http://git.netsurf-browser.org/netsurf.git/commit/0a71be2d486f4911cd5f84f...
...tree http://git.netsurf-browser.org/netsurf.git/tree/0a71be2d486f4911cd5f84f59...
The branch, dsilvers/eventtarget has been updated
discards fb662eb2657cf01f61937f564e36cf876a1aa197 (commit)
via 0a71be2d486f4911cd5f84f59b0134b39c945925 (commit)
via e92298ab273128516d52def52adbe6f7a5da2063 (commit)
via 3691a643bf9e964a7f4d621a4a26a06dcd08a482 (commit)
via 512b568c24f3fdadd38e9a7874489729acde9055 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (fb662eb2657cf01f61937f564e36cf876a1aa197)
\
N -- N -- N (0a71be2d486f4911cd5f84f59b0134b39c945925)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=0a71be2d486f4911cd5...
commit 0a71be2d486f4911cd5f84f59b0134b39c945925
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Record that we have implemented EventTarget
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=e92298ab273128516d5...
commit e92298ab273128516d52def52adbe6f7a5da2063
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Add dom change event test
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=3691a643bf9e964a7f4...
commit 3691a643bf9e964a7f4d621a4a26a06dcd08a482
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
rework: Add EventTarget binding
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..4e168b9
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=512b568c24f3fdadd38...
commit 512b568c24f3fdadd38e9a7874489729acde9055
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
rework: Add the support for event target handlers to dukky
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 66d1b05..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -46,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -809,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -840,6 +843,12 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
return;
}
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -850,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -882,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -890,7 +895,107 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index 1d6baee..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -42,5 +42,15 @@ void dukky_register_event_listener_for(duk_context *ctx,
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
-----------------------------------------------------------------------
Summary of changes:
content/handlers/javascript/duktape/EventTarget.bnd | 3 +--
content/handlers/javascript/duktape/dukky.c | 8 ++++----
test/js/dom-change-event.html | 2 +-
test/js/index.html | 1 +
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
index fe78194..4e168b9 100644
--- a/content/handlers/javascript/duktape/EventTarget.bnd
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -16,7 +16,7 @@ class EventTarget {
prologue EventTarget()
%{
-
+
static event_listener_flags event_listener_pop_options(duk_context *ctx)
{
event_listener_flags ret = ELF_NONE;
@@ -136,7 +136,6 @@ init EventTarget()
priv->is_node = false;
priv->capture_registered = false;
priv->bubbling_registered = false;
-
%}
method EventTarget::addEventListener()
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 46ff584..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -842,13 +842,13 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
LOG("Unable to find the event target");
return;
}
-
+
/* If we're capturing right now, we skip the 'event handler'
* and go straight to the extras
*/
if (phase == DOM_CAPTURING_PHASE)
goto handle_extras;
-
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -978,7 +978,7 @@ handle_extras:
LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
duk_safe_to_string(ctx, -2));
LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
-
+
duk_pop_n(ctx, 7);
/* ... copy */
continue;
@@ -1046,7 +1046,7 @@ void dukky_register_event_listener_for(duk_context *ctx,
/* The sub-listeners are a list of {callback,flags} tuples */
/* We return true if we created a new sublistener table */
-/* If we're told to not create, but we want to, we still return true */
+/* If we're told to not create, but we want to, we still return true */
bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
{
bool ret = false;
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
index 6c6fbfb..a6d77b8 100644
--- a/test/js/dom-change-event.html
+++ b/test/js/dom-change-event.html
@@ -14,4 +14,4 @@
<body>
<div>I got inserted</div>
</body>
-</html>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a href="event-onloadfrombody.html">body.onload</a></li>
<li><a href="event-onclick.html">button.onclick</a></li>
+<li><a href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
--
NetSurf Browser
5 years, 11 months
netsurf: branch dsilvers/eventtarget updated. release/3.6-220-gfb662eb
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/fb662eb2657cf01f61937...
...commit http://git.netsurf-browser.org/netsurf.git/commit/fb662eb2657cf01f61937f5...
...tree http://git.netsurf-browser.org/netsurf.git/tree/fb662eb2657cf01f61937f564...
The branch, dsilvers/eventtarget has been updated
discards 9b640a0e989b92fce97aa2342858a1acb104f1f2 (commit)
via fb662eb2657cf01f61937f564e36cf876a1aa197 (commit)
via 108cc0cebdca9a3300c9b524d3409eb10fa09b05 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (9b640a0e989b92fce97aa2342858a1acb104f1f2)
\
N -- N -- N (fb662eb2657cf01f61937f564e36cf876a1aa197)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=fb662eb2657cf01f619...
commit fb662eb2657cf01f61937f564e36cf876a1aa197
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
rework: everything else
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..fe78194
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,278 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * 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 EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ * https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c
index 66d1b05..46ff584 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -46,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -809,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -839,7 +842,13 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
LOG("Unable to find the event target");
return;
}
-
+
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -850,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -882,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -890,7 +895,107 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
diff --git a/content/handlers/javascript/duktape/dukky.h b/content/handlers/javascript/duktape/dukky.h
index 1d6baee..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -42,5 +42,15 @@ void dukky_register_event_listener_for(duk_context *ctx,
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
diff --git a/content/handlers/javascript/duktape/netsurf.bnd b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..6c6fbfb
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
-----------------------------------------------------------------------
Summary of changes:
--
NetSurf Browser
5 years, 11 months