1
0
Fork 0

Compare commits

...

34 Commits

Author SHA1 Message Date
Witold Filipczyk 7748eb5ab9 [quickjs] Fix in url.c 2024-05-07 17:39:30 +02:00
Witold Filipczyk 948c22ea79 [quickjs] Do not FreeValue 2024-05-07 17:32:46 +02:00
Witold Filipczyk 786469da5f [quickjs] nodelist.forEach 2024-05-07 17:24:13 +02:00
Witold Filipczyk 3d92071eba [mujs] element.querySelectorAll 2024-05-07 16:51:29 +02:00
Witold Filipczyk 57202954bb [mujs] document.querySelectorAll 2024-05-07 16:45:43 +02:00
Witold Filipczyk 4da6e1f85a [mujs] element.closest 2024-05-07 16:41:30 +02:00
Witold Filipczyk 786cbf9500 [mujs] element.matches 2024-05-07 16:36:02 +02:00
Witold Filipczyk 1b954141eb [mujs] element.querySelector 2024-05-07 16:09:30 +02:00
Witold Filipczyk 6f64f8e9db [mujs] document.querySelector 2024-05-07 16:03:41 +02:00
Witold Filipczyk 14bca39543 [po] updated POTFILES 2024-05-07 15:57:51 +02:00
Witold Filipczyk ff3b231e42 [mujs] URL 2024-05-07 15:54:43 +02:00
Witold Filipczyk bd7f271b0a [ecmascript] Removed debug fprintfs 2024-05-07 15:03:14 +02:00
Witold Filipczyk 0e42cf7d63 [quickjs] element.querySelectorAll 2024-05-06 21:49:03 +02:00
Witold Filipczyk 6deeb720b9 [quickjs] document.querySelectorAll 2024-05-06 21:41:02 +02:00
Witold Filipczyk 3c81545b81 [quickjs] element.closest 2024-05-06 21:22:16 +02:00
Witold Filipczyk 3406220379 [quickjs] element.matches
TODO forEach
2024-05-06 21:07:27 +02:00
Witold Filipczyk 7c9c3f83bf [quickjs] element.querySelector 2024-05-06 21:01:04 +02:00
Witold Filipczyk 42d2da4be5 [quickjs] document.querySelector 2024-05-06 20:52:29 +02:00
Witold Filipczyk 2a0afc9631 [po] updated POTFILES 2024-05-06 20:42:42 +02:00
Witold Filipczyk a6d368d2ab [quickjs] URL 2024-05-06 20:41:55 +02:00
Witold Filipczyk 8bba9f8c4e [spidermonkey] forEach and other Array methods for nodelist 2024-05-06 18:40:02 +02:00
Witold Filipczyk 15ac18c04f [spidermonkey] element.querySelectorAll 2024-05-06 16:32:15 +02:00
Witold Filipczyk 48ff6810d4 [assert] element.querySelectorAll 2024-05-06 16:31:53 +02:00
Witold Filipczyk bbe14cddc3 [spidermonkey] document.querySelectorAll 2024-05-06 16:22:18 +02:00
Witold Filipczyk ecd7662d1a [assert] document.querySelectorAll 2024-05-06 14:56:53 +02:00
Witold Filipczyk 610eb4b450 [spidermonkey] Fixes for closest 2024-05-05 21:52:07 +02:00
Witold Filipczyk 09447c7812 [spidermonkey] element.closest
There is invalid free when selector is not matched.
2024-05-05 21:02:36 +02:00
Witold Filipczyk 10555292b4 [interlink] trigger was unitialized 2024-05-05 20:46:48 +02:00
Witold Filipczyk face74fd38 [spidermonkey] element.matches 2024-05-05 19:54:12 +02:00
Witold Filipczyk 667167bd90 [spidermonkey] element.querySelector 2024-05-05 19:36:41 +02:00
Witold Filipczyk 4a6b920586 [ecmascript] walk_tree_query moved to ecmascript-c.c 2024-05-05 19:29:52 +02:00
Witold Filipczyk 3128c22c2e [assert] element.querySelector 2024-05-05 19:22:44 +02:00
Witold Filipczyk cc718c30b5 [spidermonkey] document.querySelector
It passes test case.
2024-05-05 16:58:10 +02:00
Witold Filipczyk be67094940 [assert] document.querySelector 2024-05-05 13:28:56 +02:00
31 changed files with 2303 additions and 468 deletions

View File

@ -284,6 +284,8 @@ src/ecmascript/mujs/style.c
src/ecmascript/mujs/style.h
src/ecmascript/mujs/unibar.c
src/ecmascript/mujs/unibar.h
src/ecmascript/mujs/url.c
src/ecmascript/mujs/url.h
src/ecmascript/mujs/window.c
src/ecmascript/mujs/window.h
src/ecmascript/mujs/xhr.c
@ -340,6 +342,8 @@ src/ecmascript/quickjs/style.c
src/ecmascript/quickjs/style.h
src/ecmascript/quickjs/unibar.c
src/ecmascript/quickjs/unibar.h
src/ecmascript/quickjs/url.c
src/ecmascript/quickjs/url.h
src/ecmascript/quickjs/window.c
src/ecmascript/quickjs/window.h
src/ecmascript/quickjs/xhr.c

View File

@ -97,7 +97,11 @@ static css_error node_presentational_hint(void *pw, void *node,
return CSS_OK;
}
static css_error
resolve_url_empty(void *pw, const char *base, lwc_string *rel, lwc_string **abs)
{
return CSS_OK;
}
css_error
resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs)
@ -2309,3 +2313,122 @@ import_css2(struct html_context *html_context, struct uri *uri)
// css->import_level--;
}
}
void *
el_match_selector(const char *selector, void *node)
{
struct string text;
css_error code;
size_t size;
uint32_t count;
css_stylesheet_params params;
css_stylesheet *sheet = NULL;
css_select_ctx *select_ctx = NULL;
css_select_results *style = NULL;
uint8_t color_type;
css_color color_shade;
css_media media = {
.type = CSS_MEDIA_SCREEN,
};
css_unit_ctx unit_len_ctx = {0};
unit_len_ctx.viewport_width = 800; // TODO
unit_len_ctx.viewport_height = 600; // TODO
unit_len_ctx.device_dpi = F_90; //device_dpi;
/** \todo Change nsoption font sizes to px. */
/// f_size = FDIV(FMUL(F_96, FDIV(INTTOFIX(nsoption_int(font_size)), F_10)), F_72);
/// f_min = FDIV(FMUL(F_96, FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)), F_72);
unsigned int f_size = FDIV(FMUL(F_96, FDIV(INTTOFIX(50), F_10)), F_72); // TODO
unsigned int f_min = FDIV(FMUL(F_96, FDIV(INTTOFIX(50), F_10)), F_72); // TODO
unit_len_ctx.font_size_default = f_size;
unit_len_ctx.font_size_minimum = f_min;
void *ret = NULL;
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_21;
params.charset = "UTF-8";
params.url = "foo";
params.title = "foo";
params.allow_quirks = false;
params.inline_style = false;
params.resolve = resolve_url_empty;
params.resolve_pw = NULL;
params.import = NULL;
params.import_pw = NULL;
params.color = NULL;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
if (!selector) {
return NULL;
}
if (!init_string(&text)) {
return NULL;
}
add_to_string(&text, selector);
add_to_string(&text, "{color:#123456}");
/* create a stylesheet */
code = css_stylesheet_create(&params, &sheet);
if (code != CSS_OK) {
goto empty;
}
code = css_stylesheet_append_data(sheet, (const uint8_t *) text.source, text.length);
if (code != CSS_OK && code != CSS_NEEDDATA) {
goto empty;
}
code = css_stylesheet_data_done(sheet);
if (code != CSS_OK) {
goto empty;
}
code = css_stylesheet_size(sheet, &size);
/* prepare a selection context containing the stylesheet */
code = css_select_ctx_create(&select_ctx);
if (code != CSS_OK) {
goto empty;
}
code = css_select_ctx_append_sheet(select_ctx, sheet, CSS_ORIGIN_AUTHOR, NULL);
if (code != CSS_OK) {
goto empty;
}
code = css_select_ctx_count_sheets(select_ctx, &count);
if (code != CSS_OK) {
goto empty;
}
code = css_select_style(select_ctx, node, &unit_len_ctx, &media, NULL, &selection_handler, 0, &style);
if (code != CSS_OK) {
goto empty;
}
color_type = css_computed_color(style->styles[CSS_PSEUDO_ELEMENT_NONE], &color_shade);
if (color_type && color_shade == 0xff123456) {
ret = node;
}
empty:
if (style) {
css_select_results_destroy(style);
}
if (select_ctx) {
css_select_ctx_destroy(select_ctx);
}
if (sheet) {
css_stylesheet_destroy(sheet);
}
done_string(&text);
return ret;
}

