diff --git a/src/ecmascript/spidermonkey/Makefile b/src/ecmascript/spidermonkey/Makefile index 3007fb4e..e88155e2 100644 --- a/src/ecmascript/spidermonkey/Makefile +++ b/src/ecmascript/spidermonkey/Makefile @@ -2,7 +2,7 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) -OBJS = attr.o attributes.o collection.o console.o document.o element.o form.o heartbeat.o history.o implementation.o \ +OBJS = attr.o attributes.o collection.o console.o document.o element.o form.o heartbeat.o history.o implementation.o input.o \ location.o localstorage.o navigator.o nodelist.o screen.o unibar.o window.o include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/spidermonkey/form.c b/src/ecmascript/spidermonkey/form.c index cf3c9bf2..376cf4f0 100644 --- a/src/ecmascript/spidermonkey/form.c +++ b/src/ecmascript/spidermonkey/form.c @@ -26,6 +26,7 @@ #include "ecmascript/spidermonkey.h" #include "ecmascript/spidermonkey/document.h" #include "ecmascript/spidermonkey/form.h" +#include "ecmascript/spidermonkey/input.h" #include "ecmascript/spidermonkey/window.h" #include "intl/libintl.h" #include "main/select.h" @@ -82,1917 +83,12 @@ static JSClassOps form_ops = { }; /* Each @form_class object must have a @document_class parent. */ -static JSClass form_class = { +JSClass form_class = { "form", JSCLASS_HAS_PRIVATE, /* struct form_view *, or NULL if detached */ &form_ops }; -/* Accordingly to the JS specs, each input type should own object. That'd be a - * huge PITA though, however DOM comes to the rescue and defines just a single - * HTMLInputElement. The difference could be spotted only by some clever tricky - * JS code, but I hope it doesn't matter anywhere. --pasky */ - -static bool input_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); -static bool input_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); -static void input_finalize(JSFreeOp *op, JSObject *obj); - -static JSClassOps input_ops = { - nullptr, // addProperty - nullptr, // deleteProperty - nullptr, // enumerate - nullptr, // newEnumerate - nullptr, // resolve - nullptr, // mayResolve - input_finalize, // finalize - nullptr, // call - nullptr, // hasInstance - nullptr, // construct - JS_GlobalObjectTraceHook -}; - -/* Each @input_class object must have a @form_class parent. */ -static JSClass input_class = { - "input", /* here, we unleash ourselves */ - JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */ - &input_ops -}; - -/* Tinyids of properties. Use negative values to distinguish these - * from array indexes (even though this object has no array elements). - * ECMAScript code should not use these directly as in input[-1]; - * future versions of ELinks may change the numbers. */ -enum input_prop { - JSP_INPUT_ACCESSKEY = -1, - JSP_INPUT_ALT = -2, - JSP_INPUT_CHECKED = -3, - JSP_INPUT_DEFAULT_CHECKED = -4, - JSP_INPUT_DEFAULT_VALUE = -5, - JSP_INPUT_DISABLED = -6, - JSP_INPUT_FORM = -7, - JSP_INPUT_MAX_LENGTH = -8, - JSP_INPUT_NAME = -9, - JSP_INPUT_READONLY = -10, - JSP_INPUT_SELECTED_INDEX = -11, - JSP_INPUT_SIZE = -12, - JSP_INPUT_SRC = -13, - JSP_INPUT_TABINDEX = -14, - JSP_INPUT_TYPE = -15, - JSP_INPUT_VALUE = -16, -}; - -static JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u); -static unicode_val_T jsval_to_accesskey(JSContext *ctx, JS::MutableHandleValue hvp); -static struct form_state *input_get_form_state(JSContext *ctx, JSObject *jsinput); - - -static bool -input_get_property_accessKey(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - JSString *keystr; - - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum >= 0) link = &document->links[linknum]; - - if (!link) { - args.rval().setUndefined(); - return true; - } - - if (!link->accesskey) { - args.rval().set(JS_GetEmptyStringValue(ctx)); - } else { - keystr = unicode_to_jsstring(ctx, link->accesskey); - if (keystr) { - args.rval().setString(keystr); - } - else { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - } - return true; -} - -static bool -input_set_property_accessKey(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - unicode_val_T accesskey; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum >= 0) link = &document->links[linknum]; - -// accesskey = jsval_to_accesskey(ctx, args[0]); - - size_t len; - char16_t chr[2]; - - accesskey = UCS_NO_CHAR; - - if (!args[0].isString()) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - JSString *str = args[0].toString(); - - len = JS_GetStringLength(str); - - /* This implementation ignores extra characters in the string. */ - if (len < 1) { - accesskey = 0; /* which means no access key */ - } else if (len == 1) { - JS_GetStringCharAt(ctx, str, 0, &chr[0]); - if (!is_utf16_surrogate(chr[0])) { - accesskey = chr[0]; - } - } else { - JS_GetStringCharAt(ctx, str, 1, &chr[1]); - if (is_utf16_high_surrogate(chr[0]) - && is_utf16_low_surrogate(chr[1])) { - accesskey = join_utf16_surrogates(chr[0], chr[1]); - } - } - if (accesskey == UCS_NO_CHAR) { - JS_ReportErrorUTF8(ctx, "Invalid UTF-16 sequence"); -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - if (link) { - link->accesskey = accesskey; - } - - return true; -} - -static bool -input_get_property_alt(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - args.rval().setString(JS_NewStringCopyZ(ctx, fc->alt)); - - return true; -} - -static bool -input_set_property_alt(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - mem_free_set(&fc->alt, jsval_to_string(ctx, args[0])); - - return true; -} - -static bool -input_get_property_checked(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct form_state *fs; - - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - - args.rval().setBoolean(fs->state); - - return true; -} - -static bool -input_set_property_checked(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO) - return true; - fs->state = args[0].toBoolean(); - - return true; -} - -static bool -input_get_property_defaultChecked(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - args.rval().setBoolean(fc->default_state); - - return true; -} - -static bool -input_get_property_defaultValue(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - /* FIXME (bug 805): convert from the charset of the document */ - args.rval().setString(JS_NewStringCopyZ(ctx, fc->default_value)); - - return true; -} - -static bool -input_get_property_disabled(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - /* FIXME: --pasky */ - args.rval().setBoolean(fc->mode == FORM_MODE_DISABLED); - - return true; -} - -static bool -input_set_property_disabled(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - /* FIXME: --pasky */ - fc->mode = (args[0].toBoolean() ? FORM_MODE_DISABLED - : fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY - : FORM_MODE_NORMAL); - - return true; -} - -static bool -input_get_property_form(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - JS::RootedObject parent_form(ctx, JS::GetNonCCWObjectGlobal(hobj)); - assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); - if_assert_failed { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - args.rval().setObject(*parent_form); - - return true; -} - -static bool -input_get_property_maxLength(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - args.rval().setInt32(fc->maxlength); - - return true; -} - -static bool -input_set_property_maxLength(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - fc->maxlength = args[0].toInt32(); - - return true; -} - -static bool -input_get_property_name(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - args.rval().setString(JS_NewStringCopyZ(ctx, fc->name)); - - return true; -} - -/* @input_class.setProperty */ -static bool -input_set_property_name(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - mem_free_set(&fc->name, jsval_to_string(ctx, args[0])); - - return true; -} - -static bool -input_get_property_readonly(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - /* FIXME: --pasky */ - args.rval().setBoolean(fc->mode == FORM_MODE_READONLY); - - return true; -} - -/* @input_class.setProperty */ -static bool -input_set_property_readonly(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - /* FIXME: --pasky */ - fc->mode = (args[0].toBoolean() ? FORM_MODE_READONLY - : fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED - : FORM_MODE_NORMAL); - - return true; -} - -static bool -input_get_property_selectedIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - if (fc->type == FC_SELECT) { - args.rval().setInt32(fs->state); - } - else { - args.rval().setUndefined(); - } - - return true; -} - -/* @input_class.setProperty */ -static bool -input_set_property_selectedIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - if (fc->type == FC_SELECT) { - int item = args[0].toInt32(); - - if (item >= 0 && item < fc->nvalues) { - fs->state = item; - mem_free_set(&fs->value, stracpy(fc->values[item])); - } - } - - return true; -} - -static bool -input_get_property_size(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - args.rval().setInt32(fc->size); - - return true; -} - -static bool -input_get_property_src(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum >= 0) link = &document->links[linknum]; - - if (link && link->where_img) { - args.rval().setString(JS_NewStringCopyZ(ctx, link->where_img)); - } else { - args.rval().setUndefined(); - } - - return true; -} - -static bool -input_set_property_src(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { - return; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum >= 0) link = &document->links[linknum]; - - if (link) { - mem_free_set(&link->where_img, jsval_to_string(ctx, args[0])); - } - - return true; -} - -static bool -input_get_property_tabIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum >= 0) link = &document->links[linknum]; - - if (link) { - /* FIXME: This is WRONG. --pasky */ - args.rval().setInt32(link->number); - } else { - args.rval().setUndefined(); - } - - return true; -} - -static bool -input_get_property_type(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - char *s = NULL; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - switch (fc->type) { - case FC_TEXT: s = "text"; break; - case FC_PASSWORD: s = "password"; break; - case FC_FILE: s = "file"; break; - case FC_CHECKBOX: s = "checkbox"; break; - case FC_RADIO: s = "radio"; break; - case FC_SUBMIT: s = "submit"; break; - case FC_IMAGE: s = "image"; break; - case FC_RESET: s = "reset"; break; - case FC_BUTTON: s = "button"; break; - case FC_HIDDEN: s = "hidden"; break; - case FC_SELECT: s = "select"; break; - default: INTERNAL("input_get_property() upon a non-input item."); break; - } - args.rval().setString(JS_NewStringCopyZ(ctx, s)); - - return true; -} - -static bool -input_get_property_value(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct form_state *fs; - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - - args.rval().setString(JS_NewStringCopyZ(ctx, fs->value)); - - return true; -} - -static bool -input_set_property_value(JSContext *ctx, unsigned int argc, JS::Value *vp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::CallArgs args = CallArgsFromVp(argc, vp); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - if (!vs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - doc_view = vs->doc_view; - document = doc_view->document; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - fc = find_form_control(document, fs); - - assert(fc); - assert(fc->form && fs); - - if (fc->type != FC_FILE) { - mem_free_set(&fs->value, jsval_to_string(ctx, args[0])); - if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) - fs->state = strlen(fs->value); - } - - return true; -} - -/* XXX: Some of those are marked readonly just because we can't change them - * safely now. Changing default* values would affect all open instances of the - * document, leading to a potential security risk. Changing size and type would - * require re-rendering the document (TODO), tabindex would require renumbering - * of all links and whatnot. --pasky */ -static JSPropertySpec input_props[] = { - JS_PSGS("accessKey", input_get_property_accessKey, input_set_property_accessKey, JSPROP_ENUMERATE), - JS_PSGS("alt", input_get_property_alt, input_set_property_alt, JSPROP_ENUMERATE), - JS_PSGS("checked", input_get_property_checked, input_set_property_checked, JSPROP_ENUMERATE), - JS_PSG("defaultChecked", input_get_property_defaultChecked, JSPROP_ENUMERATE), - JS_PSG("defaultValue",input_get_property_defaultValue, JSPROP_ENUMERATE), - JS_PSGS("disabled", input_get_property_disabled, input_set_property_disabled, JSPROP_ENUMERATE), - JS_PSG("form", input_get_property_form, JSPROP_ENUMERATE), - JS_PSGS("maxLength", input_get_property_maxLength, input_set_property_maxLength, JSPROP_ENUMERATE), - JS_PSGS("name", input_get_property_name, input_set_property_name, JSPROP_ENUMERATE), - JS_PSGS("readonly", input_get_property_readonly, input_set_property_readonly, JSPROP_ENUMERATE), - JS_PSGS("selectedIndex", input_get_property_selectedIndex, input_set_property_selectedIndex, JSPROP_ENUMERATE), - JS_PSG("size", input_get_property_size, JSPROP_ENUMERATE), - JS_PSGS("src", input_get_property_src, input_set_property_src,JSPROP_ENUMERATE), - JS_PSG("tabindex", input_get_property_tabIndex, JSPROP_ENUMERATE), - JS_PSG("type", input_get_property_type, JSPROP_ENUMERATE), - JS_PSGS("value", input_get_property_value, input_set_property_value, JSPROP_ENUMERATE), - JS_PS_END -}; - -static bool input_blur(JSContext *ctx, unsigned int argc, JS::Value *rval); -static bool input_click(JSContext *ctx, unsigned int argc, JS::Value *rval); -static bool input_focus(JSContext *ctx, unsigned int argc, JS::Value *rval); -static bool input_select(JSContext *ctx, unsigned int argc, JS::Value *rval); - -static const spidermonkeyFunctionSpec input_funcs[] = { - { "blur", input_blur, 0 }, - { "click", input_click, 0 }, - { "focus", input_focus, 0 }, - { "select", input_select, 0 }, - { NULL } -}; - -static struct form_state * -input_get_form_state(JSContext *ctx, JSObject *jsinput) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::RootedObject r_jsinput(ctx, jsinput); - struct form_state *fs = JS_GetInstancePrivate(ctx, r_jsinput, - &input_class, - NULL); - - if (!fs) return NULL; /* detached */ - - assert(fs->ecmascript_obj == jsinput); - if_assert_failed return NULL; - - return fs; -} - -/* @input_class.getProperty */ -static bool -input_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::RootedObject parent_form(ctx); /* instance of @form_class */ - JS::RootedObject parent_doc(ctx); /* instance of @document_class */ - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - hvp.setUndefined(); - - return true; -} - -/* @input_class.setProperty */ -static bool -input_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - ELINKS_CAST_PROP_PARAMS - jsid id = hid.get(); - - JS::RootedObject parent_form(ctx); /* instance of @form_class */ - JS::RootedObject parent_doc(ctx); /* instance of @document_class */ - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - struct link *link = NULL; - unicode_val_T accesskey; - - /* This can be called if @obj if not itself an instance of the - * appropriate class but has one in its prototype chain. Fail - * such calls. */ - if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - return true; -} - -/* @input_funcs{"blur"} */ -static bool -input_blur(JSContext *ctx, unsigned int argc, JS::Value *rval) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - /* We are a text-mode browser and there *always* has to be something - * selected. So we do nothing for now. (That was easy.) */ - return true; -} - -/* @input_funcs{"click"} */ -static bool -input_click(JSContext *ctx, unsigned int argc, JS::Value *rval) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::Value val; - JS::RootedObject parent_form(ctx); /* instance of @form_class */ - JS::RootedObject parent_doc(ctx); /* instance of @document_class */ - JS::CallArgs args = JS::CallArgsFromVp(argc, rval); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct session *ses; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - if (!JS_InstanceOf(ctx, hobj, &input_class, &args)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - doc_view = vs->doc_view; - document = doc_view->document; - ses = doc_view->session; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - - assert(fs); - fc = find_form_control(document, fs); - assert(fc); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum < 0) - return true; - - /* Restore old current_link afterwards? */ - jump_to_link_number(ses, doc_view, linknum); - if (enter(ses, doc_view, 0) == FRAME_EVENT_REFRESH) - refresh_view(ses, doc_view, 0); - else - print_screen_status(ses); - - args.rval().setBoolean(false); - - return true; -} - -/* @input_funcs{"focus"} */ -static bool -input_focus(JSContext *ctx, unsigned int argc, JS::Value *rval) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - JS::Value val; - JS::RootedObject parent_form(ctx); /* instance of @form_class */ - JS::RootedObject parent_doc(ctx); /* instance of @document_class */ - JS::CallArgs args = JS::CallArgsFromVp(argc, rval); - JS::RootedObject hobj(ctx, &args.thisv().toObject()); - - struct view_state *vs; - struct document_view *doc_view; - struct document *document; - struct session *ses; - struct form_state *fs; - struct el_form_control *fc; - int linknum; - JS::Realm *comp = js::GetContextRealm(ctx); - - if (!comp) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); - - if (!JS_InstanceOf(ctx, hobj, &input_class, &args)) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; - } - - vs = interpreter->vs; - doc_view = vs->doc_view; - document = doc_view->document; - ses = doc_view->session; - fs = input_get_form_state(ctx, hobj); - if (!fs) { -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); -#endif - return false; /* detached */ - } - - assert(fs); - fc = find_form_control(document, fs); - assert(fc); - - linknum = get_form_control_link(document, fc); - /* Hiddens have no link. */ - if (linknum < 0) - return true; - - jump_to_link_number(ses, doc_view, linknum); - - args.rval().setBoolean(false); - return true; -} - -/* @input_funcs{"select"} */ -static bool -input_select(JSContext *ctx, unsigned int argc, JS::Value *rval) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - /* We support no text selecting yet. So we do nothing for now. - * (That was easy, too.) */ - return true; -} - -static JSObject * -get_input_object(JSContext *ctx, struct form_state *fs) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - - JSObject *jsinput = fs->ecmascript_obj; - - if (jsinput) { - JS::RootedObject r_jsinput(ctx, jsinput); - /* This assumes JS_GetInstancePrivate cannot GC. */ - assert(JS_GetInstancePrivate(ctx, r_jsinput, - &input_class, NULL) - == fs); - if_assert_failed return NULL; - - return jsinput; - } - - /* jsform ('form') is input's parent */ - /* FIXME: That is NOT correct since the real containing element - * should be its parent, but gimme DOM first. --pasky */ - jsinput = JS_NewObject(ctx, &input_class); - if (!jsinput) - return NULL; - - JS::RootedObject r_jsinput(ctx, jsinput); - - JS_DefineProperties(ctx, r_jsinput, (JSPropertySpec *) input_props); - spidermonkey_DefineFunctions(ctx, jsinput, input_funcs); - - JS_SetPrivate(jsinput, fs); /* to @input_class */ - fs->ecmascript_obj = jsinput; - - return jsinput; -} - -static void -input_finalize(JSFreeOp *op, JSObject *jsinput) -{ -#ifdef ECMASCRIPT_DEBUG - fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); -#endif - struct form_state *fs = JS_GetPrivate(jsinput); - - if (fs) { - /* If this assertion fails, leave fs->ecmascript_obj - * unchanged, because it may point to a different - * JSObject whose private pointer will later have to - * be updated to avoid crashes. */ - assert(fs->ecmascript_obj == jsinput); - if_assert_failed return; - - fs->ecmascript_obj = NULL; - /* No need to JS_SetPrivate, because jsinput is being - * destroyed. */ - } -} - void spidermonkey_detach_form_state(struct form_state *fs) { @@ -3965,8 +2061,7 @@ forms_namedItem(JSContext *ctx, unsigned int argc, JS::Value *vp) return true; } - -static JSString * +JSString * unicode_to_jsstring(JSContext *ctx, unicode_val_T u) { #ifdef ECMASCRIPT_DEBUG diff --git a/src/ecmascript/spidermonkey/form.h b/src/ecmascript/spidermonkey/form.h index 73dd7e6a..a9a4087a 100644 --- a/src/ecmascript/spidermonkey/form.h +++ b/src/ecmascript/spidermonkey/form.h @@ -1,4 +1,3 @@ - #ifndef EL__ECMASCRIPT_SPIDERMONKEY_FORM_H #define EL__ECMASCRIPT_SPIDERMONKEY_FORM_H @@ -6,6 +5,7 @@ struct form; +extern JSClass form_class; extern JSClass forms_class; extern const spidermonkeyFunctionSpec forms_funcs[]; extern JSPropertySpec forms_props[]; @@ -13,4 +13,6 @@ extern JSPropertySpec forms_props[]; JSObject *get_form_object(JSContext *ctx, JSObject *jsdoc, struct form *form); JSObject *getForms(JSContext *ctx, void *node); +JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u); + #endif diff --git a/src/ecmascript/spidermonkey/input.c b/src/ecmascript/spidermonkey/input.c new file mode 100644 index 00000000..7b728667 --- /dev/null +++ b/src/ecmascript/spidermonkey/input.c @@ -0,0 +1,1957 @@ +/* The SpiderMonkey window object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/spidermonkey/util.h" +#include + +#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/spidermonkey.h" +#include "ecmascript/spidermonkey/document.h" +#include "ecmascript/spidermonkey/form.h" +#include "ecmascript/spidermonkey/input.h" +#include "ecmascript/spidermonkey/window.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.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" + +#include + +/* Accordingly to the JS specs, each input type should own object. That'd be a + * huge PITA though, however DOM comes to the rescue and defines just a single + * HTMLInputElement. The difference could be spotted only by some clever tricky + * JS code, but I hope it doesn't matter anywhere. --pasky */ + +static bool input_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +static bool input_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +static void input_finalize(JSFreeOp *op, JSObject *obj); + +static JSClassOps input_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + input_finalize, // finalize + nullptr, // call + nullptr, // hasInstance + nullptr, // construct + JS_GlobalObjectTraceHook +}; + +/* Each @input_class object must have a @form_class parent. */ +static JSClass input_class = { + "input", /* here, we unleash ourselves */ + JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */ + &input_ops +}; + +/* Tinyids of properties. Use negative values to distinguish these + * from array indexes (even though this object has no array elements). + * ECMAScript code should not use these directly as in input[-1]; + * future versions of ELinks may change the numbers. */ +enum input_prop { + JSP_INPUT_ACCESSKEY = -1, + JSP_INPUT_ALT = -2, + JSP_INPUT_CHECKED = -3, + JSP_INPUT_DEFAULT_CHECKED = -4, + JSP_INPUT_DEFAULT_VALUE = -5, + JSP_INPUT_DISABLED = -6, + JSP_INPUT_FORM = -7, + JSP_INPUT_MAX_LENGTH = -8, + JSP_INPUT_NAME = -9, + JSP_INPUT_READONLY = -10, + JSP_INPUT_SELECTED_INDEX = -11, + JSP_INPUT_SIZE = -12, + JSP_INPUT_SRC = -13, + JSP_INPUT_TABINDEX = -14, + JSP_INPUT_TYPE = -15, + JSP_INPUT_VALUE = -16, +}; + +static JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u); +static unicode_val_T jsval_to_accesskey(JSContext *ctx, JS::MutableHandleValue hvp); +static struct form_state *input_get_form_state(JSContext *ctx, JSObject *jsinput); + + +static bool +input_get_property_accessKey(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + JSString *keystr; + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (!link) { + args.rval().setUndefined(); + return true; + } + + if (!link->accesskey) { + args.rval().set(JS_GetEmptyStringValue(ctx)); + } else { + keystr = unicode_to_jsstring(ctx, link->accesskey); + if (keystr) { + args.rval().setString(keystr); + } + else { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + } + return true; +} + +static bool +input_set_property_accessKey(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + unicode_val_T accesskey; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + +// accesskey = jsval_to_accesskey(ctx, args[0]); + + size_t len; + char16_t chr[2]; + + accesskey = UCS_NO_CHAR; + + if (!args[0].isString()) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + JSString *str = args[0].toString(); + + len = JS_GetStringLength(str); + + /* This implementation ignores extra characters in the string. */ + if (len < 1) { + accesskey = 0; /* which means no access key */ + } else if (len == 1) { + JS_GetStringCharAt(ctx, str, 0, &chr[0]); + if (!is_utf16_surrogate(chr[0])) { + accesskey = chr[0]; + } + } else { + JS_GetStringCharAt(ctx, str, 1, &chr[1]); + if (is_utf16_high_surrogate(chr[0]) + && is_utf16_low_surrogate(chr[1])) { + accesskey = join_utf16_surrogates(chr[0], chr[1]); + } + } + if (accesskey == UCS_NO_CHAR) { + JS_ReportErrorUTF8(ctx, "Invalid UTF-16 sequence"); +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + if (link) { + link->accesskey = accesskey; + } + + return true; +} + +static bool +input_get_property_alt(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + args.rval().setString(JS_NewStringCopyZ(ctx, fc->alt)); + + return true; +} + +static bool +input_set_property_alt(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + mem_free_set(&fc->alt, jsval_to_string(ctx, args[0])); + + return true; +} + +static bool +input_get_property_checked(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct form_state *fs; + + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + + args.rval().setBoolean(fs->state); + + return true; +} + +static bool +input_set_property_checked(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO) + return true; + fs->state = args[0].toBoolean(); + + return true; +} + +static bool +input_get_property_defaultChecked(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + args.rval().setBoolean(fc->default_state); + + return true; +} + +static bool +input_get_property_defaultValue(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME (bug 805): convert from the charset of the document */ + args.rval().setString(JS_NewStringCopyZ(ctx, fc->default_value)); + + return true; +} + +static bool +input_get_property_disabled(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + args.rval().setBoolean(fc->mode == FORM_MODE_DISABLED); + + return true; +} + +static bool +input_set_property_disabled(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + fc->mode = (args[0].toBoolean() ? FORM_MODE_DISABLED + : fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY + : FORM_MODE_NORMAL); + + return true; +} + +static bool +input_get_property_form(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::RootedObject parent_form(ctx, JS::GetNonCCWObjectGlobal(hobj)); + assert(JS_InstanceOf(ctx, parent_form, &form_class, NULL)); + if_assert_failed { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + args.rval().setObject(*parent_form); + + return true; +} + +static bool +input_get_property_maxLength(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + args.rval().setInt32(fc->maxlength); + + return true; +} + +static bool +input_set_property_maxLength(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + fc->maxlength = args[0].toInt32(); + + return true; +} + +static bool +input_get_property_name(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + args.rval().setString(JS_NewStringCopyZ(ctx, fc->name)); + + return true; +} + +/* @input_class.setProperty */ +static bool +input_set_property_name(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + mem_free_set(&fc->name, jsval_to_string(ctx, args[0])); + + return true; +} + +static bool +input_get_property_readonly(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + args.rval().setBoolean(fc->mode == FORM_MODE_READONLY); + + return true; +} + +/* @input_class.setProperty */ +static bool +input_set_property_readonly(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + /* FIXME: --pasky */ + fc->mode = (args[0].toBoolean() ? FORM_MODE_READONLY + : fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED + : FORM_MODE_NORMAL); + + return true; +} + +static bool +input_get_property_selectedIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type == FC_SELECT) { + args.rval().setInt32(fs->state); + } + else { + args.rval().setUndefined(); + } + + return true; +} + +/* @input_class.setProperty */ +static bool +input_set_property_selectedIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type == FC_SELECT) { + int item = args[0].toInt32(); + + if (item >= 0 && item < fc->nvalues) { + fs->state = item; + mem_free_set(&fs->value, stracpy(fc->values[item])); + } + } + + return true; +} + +static bool +input_get_property_size(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + args.rval().setInt32(fc->size); + + return true; +} + +static bool +input_get_property_src(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (link && link->where_img) { + args.rval().setString(JS_NewStringCopyZ(ctx, link->where_img)); + } else { + args.rval().setUndefined(); + } + + return true; +} + +static bool +input_set_property_src(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { + return; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (link) { + mem_free_set(&link->where_img, jsval_to_string(ctx, args[0])); + } + + return true; +} + +static bool +input_get_property_tabIndex(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum >= 0) link = &document->links[linknum]; + + if (link) { + /* FIXME: This is WRONG. --pasky */ + args.rval().setInt32(link->number); + } else { + args.rval().setUndefined(); + } + + return true; +} + +static bool +input_get_property_type(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + char *s = NULL; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + switch (fc->type) { + case FC_TEXT: s = "text"; break; + case FC_PASSWORD: s = "password"; break; + case FC_FILE: s = "file"; break; + case FC_CHECKBOX: s = "checkbox"; break; + case FC_RADIO: s = "radio"; break; + case FC_SUBMIT: s = "submit"; break; + case FC_IMAGE: s = "image"; break; + case FC_RESET: s = "reset"; break; + case FC_BUTTON: s = "button"; break; + case FC_HIDDEN: s = "hidden"; break; + case FC_SELECT: s = "select"; break; + default: INTERNAL("input_get_property() upon a non-input item."); break; + } + args.rval().setString(JS_NewStringCopyZ(ctx, s)); + + return true; +} + +static bool +input_get_property_value(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct form_state *fs; + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + + args.rval().setString(JS_NewStringCopyZ(ctx, fs->value)); + + return true; +} + +static bool +input_set_property_value(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + fc = find_form_control(document, fs); + + assert(fc); + assert(fc->form && fs); + + if (fc->type != FC_FILE) { + mem_free_set(&fs->value, jsval_to_string(ctx, args[0])); + if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) + fs->state = strlen(fs->value); + } + + return true; +} + +/* XXX: Some of those are marked readonly just because we can't change them + * safely now. Changing default* values would affect all open instances of the + * document, leading to a potential security risk. Changing size and type would + * require re-rendering the document (TODO), tabindex would require renumbering + * of all links and whatnot. --pasky */ +static JSPropertySpec input_props[] = { + JS_PSGS("accessKey", input_get_property_accessKey, input_set_property_accessKey, JSPROP_ENUMERATE), + JS_PSGS("alt", input_get_property_alt, input_set_property_alt, JSPROP_ENUMERATE), + JS_PSGS("checked", input_get_property_checked, input_set_property_checked, JSPROP_ENUMERATE), + JS_PSG("defaultChecked", input_get_property_defaultChecked, JSPROP_ENUMERATE), + JS_PSG("defaultValue",input_get_property_defaultValue, JSPROP_ENUMERATE), + JS_PSGS("disabled", input_get_property_disabled, input_set_property_disabled, JSPROP_ENUMERATE), + JS_PSG("form", input_get_property_form, JSPROP_ENUMERATE), + JS_PSGS("maxLength", input_get_property_maxLength, input_set_property_maxLength, JSPROP_ENUMERATE), + JS_PSGS("name", input_get_property_name, input_set_property_name, JSPROP_ENUMERATE), + JS_PSGS("readonly", input_get_property_readonly, input_set_property_readonly, JSPROP_ENUMERATE), + JS_PSGS("selectedIndex", input_get_property_selectedIndex, input_set_property_selectedIndex, JSPROP_ENUMERATE), + JS_PSG("size", input_get_property_size, JSPROP_ENUMERATE), + JS_PSGS("src", input_get_property_src, input_set_property_src,JSPROP_ENUMERATE), + JS_PSG("tabindex", input_get_property_tabIndex, JSPROP_ENUMERATE), + JS_PSG("type", input_get_property_type, JSPROP_ENUMERATE), + JS_PSGS("value", input_get_property_value, input_set_property_value, JSPROP_ENUMERATE), + JS_PS_END +}; + +static bool input_blur(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool input_click(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool input_focus(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool input_select(JSContext *ctx, unsigned int argc, JS::Value *rval); + +static const spidermonkeyFunctionSpec input_funcs[] = { + { "blur", input_blur, 0 }, + { "click", input_click, 0 }, + { "focus", input_focus, 0 }, + { "select", input_select, 0 }, + { NULL } +}; + +static struct form_state * +input_get_form_state(JSContext *ctx, JSObject *jsinput) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::RootedObject r_jsinput(ctx, jsinput); + struct form_state *fs = JS_GetInstancePrivate(ctx, r_jsinput, + &input_class, + NULL); + + if (!fs) return NULL; /* detached */ + + assert(fs->ecmascript_obj == jsinput); + if_assert_failed return NULL; + + return fs; +} + +/* @input_class.getProperty */ +static bool +input_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::RootedObject parent_form(ctx); /* instance of @form_class */ + JS::RootedObject parent_doc(ctx); /* instance of @document_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + hvp.setUndefined(); + + return true; +} + +/* @input_class.setProperty */ +static bool +input_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + ELINKS_CAST_PROP_PARAMS + jsid id = hid.get(); + + JS::RootedObject parent_form(ctx); /* instance of @form_class */ + JS::RootedObject parent_doc(ctx); /* instance of @document_class */ + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + struct link *link = NULL; + unicode_val_T accesskey; + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &input_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + return true; +} + +/* @input_funcs{"blur"} */ +static bool +input_blur(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + /* We are a text-mode browser and there *always* has to be something + * selected. So we do nothing for now. (That was easy.) */ + return true; +} + +/* @input_funcs{"click"} */ +static bool +input_click(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::Value val; + JS::RootedObject parent_form(ctx); /* instance of @form_class */ + JS::RootedObject parent_doc(ctx); /* instance of @document_class */ + JS::CallArgs args = JS::CallArgsFromVp(argc, rval); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct session *ses; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + if (!JS_InstanceOf(ctx, hobj, &input_class, &args)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + doc_view = vs->doc_view; + document = doc_view->document; + ses = doc_view->session; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + + assert(fs); + fc = find_form_control(document, fs); + assert(fc); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum < 0) + return true; + + /* Restore old current_link afterwards? */ + jump_to_link_number(ses, doc_view, linknum); + if (enter(ses, doc_view, 0) == FRAME_EVENT_REFRESH) + refresh_view(ses, doc_view, 0); + else + print_screen_status(ses); + + args.rval().setBoolean(false); + + return true; +} + +/* @input_funcs{"focus"} */ +static bool +input_focus(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::Value val; + JS::RootedObject parent_form(ctx); /* instance of @form_class */ + JS::RootedObject parent_doc(ctx); /* instance of @document_class */ + JS::CallArgs args = JS::CallArgsFromVp(argc, rval); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct session *ses; + struct form_state *fs; + struct el_form_control *fc; + int linknum; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = JS::GetRealmPrivate(comp); + + if (!JS_InstanceOf(ctx, hobj, &input_class, &args)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + doc_view = vs->doc_view; + document = doc_view->document; + ses = doc_view->session; + fs = input_get_form_state(ctx, hobj); + if (!fs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; /* detached */ + } + + assert(fs); + fc = find_form_control(document, fs); + assert(fc); + + linknum = get_form_control_link(document, fc); + /* Hiddens have no link. */ + if (linknum < 0) + return true; + + jump_to_link_number(ses, doc_view, linknum); + + args.rval().setBoolean(false); + return true; +} + +/* @input_funcs{"select"} */ +static bool +input_select(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + /* We support no text selecting yet. So we do nothing for now. + * (That was easy, too.) */ + return true; +} + +JSObject * +get_input_object(JSContext *ctx, struct form_state *fs) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + + JSObject *jsinput = fs->ecmascript_obj; + + if (jsinput) { + JS::RootedObject r_jsinput(ctx, jsinput); + /* This assumes JS_GetInstancePrivate cannot GC. */ + assert(JS_GetInstancePrivate(ctx, r_jsinput, + &input_class, NULL) + == fs); + if_assert_failed return NULL; + + return jsinput; + } + + /* jsform ('form') is input's parent */ + /* FIXME: That is NOT correct since the real containing element + * should be its parent, but gimme DOM first. --pasky */ + jsinput = JS_NewObject(ctx, &input_class); + if (!jsinput) + return NULL; + + JS::RootedObject r_jsinput(ctx, jsinput); + + JS_DefineProperties(ctx, r_jsinput, (JSPropertySpec *) input_props); + spidermonkey_DefineFunctions(ctx, jsinput, input_funcs); + + JS_SetPrivate(jsinput, fs); /* to @input_class */ + fs->ecmascript_obj = jsinput; + + return jsinput; +} + +static void +input_finalize(JSFreeOp *op, JSObject *jsinput) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct form_state *fs = JS_GetPrivate(jsinput); + + if (fs) { + /* If this assertion fails, leave fs->ecmascript_obj + * unchanged, because it may point to a different + * JSObject whose private pointer will later have to + * be updated to avoid crashes. */ + assert(fs->ecmascript_obj == jsinput); + if_assert_failed return; + + fs->ecmascript_obj = NULL; + /* No need to JS_SetPrivate, because jsinput is being + * destroyed. */ + } +} + diff --git a/src/ecmascript/spidermonkey/input.h b/src/ecmascript/spidermonkey/input.h new file mode 100644 index 00000000..742029c3 --- /dev/null +++ b/src/ecmascript/spidermonkey/input.h @@ -0,0 +1,10 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_INPUT_H +#define EL__ECMASCRIPT_SPIDERMONKEY_INPUT_H + +#include "ecmascript/spidermonkey/util.h" + +struct form_state; + +JSObject *get_input_object(JSContext *ctx, struct form_state *fs); + +#endif diff --git a/src/ecmascript/spidermonkey/meson.build b/src/ecmascript/spidermonkey/meson.build index 21fa63ee..204bbef1 100644 --- a/src/ecmascript/spidermonkey/meson.build +++ b/src/ecmascript/spidermonkey/meson.build @@ -1,3 +1,3 @@ #INCLUDES += $(SPIDERMONKEY_CFLAGS) -srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'document.c', 'element.c', 'form.c', 'heartbeat.c', 'history.c', 'implementation.c', 'location.c', 'localstorage.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c') +srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'document.c', 'element.c', 'form.c', 'heartbeat.c', 'history.c', 'implementation.c', 'input.c', 'location.c', 'localstorage.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c')