/* The QuickJS document object implementation. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifdef CONFIG_LIBDOM #include #include #endif #include "elinks.h" #include "cookies/cookies.h" #include "dialogs/status.h" #include "document/document.h" #include "document/libdom/doc.h" #include "document/libdom/mapa.h" #include "document/view.h" #include "js/ecmascript.h" #include "js/ecmascript-c.h" #include "js/libdom/parse.h" #include "js/quickjs/mapa.h" #include "js/quickjs.h" #include "js/quickjs/collection.h" #include "js/quickjs/event.h" #include "js/quickjs/form.h" #include "js/quickjs/forms.h" #include "js/quickjs/fragment.h" #include "js/quickjs/implementation.h" #include "js/quickjs/location.h" #include "js/quickjs/document.h" #include "js/quickjs/element.h" #include "js/quickjs/nodelist.h" #include "js/quickjs/nodelist2.h" #include "js/quickjs/text.h" #include "js/quickjs/window.h" #include "session/session.h" #include "viewer/text/vs.h" #define countof(x) (sizeof(x) / sizeof((x)[0])) static JSClassID js_doctype_class_id; static JSClassID js_document_class_id; struct document_listener { LIST_HEAD_EL(struct document_listener); char *typ; JSValue fun; }; enum readyState { LOADING = 0, INTERACTIVE, COMPLETE }; struct js_document_private { LIST_OF(struct document_listener) listeners; struct ecmascript_interpreter *interpreter; JSValue thisval; dom_event_listener *listener; void *node; enum readyState state; }; static void document_event_handler(dom_event *event, void *pw); void * js_doc_getopaque(JSValueConst obj) { REF_JS(obj); struct js_document_private *res = (struct js_document_private *)JS_GetOpaque(obj, js_document_class_id); if (!res) { return NULL; } return res->node; } void * document_get_node(JSValueConst obj) { return js_doc_getopaque(obj); } static void js_document_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(val); struct js_document_private *doc_private = (struct js_document_private *)JS_GetOpaque(val, js_document_class_id); if (doc_private) { struct document_listener *l; foreach(l, doc_private->listeners) { JS_MarkValue(rt, l->fun, mark_func); } } } static JSValue js_document_get_property_anchors(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_collection *anchors = NULL; dom_exception exc = dom_html_document_get_anchors(doc, &anchors); if (exc != DOM_NO_ERR || !anchors) { //dom_node_unref(doc); return JS_NULL; } JSValue rr = getCollection(ctx, anchors); //dom_node_unref(doc); RETURN_JS(rr); } static JSValue js_document_get_property_baseURI(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct view_state *vs; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } char *str = get_uri_string(vs->uri, URI_BASE); 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_document_get_property_body(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_element *body = NULL; dom_exception exc = dom_html_document_get_body(doc, &body); if (exc != DOM_NO_ERR || !body) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); JSValue rr = getElement(ctx, body); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(body); return rr; } static JSValue js_document_set_property_body(JSContext *ctx, JSValueConst this_val, JSValue val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); REF_JS(val); // TODO return JS_UNDEFINED; } #ifdef CONFIG_COOKIES static JSValue js_document_get_property_cookie(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct string *cookies; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } cookies = send_cookies_js(vs->uri); if (cookies) { static char cookiestr[1024]; strncpy(cookiestr, cookies->source, 1023); done_string(cookies); JSValue r = JS_NewString(ctx, cookiestr); RETURN_JS(r); } else { JSValue rr = JS_NewStringLen(ctx, "", 0); RETURN_JS(rr); } } static JSValue js_document_set_property_cookie(JSContext *ctx, JSValueConst this_val, JSValue val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); REF_JS(val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } const char *text; char *str; size_t len; text = JS_ToCStringLen(ctx, &len, val); if (!text) { return JS_EXCEPTION; } str = stracpy(text); if (str) { set_cookie(vs->uri, str); mem_free(str); } JS_FreeCString(ctx, text); return JS_UNDEFINED; } #endif static JSValue js_document_get_property_charset(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); // TODO JSValue r = JS_NewStringLen(ctx, "utf-8", strlen("utf-8")); RETURN_JS(r); } static JSValue js_document_get_property_childNodes(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_element *root = NULL; dom_exception exc = dom_document_get_document_element(doc, &root); if (exc != DOM_NO_ERR || !root) { //dom_node_unref(doc); return JS_NULL; } dom_nodelist *nodes = NULL; exc = dom_node_get_child_nodes(root, &nodes); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(root); if (exc != DOM_NO_ERR || !nodes) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); return getNodeList(ctx, nodes); } static JSValue js_document_get_property_currentScript(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; struct document *document; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; document = doc_view->document; void *mapa = (void *)document->element_map; if (mapa) { dom_node *elem = (dom_node *)find_in_map(mapa, interpreter->element_offset); if (elem) { dom_string *tag_name = NULL; dom_exception exc = dom_node_get_node_name(elem, &tag_name); if (exc != DOM_NO_ERR || !tag_name) { return JS_NULL; } bool isScript = !strcmp("SCRIPT", dom_string_data(tag_name)); dom_string_unref(tag_name); if (isScript) { return getElement(ctx, elem); } } } return JS_NULL; } static JSValue js_document_get_property_defaultView(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); JSValue global_obj = JS_GetGlobalObject(ctx); RETURN_JS(global_obj); } static JSValue js_document_get_property_doctype(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_document_type *dtd; dom_document_get_doctype(doc, &dtd); //dom_node_unref(doc); return getDoctype(ctx, dtd); } static JSValue js_document_get_property_documentElement(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_element *root = NULL; dom_exception exc = dom_document_get_document_element(doc, &root); if (exc != DOM_NO_ERR || !root) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); JSValue rr = getElement(ctx, root); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(root); return rr; } static JSValue js_document_get_property_documentURI(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct view_state *vs; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); vs = interpreter->vs; if (!vs) { return JS_NULL; } char *str = get_uri_string(vs->uri, URI_BASE); 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_document_get_property_domain(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct view_state *vs; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } char *str = get_uri_string(vs->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_document_get_property_forms(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_collection *forms = NULL; dom_exception exc = dom_html_document_get_forms(doc, &forms); if (exc != DOM_NO_ERR || !forms) { //dom_node_unref(doc); return JS_NULL; } JSValue rr = getForms(ctx, forms); JS_FreeValue(ctx, rr); //dom_node_unref(doc); RETURN_JS(rr); } static JSValue js_document_get_property_head(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); // TODO return JS_NULL; // return getElement(ctx, element); } static JSValue js_document_get_property_images(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_collection *images = NULL; dom_exception exc = dom_html_document_get_images(doc, &images); if (exc != DOM_NO_ERR || !images) { //dom_node_unref(doc); return JS_NULL; } JSValue rr = getCollection(ctx, images); //dom_node_unref(doc); RETURN_JS(rr); } static JSValue js_document_get_property_implementation(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); return getImplementation(ctx); } static JSValue js_document_get_property_links(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_html_collection *links = NULL; dom_exception exc = dom_html_document_get_links(doc, &links); if (exc != DOM_NO_ERR || !links) { //dom_node_unref(doc); return JS_NULL; } JSValue rr = getCollection(ctx, links); //dom_node_unref(doc); RETURN_JS(rr); } static JSValue js_document_get_property_location(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); JSValue ret = getLocation(ctx); RETURN_JS(ret); } static JSValue js_document_get_property_nodeType(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); return JS_NewInt32(ctx, 9); } static JSValue js_document_set_property_location(JSContext *ctx, JSValueConst this_val, JSValue val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); REF_JS(val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; const char *url; size_t len; url = JS_ToCStringLen(ctx, &len, val); if (!url) { return JS_EXCEPTION; } location_goto_const(doc_view, url, 0); JS_FreeCString(ctx, url); return JS_UNDEFINED; } static JSValue js_document_get_property_readyState(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct js_document_private *doc_private = (struct js_document_private *)(JS_GetOpaque(this_val, js_document_class_id)); if (!doc_private) { return JS_NULL; } JSValue r; switch (doc_private->state) { case LOADING: r = JS_NewString(ctx, "loading"); break; case INTERACTIVE: r = JS_NewString(ctx, "interactive"); break; case COMPLETE: r = JS_NewString(ctx, "complete"); break; } RETURN_JS(r); } static JSValue js_document_get_property_referrer(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; struct document *document; struct session *ses; char *str; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; document = doc_view->document; ses = doc_view->session; switch (get_opt_int("protocol.http.referer.policy", NULL)) { case REFERER_NONE: /* oh well */ return JS_UNDEFINED; case REFERER_FAKE: return JS_NewString(ctx, get_opt_str("protocol.http.referer.fake", NULL)); case REFERER_TRUE: /* XXX: Encode as in add_url_to_httset_prop_string(&prop, ) ? --pasky */ if (ses->referrer) { str = get_uri_string(ses->referrer, URI_HTTP_REFERRER); if (str) { JSValue ret = JS_NewString(ctx, str); mem_free(str); RETURN_JS(ret); } else { return JS_UNDEFINED; } } break; case REFERER_SAME_URL: str = get_uri_string(document->uri, URI_HTTP_REFERRER); if (str) { JSValue ret = JS_NewString(ctx, str); mem_free(str); RETURN_JS(ret); } else { return JS_UNDEFINED; } break; } return JS_UNDEFINED; } static JSValue js_document_get_property_scripts(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); // TODO //dom_html_document *doc = (dom_html_document *)document->dom; return JS_NULL; // JSValue rr = getCollection(ctx, elements); // JS_FreeValue(ctx, rr); // RETURN_JS(rr); } static JSValue js_document_get_property_title(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; struct document *document; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; document = doc_view->document; JSValue r = JS_NewString(ctx, document->title); RETURN_JS(r); } static JSValue js_document_set_property_title(JSContext *ctx, JSValueConst this_val, JSValue val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); REF_JS(val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; struct document *document; vs = interpreter->vs; if (!vs || !vs->doc_view) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; document = doc_view->document; const char *str; char *string; size_t len; str = JS_ToCStringLen(ctx, &len, val); if (!str) { return JS_EXCEPTION; } string = stracpy(str); JS_FreeCString(ctx, str); mem_free_set(&document->title, string); print_screen_status(doc_view->session); return JS_UNDEFINED; } static JSValue js_document_get_property_url(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; struct document *document; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; document = doc_view->document; char *str = get_uri_string(document->uri, URI_ORIGINAL); if (str) { JSValue ret = JS_NewString(ctx, str); mem_free(str); RETURN_JS(ret); } else { return JS_UNDEFINED; } } static JSValue js_document_set_property_url(JSContext *ctx, JSValueConst this_val, JSValue val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); REF_JS(val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct view_state *vs; struct document_view *doc_view; vs = interpreter->vs; if (!vs) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); #endif return JS_NULL; } doc_view = vs->doc_view; const char *url; size_t len; url = JS_ToCStringLen(ctx, &len, val); if (!url) { return JS_EXCEPTION; } location_goto_const(doc_view, url, 0); JS_FreeCString(ctx, url); return JS_UNDEFINED; } static JSValue js_document_write_do(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int newline) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); if (argc >= 1) { int element_offset = interpreter->element_offset; struct string string; if (init_string(&string)) { for (int i = 0; i < argc; ++i) { const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[i]); if (!str) { done_string(&string); return JS_EXCEPTION; } add_bytes_to_string(&string, str, len); JS_FreeCString(ctx, str); } if (newline) { add_to_string(&string, "\n"); } if (element_offset == interpreter->current_writecode->element_offset) { add_string_to_string(&interpreter->current_writecode->string, &string); done_string(&string); } else { (void)add_to_ecmascript_string_list(&interpreter->writecode, string.source, string.length, element_offset); done_string(&string); interpreter->current_writecode = interpreter->current_writecode->next; } interpreter->changed = 1; interpreter->was_write = 1; } } #ifdef CONFIG_LEDS set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); #endif return JS_FALSE; } /* @document_funcs{"write"} */ static JSValue js_document_write(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_document_write_do(ctx, this_val, argc, argv, 0); } /* @document_funcs{"writeln"} */ static JSValue js_document_writeln(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_document_write_do(ctx, this_val, argc, argv, 1); } /* @document_funcs{"replace"} */ static JSValue js_document_replace(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); struct document_view *doc_view = interpreter->vs->doc_view; struct document *document; document = doc_view->document; if (argc != 2) { return JS_FALSE; } struct string needle; struct string heystack; if (!init_string(&needle)) { return JS_EXCEPTION; } if (!init_string(&heystack)) { done_string(&needle); return JS_EXCEPTION; } const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (str) { add_bytes_to_string(&needle, str, len); JS_FreeCString(ctx, str); } str = JS_ToCStringLen(ctx, &len, argv[1]); if (str) { add_bytes_to_string(&heystack, str, len); JS_FreeCString(ctx, str); } //DBG("doc replace %s %s\n", needle.source, heystack.source); struct cache_entry *cached = doc_view->document->cached; struct fragment *f = get_cache_fragment(cached); if (f && f->length) { struct string f_data; if (init_string(&f_data)) { add_bytes_to_string(&f_data, f->data, f->length); struct string nu_str; if (init_string(&nu_str)) { el_string_replace(&nu_str, &f_data, &needle, &heystack); delete_entry_content(cached); /* TBD: somehow better rerender the document * now it's places on the session level in doc_loading_callback */ add_fragment(cached, 0, nu_str.source, nu_str.length); normalize_cache_entry(cached, nu_str.length); document->ecmascript_counter++; done_string(&nu_str); } //DBG("doc replace %s %s\n", needle.source, heystack.source); done_string(&f_data); } } done_string(&needle); done_string(&heystack); return JS_TRUE; } static JSValue js_document_addEventListener(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct js_document_private *doc_private = (struct js_document_private *)(JS_GetOpaque(this_val, js_document_class_id)); if (!doc_private) { return JS_NULL; } dom_html_document *doc = doc_private->node; if (argc < 2) { return JS_UNDEFINED; } const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { return JS_EXCEPTION; } char *method = stracpy(str); JS_FreeCString(ctx, str); if (!method) { return JS_EXCEPTION; } JSValue fun = argv[1]; struct document_listener *l; foreach(l, doc_private->listeners) { if (strcmp(l->typ, method)) { continue; } if (JS_VALUE_GET_PTR(l->fun) == JS_VALUE_GET_PTR(fun)) { mem_free(method); return JS_UNDEFINED; } } struct document_listener *n = (struct document_listener *)mem_calloc(1, sizeof(*n)); if (!n) { return JS_UNDEFINED; } n->fun = JS_DupValue(ctx, fun); n->typ = method; add_to_list_end(doc_private->listeners, n); dom_exception exc; if (doc_private->listener) { dom_event_listener_ref(doc_private->listener); } else { exc = dom_event_listener_create(document_event_handler, doc_private, &doc_private->listener); if (exc != DOM_NO_ERR || !doc_private->listener) { return JS_UNDEFINED; } } dom_string *typ = NULL; exc = dom_string_create((const uint8_t *)method, strlen(method), &typ); if (exc != DOM_NO_ERR || !typ) { goto ex; } exc = dom_event_target_add_event_listener(doc, typ, doc_private->listener, false); if (exc == DOM_NO_ERR) { dom_event_listener_ref(doc_private->listener); } ex: if (typ) { dom_string_unref(typ); } dom_event_listener_unref(doc_private->listener); return JS_UNDEFINED; } static JSValue js_document_dispatchEvent(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct js_document_private *doc_private = (struct js_document_private *)(JS_GetOpaque(this_val, js_document_class_id)); if (!doc_private) { return JS_FALSE; } dom_html_document *doc = doc_private->node; if (!doc) { return JS_FALSE; } //dom_node_ref(doc); if (argc < 1) { //dom_node_unref(doc); return JS_FALSE; } JSValue eve = argv[0]; dom_event *event = (dom_event *)(JS_GetOpaque(eve, js_event_class_id)); if (event) { dom_event_ref(event); } bool result = false; (void)dom_event_target_dispatch_event(doc, event, &result); if (event) { dom_event_unref(event); } //dom_node_unref(doc); return JS_NewBool(ctx, result); } static JSValue js_document_removeEventListener(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); struct js_document_private *doc_private = (struct js_document_private *)(JS_GetOpaque(this_val, js_document_class_id)); if (!doc_private) { return JS_NULL; } //dom_node_ref(doc); if (argc < 2) { //dom_node_unref(doc); return JS_UNDEFINED; } const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } char *method = stracpy(str); JS_FreeCString(ctx, str); if (!method) { //dom_node_unref(doc); return JS_EXCEPTION; } JSValue fun = argv[1]; struct document_listener *l; foreach(l, doc_private->listeners) { if (strcmp(l->typ, method)) { continue; } if (JS_VALUE_GET_PTR(l->fun) == JS_VALUE_GET_PTR(fun)) { dom_string *typ = NULL; dom_exception exc = dom_string_create((const uint8_t *)method, strlen(method), &typ); if (exc != DOM_NO_ERR || !typ) { continue; } //dom_event_target_remove_event_listener(doc, typ, doc_private->listener, false); dom_string_unref(typ); del_from_list(l); mem_free_set(&l->typ, NULL); mem_free(l); mem_free(method); //dom_node_unref(doc); return JS_UNDEFINED; } } mem_free(method); //dom_node_unref(doc); return JS_UNDEFINED; } static JSValue js_document_createComment(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_string *data = NULL; dom_exception exc; const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } exc = dom_string_create((const uint8_t *)str, len, &data); JS_FreeCString(ctx, str); if (exc != DOM_NO_ERR || !data) { //dom_node_unref(doc); return JS_NULL; } dom_comment *comment = NULL; exc = dom_document_create_comment(doc, data, &comment); dom_string_unref(data); if (exc != DOM_NO_ERR || !comment) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); return getElement(ctx, comment); } static JSValue js_document_createDocumentFragment(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 0) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_document_fragment *fragment = NULL; dom_exception exc = dom_document_create_document_fragment(doc, &fragment); if (exc != DOM_NO_ERR || !fragment) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); return getDocumentFragment(ctx, fragment); } static JSValue js_document_createElement(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_string *tag_name = NULL; dom_exception exc; const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } exc = dom_string_create((const uint8_t *)str, len, &tag_name); JS_FreeCString(ctx, str); if (exc != DOM_NO_ERR || !tag_name) { //dom_node_unref(doc); return JS_NULL; } dom_element *element = NULL; exc = dom_document_create_element(doc, tag_name, &element); dom_string_unref(tag_name); if (exc != DOM_NO_ERR || !element) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); JSValue rr = getElement(ctx, element); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(element); return rr; } static JSValue js_document_createTextNode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_string *data = NULL; dom_exception exc; const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } exc = dom_string_create((const uint8_t *)str, len, &data); JS_FreeCString(ctx, str); if (exc != DOM_NO_ERR || !data) { //dom_node_unref(doc); return JS_NULL; } dom_text *text_node = NULL; exc = dom_document_create_text_node(doc, data, &text_node); dom_string_unref(data); if (exc != DOM_NO_ERR || !text_node) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); return getText(ctx, text_node); } static JSValue js_document_getElementById(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_string *id = NULL; dom_exception exc; const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } exc = dom_string_create((const uint8_t *)str, len, &id); JS_FreeCString(ctx, str); if (exc != DOM_NO_ERR || !id) { //dom_node_unref(doc); return JS_NULL; } dom_element *element = NULL; exc = dom_document_get_element_by_id(doc, id, &element); dom_string_unref(id); if (exc != DOM_NO_ERR || !element) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); JSValue rr = getElement(ctx, element); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(element); return rr; } static JSValue js_document_getElementsByClassName(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } if (argc != 1) { return JS_NULL; } const char *classes = JS_ToCString(ctx, argv[0]); dom_html_collection *col = (dom_html_collection *)get_elements_by_class_name(doc, (dom_node *)doc, classes); if (classes) { JS_FreeCString(ctx, classes); } if (!col) { return JS_NULL; } JSValue ret = getCollection2(ctx, col); RETURN_JS(ret); } #if 0 static JSValue js_document_getElementsByName(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); // 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; } xmlpp::ustring id = str; JS_FreeCString(ctx, str); xmlpp::ustring xpath = "//*[@id=\""; xpath += id; xpath += "\"]|//*[@name=\""; xpath += id; xpath += "\"]"; xmlpp::Node::NodeSet *elements = new(std::nothrow) xmlpp::Node::NodeSet; if (!elements) { return JS_NULL; } *elements = root->find(xpath); JSValue rr = getCollection(ctx, elements); JS_FreeValue(ctx, rr); RETURN_JS(rr); #endif } #endif static JSValue js_document_getElementsByTagName(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_string *tagname = NULL; dom_exception exc; const char *str; size_t len; str = JS_ToCStringLen(ctx, &len, argv[0]); if (!str) { //dom_node_unref(doc); return JS_EXCEPTION; } exc = dom_string_create((const uint8_t *)str, len, &tagname); JS_FreeCString(ctx, str); if (exc != DOM_NO_ERR || !tagname) { //dom_node_unref(doc); return JS_NULL; } dom_nodelist *nodes = NULL; exc = dom_document_get_elements_by_tag_name(doc, tagname, &nodes); dom_string_unref(tagname); if (exc != DOM_NO_ERR || !nodes) { //dom_node_unref(doc); return JS_NULL; } JSValue rr = getNodeList(ctx, nodes); //dom_node_unref(doc); RETURN_JS(rr); } static JSValue js_document_querySelector(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_node *root = NULL; /* root element of document */ /* Get root element */ dom_exception exc = dom_document_get_document_element(doc, &root); if (exc != DOM_NO_ERR) { //dom_node_unref(doc); return JS_NULL; } size_t len; const char *selector = JS_ToCStringLen(ctx, &len, argv[0]); if (!selector) { //dom_node_unref(doc); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(root); return JS_NULL; } void *ret = walk_tree_query(root, selector, 0); JS_FreeCString(ctx, selector); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(root); if (!ret) { //dom_node_unref(doc); return JS_NULL; } //dom_node_unref(doc); return getElement(ctx, ret); } static JSValue js_document_querySelectorAll(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); if (argc != 1) { return JS_FALSE; } dom_html_document *doc = (struct dom_html_document *)js_doc_getopaque(this_val); if (!doc) { return JS_NULL; } //dom_node_ref(doc); dom_node *doc_root = NULL; /* root element of document */ /* Get root element */ dom_exception exc = dom_document_get_document_element(doc, &doc_root); if (exc != DOM_NO_ERR) { //dom_node_unref(doc); return JS_NULL; } size_t len; const char *selector = JS_ToCStringLen(ctx, &len, argv[0]); if (!selector) { //dom_node_unref(doc); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(doc_root); return JS_NULL; } LIST_OF(struct selector_node) *result_list = (LIST_OF(struct selector_node) *)mem_calloc(1, sizeof(*result_list)); if (!result_list) { //dom_node_unref(doc); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(doc_root); JS_FreeCString(ctx, selector); return JS_NULL; } init_list(*result_list); walk_tree_query_append(doc_root, selector, 0, result_list); #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(doc_root); JS_FreeCString(ctx, selector); //dom_node_unref(doc); JSValue rr = getNodeList2(ctx, result_list); free_list(*result_list); mem_free(result_list); return rr; } #if 0 JSClass doctype_class = { "doctype", JSCLASS_HAS_PRIVATE, &doctype_ops }; #endif static JSValue js_doctype_get_property_name(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_document_type *dtd = (dom_document_type *)(JS_GetOpaque(this_val, js_doctype_class_id)); if (!dtd) { return JS_NULL; } dom_string *name = NULL; dom_exception exc = dom_document_type_get_name(dtd, &name); if (exc != DOM_NO_ERR || !name) { return JS_NULL; } JSValue ret = JS_NewStringLen(ctx, dom_string_data(name), dom_string_length(name)); dom_string_unref(name); return ret; } static JSValue js_doctype_get_property_publicId(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_document_type *dtd = (dom_document_type *)(JS_GetOpaque(this_val, js_doctype_class_id)); if (!dtd) { return JS_NULL; } dom_string *public_id = NULL; dom_exception exc = dom_document_type_get_public_id(dtd, &public_id); if (exc != DOM_NO_ERR || !public_id) { return JS_NULL; } JSValue ret = JS_NewStringLen(ctx, dom_string_data(public_id), dom_string_length(public_id)); dom_string_unref(public_id); return ret; } static JSValue js_doctype_get_property_systemId(JSContext *ctx, JSValueConst this_val) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif REF_JS(this_val); dom_document_type *dtd = (dom_document_type *)(JS_GetOpaque(this_val, js_doctype_class_id)); if (!dtd) { return JS_NULL; } dom_string *system_id = NULL; dom_exception exc = dom_document_type_get_system_id(dtd, &system_id); if (exc != DOM_NO_ERR || !system_id) { return JS_NULL; } JSValue ret = JS_NewStringLen(ctx, dom_string_data(system_id), dom_string_length(system_id)); dom_string_unref(system_id); return ret; } static JSValue js_document_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_NewString(ctx, "[document object]"); } static const JSCFunctionListEntry js_document_proto_funcs[] = { JS_CGETSET_DEF("anchors", js_document_get_property_anchors, NULL), JS_CGETSET_DEF("baseURI", js_document_get_property_baseURI, NULL), JS_CGETSET_DEF("body", js_document_get_property_body, js_document_set_property_body), #ifdef CONFIG_COOKIES JS_CGETSET_DEF("cookie", js_document_get_property_cookie, js_document_set_property_cookie), #endif JS_CGETSET_DEF("charset", js_document_get_property_charset, NULL), JS_CGETSET_DEF("characterSet", js_document_get_property_charset, NULL), JS_CGETSET_DEF("childNodes", js_document_get_property_childNodes, NULL), JS_CGETSET_DEF("currentScript", js_document_get_property_currentScript, NULL), JS_CGETSET_DEF("defaultView", js_document_get_property_defaultView, NULL), JS_CGETSET_DEF("doctype", js_document_get_property_doctype, NULL), JS_CGETSET_DEF("documentElement", js_document_get_property_documentElement, NULL), JS_CGETSET_DEF("documentURI", js_document_get_property_documentURI, NULL), JS_CGETSET_DEF("domain", js_document_get_property_domain, NULL), JS_CGETSET_DEF("forms", js_document_get_property_forms, NULL), JS_CGETSET_DEF("head", js_document_get_property_head, NULL), JS_CGETSET_DEF("images", js_document_get_property_images, NULL), JS_CGETSET_DEF("implementation", js_document_get_property_implementation, NULL), JS_CGETSET_DEF("inputEncoding", js_document_get_property_charset, NULL), JS_CGETSET_DEF("links", js_document_get_property_links, NULL), JS_CGETSET_DEF("location", js_document_get_property_location, js_document_set_property_location), JS_CGETSET_DEF("nodeType", js_document_get_property_nodeType, NULL), JS_CGETSET_DEF("readyState", js_document_get_property_readyState, NULL), JS_CGETSET_DEF("referrer", js_document_get_property_referrer, NULL), JS_CGETSET_DEF("scripts", js_document_get_property_scripts, NULL), JS_CGETSET_DEF("title", js_document_get_property_title, js_document_set_property_title), /* TODO: Charset? */ JS_CGETSET_DEF("URL", js_document_get_property_url, js_document_set_property_url), JS_CFUNC_DEF("addEventListener", 3, js_document_addEventListener), JS_CFUNC_DEF("createComment", 1, js_document_createComment), JS_CFUNC_DEF("createDocumentFragment", 0, js_document_createDocumentFragment), JS_CFUNC_DEF("createElement", 1, js_document_createElement), JS_CFUNC_DEF("createTextNode", 1, js_document_createTextNode), JS_CFUNC_DEF("dispatchEvent", 1, js_document_dispatchEvent), JS_CFUNC_DEF("write", 1, js_document_write), JS_CFUNC_DEF("writeln", 1, js_document_writeln), JS_CFUNC_DEF("removeEventListener", 3, js_document_removeEventListener), JS_CFUNC_DEF("replace", 2, js_document_replace), JS_CFUNC_DEF("getElementById", 1, js_document_getElementById), JS_CFUNC_DEF("getElementsByClassName", 1, js_document_getElementsByClassName), // JS_CFUNC_DEF("getElementsByName", 1, js_document_getElementsByName), JS_CFUNC_DEF("getElementsByTagName", 1, js_document_getElementsByTagName), JS_CFUNC_DEF("querySelector", 1, js_document_querySelector), JS_CFUNC_DEF("querySelectorAll", 1, js_document_querySelectorAll), JS_CFUNC_DEF("toString", 0, js_document_toString) }; static void js_document_finalizer(JSRuntime *rt, JSValue val) { REF_JS(val); struct js_document_private *doc_private = (struct js_document_private *)JS_GetOpaque(val, js_document_class_id); if (doc_private) { struct document_listener *l; if (doc_private->listener) { dom_event_listener_unref(doc_private->listener); } foreach(l, doc_private->listeners) { mem_free_set(&l->typ, NULL); JS_FreeValueRT(rt, l->fun); } free_list(doc_private->listeners); if (doc_private->node) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref((dom_node *)doc_private->node); } mem_free(doc_private); } } static JSClassDef js_document_class = { "document", .finalizer = js_document_finalizer, .gc_mark = js_document_mark }; static JSValue js_doctype_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_NewString(ctx, "[doctype object]"); } static const JSCFunctionListEntry js_doctype_proto_funcs[] = { JS_CGETSET_DEF("name", js_doctype_get_property_name, NULL), JS_CGETSET_DEF("publicId", js_doctype_get_property_publicId, NULL), JS_CGETSET_DEF("systemId", js_doctype_get_property_systemId, NULL), JS_CFUNC_DEF("toString", 0, js_doctype_toString) }; void *map_doctypes; static void js_doctype_finalizer(JSRuntime *rt, JSValue val) { REF_JS(val); dom_node *node = (dom_node *)JS_GetOpaque(val, js_doctype_class_id); if (node) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_unref(node); } } static JSClassDef js_doctype_class = { "doctype", js_doctype_finalizer }; int js_doctype_init(JSContext *ctx) { JSValue doctype_proto; /* create the doctype class */ JS_NewClassID(&js_doctype_class_id); JS_NewClass(JS_GetRuntime(ctx), js_doctype_class_id, &js_doctype_class); JSValue global_obj = JS_GetGlobalObject(ctx); REF_JS(global_obj); doctype_proto = JS_NewObject(ctx); REF_JS(doctype_proto); JS_SetPropertyFunctionList(ctx, doctype_proto, js_doctype_proto_funcs, countof(js_doctype_proto_funcs)); JS_SetClassProto(ctx, js_doctype_class_id, doctype_proto); JS_SetPropertyStr(ctx, global_obj, "doctype", JS_DupValue(ctx, doctype_proto)); JS_FreeValue(ctx, global_obj); return 0; } JSValue getDoctype(JSContext *ctx, void *node) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif static int initialized; /* create the element class */ if (!initialized) { JS_NewClassID(&js_doctype_class_id); JS_NewClass(JS_GetRuntime(ctx), js_doctype_class_id, &js_doctype_class); initialized = 1; } JSValue doctype_obj = JS_NewObjectClass(ctx, js_doctype_class_id); JS_SetPropertyFunctionList(ctx, doctype_obj, js_doctype_proto_funcs, countof(js_doctype_proto_funcs)); JS_SetClassProto(ctx, js_doctype_class_id, doctype_obj); JS_SetOpaque(doctype_obj, node); JSValue rr = JS_DupValue(ctx, doctype_obj); RETURN_JS(rr); } JSValue getDocument(JSContext *ctx, void *doc) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct js_document_private *doc_private = (struct js_document_private *)mem_calloc(1, sizeof(*doc_private)); if (!doc_private) { return JS_NULL; } init_list(doc_private->listeners); if (doc) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "Before: %s:%d\n", __FUNCTION__, __LINE__); #endif dom_node_ref((dom_node *)doc); } doc_private->node = doc; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); doc_private->interpreter = interpreter; static int initialized; JSValue global_obj = JS_GetGlobalObject(ctx); /* create the element class */ if (!initialized) { JS_NewClassID(&js_document_class_id); JS_NewClass(JS_GetRuntime(ctx), js_document_class_id, &js_document_class); initialized = 1; } //REF_JS(global_obj); JSValue document_obj = JS_NewObjectClass(ctx, js_document_class_id); JS_SetPropertyFunctionList(ctx, document_obj, js_document_proto_funcs, countof(js_document_proto_funcs)); // document_class = JS_NewCFunction2(ctx, js_document_ctor, "document", 0, JS_CFUNC_constructor, 0); // JS_SetConstructor(ctx, document_class, document_obj); JS_SetOpaque(document_obj, doc_private); // JS_SetClassProto(ctx, js_document_class_id, document_obj); JS_SetPropertyStr(ctx, global_obj, "document", document_obj); JS_FreeValue(ctx, global_obj); doc_private->thisval = document_obj; RETURN_JS(document_obj); } JSValue getDocument2(JSContext *ctx, void *doc) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct js_document_private *doc_private = (struct js_document_private *)mem_calloc(1, sizeof(*doc_private)); if (!doc_private) { return JS_NULL; } init_list(doc_private->listeners); // if (doc) { // dom_node_ref((dom_node *)doc); // } doc_private->node = doc; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); doc_private->interpreter = interpreter; JSValue document_obj = JS_NewObjectClass(ctx, js_document_class_id); JS_SetPropertyFunctionList(ctx, document_obj, js_document_proto_funcs, countof(js_document_proto_funcs)); JS_SetOpaque(document_obj, doc_private); doc_private->thisval = document_obj; RETURN_JS(document_obj); } static void document_event_handler(dom_event *event, void *pw) { #ifdef ECMASCRIPT_DEBUG fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); #endif struct js_document_private *doc_private = (struct js_document_private *)pw; struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)doc_private->interpreter; if (!interp_find_in_map(map_interp, interpreter)) { return; } JSContext *ctx = (JSContext *)interpreter->backend_data; if (!event) { return; } dom_string *typ = NULL; dom_exception exc = dom_event_get_type(event, &typ); if (exc != DOM_NO_ERR || !typ) { return; } if (!strcmp("DOMContentLoaded", dom_string_data(typ))) { if (doc_private->state == COMPLETE) { dom_string_unref(typ); return; } doc_private->state = COMPLETE; } // interpreter->heartbeat = add_heartbeat(interpreter); struct document_listener *l, *next; foreachsafe(l, next, doc_private->listeners) { if (strcmp(l->typ, dom_string_data(typ))) { continue; } JSValue func = JS_DupValue(ctx, l->fun); JSValue arg = getEvent(ctx, event); JSValue ret = JS_Call(ctx, func, doc_private->thisval, 1, (JSValueConst *) &arg); JS_FreeValue(ctx, ret); JS_FreeValue(ctx, func); JS_FreeValue(ctx, arg); } // done_heartbeat(interpreter->heartbeat); check_for_rerender(interpreter, dom_string_data(typ)); dom_string_unref(typ); }