View File

@ -11,6 +11,7 @@ struct string;
void *document_parse_text(const char *charset, char *data, size_t length);
void *document_parse(struct document *document, struct string *source);
void free_document(void *doc);
void *el_match_selector(const char *selector, void *node);
#ifdef __cplusplus
}

View File

@ -8,6 +8,7 @@
#include "dialogs/status.h"
#include "document/document.h"
#include "document/libdom/doc.h"
#include "document/libdom/mapa.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
@ -481,3 +482,114 @@ void ecmascript_moved_form_state(struct form_state *fs)
spidermonkey_moved_form_state(fs);
#endif
}
void *
walk_tree_query(dom_node *node, const char *selector, int depth)
{
dom_exception exc;
dom_node *child;
void *res = NULL;
dom_node_type typ;
/* Only interested in element nodes */
exc = dom_node_get_node_type(node, &typ);
if (typ != DOM_ELEMENT_NODE) {
return NULL;
}
if (res = el_match_selector(selector, node)) {
/* There was an error; return */
return res;
}
/* Get the node's first child */
exc = dom_node_get_first_child(node, &child);
if (exc != DOM_NO_ERR) {
return NULL;
} else if (child != NULL) {
/* node has children; decend to children's depth */
depth++;
/* Loop though all node's children */
do {
dom_node *next_child;
/* Visit node's descendents */
res = walk_tree_query(child, selector, depth);
/* There was an error; return */
if (res) {
dom_node_unref(child);
return res;
}
/* Go to next sibling */
exc = dom_node_get_next_sibling(child, &next_child);
if (exc != DOM_NO_ERR) {
dom_node_unref(child);
return NULL;
}
dom_node_unref(child);
child = next_child;
} while (child != NULL); /* No more children */
}
return NULL;
}
void
walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth)
{
dom_exception exc;
dom_node *child;
void *res = NULL;
dom_node_type typ;
/* Only interested in element nodes */
exc = dom_node_get_node_type(node, &typ);
if (typ != DOM_ELEMENT_NODE) {
return;
}
if (res = el_match_selector(selector, node)) {
dom_node *clone = NULL;
exc = dom_node_clone_node(res, false, &clone);
if (exc != DOM_NO_ERR || !clone) {
} else {
dom_node *result = NULL;
exc = dom_node_append_child(root, clone, &result);
}
if (exc != DOM_NO_ERR) {
return;
}
}
/* Get the node's first child */
exc = dom_node_get_first_child(node, &child);
if (exc != DOM_NO_ERR) {
return;
} else if (child != NULL) {
/* node has children; decend to children's depth */
depth++;
/* Loop though all node's children */
do {
dom_node *next_child;
/* Visit node's descendents */
walk_tree_query_append(root, child, selector, depth);
/* Go to next sibling */
exc = dom_node_get_next_sibling(child, &next_child);
if (exc != DOM_NO_ERR) {
dom_node_unref(child);
return;
}
dom_node_unref(child);
child = next_child;
} while (child != NULL); /* No more children */
}
}

View File

@ -40,6 +40,9 @@ void ecmascript_detach_form_view(struct form_view *fv);
void ecmascript_detach_form_state(struct form_state *fs);
void ecmascript_moved_form_state(struct form_state *fs);
void *walk_tree_query(dom_node *node, const char *selector, int depth);
void walk_tree_query_append(dom_node *root, dom_node *node, const char *selector, int depth);
extern struct module ecmascript_module;
#ifdef __cplusplus

View File

@ -39,6 +39,7 @@
#include "ecmascript/mujs/navigator.h"
#include "ecmascript/mujs/screen.h"
#include "ecmascript/mujs/unibar.h"
#include "ecmascript/mujs/url.h"
#include "ecmascript/mujs/window.h"
#include "ecmascript/mujs/xhr.h"
#include "intl/libintl.h"
@ -143,6 +144,7 @@ mujs_get_interpreter(struct ecmascript_interpreter *interpreter)
mjs_keyboardEvent_init(J);
mjs_messageEvent_init(J);
mjs_customEvent_init(J);
mjs_url_init(J);
return J;
#if 0

View File

@ -2,6 +2,6 @@ top_builddir=../../..
include $(top_builddir)/Makefile.config
OBJS = attr.o attributes.o collection.o console.o css.o customevent.o document.o element.o event.o form.o forms.o history.o implementation.o input.o \
keyboard.o localstorage.o location.o mapa.o message.o navigator.o nodelist.o screen.o style.o unibar.o window.o xhr.o
keyboard.o localstorage.o location.o mapa.o message.o navigator.o nodelist.o screen.o style.o unibar.o url.o window.o xhr.o
include $(top_srcdir)/Makefile.lib

View File

@ -28,6 +28,7 @@
#include "document/libdom/doc.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/mujs/mapa.h"
#include "ecmascript/libdom/parse.h"
#include "ecmascript/mujs.h"
@ -1337,36 +1338,29 @@ mjs_document_querySelector(js_State *J)
js_pushnull(J);
return;
}
// TODO
#if 0
xmlpp::Document *docu = (xmlpp::Document *)document->dom;
xmlpp::Element* root = (xmlpp::Element *)docu->get_root_node();
const char *str = js_tostring(J, 1);
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
if (!str) {
js_error(J, "!str");
return;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet elements;
try {
elements = root->find(xpath);
} catch (xmlpp::exception &e) {
if (exc != DOM_NO_ERR) {
js_pushnull(J);
return;
}
const char *selector = js_tostring(J, 1);
if (elements.size() == 0) {
if (!selector) {
dom_node_unref(root);
js_pushnull(J);
return;
}
auto node = elements[0];
mjs_push_element(J, node);
#endif
js_pushnull(J);
void *ret = walk_tree_query(root, selector, 0);
dom_node_unref(root);
if (!ret) {
js_pushnull(J);
return;
}
mjs_push_element(J, ret);
}
static void
@ -1383,33 +1377,51 @@ mjs_document_querySelectorAll(js_State *J)
js_pushnull(J);
return;
}
dom_node *doc_root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &doc_root);
// TODO
#if 0
xmlpp::Document *docu = (xmlpp::Document *)document->dom;
xmlpp::Element* root = (xmlpp::Element *)docu->get_root_node();
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "!str");
if (exc != DOM_NO_ERR) {
js_pushnull(J);
return;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet *elements = new(std::nothrow) xmlpp::Node::NodeSet;
const char *selector = js_tostring(J, 1);
if (!elements) {
if (!selector) {
dom_node_unref(doc_root);
js_pushnull(J);
return;
}
try {
*elements = root->find(xpath);
} catch (xmlpp::exception &e) {
dom_string *tag_name = NULL;
exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
if (exc != DOM_NO_ERR || !tag_name) {
dom_node_unref(doc_root);
js_pushnull(J);
return;
}
mjs_push_collection(J, elements);
#endif
js_pushnull(J);
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
dom_node_unref(doc_root);
js_pushnull(J);
return;
}
walk_tree_query_append((dom_node *)element, doc_root, selector, 0);
dom_node_unref(doc_root);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
js_pushnull(J);
return;
}
mjs_push_nodelist(J, nodes);
}
static void

View File

