1 /* The SpiderMonkey window object implementation. */
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
80 JS_PropertyStub
, JS_PropertyStub
,
81 input_get_property
, input_set_property
,
82 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
89 JSP_INPUT_DEFAULT_CHECKED
,
90 JSP_INPUT_DEFAULT_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
},
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 },
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
,
147 int n
= JSVAL_TO_INT(PRIVATE_TO_JSVAL(private));
149 return &vs
->form_info
[n
];
152 /* @input_class.getProperty */
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
;
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
170 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &input_class
, NULL
))
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
);
190 assert(fc
->form
&& fs
);
192 if (!JSVAL_IS_INT(id
))
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
;
208 init_string(&keystr
);
209 add_accesskey_to_string(&keystr
, link
->accesskey
);
210 string_to_jsval(ctx
, vp
, keystr
.source
);
211 done_string(&keystr
);
215 string_to_jsval(ctx
, vp
, fc
->alt
);
217 case JSP_INPUT_CHECKED
:
218 boolean_to_jsval(ctx
, vp
, fs
->state
);
220 case JSP_INPUT_DEFAULT_CHECKED
:
221 boolean_to_jsval(ctx
, vp
, fc
->default_state
);
223 case JSP_INPUT_DEFAULT_VALUE
:
224 string_to_jsval(ctx
, vp
, fc
->default_value
);
226 case JSP_INPUT_DISABLED
:
227 /* FIXME: <input readonly disabled> --pasky */
228 boolean_to_jsval(ctx
, vp
, fc
->mode
== FORM_MODE_DISABLED
);
231 object_to_jsval(ctx
, vp
, parent_form
);
233 case JSP_INPUT_MAX_LENGTH
:
234 int_to_jsval(ctx
, vp
, fc
->maxlength
);
237 string_to_jsval(ctx
, vp
, fc
->name
);
239 case JSP_INPUT_READONLY
:
240 /* FIXME: <input readonly disabled> --pasky */
241 boolean_to_jsval(ctx
, vp
, fc
->mode
== FORM_MODE_READONLY
);
244 int_to_jsval(ctx
, vp
, fc
->size
);
247 if (link
&& link
->where_img
)
248 string_to_jsval(ctx
, vp
, link
->where_img
);
250 case JSP_INPUT_TABINDEX
:
252 /* FIXME: This is WRONG. --pasky */
253 int_to_jsval(ctx
, vp
, link
->number
);
257 unsigned char *s
= NULL
;
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
);
275 case JSP_INPUT_VALUE
:
276 string_to_jsval(ctx
, vp
, fs
->value
);
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.) */
292 /* @input_class.setProperty */
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
;
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
310 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &input_class
, NULL
))
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
);
330 assert(fc
->form
&& fs
);
332 if (!JSVAL_IS_INT(id
))
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
:
342 link
->accesskey
= accesskey_string_to_unicode(jsval_to_string(ctx
, vp
));
345 mem_free_set(&fc
->alt
, stracpy(jsval_to_string(ctx
, vp
)));
347 case JSP_INPUT_CHECKED
:
348 if (fc
->type
!= FC_CHECKBOX
&& fc
->type
!= FC_RADIO
)
350 fs
->state
= jsval_to_boolean(ctx
, vp
);
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
358 case JSP_INPUT_MAX_LENGTH
:
359 fc
->maxlength
= atol(jsval_to_string(ctx
, vp
));
362 mem_free_set(&fc
->name
, stracpy(jsval_to_string(ctx
, vp
)));
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
372 mem_free_set(&link
->where_img
, stracpy(jsval_to_string(ctx
, vp
)));
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
);
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. */
394 /* @input_funcs{"blur"} */
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.) */
403 /* @input_funcs{"click"} */
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
;
414 struct form_state
*fs
;
415 struct form_control
*fc
;
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
);
437 fc
= find_form_control(document
, fs
);
440 linknum
= get_form_control_link(document
, fc
);
441 /* Hiddens have no link. */
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);
450 print_screen_status(ses
);
452 boolean_to_jsval(ctx
, rval
, 0);
456 /* @input_funcs{"focus"} */
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
;
467 struct form_state
*fs
;
468 struct form_control
*fc
;
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
);
490 fc
= find_form_control(document
, fs
);
493 linknum
= get_form_control_link(document
, fc
);
494 /* Hiddens have no link. */
498 jump_to_link_number(ses
, doc_view
, linknum
);
500 boolean_to_jsval(ctx
, rval
, 0);
504 /* @input_funcs{"select"} */
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.) */
514 get_input_object(JSContext
*ctx
, JSObject
*jsform
, long number
)
517 if (fs
->ecmascript_obj
)
518 return fs
->ecmascript_obj
;
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 */
534 get_form_control_object(JSContext
*ctx
, JSObject
*jsform
, enum form_type type
, int number
)
547 return get_input_object(ctx
, jsform
, (long)number
);
555 INTERNAL("Weird fc->type %d", type
);
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
= {
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 },
582 /* INTs from 0 up are equivalent to item(INT), so we have to stuff length out
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
},
590 /* @form_elements_class.getProperty */
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
;
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
606 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_elements_class
, NULL
))
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
);
631 if (!JSVAL_IS_INT(id
))
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
));
642 form_elements_item(ctx
, obj
, 1, &id
, vp
);
649 /* @form_elements_funcs{"item"} */
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
;
661 struct form_control
*fc
;
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
);
687 index
= atol(jsval_to_string(ctx
, &argv
[0]));
689 undef_to_jsval(ctx
, rval
);
691 foreach (fc
, form
->items
) {
693 if (counter
== index
) {
694 struct form_state
*fs
= find_form_state(doc_view
, fc
);
697 JSObject
*fcobj
= get_form_control_object(ctx
, parent_form
, fc
->type
, fc
->g_ctrl_num
);
700 object_to_jsval(ctx
, rval
, fcobj
);
709 /* @form_elements_funcs{"namedItem"} */
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
;
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
);
746 string
= jsval_to_string(ctx
, &argv
[0]);
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
);
757 JSObject
*fcobj
= get_form_control_object(ctx
, parent_form
, fc
->type
, fc
->g_ctrl_num
);
760 object_to_jsval(ctx
, rval
, fcobj
);
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
= {
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
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
},
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 },
813 /* @form_class.getProperty */
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
;
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
828 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, NULL
))
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
);
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
))
857 undef_to_jsval(ctx
, vp
);
858 fs
= find_form_state(doc_view
, fc
);
860 fcobj
= get_form_control_object(ctx
, obj
, fc
->type
, fc
->g_ctrl_num
);
862 object_to_jsval(ctx
, vp
, fcobj
);
869 if (!JSVAL_IS_INT(id
))
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
);
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. */
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");
899 case FORM_METHOD_POST_MP
:
900 string_to_jsval(ctx
, vp
, "multipart/form-data");
902 case FORM_METHOD_POST_TEXT_PLAIN
:
903 string_to_jsval(ctx
, vp
, "text/plain");
908 case JSP_FORM_LENGTH
:
909 int_to_jsval(ctx
, vp
, list_size(&form
->items
));
912 case JSP_FORM_METHOD
:
913 switch (form
->method
) {
914 case FORM_METHOD_GET
:
915 string_to_jsval(ctx
, vp
, "GET");
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");
927 string_to_jsval(ctx
, vp
, form
->name
);
930 case JSP_FORM_TARGET
:
931 string_to_jsval(ctx
, vp
, form
->target
);
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.) */
947 /* @form_class.setProperty */
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
;
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
962 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, NULL
))
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
);
979 if (!JSVAL_IS_INT(id
))
982 switch (JSVAL_TO_INT(id
)) {
983 case JSP_FORM_ACTION
:
984 mem_free_set(&form
->action
, stracpy(jsval_to_string(ctx
, vp
)));
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
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
;
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
;
1009 mem_free_set(&form
->name
, stracpy(jsval_to_string(ctx
, vp
)));
1012 case JSP_FORM_TARGET
:
1013 mem_free_set(&form
->target
, stracpy(jsval_to_string(ctx
, vp
)));
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. */
1027 /* @form_funcs{"reset"} */
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
;
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
);
1054 do_reset_form(doc_view
, form
);
1055 draw_forms(doc_view
->session
->tab
->term
, doc_view
);
1057 boolean_to_jsval(ctx
, rval
, 0);
1062 /* @form_funcs{"submit"} */
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
;
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
);
1090 submit_given_form(ses
, doc_view
, form
);
1092 boolean_to_jsval(ctx
, rval
, 0);
1098 get_form_object(JSContext
*ctx
, JSObject
*jsdoc
, struct form_view
*fv
)
1101 if (fv
->ecmascript_obj
)
1102 return fv
->ecmascript_obj
;
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
= {
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 },
1135 /* INTs from 0 up are equivalent to item(INT), so we have to stuff length out
1137 enum forms_prop
{ JSP_FORMS_LENGTH
= -1 };
1138 const JSPropertySpec forms_props
[] = {
1139 { "length", JSP_FORMS_LENGTH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
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. */
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
);
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
)));
1166 /* @forms_class.getProperty */
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
1179 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &forms_class
, NULL
))
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
);
1204 if (!JSVAL_IS_INT(id
))
1207 switch (JSVAL_TO_INT(id
)) {
1208 case JSP_FORMS_LENGTH
:
1209 int_to_jsval(ctx
, vp
, list_size(&document
->forms
));
1213 forms_item(ctx
, obj
, 1, &id
, vp
);
1220 /* @forms_funcs{"item"} */
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
;
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
);
1245 index
= atol(jsval_to_string(ctx
, &argv
[0]));
1247 undef_to_jsval(ctx
, rval
);
1249 foreach (fv
, vs
->forms
) {
1251 if (counter
== index
) {
1252 object_to_jsval(ctx
, rval
, get_form_object(ctx
, parent_doc
, fv
));
1260 /* @forms_funcs{"namedItem"} */
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
;
1284 undef_to_jsval(ctx
, rval
);
1285 find_form_by_name(ctx
, parent_doc
, doc_view
, argv
[0], rval
);