mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
[click] Added eventListener. It works for these two test cases.
This commit is contained in:
parent
3330427738
commit
d7f4f94a62
@ -82,6 +82,19 @@
|
|||||||
|
|
||||||
static INIT_LIST_OF(struct document, format_cache);
|
static INIT_LIST_OF(struct document, format_cache);
|
||||||
|
|
||||||
|
const char *script_event_hook_name[] = {
|
||||||
|
"click",
|
||||||
|
"dblclick",
|
||||||
|
"mouseover",
|
||||||
|
"hover",
|
||||||
|
"focus",
|
||||||
|
"mouseout",
|
||||||
|
"blur",
|
||||||
|
"keydown",
|
||||||
|
"keyup",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef HAVE_INET_NTOP
|
#ifdef HAVE_INET_NTOP
|
||||||
/* DNS callback. */
|
/* DNS callback. */
|
||||||
static void
|
static void
|
||||||
|
@ -90,6 +90,9 @@ enum script_event_hook_type {
|
|||||||
SEVHOOK_ONKEYUP
|
SEVHOOK_ONKEYUP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* keep in sync with above */
|
||||||
|
extern const char *script_event_hook_name[];
|
||||||
|
|
||||||
struct script_event_hook {
|
struct script_event_hook {
|
||||||
LIST_HEAD(struct script_event_hook);
|
LIST_HEAD(struct script_event_hook);
|
||||||
|
|
||||||
@ -102,6 +105,9 @@ struct link {
|
|||||||
|
|
||||||
enum link_type type;
|
enum link_type type;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ECMASCRIPT
|
||||||
|
int element_offset;
|
||||||
|
#endif
|
||||||
char *where;
|
char *where;
|
||||||
char *target;
|
char *target;
|
||||||
char *where_img;
|
char *where_img;
|
||||||
@ -214,6 +220,7 @@ struct document {
|
|||||||
LIST_OF(struct ecmascript_timeout) timeouts;
|
LIST_OF(struct ecmascript_timeout) timeouts;
|
||||||
int ecmascript_counter;
|
int ecmascript_counter;
|
||||||
void *dom;
|
void *dom;
|
||||||
|
void *element_map;
|
||||||
char *text;
|
char *text;
|
||||||
void *forms_nodeset;
|
void *forms_nodeset;
|
||||||
#endif
|
#endif
|
||||||
|
@ -76,6 +76,8 @@ struct text_attrib {
|
|||||||
char *onblur;
|
char *onblur;
|
||||||
char *onkeydown;
|
char *onkeydown;
|
||||||
char *onkeyup;
|
char *onkeyup;
|
||||||
|
|
||||||
|
char *top_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This enum is pretty ugly, yes ;). */
|
/* This enum is pretty ugly, yes ;). */
|
||||||
|
@ -141,13 +141,14 @@ init_form_control(enum form_type type, char *attr,
|
|||||||
|
|
||||||
void
|
void
|
||||||
html_button(struct html_context *html_context, char *a,
|
html_button(struct html_context *html_context, char *a,
|
||||||
char *xxx3, char *xxx4, char **xxx5)
|
char *html, char *xxx4, char **xxx5)
|
||||||
{
|
{
|
||||||
char *al;
|
char *al;
|
||||||
struct el_form_control *fc;
|
struct el_form_control *fc;
|
||||||
enum form_type type = FC_SUBMIT;
|
enum form_type type = FC_SUBMIT;
|
||||||
int cp = html_context->doc_cp;
|
int cp = html_context->doc_cp;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
al = get_attr_val(a, "type", cp);
|
al = get_attr_val(a, "type", cp);
|
||||||
@ -192,9 +193,11 @@ html_input_format(struct html_context *html_context, char *a,
|
|||||||
struct el_form_control *fc)
|
struct el_form_control *fc)
|
||||||
{
|
{
|
||||||
put_chrs(html_context, " ", 1);
|
put_chrs(html_context, " ", 1);
|
||||||
|
char *top_name = html_top->name;
|
||||||
html_stack_dup(html_context, ELEMENT_KILLABLE);
|
html_stack_dup(html_context, ELEMENT_KILLABLE);
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
elformat.form = fc;
|
elformat.form = fc;
|
||||||
|
elformat.top_name = top_name;
|
||||||
mem_free_if(elformat.title);
|
mem_free_if(elformat.title);
|
||||||
elformat.title = get_attr_val(a, "title", html_context->doc_cp);
|
elformat.title = get_attr_val(a, "title", html_context->doc_cp);
|
||||||
switch (fc->type) {
|
switch (fc->type) {
|
||||||
@ -354,6 +357,7 @@ do_html_select(char *attr, char *html,
|
|||||||
int i, max_width;
|
int i, max_width;
|
||||||
int closing_tag;
|
int closing_tag;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, attr);
|
html_focusable(html_context, attr);
|
||||||
init_menu(&lnk_menu);
|
init_menu(&lnk_menu);
|
||||||
|
|
||||||
@ -529,6 +533,7 @@ do_html_select_multiple(struct html_context *html_context, char *a,
|
|||||||
char *al = get_attr_val(a, "name", html_context->doc_cp);
|
char *al = get_attr_val(a, "name", html_context->doc_cp);
|
||||||
|
|
||||||
if (!al) return;
|
if (!al) return;
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
html_top->type = ELEMENT_DONT_KILL;
|
html_top->type = ELEMENT_DONT_KILL;
|
||||||
mem_free_set(&elformat.select, al);
|
mem_free_set(&elformat.select, al);
|
||||||
@ -636,6 +641,7 @@ html_textarea(struct html_context *html_context, char *attr,
|
|||||||
int cols, rows;
|
int cols, rows;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, attr);
|
html_focusable(html_context, attr);
|
||||||
while (html < eof && (*html == '\n' || *html == '\r')) html++;
|
while (html < eof && (*html == '\n' || *html == '\r')) html++;
|
||||||
p = html;
|
p = html;
|
||||||
|
@ -1047,6 +1047,7 @@ html_frame(struct html_context *html_context, char *a,
|
|||||||
if (!name) return;
|
if (!name) return;
|
||||||
|
|
||||||
if (!html_context->options->frames || !html_top->frameset) {
|
if (!html_context->options->frames || !html_top->frameset) {
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
put_link_line("Frame: ", name, url, "", html_context);
|
put_link_line("Frame: ", name, url, "", html_context);
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ html_a(struct html_context *html_context, char *a,
|
|||||||
mem_free_set(&elformat.title,
|
mem_free_set(&elformat.title,
|
||||||
get_attr_val(a, "title", html_context->doc_cp));
|
get_attr_val(a, "title", html_context->doc_cp));
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -205,6 +206,7 @@ put_image_label(char *a, char *label,
|
|||||||
/* This is not 100% appropriate for <img>, but well, accepting
|
/* This is not 100% appropriate for <img>, but well, accepting
|
||||||
* accesskey and tabindex near <img> is just our little
|
* accesskey and tabindex near <img> is just our little
|
||||||
* extension to the standard. After all, it makes sense. */
|
* extension to the standard. After all, it makes sense. */
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
saved_foreground = elformat.style.color.foreground;
|
saved_foreground = elformat.style.color.foreground;
|
||||||
@ -381,7 +383,7 @@ html_source(struct html_context *html_context, char *a,
|
|||||||
mem_free_set(&title, get_image_filename_from_src(options->image_link.filename_maxlen, src));
|
mem_free_set(&title, get_image_filename_from_src(options->image_link.filename_maxlen, src));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
if (title && *title) {
|
if (title && *title) {
|
||||||
@ -433,7 +435,7 @@ html_applet(struct html_context *html_context, char *a,
|
|||||||
if (!code) return;
|
if (!code) return;
|
||||||
|
|
||||||
alt = get_attr_val(a, "alt", html_context->doc_cp);
|
alt = get_attr_val(a, "alt", html_context->doc_cp);
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
if (alt && *alt) {
|
if (alt && *alt) {
|
||||||
@ -459,6 +461,7 @@ html_audio(struct html_context *html_context, char *a,
|
|||||||
url = get_url_val(a, "src", html_context->doc_cp);
|
url = get_url_val(a, "src", html_context->doc_cp);
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
put_link_line("Audio: ", basename(url), url,
|
put_link_line("Audio: ", basename(url), url,
|
||||||
@ -489,6 +492,7 @@ html_iframe_do(char *a, char *object_src,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
if (html_context->options->iframes) {
|
if (html_context->options->iframes) {
|
||||||
@ -574,6 +578,7 @@ html_object(struct html_context *html_context, char *a,
|
|||||||
|
|
||||||
name = get_attr_val(a, "standby", html_context->doc_cp);
|
name = get_attr_val(a, "standby", html_context->doc_cp);
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
if (name && *name) {
|
if (name && *name) {
|
||||||
@ -638,6 +643,7 @@ html_video(struct html_context *html_context, char *a,
|
|||||||
url = get_url_val(a, "src", html_context->doc_cp);
|
url = get_url_val(a, "src", html_context->doc_cp);
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
put_link_line("Video: ", basename(url), url,
|
put_link_line("Video: ", basename(url), url,
|
||||||
@ -944,6 +950,7 @@ html_link(struct html_context *html_context, char *a,
|
|||||||
if (!name) goto free_and_return;
|
if (!name) goto free_and_return;
|
||||||
if (!init_string(&text)) goto free_and_return;
|
if (!init_string(&text)) goto free_and_return;
|
||||||
|
|
||||||
|
elformat.top_name = html_top->name;
|
||||||
html_focusable(html_context, a);
|
html_focusable(html_context, a);
|
||||||
|
|
||||||
if (link.title) {
|
if (link.title) {
|
||||||
|
@ -1551,6 +1551,10 @@ new_link(struct html_context *html_context, const char *name, int namelen)
|
|||||||
? elformat.style.color.foreground
|
? elformat.style.color.foreground
|
||||||
: elformat.color.clink;
|
: elformat.color.clink;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ECMASCRIPT
|
||||||
|
link->element_offset = elformat.top_name ? elformat.top_name - document->text : 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
init_link_event_hooks(html_context, link);
|
init_link_event_hooks(html_context, link);
|
||||||
|
|
||||||
document->links_sorted = 0;
|
document->links_sorted = 0;
|
||||||
|
@ -293,8 +293,8 @@ render_encoded_document(struct cache_entry *cached, struct document *document)
|
|||||||
&& (!c_strlcasecmp("text/gemini", 11, cached->content_type, -1)))
|
&& (!c_strlcasecmp("text/gemini", 11, cached->content_type, -1)))
|
||||||
render_gemini_document(cached, document, &buffer);
|
render_gemini_document(cached, document, &buffer);
|
||||||
else
|
else
|
||||||
#ifdef CONFIG_XML
|
#if defined(CONFIG_XML) && defined(CONFIG_ECMASCRIPT)
|
||||||
if (false) render_xhtml_document(cached, document, &buffer);
|
if (true) render_xhtml_document(cached, document, NULL);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
render_html_document(cached, document, &buffer);
|
render_html_document(cached, document, &buffer);
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
#include <libxml++/libxml++.h>
|
#include <libxml++/libxml++.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
@ -267,6 +269,65 @@ dump_dom_structure(struct source_renderer *renderer, void *nod, int depth)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_element(std::map<int, xmlpp::Element *> *mapa, struct string *buf, xmlpp::Element *element)
|
||||||
|
{
|
||||||
|
add_char_to_string(buf, '<');
|
||||||
|
(*mapa)[buf->length] = element;
|
||||||
|
|
||||||
|
add_to_string(buf, element->get_name().c_str());
|
||||||
|
auto attrs = element->get_attributes();
|
||||||
|
auto it = attrs.begin();
|
||||||
|
auto end = attrs.end();
|
||||||
|
|
||||||
|
for (;it != end; ++it) {
|
||||||
|
add_char_to_string(buf, ' ');
|
||||||
|
add_to_string(buf, (*it)->get_name().c_str());
|
||||||
|
add_char_to_string(buf, '=');
|
||||||
|
add_char_to_string(buf, '"');
|
||||||
|
add_to_string(buf, (*it)->get_value().c_str());
|
||||||
|
add_char_to_string(buf, '"');
|
||||||
|
}
|
||||||
|
add_char_to_string(buf, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
walk_tree(std::map<int, xmlpp::Element *> *mapa, struct string *buf, void *nod, bool start)
|
||||||
|
{
|
||||||
|
xmlpp::Node *node = static_cast<xmlpp::Node *>(nod);
|
||||||
|
|
||||||
|
if (!start) {
|
||||||
|
const auto textNode = dynamic_cast<const xmlpp::ContentNode*>(node);
|
||||||
|
|
||||||
|
if (textNode) {
|
||||||
|
add_bytes_to_string(buf, textNode->get_content().c_str(), textNode->get_content().length());
|
||||||
|
} else {
|
||||||
|
auto element = dynamic_cast<xmlpp::Element*>(node);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
dump_element(mapa, buf, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto childs = node->get_children();
|
||||||
|
auto it = childs.begin();
|
||||||
|
auto end = childs.end();
|
||||||
|
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
walk_tree(mapa, buf, *it, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!start) {
|
||||||
|
const auto element = dynamic_cast<const xmlpp::Element*>(node);
|
||||||
|
if (element) {
|
||||||
|
add_to_string(buf, "</");
|
||||||
|
add_to_string(buf, element->get_name().c_str());
|
||||||
|
add_char_to_string(buf, '>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
render_xhtml_document(struct cache_entry *cached, struct document *document, struct string *buffer)
|
render_xhtml_document(struct cache_entry *cached, struct document *document, struct string *buffer)
|
||||||
{
|
{
|
||||||
@ -278,7 +339,6 @@ render_xhtml_document(struct cache_entry *cached, struct document *document, str
|
|||||||
render_html_document(cached, document, buffer);
|
render_html_document(cached, document, buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct string head;
|
struct string head;
|
||||||
|
|
||||||
assert(cached && document);
|
assert(cached && document);
|
||||||
@ -300,19 +360,29 @@ render_xhtml_document(struct cache_entry *cached, struct document *document, str
|
|||||||
}
|
}
|
||||||
|
|
||||||
xmlpp::Document *doc = (xmlpp::Document *)document->dom;
|
xmlpp::Document *doc = (xmlpp::Document *)document->dom;
|
||||||
|
xmlpp::Element* root = (xmlpp::Element *)doc->get_root_node();
|
||||||
|
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
xmlpp::ustring text = doc->write_to_string_formatted();
|
|
||||||
struct string tt;
|
struct string tt;
|
||||||
|
|
||||||
if (!init_string(&tt)) {
|
if (!init_string(&tt)) {
|
||||||
done_string(&head);
|
done_string(&head);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
add_bytes_to_string(&tt, text.c_str(), text.size());
|
std::map<int, xmlpp::Element *> *mapa = (std::map<int, xmlpp::Element *> *)document->element_map;
|
||||||
|
|
||||||
|
if (!mapa) {
|
||||||
|
mapa = new std::map<int, xmlpp::Element *>;
|
||||||
|
document->element_map = (void *)mapa;
|
||||||
|
} else {
|
||||||
|
mapa->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
walk_tree(mapa, &tt, root, true);
|
||||||
buffer = &tt;
|
buffer = &tt;
|
||||||
document->text = tt.source;
|
document->text = tt.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_to_head) {
|
if (add_to_head) {
|
||||||
mem_free_set(&cached->head, head.source);
|
mem_free_set(&cached->head, head.source);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "ecmascript/spidermonkey/attributes.h"
|
#include "ecmascript/spidermonkey/attributes.h"
|
||||||
#include "ecmascript/spidermonkey/collection.h"
|
#include "ecmascript/spidermonkey/collection.h"
|
||||||
#include "ecmascript/spidermonkey/element.h"
|
#include "ecmascript/spidermonkey/element.h"
|
||||||
|
#include "ecmascript/spidermonkey/heartbeat.h"
|
||||||
#include "ecmascript/spidermonkey/nodelist.h"
|
#include "ecmascript/spidermonkey/nodelist.h"
|
||||||
#include "ecmascript/spidermonkey/window.h"
|
#include "ecmascript/spidermonkey/window.h"
|
||||||
#include "intl/libintl.h"
|
#include "intl/libintl.h"
|
||||||
@ -97,6 +98,18 @@ static bool element_set_property_textContent(JSContext *ctx, unsigned int argc,
|
|||||||
static bool element_get_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp);
|
static bool element_get_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp);
|
||||||
static bool element_set_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp);
|
static bool element_set_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp);
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
LIST_HEAD(struct listener);
|
||||||
|
char *typ;
|
||||||
|
JS::RootedValue fun;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct element_private {
|
||||||
|
LIST_OF(struct listener) listeners;
|
||||||
|
struct ecmascript_interpreter *interpreter;
|
||||||
|
JS::RootedObject thisval;
|
||||||
|
};
|
||||||
|
|
||||||
static void element_finalize(JS::GCContext *op, JSObject *obj);
|
static void element_finalize(JS::GCContext *op, JSObject *obj);
|
||||||
|
|
||||||
JSClassOps element_ops = {
|
JSClassOps element_ops = {
|
||||||
@ -114,7 +127,7 @@ JSClassOps element_ops = {
|
|||||||
|
|
||||||
JSClass element_class = {
|
JSClass element_class = {
|
||||||
"element",
|
"element",
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(1),
|
JSCLASS_HAS_RESERVED_SLOTS(2),
|
||||||
&element_ops
|
&element_ops
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2310,6 +2323,7 @@ element_set_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool element_addEventListener(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_appendChild(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_appendChild(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_cloneNode(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_cloneNode(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_closest(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_closest(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
@ -2327,9 +2341,11 @@ static bool element_querySelector(JSContext *ctx, unsigned int argc, JS::Value *
|
|||||||
static bool element_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_remove(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_remove(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_removeChild(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_removeChild(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
|
static bool element_removeEventListener(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
static bool element_setAttribute(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
static bool element_setAttribute(JSContext *ctx, unsigned int argc, JS::Value *rval);
|
||||||
|
|
||||||
const spidermonkeyFunctionSpec element_funcs[] = {
|
const spidermonkeyFunctionSpec element_funcs[] = {
|
||||||
|
{ "addEventListener", element_addEventListener, 3 },
|
||||||
{ "appendChild", element_appendChild, 1 },
|
{ "appendChild", element_appendChild, 1 },
|
||||||
{ "cloneNode", element_cloneNode, 1 },
|
{ "cloneNode", element_cloneNode, 1 },
|
||||||
{ "closest", element_closest, 1 },
|
{ "closest", element_closest, 1 },
|
||||||
@ -2347,6 +2363,7 @@ const spidermonkeyFunctionSpec element_funcs[] = {
|
|||||||
{ "querySelectorAll", element_querySelectorAll, 1 },
|
{ "querySelectorAll", element_querySelectorAll, 1 },
|
||||||
{ "remove", element_remove, 0 },
|
{ "remove", element_remove, 0 },
|
||||||
{ "removeChild", element_removeChild, 1 },
|
{ "removeChild", element_removeChild, 1 },
|
||||||
|
{ "removeEventListener", element_removeEventListener, 3 },
|
||||||
{ "setAttribute", element_setAttribute, 2 },
|
{ "setAttribute", element_setAttribute, 2 },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
@ -2385,6 +2402,137 @@ check_contains(xmlpp::Node *node, xmlpp::Node *searched, bool *result_set, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
element_addEventListener(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
||||||
|
{
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
JS::Realm *comp = js::GetContextRealm(ctx);
|
||||||
|
|
||||||
|
if (!comp) {
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::CallArgs args = CallArgsFromVp(argc, rval);
|
||||||
|
JS::RootedObject hobj(ctx, &args.thisv().toObject());
|
||||||
|
|
||||||
|
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
|
||||||
|
|
||||||
|
if (!JS_InstanceOf(ctx, hobj, &element_class, NULL)) {
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
|
||||||
|
struct element_private *el_private = JS::GetMaybePtrFromReservedSlot<struct element_private>(hobj, 1);
|
||||||
|
|
||||||
|
if (!el || !el_private) {
|
||||||
|
args.rval().setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
char *method = jsval_to_string(ctx, args[0]);
|
||||||
|
JS::RootedValue fun(ctx, args[1]);
|
||||||
|
|
||||||
|
struct listener *l;
|
||||||
|
|
||||||
|
foreach(l, el_private->listeners) {
|
||||||
|
if (strcmp(l->typ, method)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (l->fun == fun) {
|
||||||
|
args.rval().setUndefined();
|
||||||
|
mem_free(method);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct listener *n = (struct listener *)mem_calloc(1, sizeof(*n));
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
n->typ = method;
|
||||||
|
n->fun = fun;
|
||||||
|
add_to_list_end(el_private->listeners, n);
|
||||||
|
}
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
element_removeEventListener(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
||||||
|
{
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
|
||||||
|
#endif
|
||||||
|
JS::Realm *comp = js::GetContextRealm(ctx);
|
||||||
|
|
||||||
|
if (!comp) {
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::CallArgs args = CallArgsFromVp(argc, rval);
|
||||||
|
JS::RootedObject hobj(ctx, &args.thisv().toObject());
|
||||||
|
|
||||||
|
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
|
||||||
|
|
||||||
|
if (!JS_InstanceOf(ctx, hobj, &element_class, NULL)) {
|
||||||
|
#ifdef ECMASCRIPT_DEBUG
|
||||||
|
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
|
||||||
|
struct element_private *el_private = JS::GetMaybePtrFromReservedSlot<struct element_private>(hobj, 1);
|
||||||
|
|
||||||
|
if (!el || !el_private) {
|
||||||
|
args.rval().setNull();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
char *method = jsval_to_string(ctx, args[0]);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JS::RootedValue fun(ctx, args[1]);
|
||||||
|
|
||||||
|
struct listener *l;
|
||||||
|
|
||||||
|
foreach(l, el_private->listeners) {
|
||||||
|
if (strcmp(l->typ, method)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (l->fun == fun) {
|
||||||
|
del_from_list(l);
|
||||||
|
mem_free_set(&l->typ, NULL);
|
||||||
|
mem_free(l);
|
||||||
|
mem_free(method);
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mem_free(method);
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
element_appendChild(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
element_appendChild(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
||||||
{
|
{
|
||||||
@ -3316,14 +3464,34 @@ element_setAttribute(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::map<void *, struct element_private *> map_privates;
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
getElement(JSContext *ctx, void *node)
|
getElement(JSContext *ctx, void *node)
|
||||||
{
|
{
|
||||||
|
auto elem = map_privates.find(node);
|
||||||
|
struct element_private *el_private = NULL;
|
||||||
|
|
||||||
|
if (elem != map_privates.end()) {
|
||||||
|
el_private = elem->second;
|
||||||
|
} else {
|
||||||
|
el_private = (struct element_private *)mem_calloc(1, sizeof(*el_private));
|
||||||
|
|
||||||
|
if (!el_private) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
init_list(el_private->listeners);
|
||||||
|
}
|
||||||
|
|
||||||
JSObject *el = JS_NewObject(ctx, &element_class);
|
JSObject *el = JS_NewObject(ctx, &element_class);
|
||||||
|
|
||||||
if (!el) {
|
if (!el) {
|
||||||
|
mem_free(el_private);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
JS::Realm *comp = js::GetContextRealm(ctx);
|
||||||
|
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
|
||||||
|
el_private->interpreter = interpreter;
|
||||||
|
|
||||||
JS::RootedObject r_el(ctx, el);
|
JS::RootedObject r_el(ctx, el);
|
||||||
|
|
||||||
@ -3331,6 +3499,39 @@ getElement(JSContext *ctx, void *node)
|
|||||||
spidermonkey_DefineFunctions(ctx, el, element_funcs);
|
spidermonkey_DefineFunctions(ctx, el, element_funcs);
|
||||||
|
|
||||||
JS::SetReservedSlot(el, 0, JS::PrivateValue(node));
|
JS::SetReservedSlot(el, 0, JS::PrivateValue(node));
|
||||||
|
JS::SetReservedSlot(el, 1, JS::PrivateValue(el_private));
|
||||||
|
|
||||||
|
el_private->thisval = r_el;
|
||||||
|
map_privates[node] = el_private;
|
||||||
|
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
check_element_event(void *elem, const char *event_name)
|
||||||
|
{
|
||||||
|
auto el = map_privates.find(elem);
|
||||||
|
|
||||||
|
if (el == map_privates.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct element_private *el_private = el->second;
|
||||||
|
struct ecmascript_interpreter *interpreter = el_private->interpreter;
|
||||||
|
JSContext *ctx = (JSContext *)interpreter->backend_data;
|
||||||
|
JS::Realm *comp = JS::EnterRealm(ctx, (JSObject *)interpreter->ac);
|
||||||
|
JS::RootedValue r_val(ctx);
|
||||||
|
interpreter->heartbeat = add_heartbeat(interpreter);
|
||||||
|
|
||||||
|
struct listener *l;
|
||||||
|
|
||||||
|
foreach(l, el_private->listeners) {
|
||||||
|
if (strcmp(l->typ, event_name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JS_CallFunctionValue(ctx, el_private->thisval, l->fun, JS::HandleValueArray::empty(), &r_val);
|
||||||
|
}
|
||||||
|
done_heartbeat(interpreter->heartbeat);
|
||||||
|
JS::LeaveRealm(ctx, comp);
|
||||||
|
|
||||||
|
check_for_rerender(interpreter, event_name);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
|
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
|
||||||
#define EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
|
#define EL__ECMASCRIPT_SPIDERMONKEY_ELEMENT_H
|
||||||
|
|
||||||
@ -11,4 +10,6 @@ JSObject *getElement(JSContext *ctx, void *node);
|
|||||||
|
|
||||||
void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false);
|
void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false);
|
||||||
|
|
||||||
|
void check_element_event(void *elem, const char *event_name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,7 +112,6 @@ struct listener {
|
|||||||
JS::RootedValue fun;
|
JS::RootedValue fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct classcomp {
|
struct classcomp {
|
||||||
bool operator() (const std::string& lhs, const std::string& rhs) const
|
bool operator() (const std::string& lhs, const std::string& rhs) const
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,12 @@
|
|||||||
#include "document/options.h"
|
#include "document/options.h"
|
||||||
#include "document/view.h"
|
#include "document/view.h"
|
||||||
#include "ecmascript/ecmascript.h"
|
#include "ecmascript/ecmascript.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_ECMASCRIPT_SMJS
|
||||||
|
#include "ecmascript/spidermonkey/element.h"
|
||||||
|
#include <libxml++/libxml++.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "intl/libintl.h"
|
#include "intl/libintl.h"
|
||||||
#include "main/object.h"
|
#include "main/object.h"
|
||||||
#include "protocol/uri.h"
|
#include "protocol/uri.h"
|
||||||
@ -44,6 +50,7 @@
|
|||||||
#include "viewer/text/view.h"
|
#include "viewer/text/view.h"
|
||||||
#include "viewer/text/vs.h"
|
#include "viewer/text/vs.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/* Perhaps some of these would be more fun to have in viewer/common/, dunno.
|
/* Perhaps some of these would be more fun to have in viewer/common/, dunno.
|
||||||
* --pasky */
|
* --pasky */
|
||||||
@ -59,10 +66,21 @@ current_link_evhook(struct document_view *doc_view, enum script_event_hook_type
|
|||||||
assert(doc_view && doc_view->vs);
|
assert(doc_view && doc_view->vs);
|
||||||
link = get_current_link(doc_view);
|
link = get_current_link(doc_view);
|
||||||
if (!link) return -1;
|
if (!link) return -1;
|
||||||
if (!link->event_hooks) return -1;
|
|
||||||
|
|
||||||
if (!doc_view->vs->ecmascript) return -1;
|
if (!doc_view->vs->ecmascript) return -1;
|
||||||
|
|
||||||
|
std::map<int, xmlpp::Element *> *mapa = (std::map<int, xmlpp::Element *> *)doc_view->document->element_map;
|
||||||
|
|
||||||
|
if (mapa) {
|
||||||
|
auto element = (*mapa).find(link->element_offset);
|
||||||
|
|
||||||
|
if (element != (*mapa).end()) {
|
||||||
|
const char *event_name = script_event_hook_name[(int)type];
|
||||||
|
check_element_event(element->second, event_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!link->event_hooks) return -1;
|
||||||
|
|
||||||
foreach (evhook, *link->event_hooks) {
|
foreach (evhook, *link->event_hooks) {
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
|
20
test/ecmascript/clickListener.html
Normal file
20
test/ecmascript/clickListener.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
function cli()
|
||||||
|
{
|
||||||
|
document.location.href='http://www.elinks.cz';
|
||||||
|
}
|
||||||
|
|
||||||
|
function loader()
|
||||||
|
{
|
||||||
|
document.getElementById('c').addEventListener('click', cli);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="loader()">
|
||||||
|
<center>
|
||||||
|
<input type="button" id="c" value="ELinks homepage">
|
||||||
|
</center>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
test/ecmascript/clickListener2.html
Normal file
21
test/ecmascript/clickListener2.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
function cli()
|
||||||
|
{
|
||||||
|
alert("document.location.href='http://www.elinks.cz';");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loader()
|
||||||
|
{
|
||||||
|
document.getElementById('c').addEventListener('click', function() { window.alert('aaaa'); });
|
||||||
|
document.getElementById('c').addEventListener('click', cli);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="loader()">
|
||||||
|
<center>
|
||||||
|
<button id="c" value="ELinks homepage">AAA</button>
|
||||||
|
</center>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user