@ -24,10 +24,12 @@
#include "document/document.h"
#include "document/forms.h"
#include "document/libdom/corestrings.h"
#include "document/libdom/doc.h"
#include "document/libdom/mapa.h"
#include "document/libdom/renderer2.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/mujs/mapa.h"
#include "ecmascript/mujs.h"
#include "ecmascript/mujs/attr.h"
@ -2254,46 +2256,54 @@ mjs_element_closest(js_State *J)
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
// TODO
#if 0
xmlpp::Element *el = static_cast<xmlpp::Element *>(mjs_getprivate(J, 0));
dom_node *el = (dom_node *)(mjs_getprivate(J, 0));
void *res = NULL;
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!el) {
if (!document->dom) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
const char *selector = js_tostring(J, 1);
xmlpp::Node::NodeSet elements;
if (!selector) {
js_pushnull(J);
return;
}
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (exc != DOM_NO_ERR || !root) {
js_pushnull(J);
return;
}
if (elements.size() == 0) {
js_pushnull(J);
return;
}
while (el) {
res = el_match_selector(selector, el);
while (el)
{
for (auto node: elements)
{
if (isAncestor(el, node))
{
mjs_push_element(J, node);
return;
}
if (res) {
break;
}
el = el->get_parent();
if (el == root) {
break;
}
dom_node *node = NULL;
exc = dom_node_get_parent_node(el, &node);
if (exc != DOM_NO_ERR || !node) {
break;
}
el = node;
}
#endif
js_pushnull(J);
dom_node_unref(root);
if (!res) {
js_pushnull(J);
return;
}
mjs_push_element(J, res);
}
static void
@ -2656,35 +2666,21 @@ mjs_element_matches(js_State *J)
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
// TODO
#if 0
xmlpp::Element *el = static_cast<xmlpp::Element *>(mjs_getprivate(J, 0));
dom_node *el = (dom_node *)(mjs_getprivate(J, 0));
if (!el) {
js_pushboolean(J, 0);
return;
}
const char *str = js_tostring(J, 1);
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
const char *selector = js_tostring(J, 1);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (!selector) {
js_pushboolean(J, 0);
return;
}
void *res = el_match_selector(selector, el);
for (auto node: elements) {
if (node == el) {
js_pushboolean(J, 1);
return;
}
}
#endif
js_pushboolean(J, 0);
js_pushboolean(J, res);
}
static void
@ -2693,36 +2689,25 @@ mjs_element_querySelector(js_State *J)
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
// TODO
#if 0
xmlpp::Element *el = static_cast<xmlpp::Element *>(mjs_getprivate(J, 0));
dom_node *el = (dom_node *)(mjs_getprivate(J, 0));
if (!el) {
js_pushboolean(J, 0);
return;
}
const char *str = js_tostring(J, 1);
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
js_pushnull(J);
return;
}
const char *selector = js_tostring(J, 1);
for (auto node: elements)
{
if (isAncestor(el, node))
{
mjs_push_element(J, node);
return;
}
if (!selector) {
js_pushnull(J);
return;
}
#endif
js_pushnull(J);
void *ret = walk_tree_query(el, selector, 0);
if (!ret) {
js_pushnull(J);
return;
}
mjs_push_element(J, ret);
}
static void
@ -2731,38 +2716,52 @@ mjs_element_querySelectorAll(js_State *J)
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
// TODO
#if 0
xmlpp::Element *el = static_cast<xmlpp::Element *>(mjs_getprivate(J, 0));
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!el) {
js_pushboolean(J, 0);
return;
}
const char *str = js_tostring(J, 1);
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet elements;
xmlpp::Node::NodeSet *res = new(std::nothrow) xmlpp::Node::NodeSet;
if (!res) {
if (!document->dom) {
js_pushnull(J);
return;
}
dom_node *el = (dom_node *)(mjs_getprivate(J, 0));
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {}
for (auto node: elements)
{
if (isAncestor(el, node)) {
res->push_back(node);
}
if (!el) {
js_pushnull(J);
return;
}
mjs_push_collection(J, res);
#endif
js_pushnull(J);
const char *selector = js_tostring(J, 1);
if (!selector) {
js_pushnull(J);
return;
}
dom_string *tag_name = NULL;
dom_exception exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
if (exc != DOM_NO_ERR || !tag_name) {
js_pushnull(J);
return;
}
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
js_pushnull(J);
return;
}
walk_tree_query_append((dom_node *)element, el, selector, 0);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
js_pushnull(J);
return;
}
mjs_push_nodelist(J, nodes);
}
static void

View File

@ -1,2 +1,2 @@
srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'css.c', 'customevent.c', 'document.c', 'element.c', 'event.c', 'form.c', 'forms.c', 'history.c', 'implementation.c', 'input.c', 'keyboard.c',
'localstorage.c', 'location.c', 'mapa.c', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'window.c', 'xhr.c')
'localstorage.c', 'location.c', 'mapa.c', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'url.c', 'window.c', 'xhr.c')

606
src/ecmascript/mujs/url.c Normal file
View File

@ -0,0 +1,606 @@
/* The MuJS URL object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/mujs.h"
#include "ecmascript/mujs/url.h"
#include "protocol/uri.h"
struct eljs_url {
struct uri uri;
char *hash;
char *host;
char *pathname;
char *port;
char *protocol;
char *search;
};
static void
mjs_url_finalizer(js_State *J, void *val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)val;
if (url) {
done_uri(&url->uri);
mem_free_if(url->hash);
mem_free_if(url->host);
mem_free_if(url->pathname);
mem_free_if(url->port);
mem_free_if(url->protocol);
mem_free_if(url->search);
mem_free(url);
}
}
static void
mjs_url_get_property_hash(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
struct string fragment;
if (!init_string(&fragment)) {
js_error(J, "out of memory");
return;
}
if (url->uri.fragmentlen) {
add_bytes_to_string(&fragment, url->uri.fragment, url->uri.fragmentlen);
}
js_pushstring(J, fragment.source);
done_string(&fragment);
}
static void
mjs_url_get_property_host(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
char *str = get_uri_string(&url->uri, URI_HOST_PORT);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
js_error(J, "out of memory");
return;
}
js_pushstring(J, str);
mem_free(str);
}
static void
mjs_url_get_property_hostname(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
char *str = get_uri_string(&url->uri, URI_HOST);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
js_error(J, "out of memory");
return;
}
js_pushstring(J, str);
mem_free(str);
}
static void
mjs_url_get_property_href(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
char *str = get_uri_string(&url->uri, URI_ORIGINAL);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
js_error(J, "out of memory");
return;
}
js_pushstring(J, str);
mem_free(str);
}
static void
mjs_url_get_property_origin(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
char *str = get_uri_string(&url->uri, URI_SERVER);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
js_error(J, "out of memory");
return;
}
js_pushstring(J, str);
mem_free(str);
}
static void
mjs_url_get_property_pathname(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
struct string pathname;
if (!init_string(&pathname)) {
js_error(J, "out of memory");
return;
}
const char *query = (const char *)memchr(url->uri.data, '?', url->uri.datalen);
int len = (query ? query - url->uri.data : url->uri.datalen);
add_char_to_string(&pathname, '/');
add_bytes_to_string(&pathname, url->uri.data, len);
js_pushstring(J, pathname.source);
done_string(&pathname);
}
static void
mjs_url_get_property_port(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
struct string port;
if (!init_string(&port)) {
js_error(J, "out of memory");
return;
}
if (url->uri.portlen) {
add_bytes_to_string(&port, url->uri.port, url->uri.portlen);
}
js_pushstring(J, port.source);
done_string(&port);
}
static void
mjs_url_get_property_protocol(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
struct string proto;
if (!init_string(&proto)) {
js_error(J, "out of memory");
return;
}
/* Custom or unknown keep the URI untouched. */
if (url->uri.protocol == PROTOCOL_UNKNOWN) {
add_to_string(&proto, struri(&url->uri));
} else {
add_bytes_to_string(&proto, url->uri.string, url->uri.protocollen);
add_char_to_string(&proto, ':');
}
js_pushstring(J, proto.source);
done_string(&proto);
}
static void
mjs_url_get_property_search(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
struct string search;
if (!init_string(&search)) {
js_error(J, "out of memory");
return;
}
const char *query = (const char *)memchr(url->uri.data, '?', url->uri.datalen);
if (query) {
add_bytes_to_string(&search, query, strcspn(query, "#" POST_CHAR_S));
}
js_pushstring(J, search.source);
done_string(&search);
}
static void
mjs_url_set_property_hash(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *hash = stracpy(str);
mem_free_set(&url->hash, hash);
if (hash) {
url->uri.fragment = hash;
url->uri.fragmentlen = strlen(hash);
}
js_pushundefined(J);
}
static void
mjs_url_set_property_host(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *host = stracpy(str);
mem_free_set(&url->host, host);
if (host) {
url->uri.host = host;
url->uri.hostlen = strlen(str);
}
js_pushundefined(J);
}
static void
mjs_url_set_property_hostname(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *hostname = stracpy(str);
mem_free_set(&url->host, hostname);
if (hostname) {
url->uri.host = hostname;
url->uri.hostlen = strlen(hostname);
}
js_pushundefined(J);
}
static void
mjs_url_set_property_href(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
done_uri(&url->uri);
char *urlstring = stracpy(str);
if (!urlstring) {
js_error(J, "out of memory");
return;
}
int ret = parse_uri(&url->uri, urlstring);
if (ret != URI_ERRNO_OK) {
js_error(J, "error");
return;
}
js_pushundefined(J);
}
static void
mjs_url_set_property_pathname(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *pathname = stracpy(str);
mem_free_set(&url->pathname, pathname);
if (pathname) {
url->uri.data = pathname;
url->uri.datalen = strlen(pathname);
}
js_pushundefined(J);
}
static void
mjs_url_set_property_port(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *port = stracpy(str);
mem_free_set(&url->port, port);
if (port) {
url->uri.port = port;
url->uri.portlen = strlen(port);
}
js_pushundefined(J);
}
static inline int
get_protocol_length(const char *url)
{
char *end = (char *) url;
/* Seek the end of the protocol name if any. */
/* RFC1738:
* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
* (but per its recommendations we accept "upalpha" too) */
while (isalnum(*end) || *end == '+' || *end == '-' || *end == '.')
end++;
/* Now we make something to support our "IP version in protocol scheme
* name" hack and silently chop off the last digit if it's there. The
* IETF's not gonna notice I hope or it'd be going after us hard. */
if (end != url && isdigit(end[-1]))
end--;
/* Also return 0 if there's no protocol name (@end == @url). */
return (*end == ':' || isdigit(*end)) ? end - url : 0;
}
static void
mjs_url_set_property_protocol(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *protocol = stracpy(str);
mem_free_set(&url->protocol, protocol);
if (protocol) {
url->uri.protocollen = get_protocol_length(protocol);
/* Figure out whether the protocol is known */
url->uri.protocol = get_protocol(protocol, url->uri.protocollen);
}
js_pushundefined(J);
}
static void
mjs_url_set_property_search(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)js_touserdata(J, 0, "URL");
if (!url) {
js_pushnull(J);
return;
}
const char *str = js_tostring(J, 1);
if (!str) {
js_error(J, "out of memory");
return;
}
char *search = stracpy(str);
mem_free_set(&url->search, search);
if (search) {
// TODO
}
js_pushundefined(J);
}
static void
mjs_url_toString(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
mjs_url_get_property_href(J);
}
static void
mjs_url_fun(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
js_pushundefined(J);
}
static void
mjs_url_constructor(js_State *J)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
struct eljs_url *url = (struct eljs_url *)mem_calloc(1, sizeof(*url));
if (!url) {
js_error(J, "out of memory");
return;
}
const char *urlstring = js_tostring(J, 1);
if (!urlstring) {
js_error(J, "out of memory");
return;
}
int ret = parse_uri(&url->uri, urlstring);
if (ret != URI_ERRNO_OK) {
js_error(J, "error");
return;
}
js_newobject(J);
{
js_newuserdata(J, "URL", url, mjs_url_finalizer);
addmethod(J, "toString", mjs_url_toString, 0);
addproperty(J, "hash", mjs_url_get_property_hash, mjs_url_set_property_hash);
addproperty(J, "host", mjs_url_get_property_host, mjs_url_set_property_host);
addproperty(J, "hostname", mjs_url_get_property_hostname, mjs_url_set_property_hostname);
addproperty(J, "href", mjs_url_get_property_href, mjs_url_set_property_href);
addproperty(J, "origin", mjs_url_get_property_origin, NULL);
addproperty(J, "pathname", mjs_url_get_property_pathname, mjs_url_set_property_pathname);
addproperty(J, "port", mjs_url_get_property_port, mjs_url_set_property_port);
addproperty(J, "protocol", mjs_url_get_property_protocol, mjs_url_set_property_protocol);
addproperty(J, "search", mjs_url_get_property_search, mjs_url_set_property_search);
}
}
int
mjs_url_init(js_State *J)
{
js_pushglobal(J);
js_newcconstructor(J, mjs_url_fun, mjs_url_constructor, "URL", 0);
js_defglobal(J, "URL", JS_DONTENUM);
return 0;
}

