grafthistory: support curl
[elinks/elinks-j605.git] / src / ecmascript / spidermonkey / form.c
blobc0d3e43f3674e1ce09af8ba52aeb09a1263704e5
1 /* The SpiderMonkey window object implementation. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include "elinks.h"
13 #include "ecmascript/spidermonkey/util.h"
15 #include "bfu/dialog.h"
16 #include "cache/cache.h"
17 #include "cookies/cookies.h"
18 #include "dialogs/menu.h"
19 #include "dialogs/status.h"
20 #include "document/html/frames.h"
21 #include "document/document.h"
22 #include "document/forms.h"
23 #include "document/view.h"
24 #include "ecmascript/ecmascript.h"
25 #include "ecmascript/spidermonkey/document.h"
26 #include "ecmascript/spidermonkey/form.h"
27 #include "ecmascript/spidermonkey/window.h"
28 #include "intl/gettext/libintl.h"
29 #include "main/select.h"
30 #include "osdep/newwin.h"
31 #include "osdep/sysname.h"
32 #include "protocol/http/http.h"
33 #include "protocol/uri.h"
34 #include "session/history.h"
35 #include "session/location.h"
36 #include "session/session.h"
37 #include "session/task.h"
38 #include "terminal/tab.h"
39 #include "terminal/terminal.h"
40 #include "util/conv.h"
41 #include "util/memory.h"
42 #include "util/string.h"
43 #include "viewer/text/draw.h"
44 #include "viewer/text/form.h"
45 #include "viewer/text/link.h"
46 #include "viewer/text/vs.h"
49 static const JSClass form_class; /* defined below */
52 /* Accordingly to the JS specs, each input type should own object. That'd be a
53 * huge PITA though, however DOM comes to the rescue and defines just a single
54 * HTMLInputElement. The difference could be spotted only by some clever tricky
55 * JS code, but I hope it doesn't matter anywhere. --pasky */
57 static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
58 static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
60 /* Each @input_class object must have a @form_class parent. */
61 static const JSClass input_class = {
62 "input", /* here, we unleash ourselves */
63 /* In instances of @input_class, the private data is not
64 * actually a pointer, although SMJS assumes so. Rather, it
65 * is an integer used as an index to view_state.form_info[].
66 * This allows ELinks to reallocate form_info[] without
67 * keeping track of SMJS objects that refer to its elements.
69 * JS_SetPrivate converts private pointers to jsval, and
70 * JS_GetPrivate converts back. These conversions assume that
71 * private pointers are aligned. Therefore, ELinks must not
72 * cast the integer directly to void *. Instead, ELinks takes
73 * advantage of the fact that the jsval format for private
74 * pointers is the same as for integers (presumably to make GC
75 * ignore the pointers). So when ELinks is initializing the
76 * private data, it converts the integer to a jsval and from
77 * there to a pointer, which SMJS then converts back to the
78 * same jsval. */
79 JSCLASS_HAS_PRIVATE,
80 JS_PropertyStub, JS_PropertyStub,
81 input_get_property, input_set_property,
82 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
85 enum input_prop {
86 JSP_INPUT_ACCESSKEY,
87 JSP_INPUT_ALT,
88 JSP_INPUT_CHECKED,
89 JSP_INPUT_DEFAULT_CHECKED,
90 JSP_INPUT_DEFAULT_VALUE,
91 JSP_INPUT_DISABLED,
92 JSP_INPUT_FORM,
93 JSP_INPUT_MAX_LENGTH,
94 JSP_INPUT_NAME,
95 JSP_INPUT_READONLY,
96 JSP_INPUT_SIZE,
97 JSP_INPUT_SRC,
98 JSP_INPUT_TABINDEX,
99 JSP_INPUT_TYPE,
100 JSP_INPUT_VALUE
103 /* XXX: Some of those are marked readonly just because we can't change them
104 * safely now. Changing default* values would affect all open instances of the
105 * document, leading to a potential security risk. Changing size and type would
106 * require re-rendering the document (TODO), tabindex would require renumbering
107 * of all links and whatnot. --pasky */
108 static const JSPropertySpec input_props[] = {
109 { "accessKey", JSP_INPUT_ACCESSKEY, JSPROP_ENUMERATE },
110 { "alt", JSP_INPUT_ALT, JSPROP_ENUMERATE },
111 { "checked", JSP_INPUT_CHECKED, JSPROP_ENUMERATE },
112 { "defaultChecked",JSP_INPUT_DEFAULT_CHECKED,JSPROP_ENUMERATE },
113 { "defaultValue",JSP_INPUT_DEFAULT_VALUE,JSPROP_ENUMERATE },
114 { "disabled", JSP_INPUT_DISABLED, JSPROP_ENUMERATE },
115 { "form", JSP_INPUT_FORM, JSPROP_ENUMERATE | JSPROP_READONLY },
116 { "maxLength", JSP_INPUT_MAX_LENGTH, JSPROP_ENUMERATE },
117 { "name", JSP_INPUT_NAME, JSPROP_ENUMERATE },
118 { "readonly", JSP_INPUT_READONLY, JSPROP_ENUMERATE },
119 { "size", JSP_INPUT_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY },
120 { "src", JSP_INPUT_SRC, JSPROP_ENUMERATE },
121 { "tabindex", JSP_INPUT_TABINDEX, JSPROP_ENUMERATE | JSPROP_READONLY },
122 { "type", JSP_INPUT_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY },
123 { "value", JSP_INPUT_VALUE, JSPROP_ENUMERATE },
124 { NULL }
127 static JSBool input_blur(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
128 static JSBool input_click(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
129 static JSBool input_focus(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
130 static JSBool input_select(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
132 static const spidermonkeyFunctionSpec input_funcs[] = {
133 { "blur", input_blur, 0 },
134 { "click", input_click, 0 },
135 { "focus", input_focus, 0 },
136 { "select", input_select, 0 },
137 { NULL }
141 static struct form_state *
142 input_get_form_state(JSContext *ctx, JSObject *obj, struct view_state *vs)
144 void *private = JS_GetInstancePrivate(ctx, obj,
145 (JSClass *) &input_class,
146 NULL);
147 int n = JSVAL_TO_INT(PRIVATE_TO_JSVAL(private));
149 return &vs->form_info[n];
152 /* @input_class.getProperty */
153 static JSBool
154 input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
156 JSObject *parent_form; /* instance of @form_class */
157 JSObject *parent_doc; /* instance of @document_class */
158 JSObject *parent_win; /* instance of @window_class */
159 struct view_state *vs;
160 struct document_view *doc_view;
161 struct document *document;
162 struct form_state *fs;
163 struct form_control *fc;
164 int linknum;
165 struct link *link = NULL;
167 /* This can be called if @obj if not itself an instance of the
168 * appropriate class but has one in its prototype chain. Fail
169 * such calls. */
170 if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, NULL))
171 return JS_FALSE;
172 parent_form = JS_GetParent(ctx, obj);
173 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
174 if_assert_failed return JS_FALSE;
175 parent_doc = JS_GetParent(ctx, parent_form);
176 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
177 if_assert_failed return JS_FALSE;
178 parent_win = JS_GetParent(ctx, parent_doc);
179 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
180 if_assert_failed return JS_FALSE;
182 vs = JS_GetInstancePrivate(ctx, parent_win,
183 (JSClass *) &window_class, NULL);
184 doc_view = vs->doc_view;
185 document = doc_view->document;
186 fs = input_get_form_state(ctx, obj, vs);
187 fc = find_form_control(document, fs);
189 assert(fc);
190 assert(fc->form && fs);
192 if (!JSVAL_IS_INT(id))
193 return JS_TRUE;
195 linknum = get_form_control_link(document, fc);
196 /* Hiddens have no link. */
197 if (linknum >= 0) link = &document->links[linknum];
199 undef_to_jsval(ctx, vp);
201 switch (JSVAL_TO_INT(id)) {
202 case JSP_INPUT_ACCESSKEY:
204 struct string keystr;
206 if (!link) break;
208 init_string(&keystr);
209 add_accesskey_to_string(&keystr, link->accesskey);
210 string_to_jsval(ctx, vp, keystr.source);
211 done_string(&keystr);
212 break;
214 case JSP_INPUT_ALT:
215 string_to_jsval(ctx, vp, fc->alt);
216 break;
217 case JSP_INPUT_CHECKED:
218 boolean_to_jsval(ctx, vp, fs->state);
219 break;
220 case JSP_INPUT_DEFAULT_CHECKED:
221 boolean_to_jsval(ctx, vp, fc->default_state);
222 break;
223 case JSP_INPUT_DEFAULT_VALUE:
224 string_to_jsval(ctx, vp, fc->default_value);
225 break;
226 case JSP_INPUT_DISABLED:
227 /* FIXME: <input readonly disabled> --pasky */
228 boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_DISABLED);
229 break;
230 case JSP_INPUT_FORM:
231 object_to_jsval(ctx, vp, parent_form);
232 break;
233 case JSP_INPUT_MAX_LENGTH:
234 int_to_jsval(ctx, vp, fc->maxlength);
235 break;
236 case JSP_INPUT_NAME:
237 string_to_jsval(ctx, vp, fc->name);
238 break;
239 case JSP_INPUT_READONLY:
240 /* FIXME: <input readonly disabled> --pasky */
241 boolean_to_jsval(ctx, vp, fc->mode == FORM_MODE_READONLY);
242 break;
243 case JSP_INPUT_SIZE:
244 int_to_jsval(ctx, vp, fc->size);
245 break;
246 case JSP_INPUT_SRC:
247 if (link && link->where_img)
248 string_to_jsval(ctx, vp, link->where_img);
249 break;
250 case JSP_INPUT_TABINDEX:
251 if (link)
252 /* FIXME: This is WRONG. --pasky */
253 int_to_jsval(ctx, vp, link->number);
254 break;
255 case JSP_INPUT_TYPE:
257 unsigned char *s = NULL;
259 switch (fc->type) {
260 case FC_TEXT: s = "text"; break;
261 case FC_PASSWORD: s = "password"; break;
262 case FC_FILE: s = "file"; break;
263 case FC_CHECKBOX: s = "checkbox"; break;
264 case FC_RADIO: s = "radio"; break;
265 case FC_SUBMIT: s = "submit"; break;
266 case FC_IMAGE: s = "image"; break;
267 case FC_RESET: s = "reset"; break;
268 case FC_BUTTON: s = "button"; break;
269 case FC_HIDDEN: s = "hidden"; break;
270 default: INTERNAL("input_get_property() upon a non-input item."); break;
272 string_to_jsval(ctx, vp, s);
273 break;
275 case JSP_INPUT_VALUE:
276 string_to_jsval(ctx, vp, fs->value);
277 break;
279 default:
280 /* Unrecognized integer property ID; someone is using
281 * the object as an array. SMJS builtin classes (e.g.
282 * js_RegExpClass) just return JS_TRUE in this case
283 * and leave *@vp unchanged. Do the same here.
284 * (Actually not quite the same, as we already used
285 * @undef_to_jsval.) */
286 break;
289 return JS_TRUE;
292 /* @input_class.setProperty */
293 static JSBool
294 input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
296 JSObject *parent_form; /* instance of @form_class */
297 JSObject *parent_doc; /* instance of @document_class */
298 JSObject *parent_win; /* instance of @window_class */
299 struct view_state *vs;
300 struct document_view *doc_view;
301 struct document *document;
302 struct form_state *fs;
303 struct form_control *fc;
304 int linknum;
305 struct link *link = NULL;
307 /* This can be called if @obj if not itself an instance of the
308 * appropriate class but has one in its prototype chain. Fail
309 * such calls. */
310 if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, NULL))
311 return JS_FALSE;
312 parent_form = JS_GetParent(ctx, obj);
313 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
314 if_assert_failed return JS_FALSE;
315 parent_doc = JS_GetParent(ctx, parent_form);
316 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
317 if_assert_failed return JS_FALSE;
318 parent_win = JS_GetParent(ctx, parent_doc);
319 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
320 if_assert_failed return JS_FALSE;
322 vs = JS_GetInstancePrivate(ctx, parent_win,
323 (JSClass *) &window_class, NULL);
324 doc_view = vs->doc_view;
325 document = doc_view->document;
326 fs = input_get_form_state(ctx, obj, vs);
327 fc = find_form_control(document, fs);
329 assert(fc);
330 assert(fc->form && fs);
332 if (!JSVAL_IS_INT(id))
333 return JS_TRUE;
335 linknum = get_form_control_link(document, fc);
336 /* Hiddens have no link. */
337 if (linknum >= 0) link = &document->links[linknum];
339 switch (JSVAL_TO_INT(id)) {
340 case JSP_INPUT_ACCESSKEY:
341 if (link)
342 link->accesskey = accesskey_string_to_unicode(jsval_to_string(ctx, vp));
343 break;
344 case JSP_INPUT_ALT:
345 mem_free_set(&fc->alt, stracpy(jsval_to_string(ctx, vp)));
346 break;
347 case JSP_INPUT_CHECKED:
348 if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO)
349 break;
350 fs->state = jsval_to_boolean(ctx, vp);
351 break;
352 case JSP_INPUT_DISABLED:
353 /* FIXME: <input readonly disabled> --pasky */
354 fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_DISABLED
355 : fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY
356 : FORM_MODE_NORMAL);
357 break;
358 case JSP_INPUT_MAX_LENGTH:
359 fc->maxlength = atol(jsval_to_string(ctx, vp));
360 break;
361 case JSP_INPUT_NAME:
362 mem_free_set(&fc->name, stracpy(jsval_to_string(ctx, vp)));
363 break;
364 case JSP_INPUT_READONLY:
365 /* FIXME: <input readonly disabled> --pasky */
366 fc->mode = (jsval_to_boolean(ctx, vp) ? FORM_MODE_READONLY
367 : fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED
368 : FORM_MODE_NORMAL);
369 break;
370 case JSP_INPUT_SRC:
371 if (link) {
372 mem_free_set(&link->where_img, stracpy(jsval_to_string(ctx, vp)));
374 break;
375 case JSP_INPUT_VALUE:
376 if (fc->type == FC_FILE)
377 break; /* A huge security risk otherwise. */
378 mem_free_set(&fs->value, stracpy(jsval_to_string(ctx, vp)));
379 if (fc->type == FC_TEXT || fc->type == FC_PASSWORD)
380 fs->state = strlen(fs->value);
381 break;
383 default:
384 /* Unrecognized integer property ID; someone is using
385 * the object as an array. SMJS builtin classes (e.g.
386 * js_RegExpClass) just return JS_TRUE in this case.
387 * Do the same here. */
388 return JS_TRUE;
391 return JS_TRUE;
394 /* @input_funcs{"blur"} */
395 static JSBool
396 input_blur(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
398 /* We are a text-mode browser and there *always* has to be something
399 * selected. So we do nothing for now. (That was easy.) */
400 return JS_TRUE;
403 /* @input_funcs{"click"} */
404 static JSBool
405 input_click(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
407 JSObject *parent_form; /* instance of @form_class */
408 JSObject *parent_doc; /* instance of @document_class */
409 JSObject *parent_win; /* instance of @window_class */
410 struct view_state *vs;
411 struct document_view *doc_view;
412 struct document *document;
413 struct session *ses;
414 struct form_state *fs;
415 struct form_control *fc;
416 int linknum;
418 if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE;
419 parent_form = JS_GetParent(ctx, obj);
420 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
421 if_assert_failed return JS_FALSE;
422 parent_doc = JS_GetParent(ctx, parent_form);
423 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
424 if_assert_failed return JS_FALSE;
425 parent_win = JS_GetParent(ctx, parent_doc);
426 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
427 if_assert_failed return JS_FALSE;
429 vs = JS_GetInstancePrivate(ctx, parent_win,
430 (JSClass *) &window_class, NULL);
431 doc_view = vs->doc_view;
432 document = doc_view->document;
433 ses = doc_view->session;
434 fs = input_get_form_state(ctx, obj, vs);
436 assert(fs);
437 fc = find_form_control(document, fs);
438 assert(fc);
440 linknum = get_form_control_link(document, fc);
441 /* Hiddens have no link. */
442 if (linknum < 0)
443 return JS_TRUE;
445 /* Restore old current_link afterwards? */
446 jump_to_link_number(ses, doc_view, linknum);
447 if (enter(ses, doc_view, 0) == FRAME_EVENT_REFRESH)
448 refresh_view(ses, doc_view, 0);
449 else
450 print_screen_status(ses);
452 boolean_to_jsval(ctx, rval, 0);
453 return JS_TRUE;
456 /* @input_funcs{"focus"} */
457 static JSBool
458 input_focus(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
460 JSObject *parent_form; /* instance of @form_class */
461 JSObject *parent_doc; /* instance of @document_class */
462 JSObject *parent_win; /* instance of @window_class */
463 struct view_state *vs;
464 struct document_view *doc_view;
465 struct document *document;
466 struct session *ses;
467 struct form_state *fs;
468 struct form_control *fc;
469 int linknum;
471 if (!JS_InstanceOf(ctx, obj, (JSClass *) &input_class, argv)) return JS_FALSE;
472 parent_form = JS_GetParent(ctx, obj);
473 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
474 if_assert_failed return JS_FALSE;
475 parent_doc = JS_GetParent(ctx, parent_form);
476 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
477 if_assert_failed return JS_FALSE;
478 parent_win = JS_GetParent(ctx, parent_doc);
479 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
480 if_assert_failed return JS_FALSE;
482 vs = JS_GetInstancePrivate(ctx, parent_win,
483 (JSClass *) &window_class, NULL);
484 doc_view = vs->doc_view;
485 document = doc_view->document;
486 ses = doc_view->session;
487 fs = input_get_form_state(ctx, obj, vs);
489 assert(fs);
490 fc = find_form_control(document, fs);
491 assert(fc);
493 linknum = get_form_control_link(document, fc);
494 /* Hiddens have no link. */
495 if (linknum < 0)
496 return JS_TRUE;
498 jump_to_link_number(ses, doc_view, linknum);
500 boolean_to_jsval(ctx, rval, 0);
501 return JS_TRUE;
504 /* @input_funcs{"select"} */
505 static JSBool
506 input_select(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
508 /* We support no text selecting yet. So we do nothing for now.
509 * (That was easy, too.) */
510 return JS_TRUE;
513 static JSObject *
514 get_input_object(JSContext *ctx, JSObject *jsform, long number)
516 #if 0
517 if (fs->ecmascript_obj)
518 return fs->ecmascript_obj;
519 #endif
520 /* jsform ('form') is input's parent */
521 /* FIXME: That is NOT correct since the real containing element
522 * should be its parent, but gimme DOM first. --pasky */
523 JSObject *jsinput = JS_NewObject(ctx, (JSClass *) &input_class, NULL, jsform);
524 void *private = JSVAL_TO_PRIVATE(INT_TO_JSVAL(number));
526 JS_DefineProperties(ctx, jsinput, (JSPropertySpec *) input_props);
527 spidermonkey_DefineFunctions(ctx, jsinput, input_funcs);
528 JS_SetPrivate(ctx, jsinput, private); /* to @input_class */
529 return jsinput;;
533 static JSObject *
534 get_form_control_object(JSContext *ctx, JSObject *jsform, enum form_type type, int number)
536 switch (type) {
537 case FC_TEXT:
538 case FC_PASSWORD:
539 case FC_FILE:
540 case FC_CHECKBOX:
541 case FC_RADIO:
542 case FC_SUBMIT:
543 case FC_IMAGE:
544 case FC_RESET:
545 case FC_BUTTON:
546 case FC_HIDDEN:
547 return get_input_object(ctx, jsform, (long)number);
549 case FC_TEXTAREA:
550 case FC_SELECT:
551 /* TODO */
552 return NULL;
554 default:
555 INTERNAL("Weird fc->type %d", type);
556 return NULL;
562 static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
564 /* Each @form_elements_class object must have a @form_class parent. */
565 static const JSClass form_elements_class = {
566 "elements",
567 JSCLASS_HAS_PRIVATE,
568 JS_PropertyStub, JS_PropertyStub,
569 form_elements_get_property, JS_PropertyStub,
570 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
573 static JSBool form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
574 static JSBool form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
576 static const spidermonkeyFunctionSpec form_elements_funcs[] = {
577 { "item", form_elements_item, 1 },
578 { "namedItem", form_elements_namedItem, 1 },
579 { NULL }
582 /* INTs from 0 up are equivalent to item(INT), so we have to stuff length out
583 * of the way. */
584 enum form_elements_prop { JSP_FORM_ELEMENTS_LENGTH = -1 };
585 static const JSPropertySpec form_elements_props[] = {
586 { "length", JSP_FORM_ELEMENTS_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY},
587 { NULL }
590 /* @form_elements_class.getProperty */
591 static JSBool
592 form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
594 JSObject *parent_form; /* instance of @form_class */
595 JSObject *parent_doc; /* instance of @document_class */
596 JSObject *parent_win; /* instance of @window_class */
597 struct view_state *vs;
598 struct document_view *doc_view;
599 struct document *document;
600 struct form_view *form_view;
601 struct form *form;
603 /* This can be called if @obj if not itself an instance of the
604 * appropriate class but has one in its prototype chain. Fail
605 * such calls. */
606 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, NULL))
607 return JS_FALSE;
608 parent_form = JS_GetParent(ctx, obj);
609 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
610 if_assert_failed return JS_FALSE;
611 parent_doc = JS_GetParent(ctx, parent_form);
612 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
613 if_assert_failed return JS_FALSE;
614 parent_win = JS_GetParent(ctx, parent_doc);
615 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
616 if_assert_failed return JS_FALSE;
618 vs = JS_GetInstancePrivate(ctx, parent_win,
619 (JSClass *) &window_class, NULL);
620 doc_view = vs->doc_view;
621 document = doc_view->document;
622 form_view = JS_GetInstancePrivate(ctx, parent_form,
623 (JSClass *) &form_class, NULL);
624 form = find_form_by_form_view(document, form_view);
626 if (JSVAL_IS_STRING(id)) {
627 form_elements_namedItem(ctx, obj, 1, &id, vp);
628 return JS_TRUE;
631 if (!JSVAL_IS_INT(id))
632 return JS_TRUE;
634 undef_to_jsval(ctx, vp);
636 switch (JSVAL_TO_INT(id)) {
637 case JSP_FORM_ELEMENTS_LENGTH:
638 int_to_jsval(ctx, vp, list_size(&form->items));
639 break;
640 default:
641 /* Array index. */
642 form_elements_item(ctx, obj, 1, &id, vp);
643 break;
646 return JS_TRUE;
649 /* @form_elements_funcs{"item"} */
650 static JSBool
651 form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
653 JSObject *parent_form; /* instance of @form_class */
654 JSObject *parent_doc; /* instance of @document_class */
655 JSObject *parent_win; /* instance of @window_class */
656 struct view_state *vs;
657 struct document_view *doc_view;
658 struct document *document;
659 struct form_view *form_view;
660 struct form *form;
661 struct form_control *fc;
662 int counter = -1;
663 int index;
665 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, argv)) return JS_FALSE;
666 parent_form = JS_GetParent(ctx, obj);
667 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
668 if_assert_failed return JS_FALSE;
669 parent_doc = JS_GetParent(ctx, parent_form);
670 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
671 if_assert_failed return JS_FALSE;
672 parent_win = JS_GetParent(ctx, parent_doc);
673 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
674 if_assert_failed return JS_FALSE;
676 vs = JS_GetInstancePrivate(ctx, parent_win,
677 (JSClass *) &window_class, NULL);
678 doc_view = vs->doc_view;
679 document = doc_view->document;
680 form_view = JS_GetInstancePrivate(ctx, parent_form,
681 (JSClass *) &form_class, NULL);
682 form = find_form_by_form_view(document, form_view);
684 if (argc != 1)
685 return JS_TRUE;
687 index = atol(jsval_to_string(ctx, &argv[0]));
689 undef_to_jsval(ctx, rval);
691 foreach (fc, form->items) {
692 counter++;
693 if (counter == index) {
694 struct form_state *fs = find_form_state(doc_view, fc);
696 if (fs) {
697 JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fc->g_ctrl_num);
699 if (fcobj)
700 object_to_jsval(ctx, rval, fcobj);
702 break;
706 return JS_TRUE;
709 /* @form_elements_funcs{"namedItem"} */
710 static JSBool
711 form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
713 JSObject *parent_form; /* instance of @form_class */
714 JSObject *parent_doc; /* instance of @document_class */
715 JSObject *parent_win; /* instance of @window_class */
716 struct view_state *vs;
717 struct document_view *doc_view;
718 struct document *document;
719 struct form_view *form_view;
720 struct form *form;
721 struct form_control *fc;
722 unsigned char *string;
724 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_elements_class, argv)) return JS_FALSE;
725 parent_form = JS_GetParent(ctx, obj);
726 assert(JS_InstanceOf(ctx, parent_form, (JSClass *) &form_class, NULL));
727 if_assert_failed return JS_FALSE;
728 parent_doc = JS_GetParent(ctx, parent_form);
729 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
730 if_assert_failed return JS_FALSE;
731 parent_win = JS_GetParent(ctx, parent_doc);
732 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
733 if_assert_failed return JS_FALSE;
735 vs = JS_GetInstancePrivate(ctx, parent_win,
736 (JSClass *) &window_class, NULL);
737 doc_view = vs->doc_view;
738 document = doc_view->document;
739 form_view = JS_GetInstancePrivate(ctx, parent_form,
740 (JSClass *) &form_class, NULL);
741 form = find_form_by_form_view(document, form_view);
743 if (argc != 1)
744 return JS_TRUE;
746 string = jsval_to_string(ctx, &argv[0]);
747 if (!*string)
748 return JS_TRUE;
750 undef_to_jsval(ctx, rval);
752 foreach (fc, form->items) {
753 if (fc->name && !strcasecmp(string, fc->name)) {
754 struct form_state *fs = find_form_state(doc_view, fc);
756 if (fs) {
757 JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fc->g_ctrl_num);
759 if (fcobj)
760 object_to_jsval(ctx, rval, fcobj);
762 break;
766 return JS_TRUE;
771 static JSBool form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
772 static JSBool form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
774 /* Each @form_class object must have a @document_class parent. */
775 static const JSClass form_class = {
776 "form",
777 JSCLASS_HAS_PRIVATE, /* struct form_view * */
778 JS_PropertyStub, JS_PropertyStub,
779 form_get_property, form_set_property,
780 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
783 enum form_prop {
784 JSP_FORM_ACTION,
785 JSP_FORM_ELEMENTS,
786 JSP_FORM_ENCODING,
787 JSP_FORM_LENGTH,
788 JSP_FORM_METHOD,
789 JSP_FORM_NAME,
790 JSP_FORM_TARGET
793 static const JSPropertySpec form_props[] = {
794 { "action", JSP_FORM_ACTION, JSPROP_ENUMERATE },
795 { "elements", JSP_FORM_ELEMENTS, JSPROP_ENUMERATE },
796 { "encoding", JSP_FORM_ENCODING, JSPROP_ENUMERATE },
797 { "length", JSP_FORM_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY },
798 { "method", JSP_FORM_METHOD, JSPROP_ENUMERATE },
799 { "name", JSP_FORM_NAME, JSPROP_ENUMERATE },
800 { "target", JSP_FORM_TARGET, JSPROP_ENUMERATE },
801 { NULL }
804 static JSBool form_reset(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
805 static JSBool form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
807 static const spidermonkeyFunctionSpec form_funcs[] = {
808 { "reset", form_reset, 0 },
809 { "submit", form_submit, 0 },
810 { NULL }
813 /* @form_class.getProperty */
814 static JSBool
815 form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
817 /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */
818 JSObject *parent_doc; /* instance of @document_class */
819 JSObject *parent_win; /* instance of @window_class */
820 struct view_state *vs;
821 struct document_view *doc_view;
822 struct form_view *fv;
823 struct form *form;
825 /* This can be called if @obj if not itself an instance of the
826 * appropriate class but has one in its prototype chain. Fail
827 * such calls. */
828 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, NULL))
829 return JS_FALSE;
830 parent_doc = JS_GetParent(ctx, obj);
831 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
832 if_assert_failed return JS_FALSE;
833 parent_win = JS_GetParent(ctx, parent_doc);
834 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
835 if_assert_failed return JS_FALSE;
837 vs = JS_GetInstancePrivate(ctx, parent_win,
838 (JSClass *) &window_class, NULL);
839 doc_view = vs->doc_view;
840 fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, NULL);
841 form = find_form_by_form_view(doc_view->document, fv);
843 assert(form);
845 if (JSVAL_IS_STRING(id)) {
846 struct form_control *fc;
847 unsigned char *string;
849 string = jsval_to_string(ctx, &id);
850 foreach (fc, form->items) {
851 JSObject *fcobj = NULL;
852 struct form_state *fs;
854 if (!fc->name || strcasecmp(string, fc->name))
855 continue;
857 undef_to_jsval(ctx, vp);
858 fs = find_form_state(doc_view, fc);
859 if (fs) {
860 fcobj = get_form_control_object(ctx, obj, fc->type, fc->g_ctrl_num);
861 if (fcobj)
862 object_to_jsval(ctx, vp, fcobj);
864 break;
866 return JS_TRUE;
869 if (!JSVAL_IS_INT(id))
870 return JS_TRUE;
872 undef_to_jsval(ctx, vp);
874 switch (JSVAL_TO_INT(id)) {
875 case JSP_FORM_ACTION:
876 string_to_jsval(ctx, vp, form->action);
877 break;
879 case JSP_FORM_ELEMENTS:
881 /* jsform ('form') is form_elements' parent; who knows is that's correct */
882 JSObject *jsform_elems = JS_NewObject(ctx, (JSClass *) &form_elements_class, NULL, obj);
884 JS_DefineProperties(ctx, jsform_elems, (JSPropertySpec *) form_elements_props);
885 spidermonkey_DefineFunctions(ctx, jsform_elems,
886 form_elements_funcs);
887 object_to_jsval(ctx, vp, jsform_elems);
888 /* SM will cache this property value for us so we create this
889 * just once per form. */
891 break;
893 case JSP_FORM_ENCODING:
894 switch (form->method) {
895 case FORM_METHOD_GET:
896 case FORM_METHOD_POST:
897 string_to_jsval(ctx, vp, "application/x-www-form-urlencoded");
898 break;
899 case FORM_METHOD_POST_MP:
900 string_to_jsval(ctx, vp, "multipart/form-data");
901 break;
902 case FORM_METHOD_POST_TEXT_PLAIN:
903 string_to_jsval(ctx, vp, "text/plain");
904 break;
906 break;
908 case JSP_FORM_LENGTH:
909 int_to_jsval(ctx, vp, list_size(&form->items));
910 break;
912 case JSP_FORM_METHOD:
913 switch (form->method) {
914 case FORM_METHOD_GET:
915 string_to_jsval(ctx, vp, "GET");
916 break;
918 case FORM_METHOD_POST:
919 case FORM_METHOD_POST_MP:
920 case FORM_METHOD_POST_TEXT_PLAIN:
921 string_to_jsval(ctx, vp, "POST");
922 break;
924 break;
926 case JSP_FORM_NAME:
927 string_to_jsval(ctx, vp, form->name);
928 break;
930 case JSP_FORM_TARGET:
931 string_to_jsval(ctx, vp, form->target);
932 break;
934 default:
935 /* Unrecognized integer property ID; someone is using
936 * the object as an array. SMJS builtin classes (e.g.
937 * js_RegExpClass) just return JS_TRUE in this case
938 * and leave *@vp unchanged. Do the same here.
939 * (Actually not quite the same, as we already used
940 * @undef_to_jsval.) */
941 break;
944 return JS_TRUE;
947 /* @form_class.setProperty */
948 static JSBool
949 form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
951 JSObject *parent_doc; /* instance of @document_class */
952 JSObject *parent_win; /* instance of @window_class */
953 struct view_state *vs;
954 struct document_view *doc_view;
955 struct form_view *fv;
956 struct form *form;
957 unsigned char *string;
959 /* This can be called if @obj if not itself an instance of the
960 * appropriate class but has one in its prototype chain. Fail
961 * such calls. */
962 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, NULL))
963 return JS_FALSE;
964 parent_doc = JS_GetParent(ctx, obj);
965 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
966 if_assert_failed return JS_FALSE;
967 parent_win = JS_GetParent(ctx, parent_doc);
968 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
969 if_assert_failed return JS_FALSE;
971 vs = JS_GetInstancePrivate(ctx, parent_win,
972 (JSClass *) &window_class, NULL);
973 doc_view = vs->doc_view;
974 fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, NULL);
975 form = find_form_by_form_view(doc_view->document, fv);
977 assert(form);
979 if (!JSVAL_IS_INT(id))
980 return JS_TRUE;
982 switch (JSVAL_TO_INT(id)) {
983 case JSP_FORM_ACTION:
984 mem_free_set(&form->action, stracpy(jsval_to_string(ctx, vp)));
985 break;
987 case JSP_FORM_ENCODING:
988 string = jsval_to_string(ctx, vp);
989 if (!strcasecmp(string, "application/x-www-form-urlencoded")) {
990 form->method = form->method == FORM_METHOD_GET ? FORM_METHOD_GET
991 : FORM_METHOD_POST;
992 } else if (!strcasecmp(string, "multipart/form-data")) {
993 form->method = FORM_METHOD_POST_MP;
994 } else if (!strcasecmp(string, "text/plain")) {
995 form->method = FORM_METHOD_POST_TEXT_PLAIN;
997 break;
999 case JSP_FORM_METHOD:
1000 string = jsval_to_string(ctx, vp);
1001 if (!strcasecmp(string, "GET")) {
1002 form->method = FORM_METHOD_GET;
1003 } else if (!strcasecmp(string, "POST")) {
1004 form->method = FORM_METHOD_POST;
1006 break;
1008 case JSP_FORM_NAME:
1009 mem_free_set(&form->name, stracpy(jsval_to_string(ctx, vp)));
1010 break;
1012 case JSP_FORM_TARGET:
1013 mem_free_set(&form->target, stracpy(jsval_to_string(ctx, vp)));
1014 break;
1016 default:
1017 /* Unrecognized integer property ID; someone is using
1018 * the object as an array. SMJS builtin classes (e.g.
1019 * js_RegExpClass) just return JS_TRUE in this case.
1020 * Do the same here. */
1021 break;
1024 return JS_TRUE;
1027 /* @form_funcs{"reset"} */
1028 static JSBool
1029 form_reset(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1031 JSObject *parent_doc; /* instance of @document_class */
1032 JSObject *parent_win; /* instance of @window_class */
1033 struct view_state *vs;
1034 struct document_view *doc_view;
1035 struct form_view *fv;
1036 struct form *form;
1038 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, argv)) return JS_FALSE;
1039 parent_doc = JS_GetParent(ctx, obj);
1040 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
1041 if_assert_failed return JS_FALSE;
1042 parent_win = JS_GetParent(ctx, parent_doc);
1043 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
1044 if_assert_failed return JS_FALSE;
1046 vs = JS_GetInstancePrivate(ctx, parent_win,
1047 (JSClass *) &window_class, NULL);
1048 doc_view = vs->doc_view;
1049 fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, argv);
1050 form = find_form_by_form_view(doc_view->document, fv);
1052 assert(form);
1054 do_reset_form(doc_view, form);
1055 draw_forms(doc_view->session->tab->term, doc_view);
1057 boolean_to_jsval(ctx, rval, 0);
1059 return JS_TRUE;
1062 /* @form_funcs{"submit"} */
1063 static JSBool
1064 form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1066 JSObject *parent_doc; /* instance of @document_class */
1067 JSObject *parent_win; /* instance of @window_class */
1068 struct view_state *vs;
1069 struct document_view *doc_view;
1070 struct session *ses;
1071 struct form_view *fv;
1072 struct form *form;
1074 if (!JS_InstanceOf(ctx, obj, (JSClass *) &form_class, argv)) return JS_FALSE;
1075 parent_doc = JS_GetParent(ctx, obj);
1076 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
1077 if_assert_failed return JS_FALSE;
1078 parent_win = JS_GetParent(ctx, parent_doc);
1079 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
1080 if_assert_failed return JS_FALSE;
1082 vs = JS_GetInstancePrivate(ctx, parent_win,
1083 (JSClass *) &window_class, NULL);
1084 doc_view = vs->doc_view;
1085 ses = doc_view->session;
1086 fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, argv);
1087 form = find_form_by_form_view(doc_view->document, fv);
1089 assert(form);
1090 submit_given_form(ses, doc_view, form);
1092 boolean_to_jsval(ctx, rval, 0);
1094 return JS_TRUE;
1097 JSObject *
1098 get_form_object(JSContext *ctx, JSObject *jsdoc, struct form_view *fv)
1100 #if 0
1101 if (fv->ecmascript_obj)
1102 return fv->ecmascript_obj;
1103 #endif
1104 /* jsdoc ('document') is fv's parent */
1105 /* FIXME: That is NOT correct since the real containing element
1106 * should be its parent, but gimme DOM first. --pasky */
1107 JSObject *jsform = JS_NewObject(ctx, (JSClass *) &form_class, NULL, jsdoc);
1109 JS_DefineProperties(ctx, jsform, (JSPropertySpec *) form_props);
1110 spidermonkey_DefineFunctions(ctx, jsform, form_funcs);
1111 JS_SetPrivate(ctx, jsform, fv); /* to @form_class */
1112 fv->ecmascript_obj = jsform;
1113 return fv->ecmascript_obj;
1115 static JSBool forms_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
1117 /* Each @forms_class object must have a @document_class parent. */
1118 const JSClass forms_class = {
1119 "forms",
1120 JSCLASS_HAS_PRIVATE,
1121 JS_PropertyStub, JS_PropertyStub,
1122 forms_get_property, JS_PropertyStub,
1123 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
1126 static JSBool forms_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
1127 static JSBool forms_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
1129 const spidermonkeyFunctionSpec forms_funcs[] = {
1130 { "item", forms_item, 1 },
1131 { "namedItem", forms_namedItem, 1 },
1132 { NULL }
1135 /* INTs from 0 up are equivalent to item(INT), so we have to stuff length out
1136 * of the way. */
1137 enum forms_prop { JSP_FORMS_LENGTH = -1 };
1138 const JSPropertySpec forms_props[] = {
1139 { "length", JSP_FORMS_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY},
1140 { NULL }
1143 /* Find the form whose name is @name, which should normally be a
1144 * string (but might not be). If found, set *rval = the DOM
1145 * object. If not found, leave *rval unchanged. */
1146 static void
1147 find_form_by_name(JSContext *ctx, JSObject *jsdoc,
1148 struct document_view *doc_view,
1149 jsval name, jsval *rval)
1151 unsigned char *string = jsval_to_string(ctx, &name);
1152 struct form *form;
1154 if (!*string)
1155 return;
1157 foreach (form, doc_view->document->forms) {
1158 if (form->name && !strcasecmp(string, form->name)) {
1159 object_to_jsval(ctx, rval, get_form_object(ctx, jsdoc,
1160 find_form_view(doc_view, form)));
1161 break;
1166 /* @forms_class.getProperty */
1167 static JSBool
1168 forms_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
1170 JSObject *parent_doc; /* instance of @document_class */
1171 JSObject *parent_win; /* instance of @window_class */
1172 struct view_state *vs;
1173 struct document_view *doc_view;
1174 struct document *document;
1176 /* This can be called if @obj if not itself an instance of the
1177 * appropriate class but has one in its prototype chain. Fail
1178 * such calls. */
1179 if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, NULL))
1180 return JS_FALSE;
1181 parent_doc = JS_GetParent(ctx, obj);
1182 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
1183 if_assert_failed return JS_FALSE;
1184 parent_win = JS_GetParent(ctx, parent_doc);
1185 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
1186 if_assert_failed return JS_FALSE;
1188 vs = JS_GetInstancePrivate(ctx, parent_win,
1189 (JSClass *) &window_class, NULL);
1190 doc_view = vs->doc_view;
1191 document = doc_view->document;
1193 if (JSVAL_IS_STRING(id)) {
1194 /* When SMJS evaluates forms.namedItem("foo"), it first
1195 * calls forms_get_property with id = JSString "namedItem"
1196 * and *vp = JSObject JSFunction forms_namedItem.
1197 * If we don't find a form whose name is id,
1198 * we must leave *vp unchanged here, to avoid
1199 * "TypeError: forms.namedItem is not a function". */
1200 find_form_by_name(ctx, parent_doc, doc_view, id, vp);
1201 return JS_TRUE;
1204 if (!JSVAL_IS_INT(id))
1205 return JS_TRUE;
1207 switch (JSVAL_TO_INT(id)) {
1208 case JSP_FORMS_LENGTH:
1209 int_to_jsval(ctx, vp, list_size(&document->forms));
1210 break;
1211 default:
1212 /* Array index. */
1213 forms_item(ctx, obj, 1, &id, vp);
1214 break;
1217 return JS_TRUE;
1220 /* @forms_funcs{"item"} */
1221 static JSBool
1222 forms_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1224 JSObject *parent_doc; /* instance of @document_class */
1225 JSObject *parent_win; /* instance of @window_class */
1226 struct view_state *vs;
1227 struct form_view *fv;
1228 int counter = -1;
1229 int index;
1231 if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, argv)) return JS_FALSE;
1232 parent_doc = JS_GetParent(ctx, obj);
1233 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
1234 if_assert_failed return JS_FALSE;
1235 parent_win = JS_GetParent(ctx, parent_doc);
1236 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
1237 if_assert_failed return JS_FALSE;
1239 vs = JS_GetInstancePrivate(ctx, parent_win,
1240 (JSClass *) &window_class, NULL);
1242 if (argc != 1)
1243 return JS_TRUE;
1245 index = atol(jsval_to_string(ctx, &argv[0]));
1247 undef_to_jsval(ctx, rval);
1249 foreach (fv, vs->forms) {
1250 counter++;
1251 if (counter == index) {
1252 object_to_jsval(ctx, rval, get_form_object(ctx, parent_doc, fv));
1253 break;
1257 return JS_TRUE;
1260 /* @forms_funcs{"namedItem"} */
1261 static JSBool
1262 forms_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1264 JSObject *parent_doc; /* instance of @document_class */
1265 JSObject *parent_win; /* instance of @window_class */
1266 struct view_state *vs;
1267 struct document_view *doc_view;
1269 if (!JS_InstanceOf(ctx, obj, (JSClass *) &forms_class, argv)) return JS_FALSE;
1270 parent_doc = JS_GetParent(ctx, obj);
1271 assert(JS_InstanceOf(ctx, parent_doc, (JSClass *) &document_class, NULL));
1272 if_assert_failed return JS_FALSE;
1273 parent_win = JS_GetParent(ctx, parent_doc);
1274 assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL));
1275 if_assert_failed return JS_FALSE;
1277 vs = JS_GetInstancePrivate(ctx, parent_win,
1278 (JSClass *) &window_class, NULL);
1279 doc_view = vs->doc_view;
1281 if (argc != 1)
1282 return JS_TRUE;
1284 undef_to_jsval(ctx, rval);
1285 find_form_by_name(ctx, parent_doc, doc_view, argv[0], rval);
1286 return JS_TRUE;