2005-09-15 09:58:31 -04:00
|
|
|
/* The SpiderMonkey window object implementation. */
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "ecmascript/spidermonkey/util.h"
|
|
|
|
|
|
|
|
#include "bfu/dialog.h"
|
|
|
|
#include "cache/cache.h"
|
|
|
|
#include "cookies/cookies.h"
|
|
|
|
#include "dialogs/menu.h"
|
|
|
|
#include "dialogs/status.h"
|
|
|
|
#include "document/html/frames.h"
|
|
|
|
#include "document/document.h"
|
|
|
|
#include "document/forms.h"
|
|
|
|
#include "document/view.h"
|
|
|
|
#include "ecmascript/ecmascript.h"
|
2008-07-18 12:46:12 -04:00
|
|
|
#include "ecmascript/spidermonkey.h"
|
2006-11-25 01:54:58 -05:00
|
|
|
#include "ecmascript/spidermonkey/document.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "ecmascript/spidermonkey/form.h"
|
2006-11-25 01:54:58 -05:00
|
|
|
#include "ecmascript/spidermonkey/window.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "intl/gettext/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"
|
|
|
|
|
|
|
|
|
2006-11-25 01:54:58 -05:00
|
|
|
static const JSClass form_class; /* defined below */
|
|
|
|
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
/* 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 */
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
|
|
|
|
static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);
|
2008-07-18 12:46:12 -04:00
|
|
|
static void input_finalize(JSContext *ctx, JSObject *obj);
|
2007-06-24 11:46:22 -04:00
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* Each @input_class object must have a @form_class parent. */
|
2005-09-15 09:58:31 -04:00
|
|
|
static const JSClass input_class = {
|
|
|
|
"input", /* here, we unleash ourselves */
|
2008-07-18 12:46:12 -04:00
|
|
|
JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */
|
2005-09-15 09:58:31 -04:00
|
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
|
|
input_get_property, input_set_property,
|
2008-07-18 12:46:12 -04:00
|
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, input_finalize
|
2005-09-15 09:58:31 -04:00
|
|
|
};
|
|
|
|
|
2006-12-06 16:09:14 -05:00
|
|
|
/* 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. */
|
2005-09-15 09:58:31 -04:00
|
|
|
enum input_prop {
|
2006-12-06 16:09:14 -05:00
|
|
|
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,
|
2005-09-15 09:58:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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 const JSPropertySpec input_props[] = {
|
|
|
|
{ "accessKey", JSP_INPUT_ACCESSKEY, JSPROP_ENUMERATE },
|
|
|
|
{ "alt", JSP_INPUT_ALT, JSPROP_ENUMERATE },
|
|
|
|
{ "checked", JSP_INPUT_CHECKED, JSPROP_ENUMERATE },
|
|
|
|
{ "defaultChecked",JSP_INPUT_DEFAULT_CHECKED,JSPROP_ENUMERATE },
|
|
|
|
{ "defaultValue",JSP_INPUT_DEFAULT_VALUE,JSPROP_ENUMERATE },
|
|
|
|
{ "disabled", JSP_INPUT_DISABLED, JSPROP_ENUMERATE },
|
|
|
|
{ "form", JSP_INPUT_FORM, JSPROP_ENUMERATE | JSPROP_READONLY },
|
|
|
|
{ "maxLength", JSP_INPUT_MAX_LENGTH, JSPROP_ENUMERATE },
|
|
|
|
{ "name", JSP_INPUT_NAME, JSPROP_ENUMERATE },
|
|
|
|
{ "readonly", JSP_INPUT_READONLY, JSPROP_ENUMERATE },
|
2006-05-02 03:36:23 -04:00
|
|
|
{ "selectedIndex",JSP_INPUT_SELECTED_INDEX,JSPROP_ENUMERATE },
|
2005-09-15 09:58:31 -04:00
|
|
|
{ "size", JSP_INPUT_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY },
|
|
|
|
{ "src", JSP_INPUT_SRC, JSPROP_ENUMERATE },
|
|
|
|
{ "tabindex", JSP_INPUT_TABINDEX, JSPROP_ENUMERATE | JSPROP_READONLY },
|
|
|
|
{ "type", JSP_INPUT_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY },
|
|
|
|
{ "value", JSP_INPUT_VALUE, JSPROP_ENUMERATE },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
static JSBool input_blur(JSContext *ctx, uintN argc, jsval *rval);
|
|
|
|
static JSBool input_click(JSContext *ctx, uintN argc, jsval *rval);
|
|
|
|
static JSBool input_focus(JSContext *ctx, uintN argc, jsval *rval);
|
|
|
|
static JSBool input_select(JSContext *ctx, uintN argc, jsval *rval);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2008-06-16 17:25:59 -04:00
|
|
|
static const spidermonkeyFunctionSpec input_funcs[] = {
|
2005-09-15 09:58:31 -04:00
|
|
|
{ "blur", input_blur, 0 },
|
|
|
|
{ "click", input_click, 0 },
|
|
|
|
{ "focus", input_focus, 0 },
|
|
|
|
{ "select", input_select, 0 },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2006-08-20 06:37:03 -04:00
|
|
|
static JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u);
|
2006-08-20 10:10:08 -04:00
|
|
|
static unicode_val_T jsval_to_accesskey(JSContext *ctx, jsval *vp);
|
2006-08-20 06:37:03 -04:00
|
|
|
|
2007-05-22 10:07:06 -04:00
|
|
|
|
|
|
|
static struct form_state *
|
2008-07-18 12:46:12 -04:00
|
|
|
input_get_form_state(JSContext *ctx, JSObject *jsinput)
|
2007-05-22 10:07:06 -04:00
|
|
|
{
|
2008-07-18 12:46:12 -04:00
|
|
|
struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput,
|
|
|
|
(JSClass *) &input_class,
|
|
|
|
NULL);
|
2007-05-22 10:07:06 -04:00
|
|
|
|
2008-07-18 12:46:12 -04:00
|
|
|
if (!fs) return NULL; /* detached */
|
2007-06-24 11:46:22 -04:00
|
|
|
|
2008-07-18 12:46:12 -04:00
|
|
|
assert(fs->ecmascript_obj == jsinput);
|
2007-05-27 12:18:44 -04:00
|
|
|
if_assert_failed return NULL;
|
2007-06-24 11:46:22 -04:00
|
|
|
|
2008-07-18 12:46:12 -04:00
|
|
|
return fs;
|
2007-05-22 10:07:06 -04:00
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_class.getProperty */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-11-24 01:50:12 -05:00
|
|
|
JSObject *parent_form; /* instance of @form_class */
|
|
|
|
JSObject *parent_doc; /* instance of @document_class */
|
|
|
|
JSObject *parent_win; /* instance of @window_class */
|
|
|
|
struct view_state *vs;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct document *document;
|
|
|
|
struct form_state *fs;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
int linknum;
|
|
|
|
struct link *link = NULL;
|
|
|
|
|
2006-12-03 04:14:22 -05:00
|
|
|
/* 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, obj, (JSClass *) &input_class, NULL))
|
|
|
|
return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_form = JS_GetParent(ctx, obj);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_doc = JS_GetParent(ctx, parent_form);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_win = JS_GetParent(ctx, parent_doc);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
|
|
|
|
2007-05-27 11:32:53 -04:00
|
|
|
vs = JS_GetInstancePrivate(ctx, parent_win,
|
|
|
|
(JSClass *) &window_class, NULL);
|
2006-11-24 01:50:12 -05:00
|
|
|
doc_view = vs->doc_view;
|
|
|
|
document = doc_view->document;
|
2008-07-18 12:46:12 -04:00
|
|
|
fs = input_get_form_state(ctx, obj);
|
|
|
|
if (!fs) return JS_FALSE; /* detached */
|
2006-11-24 01:50:12 -05:00
|
|
|
fc = find_form_control(document, fs);
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
assert(fc);
|
|
|
|
assert(fc->form && fs);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
if (!JSID_IS_INT(id))
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
linknum = get_form_control_link(document, fc);
|
|
|
|
/* Hiddens have no link. */
|
|
|
|
if (linknum >= 0) link = &document->links[linknum];
|
|
|
|
|
|
|
|
undef_to_jsval(ctx, vp);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
switch (JSID_TO_INT(id)) {
|
2005-09-15 09:58:31 -04:00
|
|
|
case JSP_INPUT_ACCESSKEY:
|
|
|
|
{
|
2006-08-20 06:37:03 -04:00
|
|
|
JSString *keystr;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!link) break;
|
|
|
|
|
2006-08-20 06:37:03 -04:00
|
|
|
if (!link->accesskey) {
|
|
|
|
*vp = JS_GetEmptyStringValue(ctx);
|
|
|
|
} else {
|
|
|
|
keystr = unicode_to_jsstring(ctx, link->accesskey);
|
|
|
|
if (keystr)
|
|
|
|
*vp = STRING_TO_JSVAL(keystr);
|
|
|
|
else
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JSP_INPUT_ALT:
|
|
|
|
string_to_jsval(ctx, vp, fc->alt);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_CHECKED:
|
|
|
|
boolean_to_jsval(ctx, vp, fs->state);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_DEFAULT_CHECKED:
|
|
|
|
boolean_to_jsval(ctx, vp, fc->default_state);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_DEFAULT_VALUE:
|
Bug 784: Keep form_control.default_value in the document charset.
Previously, html_special_form_control converted
form_control.default_value to the terminal charset, and init_form_state
then copied the value to form_state.value. However, when CONFIG_UTF8
is defined and UTF-8 I/O is enabled, form_state.value is supposed to
be in UTF-8, rather than in the terminal charset.
This mismatch could not be conveniently fixed in
html_special_form_control because that does not know which terminal is
being used and whether UTF-8 I/O is enabled there. Also, constructing
a conversion table from the document charset to form_state.value could
have ruined renderer_context.convert_table, because src/intl/charsets.c
does not support multiple concurrent conversion tables.
So instead, we now keep form_control.default_value in the document
charset, and convert it in the viewer each time it is needed. Because
the result of the conversion is kept in form_state.value between
incremental renderings, this shouldn't even slow things down too much.
I am not implementing the proper charset conversions for the DOM
defaultValue property yet, because the current code doesn't have
them for other string properties either, and bug 805 is already open
for that.
2007-04-29 15:01:13 -04:00
|
|
|
/* FIXME (bug 805): convert from the charset of the document */
|
2005-09-15 09:58:31 -04:00
|
|
|
string_to_jsval(ctx, vp, fc->default_value);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_DISABLED:
|
|
|
|
/* FIXME: <input readonly disabled> --pasky */
|
|
|
|
boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_DISABLED);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_FORM:
|
|
|
|
object_to_jsval(ctx, vp, parent_form);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_MAX_LENGTH:
|
|
|
|
int_to_jsval(ctx, vp, fc->maxlength);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_NAME:
|
|
|
|
string_to_jsval(ctx, vp, fc->name);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_READONLY:
|
|
|
|
/* FIXME: <input readonly disabled> --pasky */
|
|
|
|
boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_READONLY);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_SIZE:
|
|
|
|
int_to_jsval(ctx, vp, fc->size);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_SRC:
|
|
|
|
if (link && link->where_img)
|
|
|
|
string_to_jsval(ctx, vp, link->where_img);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_TABINDEX:
|
|
|
|
if (link)
|
|
|
|
/* FIXME: This is WRONG. --pasky */
|
|
|
|
int_to_jsval(ctx, vp, link->number);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_TYPE:
|
|
|
|
{
|
|
|
|
unsigned char *s = NULL;
|
|
|
|
|
|
|
|
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;
|
2006-05-02 03:36:23 -04:00
|
|
|
case FC_SELECT: s = "select"; break;
|
2005-09-15 09:58:31 -04:00
|
|
|
default: INTERNAL("input_get_property() upon a non-input item."); break;
|
|
|
|
}
|
|
|
|
string_to_jsval(ctx, vp, s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case JSP_INPUT_VALUE:
|
|
|
|
string_to_jsval(ctx, vp, fs->value);
|
|
|
|
break;
|
|
|
|
|
2006-05-02 03:36:23 -04:00
|
|
|
case JSP_INPUT_SELECTED_INDEX:
|
|
|
|
if (fc->type == FC_SELECT) int_to_jsval(ctx, vp, fs->state);
|
|
|
|
break;
|
2005-09-15 09:58:31 -04:00
|
|
|
default:
|
2007-05-27 11:36:31 -04:00
|
|
|
/* Unrecognized integer property ID; someone is using
|
|
|
|
* the object as an array. SMJS builtin classes (e.g.
|
2006-12-03 05:07:07 -05:00
|
|
|
* js_RegExpClass) just return JS_TRUE in this case
|
|
|
|
* and leave *@vp unchanged. Do the same here.
|
|
|
|
* (Actually not quite the same, as we already used
|
|
|
|
* @undef_to_jsval.) */
|
2005-09-15 09:58:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_class.setProperty */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-11-24 01:50:12 -05:00
|
|
|
JSObject *parent_form; /* instance of @form_class */
|
|
|
|
JSObject *parent_doc; /* instance of @document_class */
|
|
|
|
JSObject *parent_win; /* instance of @window_class */
|
|
|
|
struct view_state *vs;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct document *document;
|
|
|
|
struct form_state *fs;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
int linknum;
|
|
|
|
struct link *link = NULL;
|
2006-08-20 10:10:08 -04:00
|
|
|
unicode_val_T accesskey;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-12-03 04:14:22 -05:00
|
|
|
/* 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, obj, (JSClass *) &input_class, NULL))
|
|
|
|
return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_form = JS_GetParent(ctx, obj);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_doc = JS_GetParent(ctx, parent_form);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_win = JS_GetParent(ctx, parent_doc);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
|
|
|
|
2007-05-27 11:32:53 -04:00
|
|
|
vs = JS_GetInstancePrivate(ctx, parent_win,
|
|
|
|
(JSClass *) &window_class, NULL);
|
2006-11-24 01:50:12 -05:00
|
|
|
doc_view = vs->doc_view;
|
|
|
|
document = doc_view->document;
|
2008-07-18 12:46:12 -04:00
|
|
|
fs = input_get_form_state(ctx, obj);
|
|
|
|
if (!fs) return JS_FALSE; /* detached */
|
2006-11-24 01:50:12 -05:00
|
|
|
fc = find_form_control(document, fs);
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
assert(fc);
|
|
|
|
assert(fc->form && fs);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
if (!JSID_IS_INT(id))
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
linknum = get_form_control_link(document, fc);
|
|
|
|
/* Hiddens have no link. */
|
|
|
|
if (linknum >= 0) link = &document->links[linknum];
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
switch (JSID_TO_INT(id)) {
|
2005-09-15 09:58:31 -04:00
|
|
|
case JSP_INPUT_ACCESSKEY:
|
2006-08-20 10:10:08 -04:00
|
|
|
accesskey = jsval_to_accesskey(ctx, vp);
|
|
|
|
if (accesskey == UCS_NO_CHAR)
|
|
|
|
return JS_FALSE;
|
|
|
|
else if (link)
|
|
|
|
link->accesskey = accesskey;
|
2005-09-15 09:58:31 -04:00
|
|
|
break;
|
|
|
|
case JSP_INPUT_ALT:
|
|
|
|
mem_free_set(&fc->alt, stracpy(jsval_to_string(ctx, vp)));
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_CHECKED:
|
|
|
|
if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO)
|
|
|
|
break;
|
|
|
|
fs->state = jsval_to_boolean(ctx, vp);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_DISABLED:
|
|
|
|
/* FIXME: <input readonly disabled> --pasky */
|
|
|
|
fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_DISABLED
|
|
|
|
: fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY
|
|
|
|
: FORM_MODE_NORMAL);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_MAX_LENGTH:
|
2007-05-29 20:10:54 -04:00
|
|
|
if (!JS_ValueToInt32(ctx, *vp, &fc->maxlength))
|
2007-05-27 11:09:37 -04:00
|
|
|
return JS_FALSE;
|
2005-09-15 09:58:31 -04:00
|
|
|
break;
|
|
|
|
case JSP_INPUT_NAME:
|
|
|
|
mem_free_set(&fc->name, stracpy(jsval_to_string(ctx, vp)));
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_READONLY:
|
|
|
|
/* FIXME: <input readonly disabled> --pasky */
|
|
|
|
fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_READONLY
|
|
|
|
: fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED
|
|
|
|
: FORM_MODE_NORMAL);
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_SRC:
|
|
|
|
if (link) {
|
|
|
|
mem_free_set(&link->where_img, stracpy(jsval_to_string(ctx, vp)));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case JSP_INPUT_VALUE:
|
|
|
|
if (fc->type == FC_FILE)
|
|
|
|
break; /* A huge security risk otherwise. */
|
|
|
|
mem_free_set(&fs->value, stracpy(jsval_to_string(ctx, vp)));
|
|
|
|
if (fc->type == FC_TEXT || fc->type == FC_PASSWORD)
|
|
|
|
fs->state = strlen(fs->value);
|
|
|
|
break;
|
2006-05-02 05:28:41 -04:00
|
|
|
case JSP_INPUT_SELECTED_INDEX:
|
|
|
|
if (fc->type == FC_SELECT) {
|
2007-05-22 03:36:39 -04:00
|
|
|
int item;
|
|
|
|
|
2007-05-27 11:09:37 -04:00
|
|
|
if (!JS_ValueToInt32(ctx, *vp, &item))
|
|
|
|
return JS_FALSE;
|
2006-05-02 05:28:41 -04:00
|
|
|
|
|
|
|
if (item >= 0 && item < fc->nvalues) {
|
|
|
|
fs->state = item;
|
|
|
|
mem_free_set(&fs->value, stracpy(fc->values[item]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
default:
|
2007-05-27 11:36:31 -04:00
|
|
|
/* Unrecognized integer property ID; someone is using
|
|
|
|
* the object as an array. SMJS builtin classes (e.g.
|
2006-12-03 05:07:07 -05:00
|
|
|
* js_RegExpClass) just return JS_TRUE in this case.
|
|
|
|
* Do the same here. */
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_funcs{"blur"} */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_blur(JSContext *ctx, uintN argc, jsval *rval)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
/* We are a text-mode browser and there *always* has to be something
|
|
|
|
* selected. So we do nothing for now. (That was easy.) */
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_funcs{"click"} */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_click(JSContext *ctx, uintN argc, jsval *rval)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2011-04-19 16:41:05 -04:00
|
|
|
jsval val;
|
2006-11-24 01:50:12 -05:00
|
|
|
JSObject *parent_form; /* instance of @form_class */
|
|
|
|
JSObject *parent_doc; /* instance of @document_class */
|
|
|
|
JSObject *parent_win; /* instance of @window_class */
|
2011-04-19 16:41:05 -04:00
|
|
|
JSObject *obj = JS_THIS_OBJECT(ctx, rval);
|
|
|
|
jsval *argv = JS_ARGV(ctx, rval);
|
2006-11-24 01:50:12 -05:00
|
|
|
struct view_state *vs;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct document *document;
|
|
|
|
struct session *ses;
|
|
|
|
struct form_state *fs;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
int linknum;
|
|
|
|
|
2006-11-25 01:54:58 -05:00
|
|
|
if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_form = JS_GetParent(ctx, obj);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_doc = JS_GetParent(ctx, parent_form);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_win = JS_GetParent(ctx, parent_doc);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
|
|
|
|
2007-05-27 11:32:53 -04:00
|
|
|
vs = JS_GetInstancePrivate(ctx, parent_win,
|
|
|
|
(JSClass *) &window_class, NULL);
|
2006-11-24 01:50:12 -05:00
|
|
|
doc_view = vs->doc_view;
|
|
|
|
document = doc_view->document;
|
|
|
|
ses = doc_view->session;
|
2008-07-18 12:46:12 -04:00
|
|
|
fs = input_get_form_state(ctx, obj);
|
|
|
|
if (!fs) return JS_FALSE; /* detached */
|
2006-11-24 01:50:12 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
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 JS_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);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
boolean_to_jsval(ctx, &val, 0);
|
|
|
|
JS_SET_RVAL(ctx, rval, val);
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_funcs{"focus"} */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_focus(JSContext *ctx, uintN argc, jsval *rval)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2011-04-19 16:41:05 -04:00
|
|
|
jsval val;
|
2006-11-24 01:50:12 -05:00
|
|
|
JSObject *parent_form; /* instance of @form_class */
|
|
|
|
JSObject *parent_doc; /* instance of @document_class */
|
|
|
|
JSObject *parent_win; /* instance of @window_class */
|
2011-04-19 16:41:05 -04:00
|
|
|
JSObject *obj = JS_THIS_OBJECT(ctx, rval);
|
|
|
|
jsval *argv = JS_ARGV(ctx, rval);
|
2006-11-24 01:50:12 -05:00
|
|
|
struct view_state *vs;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct document *document;
|
|
|
|
struct session *ses;
|
|
|
|
struct form_state *fs;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
int linknum;
|
|
|
|
|
2006-11-25 01:54:58 -05:00
|
|
|
if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_form = JS_GetParent(ctx, obj);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_doc = JS_GetParent(ctx, parent_form);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_win = JS_GetParent(ctx, parent_doc);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
|
|
|
|
2007-05-27 11:32:53 -04:00
|
|
|
vs = JS_GetInstancePrivate(ctx, parent_win,
|
|
|
|
(JSClass *) &window_class, NULL);
|
2006-11-24 01:50:12 -05:00
|
|
|
doc_view = vs->doc_view;
|
|
|
|
document = doc_view->document;
|
|
|
|
ses = doc_view->session;
|
2008-07-18 12:46:12 -04:00
|
|
|
fs = input_get_form_state(ctx, obj);
|
|
|
|
if (!fs) return JS_FALSE; /* detached */
|
2006-11-24 01:50:12 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
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 JS_TRUE;
|
|
|
|
|
|
|
|
jump_to_link_number(ses, doc_view, linknum);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
boolean_to_jsval(ctx, &val, 0);
|
|
|
|
JS_SET_RVAL(ctx, rval, val);
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @input_funcs{"select"} */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
input_select(JSContext *ctx, uintN argc, jsval *rval)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
/* We support no text selecting yet. So we do nothing for now.
|
|
|
|
* (That was easy, too.) */
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSObject *
|
2008-07-18 12:46:12 -04:00
|
|
|
get_input_object(JSContext *ctx, JSObject *jsform, struct form_state *fs)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2008-07-18 12:46:12 -04:00
|
|
|
JSObject *jsinput = fs->ecmascript_obj;
|
|
|
|
|
|
|
|
if (jsinput) {
|
|
|
|
/* This assumes JS_GetInstancePrivate cannot GC. */
|
|
|
|
assert(JS_GetInstancePrivate(ctx, jsinput,
|
|
|
|
(JSClass *) &input_class, NULL)
|
|
|
|
== fs);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
|
|
|
return jsinput;
|
|
|
|
}
|
|
|
|
|
2006-01-30 05:15:04 -05:00
|
|
|
/* 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 */
|
2008-07-18 12:46:12 -04:00
|
|
|
jsinput = JS_NewObject(ctx, (JSClass *) &input_class, NULL, jsform);
|
|
|
|
if (!jsinput)
|
|
|
|
return NULL;
|
2006-01-30 05:15:04 -05:00
|
|
|
JS_DefineProperties(ctx, jsinput, (JSPropertySpec *) input_props);
|
2008-06-16 17:25:59 -04:00
|
|
|
spidermonkey_DefineFunctions(ctx, jsinput, input_funcs);
|
2008-07-18 12:46:12 -04:00
|
|
|
|
|
|
|
if (!JS_SetPrivate(ctx, jsinput, fs)) /* to @input_class */
|
|
|
|
return NULL;
|
|
|
|
fs->ecmascript_obj = jsinput;
|
|
|
|
return jsinput;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
input_finalize(JSContext *ctx, JSObject *jsinput)
|
|
|
|
{
|
|
|
|
struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput,
|
|
|
|
(JSClass *) &input_class,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
JSObject *jsinput = fs->ecmascript_obj;
|
|
|
|
|
|
|
|
if (jsinput) {
|
|
|
|
/* This assumes JS_GetInstancePrivate and JS_SetPrivate
|
|
|
|
* cannot GC. */
|
|
|
|
|
|
|
|
/* If this assertion fails, it is not clear whether
|
|
|
|
* the private pointer of jsinput should be reset;
|
|
|
|
* crashes seem possible either way. Resetting it is
|
|
|
|
* easiest. */
|
|
|
|
assert(JS_GetInstancePrivate(spidermonkey_empty_context,
|
|
|
|
jsinput,
|
|
|
|
(JSClass *) &input_class, NULL)
|
|
|
|
== fs);
|
|
|
|
if_assert_failed {}
|
|
|
|
|
|
|
|
JS_SetPrivate(spidermonkey_empty_context, jsinput, NULL);
|
|
|
|
fs->ecmascript_obj = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
spidermonkey_moved_form_state(struct form_state *fs)
|
|
|
|
{
|
|
|
|
JSObject *jsinput = fs->ecmascript_obj;
|
|
|
|
|
|
|
|
if (jsinput) {
|
|
|
|
/* This assumes JS_SetPrivate cannot GC. If it could,
|
|
|
|
* then the GC might call input_finalize for some
|
|
|
|
* other object whose struct form_state has also been
|
|
|
|
* reallocated, and an assertion would fail in
|
|
|
|
* input_finalize. */
|
|
|
|
JS_SetPrivate(spidermonkey_empty_context, jsinput, fs);
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static JSObject *
|
2008-07-18 12:46:12 -04:00
|
|
|
get_form_control_object(JSContext *ctx, JSObject *jsform,
|
|
|
|
enum form_type type, struct form_state *fs)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case FC_TEXT:
|
|
|
|
case FC_PASSWORD:
|
|
|
|
case FC_FILE:
|
|
|
|
case FC_CHECKBOX:
|
|
|
|
case FC_RADIO:
|
|
|
|
case FC_SUBMIT:
|
|
|
|
case FC_IMAGE:
|
|
|
|
case FC_RESET:
|
|
|
|
case FC_BUTTON:
|
|
|
|
case FC_HIDDEN:
|
2006-05-02 03:36:23 -04:00
|
|
|
case FC_SELECT:
|
2008-07-18 12:46:12 -04:00
|
|
|
return get_input_object(ctx, jsform, fs);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
case FC_TEXTAREA:
|
|
|
|
/* TODO */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
INTERNAL("Weird fc->type %d", type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-18 13:16:17 -04:00
|
|
|
static struct form_view *form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv);
|
2011-04-19 16:41:05 -04:00
|
|
|
static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-11-26 10:35:33 -05:00
|
|
|
/* Each @form_elements_class object must have a @form_class parent. */
|
2005-09-15 09:58:31 -04:00
|
|
|
static const JSClass form_elements_class = {
|
|
|
|
"elements",
|
|
|
|
JSCLASS_HAS_PRIVATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub,
|
2011-04-19 16:41:05 -04:00
|
|
|
form_elements_get_property, JS_StrictPropertyStub,
|
2005-09-15 09:58:31 -04:00
|
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
|
|
|
};
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
static JSBool form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
|
|
|
|
static JSBool form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
|
|
|
|
static JSBool form_elements_item(JSContext *ctx, uintN argc, jsval *rval);
|
|
|
|
static JSBool form_elements_namedItem(JSContext *ctx, uintN argc, jsval *rval);
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2008-06-16 17:25:59 -04:00
|
|
|
static const spidermonkeyFunctionSpec form_elements_funcs[] = {
|
2005-09-15 09:58:31 -04:00
|
|
|
{ "item", form_elements_item, 1 },
|
|
|
|
{ "namedItem", form_elements_namedItem, 1 },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2006-12-06 16:09:14 -05:00
|
|
|
/* Tinyids of properties. Use negative values to distinguish these
|
|
|
|
* from array indexes (elements[INT] for INT>=0 is equivalent to
|
|
|
|
* elements.item(INT)). ECMAScript code should not use these directly
|
|
|
|
* as in elements[-1]; future versions of ELinks may change the numbers. */
|
|
|
|
enum form_elements_prop {
|
|
|
|
JSP_FORM_ELEMENTS_LENGTH = -1,
|
|
|
|
};
|
2005-09-15 09:58:31 -04:00
|
|
|
static const JSPropertySpec form_elements_props[] = {
|
|
|
|
{ "length", JSP_FORM_ELEMENTS_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY},
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2006-11-23 16:33:43 -05:00
|
|
|
/* @form_elements_class.getProperty */
|
2005-09-15 09:58:31 -04:00
|
|
|
static JSBool
|
2011-04-19 16:41:05 -04:00
|
|
|
form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2011-04-19 16:41:05 -04:00
|
|
|
jsval idval;
|
2006-11-24 01:50:12 -05:00
|
|
|
JSObject *parent_form; /* instance of @form_class */
|
|
|
|
JSObject *parent_doc; /* instance of @document_class */
|
|
|
|
JSObject *parent_win; /* instance of @window_class */
|
|
|
|
struct view_state *vs;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct document *document;
|
|
|
|
struct form_view *form_view;
|
|
|
|
struct form *form;
|
|
|
|
|
2006-12-03 04:14:22 -05:00
|
|
|
/* 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, obj, (JSClass *) &form_elements_class, NULL))
|
|
|
|
return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_form = JS_GetParent(ctx, obj);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_doc = JS_GetParent(ctx, parent_form);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
2006-11-24 01:50:12 -05:00
|
|
|
parent_win = JS_GetParent(ctx, parent_doc);
|
2006-11-25 01:54:58 -05:00
|
|
|
assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
|
|
|
|
if_assert_failed return JS_FALSE;
|
|
|
|
|
2007-05-27 11:32:53 -04:00
|
|
|
vs = JS_GetInstancePrivate(ctx, parent_win,
|
|
|
|
(JSClass *) &window_class, NULL);
|
2006-11-24 01:50:12 -05:00
|
|
|
doc_view = vs->doc_view;
|
|
|
|
document = doc_view->document;
|
2008-07-18 13:16:17 -04:00
|
|
|
form_view = form_get_form_view(ctx, parent_form, NULL);
|
|
|
|
if (!form_view) return JS_FALSE; /* detached */
|
2006-11-24 01:50:12 -05:00
|
|
|
form = find_form_by_form_view(document, form_view);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
if (JSID_IS_STRING(id)) {
|
|
|
|
JS_IdToValue(ctx, id, &idval);
|
|
|
|
form_elements_namedItem2(ctx, obj, 1, &idval, vp);
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
if (!JSID_IS_INT(id))
|
2005-09-15 09:58:31 -04:00
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
undef_to_jsval(ctx, vp);
|
|
|
|
|
2011-04-19 16:41:05 -04:00
|
|
|
switch (JSID_TO_INT(id)) {
|
2005-09-15 09:58:31 -04:00
|
|
|
case JSP_FORM_ELEMENTS_LENGTH:
|
|
|
|
int_to_jsval(ctx, vp, list_size(&form->items));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Array index. */
|
2011-04-19 16:41:05 -04:00
|
|
|
JS_IdToValue(ctx, id, &idval);
|
|
|
|
form_elements_item2(ctx, obj, 1, &idval, vp);
|
2005-09-15 09:58:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-11-25 17:15:09 -05:00
|
|
|
/* @form_elements_funcs{"item"} */
|
2011-04-19 16:41:05 -04:00
|
|
|
static JSBool
|
|
|
|
form_elements_item(JSContext *ctx, uintN argc, jsval *rval)
|
|
|
|
{
|
2012-11-18 17:34:49 -05:00
|
|
|
jsval val = JSVAL_VOID;
|
|