16
src/ecmascript/mujs/url.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef EL__ECMASCRIPT_MUJS_URL_H
#define EL__ECMASCRIPT_MUJS_URL_H
#include <mujs.h>
#ifdef __cplusplus
extern "C" {
#endif
int mjs_url_init(js_State *J);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -40,6 +40,7 @@
#include "ecmascript/quickjs/navigator.h"
#include "ecmascript/quickjs/screen.h"
#include "ecmascript/quickjs/unibar.h"
#include "ecmascript/quickjs/url.h"
#include "ecmascript/quickjs/window.h"
#include "ecmascript/quickjs/xhr.h"
#include "intl/libintl.h"
@ -182,6 +183,7 @@ quickjs_get_interpreter(struct ecmascript_interpreter *interpreter)
js_keyboardEvent_init(ctx);
js_messageEvent_init(ctx);
js_customEvent_init(ctx);
js_url_init(ctx);
interpreter->document_obj = js_document_init(ctx);

View File

@ -2,6 +2,6 @@ top_builddir=../../..
include $(top_builddir)/Makefile.config
OBJS = attr.o attributes.o collection.o console.o css.o customevent.o document.o element.o event.o form.o forms.o heartbeat.o history.o implementation.o input.o \
keyboard.o localstorage.o location.o mapa.o message.o navigator.o nodelist.o screen.o style.o unibar.o window.o xhr.o
keyboard.o localstorage.o location.o mapa.o message.o navigator.o nodelist.o screen.o style.o unibar.o url.o window.o xhr.o
include $(top_srcdir)/Makefile.lib

View File

@ -21,6 +21,7 @@
#include "document/libdom/doc.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/libdom/parse.h"
#include "ecmascript/quickjs/mapa.h"
#include "ecmascript/quickjs.h"
@ -1475,7 +1476,6 @@ js_document_getElementsByTagName(JSContext *ctx, JSValueConst this_val, int argc
return JS_NULL;
}
JSValue rr = getNodeList(ctx, nodes);
JS_FreeValue(ctx, rr);
RETURN_JS(rr);
}
@ -1498,40 +1498,28 @@ js_document_querySelector(JSContext *ctx, JSValueConst this_val, int argc, JSVal
if (!document->dom) {
return JS_NULL;
}
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
// TODO
return JS_NULL;
#if 0
xmlpp::Document *docu = (xmlpp::Document *)document->dom;
xmlpp::Element* root = (xmlpp::Element *)docu->get_root_node();
const char *str;
if (exc != DOM_NO_ERR) {
return JS_NULL;
}
size_t len;
const char *selector = JS_ToCStringLen(ctx, &len, argv[0]);
str = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
}
xmlpp::ustring css = str;
JS_FreeCString(ctx, str);
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet elements;
try {
elements = root->find(xpath);
} catch (xmlpp::exception &e) {
if (!selector) {
dom_node_unref(root);
return JS_NULL;
}
void *ret = walk_tree_query(root, selector, 0);
JS_FreeCString(ctx, selector);
dom_node_unref(root);
if (elements.size() == 0) {
if (!ret) {
return JS_NULL;
}
auto node = elements[0];
return getElement(ctx, node);
#endif
return getElement(ctx, ret);
}
static JSValue
@ -1552,38 +1540,50 @@ js_document_querySelectorAll(JSContext *ctx, JSValueConst this_val, int argc, JS
if (!document->dom) {
return JS_NULL;
}
dom_node *doc_root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &doc_root);
// TODO
return JS_NULL;
#if 0
xmlpp::Document *docu = (xmlpp::Document *)document->dom;
xmlpp::Element* root = (xmlpp::Element *)docu->get_root_node();
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
if (exc != DOM_NO_ERR) {
return JS_NULL;
}
xmlpp::ustring css = str;
JS_FreeCString(ctx, str);
xmlpp::ustring xpath = css2xpath(css);
xmlpp::Node::NodeSet *elements = new(std::nothrow) xmlpp::Node::NodeSet;
size_t len;
const char *selector = JS_ToCStringLen(ctx, &len, argv[0]);
if (!elements) {
if (!selector) {
dom_node_unref(doc_root);
return JS_NULL;
}
try {
*elements = root->find(xpath);
} catch (xmlpp::exception &e) {
}
JSValue rr = getCollection(ctx, elements);
JS_FreeValue(ctx, rr);
dom_string *tag_name = NULL;
exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
RETURN_JS(rr);
#endif
if (exc != DOM_NO_ERR || !tag_name) {
dom_node_unref(doc_root);
JS_FreeCString(ctx, selector);
return JS_NULL;
}
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
dom_node_unref(doc_root);
JS_FreeCString(ctx, selector);
return JS_NULL;
}
walk_tree_query_append((dom_node *)element, doc_root, selector, 0);
dom_node_unref(doc_root);
JS_FreeCString(ctx, selector);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
return JS_NULL;
}
return getNodeList(ctx, nodes);
}
#if 0

View File

@ -22,6 +22,7 @@
#include "document/libdom/renderer2.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/quickjs/mapa.h"
#include "ecmascript/quickjs.h"
#include "ecmascript/quickjs/attr.h"
@ -241,7 +242,6 @@ js_element_get_property_children(JSContext *ctx, JSValueConst this_val)
return JS_NULL;
}
JSValue rr = getNodeList(ctx, nodes);
JS_FreeValue(ctx, rr);
RETURN_JS(rr);
}
@ -294,7 +294,6 @@ js_element_get_property_childNodes(JSContext *ctx, JSValueConst this_val)
return JS_NULL;
}
JSValue rr = getNodeList(ctx, nodes);
JS_FreeValue(ctx, rr);
RETURN_JS(rr);
}
@ -2293,56 +2292,59 @@ js_element_closest(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
// TODO
#if 0
REF_JS(this_val);
if (argc != 1) {
return JS_UNDEFINED;
}
xmlpp::Element *el = static_cast<xmlpp::Element *>(js_getopaque(this_val, js_element_class_id));
dom_node *el = (dom_node *)(js_getopaque(this_val, js_element_class_id));
void *res = NULL;
if (!el) {
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!document->dom) {
return JS_NULL;
}
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
const char *selector = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
if (!selector) {
return JS_NULL;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
JS_FreeCString(ctx, str);
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (exc != DOM_NO_ERR || !root) {
JS_FreeCString(ctx, selector);
return JS_NULL;
}
if (elements.size() == 0) {
return JS_NULL;
}
while (el) {
res = el_match_selector(selector, el);
while (el)
{
for (auto node: elements)
{
if (isAncestor(el, node))
{
return getElement(ctx, node);
}
if (res) {
break;
}
el = el->get_parent();
if (el == root) {
break;
}
dom_node *node = NULL;
exc = dom_node_get_parent_node(el, &node);
if (exc != DOM_NO_ERR || !node) {
break;
}
el = node;
}
#endif
return JS_NULL;
JS_FreeCString(ctx, selector);
dom_node_unref(root);
if (!res) {
return JS_NULL;
}
return getElement(ctx, res);
}
static JSValue
@ -2555,7 +2557,6 @@ js_element_getElementsByTagName(JSContext *ctx, JSValueConst this_val, int argc,
return JS_NULL;
}
JSValue rr = getNodeList(ctx, nlist);
JS_FreeValue(ctx, rr);
RETURN_JS(rr);
}
@ -2786,44 +2787,25 @@ js_element_matches(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
// TODO
#if 0
if (argc != 1) {
return JS_UNDEFINED;
}
xmlpp::Element *el = static_cast<xmlpp::Element *>(js_getopaque(this_val, js_element_class_id));
dom_node *el = (dom_node *)(js_getopaque(this_val, js_element_class_id));
if (!el) {
return JS_FALSE;
}
const char *str;
const char *selector;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
selector = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
JS_FreeCString(ctx, str);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (!selector) {
return JS_FALSE;
}
void *res = el_match_selector(selector, el);
JS_FreeCString(ctx, selector);
for (auto node: elements) {
if (node == el) {
return JS_TRUE;
}
}
#endif
return JS_FALSE;
return JS_NewBool(ctx, res);
}
static JSValue
@ -2834,45 +2816,31 @@ js_element_querySelector(JSContext *ctx, JSValueConst this_val, int argc, JSValu
#endif
REF_JS(this_val);
// TODO
#if 0
if (argc != 1) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return JS_UNDEFINED;
}
xmlpp::Element *el = static_cast<xmlpp::Element *>(js_getopaque(this_val, js_element_class_id));
dom_node *el = (dom_node *)(js_getopaque(this_val, js_element_class_id));
if (!el) {
return JS_FALSE;
return JS_NULL;
}
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
const char *selector = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
if (!selector) {
return JS_NULL;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
void *ret = walk_tree_query(el, selector, 0);
JS_FreeCString(ctx, selector);
JS_FreeCString(ctx, str);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (!ret) {
return JS_NULL;
}
for (auto node: elements)
{
if (isAncestor(el, node))
{
return getElement(ctx, node);
}
}
#endif
return JS_NULL;
return getElement(ctx, ret);
}
static JSValue
@ -2882,50 +2850,54 @@ js_element_querySelectorAll(JSContext *ctx, JSValueConst this_val, int argc, JSV
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
// TODO
#if 0
if (argc != 1) {
return JS_FALSE;
}
xmlpp::Element *el = static_cast<xmlpp::Element *>(js_getopaque(this_val, js_element_class_id));
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!el) {
return JS_FALSE;
}
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
return JS_EXCEPTION;
}
xmlpp::ustring css = str;
xmlpp::ustring xpath = css2xpath(css);
JS_FreeCString(ctx, str);
xmlpp::Node::NodeSet elements;
xmlpp::Node::NodeSet *res = new(std::nothrow) xmlpp::Node::NodeSet;
if (!res) {
if (!document->dom) {
return JS_NULL;
}
dom_node *el = (dom_node *)(js_getopaque(this_val, js_element_class_id));
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {}
for (auto node: elements)
{
if (isAncestor(el, node)) {
res->push_back(node);
}
if (!el) {
return JS_NULL;
}
JSValue rr = getCollection(ctx, res);
JS_FreeValue(ctx, rr);
size_t len;
const char *selector = JS_ToCStringLen(ctx, &len, argv[0]);
RETURN_JS(rr);
#endif
return JS_FALSE;
if (!selector) {
return JS_NULL;
}
dom_string *tag_name = NULL;
dom_exception exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
if (exc != DOM_NO_ERR || !tag_name) {
JS_FreeCString(ctx, selector);
return JS_NULL;
}
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
JS_FreeCString(ctx, selector);
return JS_NULL;
}
walk_tree_query_append((dom_node *)element, el, selector, 0);
JS_FreeCString(ctx, selector);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
return JS_NULL;
}
return getNodeList(ctx, nodes);
}
static JSValue

View File

@ -1,3 +1,3 @@
srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'css.c', 'customevent.c', 'document.c', 'element.c', 'event.c', 'form.c', 'forms.c', 'heartbeat.c', 'history.c',
'implementation.c', 'input.c', 'keyboard.c', 'localstorage.c', 'location.c',
'mapa.c', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'window.c', 'xhr.c')
'mapa.c', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'style.c', 'unibar.c', 'url.c', 'window.c', 'xhr.c')

View File

@ -24,6 +24,8 @@
#define countof(x) (sizeof(x) / sizeof((x)[0]))
static JSClassID js_nodelist_class_id;
void *map_nodelist;
void *map_rev_nodelist;
@ -50,6 +52,30 @@ js_nodeList_SetOpaque(JSValueConst this_val, void *node)
}
}
static JSValue
js_nodeList_get_property_length(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
dom_nodelist *nl = (dom_nodelist *)(js_nodeList_GetOpaque(this_val));
dom_exception err;
uint32_t size;
if (!nl) {
return JS_NewInt32(ctx, 0);
}
err = dom_nodelist_get_length(nl, &size);
if (err != DOM_NO_ERR) {
return JS_NewInt32(ctx, 0);
}
return JS_NewInt32(ctx, size);
}
static JSValue
js_nodeList_item2(JSContext *ctx, JSValueConst this_val, int idx)
{
@ -146,24 +172,36 @@ js_nodeList_toString(JSContext *ctx, JSValueConst this_val, int argc, JSValueCon
}
static const JSCFunctionListEntry js_nodeList_proto_funcs[] = {
// JS_CGETSET_DEF("length", js_nodeList_get_property_length, nullptr),
// JS_CGETSET_DEF("length", js_nodeList_get_property_length, NULL),
JS_CFUNC_DEF("item", 1, js_nodeList_item),
JS_CFUNC_DEF("toString", 0, js_nodeList_toString)
};
static JSClassDef js_nodelist_class = {
"nodelist",
};
JSValue
getNodeList(JSContext *ctx, void *node)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JSValue nodeList_obj = JS_NewArray(ctx);
JS_SetPropertyFunctionList(ctx, nodeList_obj, js_nodeList_proto_funcs, countof(js_nodeList_proto_funcs));
JSValue proto;
attr_save_in_map(map_nodelist, node, nodeList_obj);
js_nodeList_SetOpaque(nodeList_obj, node);
js_nodeList_set_items(ctx, nodeList_obj, node);
JSValue rr = JS_DupValue(ctx, nodeList_obj);
/* nodelist class */
JS_NewClassID(&js_nodelist_class_id);
JS_NewClass(JS_GetRuntime(ctx), js_nodelist_class_id, &js_nodelist_class);
proto = JS_NewArray(ctx);
REF_JS(proto);
JS_SetPropertyFunctionList(ctx, proto, js_nodeList_proto_funcs, countof(js_nodeList_proto_funcs));
JS_SetClassProto(ctx, js_nodelist_class_id, proto);
attr_save_in_map(map_nodelist, node, proto);
js_nodeList_SetOpaque(proto, node);
js_nodeList_set_items(ctx, proto, node);
JSValue rr = JS_DupValue(ctx, proto);
RETURN_JS(rr);
}

View File

@ -0,0 +1,745 @@
/* The QuickJS URL object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/quickjs.h"
#include "ecmascript/quickjs/url.h"
#include "ecmascript/timer.h"
#include "intl/libintl.h"
#include "main/select.h"
#include "main/timer.h"
#include "network/connection.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/download.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
#define countof(x) (sizeof(x) / sizeof((x)[0]))
static JSClassID js_url_class_id;
struct eljs_url {
struct uri uri;
char *hash;
char *host;
char *pathname;
char *port;
char *protocol;
char *search;
};
static
void js_url_finalizer(JSRuntime *rt, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(val);
struct eljs_url *url = (struct eljs_url *)JS_GetOpaque(val, js_url_class_id);
if (url) {
done_uri(&url->uri);
mem_free_if(url->hash);
mem_free_if(url->host);
mem_free_if(url->pathname);
mem_free_if(url->port);
mem_free_if(url->protocol);
mem_free_if(url->search);
mem_free(url);
}
}
static JSValue
js_url_get_property_hash(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
struct string fragment;
if (!init_string(&fragment)) {
return JS_EXCEPTION;
}
if (url->uri.fragmentlen) {
add_bytes_to_string(&fragment, url->uri.fragment, url->uri.fragmentlen);
}
JSValue ret = JS_NewStringLen(ctx, fragment.source, fragment.length);
done_string(&fragment);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_host(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
char *str = get_uri_string(&url->uri, URI_HOST_PORT);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return JS_NULL;
}
JSValue ret = JS_NewString(ctx, str);
mem_free(str);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_hostname(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
char *str = get_uri_string(&url->uri, URI_HOST);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return JS_NULL;
}
JSValue ret = JS_NewString(ctx, str);
mem_free(str);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_href(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
char *str = get_uri_string(&url->uri, URI_ORIGINAL);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return JS_NULL;
}
JSValue ret = JS_NewString(ctx, str);
mem_free(str);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_origin(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
char *str = get_uri_string(&url->uri, URI_SERVER);
if (!str) {
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__);
#endif
return JS_NULL;
}
JSValue ret = JS_NewString(ctx, str);
mem_free(str);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_pathname(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
struct string pathname;
if (!init_string(&pathname)) {
return JS_NULL;
}
const char *query = (const char *)memchr(url->uri.data, '?', url->uri.datalen);
int len = (query ? query - url->uri.data : url->uri.datalen);
add_char_to_string(&pathname, '/');
add_bytes_to_string(&pathname, url->uri.data, len);
JSValue ret = JS_NewStringLen(ctx, pathname.source, pathname.length);
done_string(&pathname);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_port(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
struct string port;
if (!init_string(&port)) {
return JS_NULL;
}
if (url->uri.portlen) {
add_bytes_to_string(&port, url->uri.port, url->uri.portlen);
}
JSValue ret = JS_NewStringLen(ctx, port.source, port.length);
done_string(&port);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_protocol(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
struct string proto;
if (!init_string(&proto)) {
return JS_NULL;
}
/* Custom or unknown keep the URI untouched. */
if (url->uri.protocol == PROTOCOL_UNKNOWN) {
add_to_string(&proto, struri(&url->uri));
} else {
add_bytes_to_string(&proto, url->uri.string, url->uri.protocollen);
add_char_to_string(&proto, ':');
}
JSValue ret = JS_NewStringLen(ctx, proto.source, proto.length);
done_string(&proto);
RETURN_JS(ret);
}
static JSValue
js_url_get_property_search(JSContext *ctx, JSValueConst this_val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
struct string search;
if (!init_string(&search)) {
return JS_NULL;
}
const char *query = (const char *)memchr(url->uri.data, '?', url->uri.datalen);
if (query) {
add_bytes_to_string(&search, query, strcspn(query, "#" POST_CHAR_S));
}
JSValue ret = JS_NewStringLen(ctx, search.source, search.length);
done_string(&search);
RETURN_JS(ret);
}
static JSValue
js_url_set_property_hash(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *hash = memacpy(str, len);
mem_free_set(&url->hash, hash);
if (hash) {
url->uri.fragment = hash;
url->uri.fragmentlen = len;
}
JS_FreeCString(ctx, str);
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_host(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *host = memacpy(str, len);
mem_free_set(&url->host, host);
if (host) {
url->uri.host = host;
url->uri.hostlen = len;
}
JS_FreeCString(ctx, str);
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_hostname(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *hostname = memacpy(str, len);
mem_free_set(&url->host, hostname);
if (hostname) {
url->uri.host = hostname;
url->uri.hostlen = len;
}
JS_FreeCString(ctx, str);
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_href(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
done_uri(&url->uri);
char *urlstring = memacpy(str, len);
JS_FreeCString(ctx, str);
if (!urlstring) {
return JS_EXCEPTION;
}
int ret = parse_uri(&url->uri, urlstring);
if (ret != URI_ERRNO_OK) {
return JS_EXCEPTION;
}
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_pathname(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *pathname = memacpy(str, len);
JS_FreeCString(ctx, str);
mem_free_set(&url->pathname, pathname);
if (pathname) {
url->uri.data = pathname;
url->uri.datalen = len;
}
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_port(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *port = memacpy(str, len);
JS_FreeCString(ctx, str);
mem_free_set(&url->port, port);
if (port) {
url->uri.port = port;
url->uri.portlen = strlen(port);
}
return JS_UNDEFINED;
}
static inline int
get_protocol_length(const char *url)
{
char *end = (char *) url;
/* Seek the end of the protocol name if any. */
/* RFC1738:
* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ]
* (but per its recommendations we accept "upalpha" too) */
while (isalnum(*end) || *end == '+' || *end == '-' || *end == '.')
end++;
/* Now we make something to support our "IP version in protocol scheme
* name" hack and silently chop off the last digit if it's there. The
* IETF's not gonna notice I hope or it'd be going after us hard. */
if (end != url && isdigit(end[-1]))
end--;
/* Also return 0 if there's no protocol name (@end == @url). */
return (*end == ':' || isdigit(*end)) ? end - url : 0;
}
static JSValue
js_url_set_property_protocol(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *protocol = memacpy(str, len);
JS_FreeCString(ctx, str);
mem_free_set(&url->protocol, protocol);
if (protocol) {
url->uri.protocollen = get_protocol_length(protocol);
/* Figure out whether the protocol is known */
url->uri.protocol = get_protocol(protocol, url->uri.protocollen);
}
return JS_UNDEFINED;
}
static JSValue
js_url_set_property_search(JSContext *ctx, JSValueConst this_val, JSValue val)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
struct eljs_url *url = (struct eljs_url *)(JS_GetOpaque(this_val, js_url_class_id));
if (!url) {
return JS_NULL;
}
size_t len;
const char *str = JS_ToCStringLen(ctx, &len, val);
if (!str) {
return JS_EXCEPTION;
}
char *search = memacpy(str, len);
JS_FreeCString(ctx, str);
mem_free_set(&url->search, search);
if (search) {
// TODO
}
return JS_UNDEFINED;
}
static JSValue
js_url_toString(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(this_val);
return js_url_get_property_href(ctx, this_val);
}
static JSClassDef js_url_class = {
"URL",
js_url_finalizer
};
static const JSCFunctionListEntry js_url_proto_funcs[] = {
JS_CGETSET_DEF("hash", js_url_get_property_hash, js_url_set_property_hash),
JS_CGETSET_DEF("host", js_url_get_property_host, js_url_set_property_host),
JS_CGETSET_DEF("hostname", js_url_get_property_hostname, js_url_set_property_hostname),
JS_CGETSET_DEF("href", js_url_get_property_href, js_url_set_property_href),
JS_CGETSET_DEF("origin", js_url_get_property_origin, NULL),
JS_CGETSET_DEF("pathname", js_url_get_property_pathname, js_url_set_property_pathname),
JS_CGETSET_DEF("port", js_url_get_property_port, js_url_set_property_port),
JS_CGETSET_DEF("protocol", js_url_get_property_protocol, js_url_set_property_protocol),
JS_CGETSET_DEF("search", js_url_get_property_search, js_url_set_property_search),
JS_CFUNC_DEF("toString", 0, js_url_toString),
};
static JSValue
js_url_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
REF_JS(new_target);
JSValue obj = JS_NewObjectClass(ctx, js_url_class_id);
REF_JS(obj);
if (JS_IsException(obj)) {
return obj;
}
struct eljs_url *url = (struct eljs_url *)mem_calloc(1, sizeof(*url));
if (!url) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
if (argc > 0) {
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
char *urlstring = memacpy(str, len);
JS_FreeCString(ctx, str);
if (!urlstring) {
return JS_EXCEPTION;
}
int ret = parse_uri(&url->uri, urlstring);
if (ret != URI_ERRNO_OK) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
}
JS_SetOpaque(obj, url);
return obj;
}
static void
JS_NewGlobalCConstructor2(JSContext *ctx, JSValue func_obj, const char *name, JSValueConst proto)
{
REF_JS(func_obj);
REF_JS(proto);
JSValue global_object = JS_GetGlobalObject(ctx);
JS_DefinePropertyValueStr(ctx, global_object, name,
JS_DupValue(ctx, func_obj), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
JS_SetConstructor(ctx, func_obj, proto);
JS_FreeValue(ctx, func_obj);
JS_FreeValue(ctx, global_object);
}
static JSValueConst
JS_NewGlobalCConstructor(JSContext *ctx, const char *name, JSCFunction *func, int length, JSValueConst proto)
{
JSValue func_obj;
func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
REF_JS(func_obj);
REF_JS(proto);
JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
return func_obj;
}
int
js_url_init(JSContext *ctx)
{
#ifdef ECMASCRIPT_DEBUG
fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__);
#endif
JSValue proto, obj;
/* url class */
JS_NewClassID(&js_url_class_id);
JS_NewClass(JS_GetRuntime(ctx), js_url_class_id, &js_url_class);
proto = JS_NewObject(ctx);
REF_JS(proto);
JS_SetPropertyFunctionList(ctx, proto, js_url_proto_funcs, countof(js_url_proto_funcs));
JS_SetClassProto(ctx, js_url_class_id, proto);
/* url object */
obj = JS_NewGlobalCConstructor(ctx, "URL", js_url_constructor, 1, proto);
REF_JS(obj);
return 0;
}

View File

@ -0,0 +1,16 @@
#ifndef EL__ECMASCRIPT_QUICKJS_URL_H
#define EL__ECMASCRIPT_QUICKJS_URL_H
#include <quickjs/quickjs.h>
#ifdef __cplusplus
extern "C" {
#endif
int js_url_init(JSContext *ctx);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -28,6 +28,7 @@
#include "document/view.h"
#include "ecmascript/css2xpath.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/libdom/parse.h"
#include "ecmascript/spidermonkey/collection.h"
#include "ecmascript/spidermonkey/form.h"
@ -1561,7 +1562,7 @@ document_createElement(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setBoolean(false);
return true;
}
// TODO
JS::Realm *comp = js::GetContextRealm(ctx);
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
struct document_view *doc_view = interpreter->vs->doc_view;
@ -1841,8 +1842,31 @@ document_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setNull();
return true;
}
// TODO
args.rval().setNull();
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
if (exc != DOM_NO_ERR) {
args.rval().setNull();
return true;
}
char *selector = jsval_to_string(ctx, args[0]);
if (!selector) {
dom_node_unref(root);
args.rval().setNull();
return true;
}
void *ret = walk_tree_query(root, selector, 0);
mem_free(selector);
dom_node_unref(root);
if (!ret) {
args.rval().setNull();
} else {
JSObject *el = getElement(ctx, ret);
args.rval().setObject(*el);
}
return true;
}
@ -1859,7 +1883,6 @@ document_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setBoolean(false);
return true;
}
JS::Realm *comp = js::GetContextRealm(ctx);
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
struct document_view *doc_view = interpreter->vs->doc_view;
@ -1869,8 +1892,55 @@ document_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp)
args.rval().setNull();
return true;
}
// TODO
args.rval().setNull();
dom_node *doc_root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &doc_root);
if (exc != DOM_NO_ERR) {
args.rval().setNull();
return true;
}
char *selector = jsval_to_string(ctx, args[0]);
if (!selector) {
dom_node_unref(doc_root);
args.rval().setNull();
return true;
}
dom_string *tag_name = NULL;
exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
if (exc != DOM_NO_ERR || !tag_name) {
dom_node_unref(doc_root);
mem_free(selector);
args.rval().setNull();
return true;
}
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
dom_node_unref(doc_root);
mem_free(selector);
args.rval().setNull();
return true;
}
walk_tree_query_append((dom_node *)element, doc_root, selector, 0);
dom_node_unref(doc_root);
mem_free(selector);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
args.rval().setNull();
return true;
}
JSObject *obj = getNodeList(ctx, nodes);
args.rval().setObject(*obj);
return true;
}

View File

@ -24,10 +24,12 @@
#include "document/document.h"
#include "document/forms.h"
#include "document/libdom/corestrings.h"
#include "document/libdom/doc.h"
#include "document/libdom/mapa.h"
#include "document/libdom/renderer2.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/ecmascript-c.h"
#include "ecmascript/spidermonkey/attr.h"
#include "ecmascript/spidermonkey/attributes.h"
#include "ecmascript/spidermonkey/collection.h"
@ -4023,56 +4025,59 @@ element_closest(JSContext *ctx, unsigned int argc, JS::Value *vp)
#endif
return false;
}
// TODO
#if 0
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
if (!el) {
char *selector = jsval_to_string(ctx, args[0]);
if (!selector) {
args.rval().setNull();
return true;
}
struct string cssstr;
if (!init_string(&cssstr)) {
return false;
}
jshandle_value_to_char_string(&cssstr, ctx, args[0]);
xmlpp::ustring css = cssstr.source;
xmlpp::ustring xpath = css2xpath(css);
done_string(&cssstr);
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
void *res = NULL;
xmlpp::Node::NodeSet elements;
JS::Realm *comp = js::GetContextRealm(ctx);
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (!document->dom) {
args.rval().setNull();
return true;
}
dom_node *root = NULL; /* root element of document */
/* Get root element */
dom_exception exc = dom_document_get_document_element(document->dom, &root);
if (elements.size() == 0) {
if (exc != DOM_NO_ERR || !root) {
args.rval().setNull();
return true;
}
while (el)
{
for (auto node: elements)
{
if (isAncestor(el, static_cast<xmlpp::Element *>(node)))
{
JSObject *elem = getElement(ctx, node);
args.rval().setObject(*elem);
while (el) {
res = el_match_selector(selector, el);
return true;
}
if (res) {
break;
}
el = el->get_parent();
if (el == root) {
break;
}
dom_node *node = NULL;
exc = dom_node_get_parent_node(el, &node);
if (exc != DOM_NO_ERR || !node) {
break;
}
el = node;
}
args.rval().setNull();
#endif
mem_free(selector);
dom_node_unref(root);
if (!res) {
args.rval().setNull();
return true;
}
JSObject *ret = getElement(ctx, res);
args.rval().setObject(*ret);
return true;
}
@ -4676,45 +4681,25 @@ element_matches(JSContext *ctx, unsigned int argc, JS::Value *vp)
#endif
return false;
}
// TODO
#if 0
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
if (!el) {
args.rval().setBoolean(false);
return true;
}
char *selector = jsval_to_string(ctx, args[0]);
struct string cssstr;
if (!init_string(&cssstr)) {
return false;
}
jshandle_value_to_char_string(&cssstr, ctx, args[0]);
xmlpp::ustring css = cssstr.source;
xmlpp::ustring xpath = css2xpath(css);
done_string(&cssstr);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
if (!selector) {
args.rval().setBoolean(false);
return true;
}
for (auto node: elements) {
if (node == el) {
args.rval().setBoolean(true);
return true;
}
}
args.rval().setBoolean(false);
#endif
void *res = el_match_selector(selector, el);
mem_free(selector);
args.rval().setBoolean(res);
return true;
}
static bool
element_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp)
{
@ -4735,48 +4720,28 @@ element_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp)
#endif
return false;
}
// TODO
#if 0
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
if (!el) {
args.rval().setBoolean(false);
return true;
}
struct string cssstr;
if (!init_string(&cssstr)) {
return false;
}
jshandle_value_to_char_string(&cssstr, ctx, args[0]);
xmlpp::ustring css = cssstr.source;
xmlpp::ustring xpath = css2xpath(css);
done_string(&cssstr);
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {
args.rval().setNull();
return true;
}
char *selector = jsval_to_string(ctx, args[0]);
for (auto node: elements)
{
if (isAncestor(el, static_cast<xmlpp::Element *>(node)))
{
JSObject *elem = getElement(ctx, node);
if (elem) {
args.rval().setObject(*elem);
return true;
}
}
if (!selector) {
args.rval().setNull();
return true;
}
args.rval().setNull();
#endif
void *ret = walk_tree_query(el, selector, 0);
mem_free(selector);
if (!ret) {
args.rval().setNull();
} else {
JSObject *el = getElement(ctx, ret);
args.rval().setObject(*el);
}
return true;
}
@ -4800,50 +4765,58 @@ element_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp)
#endif
return false;
}
// TODO
#if 0
xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot<xmlpp::Element>(hobj, 0);
JS::Realm *comp = js::GetContextRealm(ctx);
struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp);
struct document_view *doc_view = interpreter->vs->doc_view;
struct document *document = doc_view->document;
if (!el) {
args.rval().setBoolean(false);
if (!document->dom) {
args.rval().setNull();
return true;
}
dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot<dom_node>(hobj, 0);
struct string cssstr;
if (!init_string(&cssstr)) {
return false;
}
jshandle_value_to_char_string(&cssstr, ctx, args[0]);
xmlpp::ustring css = cssstr.source;
xmlpp::ustring xpath = css2xpath(css);
done_string(&cssstr);
xmlpp::Node::NodeSet *res = new(std::nothrow) xmlpp::Node::NodeSet;
if (!res) {
return false;
}
xmlpp::Node::NodeSet elements;
try {
elements = el->find(xpath);
} catch (xmlpp::exception &e) {}
for (auto node : elements)
{
if (isAncestor(el, static_cast<xmlpp::Element *>(node))) {
res->push_back(node);
}
}
JSObject *elem = getCollection(ctx, res);
if (elem) {
args.rval().setObject(*elem);
} else {
if (!el) {
args.rval().setNull();
return true;
}
#endif
char *selector = jsval_to_string(ctx, args[0]);
if (!selector) {
args.rval().setNull();
return true;
}
dom_string *tag_name = NULL;
dom_exception exc = dom_string_create((const uint8_t *)"B", 1, &tag_name);
if (exc != DOM_NO_ERR || !tag_name) {
mem_free(selector);
args.rval().setNull();
return true;
}
dom_element *element = NULL;
exc = dom_document_create_element(document->dom, tag_name, &element);
dom_string_unref(tag_name);
if (exc != DOM_NO_ERR || !element) {
mem_free(selector);
args.rval().setNull();
return true;
}
walk_tree_query_append((dom_node *)element, el, selector, 0);
mem_free(selector);
dom_nodelist *nodes = NULL;
exc = dom_node_get_child_nodes(element, &nodes);
dom_node_unref(element);
if (exc != DOM_NO_ERR || !nodes) {
args.rval().setNull();
return true;
}
JSObject *obj = getNodeList(ctx, nodes);
args.rval().setObject(*obj);
return true;
}

View File

@ -82,7 +82,7 @@ JSClassOps nodeList_ops = {
JSClass nodeList_class = {
"nodeList",
JSCLASS_HAS_RESERVED_SLOTS(1),
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
&nodeList_ops
};

View File

@ -506,7 +506,7 @@ int
init_interlink(void)
{
int pipefds[2];
char trigger;
char trigger = 0;
ssize_t n;
int fd = connect_to_af_unix();

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<body>
<p class="a">Class a.</p>
<p class="b">Class b.</p>
<script>
function myFunction() {
var x = document.querySelector('.nonexistent');
console.assert(x === null, 'nonexistent element');
var y = document.querySelector('.b');
console.assert(!(y === null), 'Class b');
var inp = y.innerHTML;
console.assert(inp === 'Class b.', 'Class b.');
}
console.error('document.querySelector.html');
myFunction();
console.exit(0);
</script>
</body>
</html>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<body>
<p class="a">Class a.</p>
<p class="b">Class b.</p>
<script>
function myFunction() {
var x = document.querySelectorAll('.nonexistent');
console.assert(x.length === 0, 'nonexistent elements');
var y = document.querySelectorAll('p');
console.assert(y.length == 2, 'Two p');
}
console.error('document.querySelectorAll.html');
myFunction();
console.exit(0);
</script>
</body>
</html>

View File

@ -10,11 +10,16 @@
<script>
var element = document.getElementById("myElement");
var closest = element.closest(".container");
var closes2 = element.closest("div.container");
console.error('element.closest.html');
console.assert(closest.outerHTML === '<DIV class="demo container">Parent\n <DIV id="myElement" class="demo">The outer HTML of closest element will be shown.</DIV>\n </DIV>', 'TODO');
console.exit(1);
console.assert(closes2, 'not null');
//console.assert(closes2.outerHTML === '<DIV class="demo container">Parent\n <DIV id="myElement" class="demo">The outer HTML of closest element will be shown.</DIV>\n </DIV>', 'TODO');
closes2 = element.closest("p.test");
console.assert(closes2 === null, 'NULL');
console.exit(0);
</script>
</body>

View File

@ -6,15 +6,27 @@
<script type="text/javascript">
console.error('element.matches');
console.error('element.matches.html');
var birds = document.getElementsByTagName('li');
var ch = false;
console.assert(birds.length === 3, '3');
for (var i = 0; i < birds.length; i++) {
if (birds[i].matches('.endangered')) {
console.assert(birds[i].textContent === 'Philippine eagle', 'endangered');
if (birds.item(i).matches('.endangered')) {
console.assert(birds.item(i).innerHTML === 'Philippine eagle', birds.item(i).innerHTML);
ch = true;
}
}
console.assert(ch, 'was matched');
// birds = document.querySelectorAll('li');
ch = false;
// var counter = 0;
// birds.forEach(function(b) {
// counter++;
// });
// console.assert(counter === 3, 'Three');
console.exit(0);

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<body>
<p class="a">Class a.</p>
<p class="b">Class b.</p>
<p id="start">
<b class="a">This a class.</b>
<b class="b">This b class.</b>
</p>
<script>
function myFunction() {
var el = document.getElementById('start');
console.assert(!(el === null), 'start exists');
var x = el.querySelector('.nonexistent');
console.assert(x === null, 'nonexistent element');
var y = el.querySelector('.b');
console.assert(!(y === null), 'Class b');
var inp = y.innerHTML;
console.assert(inp === 'This b class.', 'Class b.');
}
console.error('element.querySelector.html');
myFunction();
console.exit(0);
</script>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<body>
<p class="a">Class a.</p>
<p class="b">Class b.</p>
<p id="start">
<b class="a">This a class.</b>
<b class="b">This b class.</b>
</p>
<script>
function myFunction() {
var el = document.getElementById('start');
var x = el.querySelectorAll('.nonexistent');
console.assert(x.length === 0, 'nonexistent element');
var y = el.querySelectorAll('.b');
console.assert(y.length === 1, 'b class b.');
}
console.error('element.querySelectorAll.html');
myFunction();
console.exit(0);
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
<ul id="birds">
<li>Orange-winged parrot</li>
<li class="endangered">Philippine eagle</li>
<li>Great white pelican</li>
</ul>
<script type="text/javascript">
console.error('nodelist.forEach.html');
var birds = document.querySelectorAll('li');
var counter = 0;
birds.forEach(function(b) {
counter++;
});
console.assert(counter === 3, 'Three');
console.exit(0);
</script>