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 JSCLASS_HAS_PRIVATE
, /* struct form_state * */
64 JS_PropertyStub
, JS_PropertyStub
,
65 input_get_property
, input_set_property
,
66 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
69 /* Tinyids of properties. Use negative values to distinguish these
70 * from array indexes (even though this object has no array elements).
71 * ECMAScript code should not use these directly as in input[-1];
72 * future versions of ELinks may change the numbers. */
74 JSP_INPUT_ACCESSKEY
= -1,
76 JSP_INPUT_CHECKED
= -3,
77 JSP_INPUT_DEFAULT_CHECKED
= -4,
78 JSP_INPUT_DEFAULT_VALUE
= -5,
79 JSP_INPUT_DISABLED
= -6,
81 JSP_INPUT_MAX_LENGTH
= -8,
83 JSP_INPUT_READONLY
= -10,
84 JSP_INPUT_SELECTED_INDEX
= -11,
87 JSP_INPUT_TABINDEX
= -14,
89 JSP_INPUT_VALUE
= -16,
92 /* XXX: Some of those are marked readonly just because we can't change them
93 * safely now. Changing default* values would affect all open instances of the
94 * document, leading to a potential security risk. Changing size and type would
95 * require re-rendering the document (TODO), tabindex would require renumbering
96 * of all links and whatnot. --pasky */
97 static const JSPropertySpec input_props
[] = {
98 { "accessKey", JSP_INPUT_ACCESSKEY
, JSPROP_ENUMERATE
},
99 { "alt", JSP_INPUT_ALT
, JSPROP_ENUMERATE
},
100 { "checked", JSP_INPUT_CHECKED
, JSPROP_ENUMERATE
},
101 { "defaultChecked",JSP_INPUT_DEFAULT_CHECKED
,JSPROP_ENUMERATE
},
102 { "defaultValue",JSP_INPUT_DEFAULT_VALUE
,JSPROP_ENUMERATE
},
103 { "disabled", JSP_INPUT_DISABLED
, JSPROP_ENUMERATE
},
104 { "form", JSP_INPUT_FORM
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
105 { "maxLength", JSP_INPUT_MAX_LENGTH
, JSPROP_ENUMERATE
},
106 { "name", JSP_INPUT_NAME
, JSPROP_ENUMERATE
},
107 { "readonly", JSP_INPUT_READONLY
, JSPROP_ENUMERATE
},
108 { "selectedIndex",JSP_INPUT_SELECTED_INDEX
,JSPROP_ENUMERATE
},
109 { "size", JSP_INPUT_SIZE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
110 { "src", JSP_INPUT_SRC
, JSPROP_ENUMERATE
},
111 { "tabindex", JSP_INPUT_TABINDEX
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
112 { "type", JSP_INPUT_TYPE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
113 { "value", JSP_INPUT_VALUE
, JSPROP_ENUMERATE
},
117 static JSBool
input_blur(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
118 static JSBool
input_click(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
119 static JSBool
input_focus(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
120 static JSBool
input_select(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
122 static const JSFunctionSpec input_funcs
[] = {
123 { "blur", input_blur
, 0 },
124 { "click", input_click
, 0 },
125 { "focus", input_focus
, 0 },
126 { "select", input_select
, 0 },
130 static JSString
*unicode_to_jsstring(JSContext
*ctx
, unicode_val_T u
);
131 static unicode_val_T
jsval_to_accesskey(JSContext
*ctx
, jsval
*vp
);
134 static struct form_state
*
135 input_get_form_state(JSContext
*ctx
, JSObject
*obj
, struct view_state
*vs
)
137 int n
= (int)(long)JS_GetPrivate(ctx
, obj
);
139 return &vs
->form_info
[n
];
142 /* @input_class.getProperty */
144 input_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
146 JSObject
*parent_form
; /* instance of @form_class */
147 JSObject
*parent_doc
; /* instance of @document_class */
148 JSObject
*parent_win
; /* instance of @window_class */
149 struct view_state
*vs
;
150 struct document_view
*doc_view
;
151 struct document
*document
;
152 struct form_state
*fs
;
153 struct form_control
*fc
;
155 struct link
*link
= NULL
;
157 /* This can be called if @obj if not itself an instance of the
158 * appropriate class but has one in its prototype chain. Fail
160 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &input_class
, NULL
))
162 parent_form
= JS_GetParent(ctx
, obj
);
163 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
164 if_assert_failed
return JS_FALSE
;
165 parent_doc
= JS_GetParent(ctx
, parent_form
);
166 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
167 if_assert_failed
return JS_FALSE
;
168 parent_win
= JS_GetParent(ctx
, parent_doc
);
169 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
170 if_assert_failed
return JS_FALSE
;
172 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
173 doc_view
= vs
->doc_view
;
174 document
= doc_view
->document
;
175 fs
= input_get_form_state(ctx
, obj
, vs
);
176 fc
= find_form_control(document
, fs
);
179 assert(fc
->form
&& fs
);
181 if (!JSVAL_IS_INT(id
))
184 linknum
= get_form_control_link(document
, fc
);
185 /* Hiddens have no link. */
186 if (linknum
>= 0) link
= &document
->links
[linknum
];
188 undef_to_jsval(ctx
, vp
);
190 switch (JSVAL_TO_INT(id
)) {
191 case JSP_INPUT_ACCESSKEY
:
197 if (!link
->accesskey
) {
198 *vp
= JS_GetEmptyStringValue(ctx
);
200 keystr
= unicode_to_jsstring(ctx
, link
->accesskey
);
202 *vp
= STRING_TO_JSVAL(keystr
);
209 string_to_jsval(ctx
, vp
, fc
->alt
);
211 case JSP_INPUT_CHECKED
:
212 boolean_to_jsval(ctx
, vp
, fs
->state
);
214 case JSP_INPUT_DEFAULT_CHECKED
:
215 boolean_to_jsval(ctx
, vp
, fc
->default_state
);
217 case JSP_INPUT_DEFAULT_VALUE
:
218 /* FIXME (bug 805): convert from the charset of the document */
219 string_to_jsval(ctx
, vp
, fc
->default_value
);
221 case JSP_INPUT_DISABLED
:
222 /* FIXME: <input readonly disabled> --pasky */
223 boolean_to_jsval(ctx
, vp
, fc
->mode
== FORM_MODE_DISABLED
);
226 object_to_jsval(ctx
, vp
, parent_form
);
228 case JSP_INPUT_MAX_LENGTH
:
229 int_to_jsval(ctx
, vp
, fc
->maxlength
);
232 string_to_jsval(ctx
, vp
, fc
->name
);
234 case JSP_INPUT_READONLY
:
235 /* FIXME: <input readonly disabled> --pasky */
236 boolean_to_jsval(ctx
, vp
, fc
->mode
== FORM_MODE_READONLY
);
239 int_to_jsval(ctx
, vp
, fc
->size
);
242 if (link
&& link
->where_img
)
243 string_to_jsval(ctx
, vp
, link
->where_img
);
245 case JSP_INPUT_TABINDEX
:
247 /* FIXME: This is WRONG. --pasky */
248 int_to_jsval(ctx
, vp
, link
->number
);
252 unsigned char *s
= NULL
;
255 case FC_TEXT
: s
= "text"; break;
256 case FC_PASSWORD
: s
= "password"; break;
257 case FC_FILE
: s
= "file"; break;
258 case FC_CHECKBOX
: s
= "checkbox"; break;
259 case FC_RADIO
: s
= "radio"; break;
260 case FC_SUBMIT
: s
= "submit"; break;
261 case FC_IMAGE
: s
= "image"; break;
262 case FC_RESET
: s
= "reset"; break;
263 case FC_BUTTON
: s
= "button"; break;
264 case FC_HIDDEN
: s
= "hidden"; break;
265 case FC_SELECT
: s
= "select"; break;
266 default: INTERNAL("input_get_property() upon a non-input item."); break;
268 string_to_jsval(ctx
, vp
, s
);
271 case JSP_INPUT_VALUE
:
272 string_to_jsval(ctx
, vp
, fs
->value
);
275 case JSP_INPUT_SELECTED_INDEX
:
276 if (fc
->type
== FC_SELECT
) int_to_jsval(ctx
, vp
, fs
->state
);
279 /* Unrecognized property ID; someone is using the
280 * object as an array. SMJS builtin classes (e.g.
281 * js_RegExpClass) just return JS_TRUE in this case
282 * and leave *@vp unchanged. Do the same here.
283 * (Actually not quite the same, as we already used
284 * @undef_to_jsval.) */
291 /* @input_class.setProperty */
293 input_set_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
295 JSObject
*parent_form
; /* instance of @form_class */
296 JSObject
*parent_doc
; /* instance of @document_class */
297 JSObject
*parent_win
; /* instance of @window_class */
298 struct view_state
*vs
;
299 struct document_view
*doc_view
;
300 struct document
*document
;
301 struct form_state
*fs
;
302 struct form_control
*fc
;
304 struct link
*link
= NULL
;
305 unicode_val_T accesskey
;
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_GetPrivate(ctx
, parent_win
); /* from @window_class */
323 doc_view
= vs
->doc_view
;
324 document
= doc_view
->document
;
325 fs
= input_get_form_state(ctx
, obj
, vs
);
326 fc
= find_form_control(document
, fs
);
329 assert(fc
->form
&& fs
);
331 if (!JSVAL_IS_INT(id
))
334 linknum
= get_form_control_link(document
, fc
);
335 /* Hiddens have no link. */
336 if (linknum
>= 0) link
= &document
->links
[linknum
];
338 switch (JSVAL_TO_INT(id
)) {
339 case JSP_INPUT_ACCESSKEY
:
340 accesskey
= jsval_to_accesskey(ctx
, vp
);
341 if (accesskey
== UCS_NO_CHAR
)
344 link
->accesskey
= accesskey
;
347 mem_free_set(&fc
->alt
, stracpy(jsval_to_string(ctx
, vp
)));
349 case JSP_INPUT_CHECKED
:
350 if (fc
->type
!= FC_CHECKBOX
&& fc
->type
!= FC_RADIO
)
352 fs
->state
= jsval_to_boolean(ctx
, vp
);
354 case JSP_INPUT_DISABLED
:
355 /* FIXME: <input readonly disabled> --pasky */
356 fc
->mode
= (jsval_to_boolean(ctx
, vp
) ? FORM_MODE_DISABLED
357 : fc
->mode
== FORM_MODE_READONLY
? FORM_MODE_READONLY
360 case JSP_INPUT_MAX_LENGTH
:
361 JS_ValueToInt32(ctx
, *vp
, &fc
->maxlength
);
364 mem_free_set(&fc
->name
, stracpy(jsval_to_string(ctx
, vp
)));
366 case JSP_INPUT_READONLY
:
367 /* FIXME: <input readonly disabled> --pasky */
368 fc
->mode
= (jsval_to_boolean(ctx
, vp
) ? FORM_MODE_READONLY
369 : fc
->mode
== FORM_MODE_DISABLED
? FORM_MODE_DISABLED
374 mem_free_set(&link
->where_img
, stracpy(jsval_to_string(ctx
, vp
)));
377 case JSP_INPUT_VALUE
:
378 if (fc
->type
== FC_FILE
)
379 break; /* A huge security risk otherwise. */
380 mem_free_set(&fs
->value
, stracpy(jsval_to_string(ctx
, vp
)));
381 if (fc
->type
== FC_TEXT
|| fc
->type
== FC_PASSWORD
)
382 fs
->state
= strlen(fs
->value
);
384 case JSP_INPUT_SELECTED_INDEX
:
385 if (fc
->type
== FC_SELECT
) {
388 JS_ValueToInt32(ctx
, *vp
, &item
);
390 if (item
>= 0 && item
< fc
->nvalues
) {
392 mem_free_set(&fs
->value
, stracpy(fc
->values
[item
]));
398 /* Unrecognized property ID; someone is using the
399 * object as an array. SMJS builtin classes (e.g.
400 * js_RegExpClass) just return JS_TRUE in this case.
401 * Do the same here. */
408 /* @input_funcs{"blur"} */
410 input_blur(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
412 /* We are a text-mode browser and there *always* has to be something
413 * selected. So we do nothing for now. (That was easy.) */
417 /* @input_funcs{"click"} */
419 input_click(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
421 JSObject
*parent_form
; /* instance of @form_class */
422 JSObject
*parent_doc
; /* instance of @document_class */
423 JSObject
*parent_win
; /* instance of @window_class */
424 struct view_state
*vs
;
425 struct document_view
*doc_view
;
426 struct document
*document
;
428 struct form_state
*fs
;
429 struct form_control
*fc
;
432 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &input_class
, argv
)) return JS_FALSE
;
433 parent_form
= JS_GetParent(ctx
, obj
);
434 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
435 if_assert_failed
return JS_FALSE
;
436 parent_doc
= JS_GetParent(ctx
, parent_form
);
437 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
438 if_assert_failed
return JS_FALSE
;
439 parent_win
= JS_GetParent(ctx
, parent_doc
);
440 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
441 if_assert_failed
return JS_FALSE
;
443 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
444 doc_view
= vs
->doc_view
;
445 document
= doc_view
->document
;
446 ses
= doc_view
->session
;
447 fs
= input_get_form_state(ctx
, obj
, vs
);
450 fc
= find_form_control(document
, fs
);
453 linknum
= get_form_control_link(document
, fc
);
454 /* Hiddens have no link. */
458 /* Restore old current_link afterwards? */
459 jump_to_link_number(ses
, doc_view
, linknum
);
460 if (enter(ses
, doc_view
, 0) == FRAME_EVENT_REFRESH
)
461 refresh_view(ses
, doc_view
, 0);
463 print_screen_status(ses
);
465 boolean_to_jsval(ctx
, rval
, 0);
469 /* @input_funcs{"focus"} */
471 input_focus(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
473 JSObject
*parent_form
; /* instance of @form_class */
474 JSObject
*parent_doc
; /* instance of @document_class */
475 JSObject
*parent_win
; /* instance of @window_class */
476 struct view_state
*vs
;
477 struct document_view
*doc_view
;
478 struct document
*document
;
480 struct form_state
*fs
;
481 struct form_control
*fc
;
484 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &input_class
, argv
)) return JS_FALSE
;
485 parent_form
= JS_GetParent(ctx
, obj
);
486 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
487 if_assert_failed
return JS_FALSE
;
488 parent_doc
= JS_GetParent(ctx
, parent_form
);
489 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
490 if_assert_failed
return JS_FALSE
;
491 parent_win
= JS_GetParent(ctx
, parent_doc
);
492 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
493 if_assert_failed
return JS_FALSE
;
495 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
496 doc_view
= vs
->doc_view
;
497 document
= doc_view
->document
;
498 ses
= doc_view
->session
;
499 fs
= input_get_form_state(ctx
, obj
, vs
);
502 fc
= find_form_control(document
, fs
);
505 linknum
= get_form_control_link(document
, fc
);
506 /* Hiddens have no link. */
510 jump_to_link_number(ses
, doc_view
, linknum
);
512 boolean_to_jsval(ctx
, rval
, 0);
516 /* @input_funcs{"select"} */
518 input_select(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
520 /* We support no text selecting yet. So we do nothing for now.
521 * (That was easy, too.) */
526 get_input_object(JSContext
*ctx
, JSObject
*jsform
, long number
)
529 if (fs
->ecmascript_obj
)
530 return fs
->ecmascript_obj
;
532 /* jsform ('form') is input's parent */
533 /* FIXME: That is NOT correct since the real containing element
534 * should be its parent, but gimme DOM first. --pasky */
535 JSObject
*jsinput
= JS_NewObject(ctx
, (JSClass
*) &input_class
, NULL
, jsform
);
537 JS_DefineProperties(ctx
, jsinput
, (JSPropertySpec
*) input_props
);
538 JS_DefineFunctions(ctx
, jsinput
, (JSFunctionSpec
*) input_funcs
);
539 JS_SetPrivate(ctx
, jsinput
, (void *)number
); /* to @input_class */
545 get_form_control_object(JSContext
*ctx
, JSObject
*jsform
, enum form_type type
, int number
)
559 return get_input_object(ctx
, jsform
, (long)number
);
566 INTERNAL("Weird fc->type %d", type
);
573 static JSBool
form_elements_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
);
575 /* Each @form_elements_class object must have a @form_class parent. */
576 static const JSClass form_elements_class
= {
579 JS_PropertyStub
, JS_PropertyStub
,
580 form_elements_get_property
, JS_PropertyStub
,
581 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
584 static JSBool
form_elements_item(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
585 static JSBool
form_elements_namedItem(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
587 static const JSFunctionSpec form_elements_funcs
[] = {
588 { "item", form_elements_item
, 1 },
589 { "namedItem", form_elements_namedItem
, 1 },
593 /* Tinyids of properties. Use negative values to distinguish these
594 * from array indexes (elements[INT] for INT>=0 is equivalent to
595 * elements.item(INT)). ECMAScript code should not use these directly
596 * as in elements[-1]; future versions of ELinks may change the numbers. */
597 enum form_elements_prop
{
598 JSP_FORM_ELEMENTS_LENGTH
= -1,
600 static const JSPropertySpec form_elements_props
[] = {
601 { "length", JSP_FORM_ELEMENTS_LENGTH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
605 /* @form_elements_class.getProperty */
607 form_elements_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
609 JSObject
*parent_form
; /* instance of @form_class */
610 JSObject
*parent_doc
; /* instance of @document_class */
611 JSObject
*parent_win
; /* instance of @window_class */
612 struct view_state
*vs
;
613 struct document_view
*doc_view
;
614 struct document
*document
;
615 struct form_view
*form_view
;
618 /* This can be called if @obj if not itself an instance of the
619 * appropriate class but has one in its prototype chain. Fail
621 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_elements_class
, NULL
))
623 parent_form
= JS_GetParent(ctx
, obj
);
624 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
625 if_assert_failed
return JS_FALSE
;
626 parent_doc
= JS_GetParent(ctx
, parent_form
);
627 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
628 if_assert_failed
return JS_FALSE
;
629 parent_win
= JS_GetParent(ctx
, parent_doc
);
630 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
631 if_assert_failed
return JS_FALSE
;
633 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
634 doc_view
= vs
->doc_view
;
635 document
= doc_view
->document
;
636 form_view
= JS_GetPrivate(ctx
, parent_form
); /* from @form_class */
637 form
= find_form_by_form_view(document
, form_view
);
639 if (JSVAL_IS_STRING(id
)) {
640 form_elements_namedItem(ctx
, obj
, 1, &id
, vp
);
644 if (!JSVAL_IS_INT(id
))
647 undef_to_jsval(ctx
, vp
);
649 switch (JSVAL_TO_INT(id
)) {
650 case JSP_FORM_ELEMENTS_LENGTH
:
651 int_to_jsval(ctx
, vp
, list_size(&form
->items
));
655 form_elements_item(ctx
, obj
, 1, &id
, vp
);
662 /* @form_elements_funcs{"item"} */
664 form_elements_item(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
666 JSObject
*parent_form
; /* instance of @form_class */
667 JSObject
*parent_doc
; /* instance of @document_class */
668 JSObject
*parent_win
; /* instance of @window_class */
669 struct view_state
*vs
;
670 struct document_view
*doc_view
;
671 struct document
*document
;
672 struct form_view
*form_view
;
674 struct form_control
*fc
;
678 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_elements_class
, argv
)) return JS_FALSE
;
679 parent_form
= JS_GetParent(ctx
, obj
);
680 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
681 if_assert_failed
return JS_FALSE
;
682 parent_doc
= JS_GetParent(ctx
, parent_form
);
683 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
684 if_assert_failed
return JS_FALSE
;
685 parent_win
= JS_GetParent(ctx
, parent_doc
);
686 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
687 if_assert_failed
return JS_FALSE
;
689 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
690 doc_view
= vs
->doc_view
;
691 document
= doc_view
->document
;
692 form_view
= JS_GetPrivate(ctx
, parent_form
); /* from @form_class */
693 form
= find_form_by_form_view(document
, form_view
);
698 JS_ValueToInt32(ctx
, argv
[0], &index
);
699 undef_to_jsval(ctx
, rval
);
701 foreach (fc
, form
->items
) {
703 if (counter
== index
) {
704 struct form_state
*fs
= find_form_state(doc_view
, fc
);
707 JSObject
*fcobj
= get_form_control_object(ctx
, parent_form
, fc
->type
, fc
->g_ctrl_num
);
710 object_to_jsval(ctx
, rval
, fcobj
);
719 /* @form_elements_funcs{"namedItem"} */
721 form_elements_namedItem(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
723 JSObject
*parent_form
; /* instance of @form_class */
724 JSObject
*parent_doc
; /* instance of @document_class */
725 JSObject
*parent_win
; /* instance of @window_class */
726 struct view_state
*vs
;
727 struct document_view
*doc_view
;
728 struct document
*document
;
729 struct form_view
*form_view
;
731 struct form_control
*fc
;
732 unsigned char *string
;
734 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_elements_class
, argv
)) return JS_FALSE
;
735 parent_form
= JS_GetParent(ctx
, obj
);
736 assert(JS_InstanceOf(ctx
, parent_form
, (JSClass
*) &form_class
, NULL
));
737 if_assert_failed
return JS_FALSE
;
738 parent_doc
= JS_GetParent(ctx
, parent_form
);
739 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
740 if_assert_failed
return JS_FALSE
;
741 parent_win
= JS_GetParent(ctx
, parent_doc
);
742 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
743 if_assert_failed
return JS_FALSE
;
745 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
746 doc_view
= vs
->doc_view
;
747 document
= doc_view
->document
;
748 form_view
= JS_GetPrivate(ctx
, parent_form
); /* from @form_class */
749 form
= find_form_by_form_view(document
, form_view
);
754 string
= jsval_to_string(ctx
, &argv
[0]);
758 undef_to_jsval(ctx
, rval
);
760 foreach (fc
, form
->items
) {
761 if ((fc
->id
&& !strcasecmp(string
, fc
->id
)) || (fc
->name
&& !strcasecmp(string
, fc
->name
))) {
762 struct form_state
*fs
= find_form_state(doc_view
, fc
);
765 JSObject
*fcobj
= get_form_control_object(ctx
, parent_form
, fc
->type
, fc
->g_ctrl_num
);
768 object_to_jsval(ctx
, rval
, fcobj
);
779 static JSBool
form_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
);
780 static JSBool
form_set_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
);
782 /* Each @form_class object must have a @document_class parent. */
783 static const JSClass form_class
= {
785 JSCLASS_HAS_PRIVATE
, /* struct form_view * */
786 JS_PropertyStub
, JS_PropertyStub
,
787 form_get_property
, form_set_property
,
788 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
791 /* Tinyids of properties. Use negative values to distinguish these
792 * from array indexes (even though this object has no array elements).
793 * ECMAScript code should not use these directly as in form[-1];
794 * future versions of ELinks may change the numbers. */
796 JSP_FORM_ACTION
= -1,
797 JSP_FORM_ELEMENTS
= -2,
798 JSP_FORM_ENCODING
= -3,
799 JSP_FORM_LENGTH
= -4,
800 JSP_FORM_METHOD
= -5,
802 JSP_FORM_TARGET
= -7,
805 static const JSPropertySpec form_props
[] = {
806 { "action", JSP_FORM_ACTION
, JSPROP_ENUMERATE
},
807 { "elements", JSP_FORM_ELEMENTS
, JSPROP_ENUMERATE
},
808 { "encoding", JSP_FORM_ENCODING
, JSPROP_ENUMERATE
},
809 { "length", JSP_FORM_LENGTH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
810 { "method", JSP_FORM_METHOD
, JSPROP_ENUMERATE
},
811 { "name", JSP_FORM_NAME
, JSPROP_ENUMERATE
},
812 { "target", JSP_FORM_TARGET
, JSPROP_ENUMERATE
},
816 static JSBool
form_reset(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
817 static JSBool
form_submit(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
819 static const JSFunctionSpec form_funcs
[] = {
820 { "reset", form_reset
, 0 },
821 { "submit", form_submit
, 0 },
825 /* @form_class.getProperty */
827 form_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
829 /* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */
830 JSObject
*parent_doc
; /* instance of @document_class */
831 JSObject
*parent_win
; /* instance of @window_class */
832 struct view_state
*vs
;
833 struct document_view
*doc_view
;
834 struct form_view
*fv
;
837 /* This can be called if @obj if not itself an instance of the
838 * appropriate class but has one in its prototype chain. Fail
840 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, NULL
))
842 parent_doc
= JS_GetParent(ctx
, obj
);
843 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
844 if_assert_failed
return JS_FALSE
;
845 parent_win
= JS_GetParent(ctx
, parent_doc
);
846 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
847 if_assert_failed
return JS_FALSE
;
849 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
850 doc_view
= vs
->doc_view
;
851 fv
= JS_GetPrivate(ctx
, obj
); /* from @form_class */
852 form
= find_form_by_form_view(doc_view
->document
, fv
);
856 if (JSVAL_IS_STRING(id
)) {
857 struct form_control
*fc
;
858 unsigned char *string
;
860 string
= jsval_to_string(ctx
, &id
);
861 foreach (fc
, form
->items
) {
862 JSObject
*fcobj
= NULL
;
863 struct form_state
*fs
;
865 if ((!fc
->id
|| strcasecmp(string
, fc
->id
)) && (!fc
->name
|| strcasecmp(string
, fc
->name
)))
868 undef_to_jsval(ctx
, vp
);
869 fs
= find_form_state(doc_view
, fc
);
871 fcobj
= get_form_control_object(ctx
, obj
, fc
->type
, fc
->g_ctrl_num
);
873 object_to_jsval(ctx
, vp
, fcobj
);
880 if (!JSVAL_IS_INT(id
))
883 undef_to_jsval(ctx
, vp
);
885 switch (JSVAL_TO_INT(id
)) {
886 case JSP_FORM_ACTION
:
887 string_to_jsval(ctx
, vp
, form
->action
);
890 case JSP_FORM_ELEMENTS
:
892 /* jsform ('form') is form_elements' parent; who knows is that's correct */
893 JSObject
*jsform_elems
= JS_NewObject(ctx
, (JSClass
*) &form_elements_class
, NULL
, obj
);
895 JS_DefineProperties(ctx
, jsform_elems
, (JSPropertySpec
*) form_elements_props
);
896 JS_DefineFunctions(ctx
, jsform_elems
, (JSFunctionSpec
*) form_elements_funcs
);
897 object_to_jsval(ctx
, vp
, jsform_elems
);
898 /* SM will cache this property value for us so we create this
899 * just once per form. */
903 case JSP_FORM_ENCODING
:
904 switch (form
->method
) {
905 case FORM_METHOD_GET
:
906 case FORM_METHOD_POST
:
907 string_to_jsval(ctx
, vp
, "application/x-www-form-urlencoded");
909 case FORM_METHOD_POST_MP
:
910 string_to_jsval(ctx
, vp
, "multipart/form-data");
912 case FORM_METHOD_POST_TEXT_PLAIN
:
913 string_to_jsval(ctx
, vp
, "text/plain");
918 case JSP_FORM_LENGTH
:
919 int_to_jsval(ctx
, vp
, list_size(&form
->items
));
922 case JSP_FORM_METHOD
:
923 switch (form
->method
) {
924 case FORM_METHOD_GET
:
925 string_to_jsval(ctx
, vp
, "GET");
928 case FORM_METHOD_POST
:
929 case FORM_METHOD_POST_MP
:
930 case FORM_METHOD_POST_TEXT_PLAIN
:
931 string_to_jsval(ctx
, vp
, "POST");
937 string_to_jsval(ctx
, vp
, form
->name
);
940 case JSP_FORM_TARGET
:
941 string_to_jsval(ctx
, vp
, form
->target
);
945 /* Unrecognized property ID; someone is using the
946 * object as an array. SMJS builtin classes (e.g.
947 * js_RegExpClass) just return JS_TRUE in this case
948 * and leave *@vp unchanged. Do the same here.
949 * (Actually not quite the same, as we already used
950 * @undef_to_jsval.) */
957 /* @form_class.setProperty */
959 form_set_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
961 JSObject
*parent_doc
; /* instance of @document_class */
962 JSObject
*parent_win
; /* instance of @window_class */
963 struct view_state
*vs
;
964 struct document_view
*doc_view
;
965 struct form_view
*fv
;
967 unsigned char *string
;
969 /* This can be called if @obj if not itself an instance of the
970 * appropriate class but has one in its prototype chain. Fail
972 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, NULL
))
974 parent_doc
= JS_GetParent(ctx
, obj
);
975 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
976 if_assert_failed
return JS_FALSE
;
977 parent_win
= JS_GetParent(ctx
, parent_doc
);
978 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
979 if_assert_failed
return JS_FALSE
;
981 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
982 doc_view
= vs
->doc_view
;
983 fv
= JS_GetPrivate(ctx
, obj
); /* from @form_class */
984 form
= find_form_by_form_view(doc_view
->document
, fv
);
988 if (!JSVAL_IS_INT(id
))
991 switch (JSVAL_TO_INT(id
)) {
992 case JSP_FORM_ACTION
:
993 string
= stracpy(jsval_to_string(ctx
, vp
));
995 ecmascript_set_action(&form
->action
, string
);
997 mem_free_set(&form
->action
, string
);
1001 case JSP_FORM_ENCODING
:
1002 string
= jsval_to_string(ctx
, vp
);
1003 if (!strcasecmp(string
, "application/x-www-form-urlencoded")) {
1004 form
->method
= form
->method
== FORM_METHOD_GET
? FORM_METHOD_GET
1006 } else if (!strcasecmp(string
, "multipart/form-data")) {
1007 form
->method
= FORM_METHOD_POST_MP
;
1008 } else if (!strcasecmp(string
, "text/plain")) {
1009 form
->method
= FORM_METHOD_POST_TEXT_PLAIN
;
1013 case JSP_FORM_METHOD
:
1014 string
= jsval_to_string(ctx
, vp
);
1015 if (!strcasecmp(string
, "GET")) {
1016 form
->method
= FORM_METHOD_GET
;
1017 } else if (!strcasecmp(string
, "POST")) {
1018 form
->method
= FORM_METHOD_POST
;
1023 mem_free_set(&form
->name
, stracpy(jsval_to_string(ctx
, vp
)));
1026 case JSP_FORM_TARGET
:
1027 mem_free_set(&form
->target
, stracpy(jsval_to_string(ctx
, vp
)));
1031 /* Unrecognized property ID; someone is using the
1032 * object as an array. SMJS builtin classes (e.g.
1033 * js_RegExpClass) just return JS_TRUE in this case.
1034 * Do the same here. */
1041 /* @form_funcs{"reset"} */
1043 form_reset(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1045 JSObject
*parent_doc
; /* instance of @document_class */
1046 JSObject
*parent_win
; /* instance of @window_class */
1047 struct view_state
*vs
;
1048 struct document_view
*doc_view
;
1049 struct form_view
*fv
;
1052 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, argv
)) return JS_FALSE
;
1053 parent_doc
= JS_GetParent(ctx
, obj
);
1054 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
1055 if_assert_failed
return JS_FALSE
;
1056 parent_win
= JS_GetParent(ctx
, parent_doc
);
1057 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
1058 if_assert_failed
return JS_FALSE
;
1060 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
1061 doc_view
= vs
->doc_view
;
1062 fv
= JS_GetPrivate(ctx
, obj
); /* from @form_class */
1063 form
= find_form_by_form_view(doc_view
->document
, fv
);
1067 do_reset_form(doc_view
, form
);
1068 draw_forms(doc_view
->session
->tab
->term
, doc_view
);
1070 boolean_to_jsval(ctx
, rval
, 0);
1075 /* @form_funcs{"submit"} */
1077 form_submit(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1079 JSObject
*parent_doc
; /* instance of @document_class */
1080 JSObject
*parent_win
; /* instance of @window_class */
1081 struct view_state
*vs
;
1082 struct document_view
*doc_view
;
1083 struct session
*ses
;
1084 struct form_view
*fv
;
1087 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &form_class
, argv
)) return JS_FALSE
;
1088 parent_doc
= JS_GetParent(ctx
, obj
);
1089 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
1090 if_assert_failed
return JS_FALSE
;
1091 parent_win
= JS_GetParent(ctx
, parent_doc
);
1092 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
1093 if_assert_failed
return JS_FALSE
;
1095 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
1096 doc_view
= vs
->doc_view
;
1097 ses
= doc_view
->session
;
1098 fv
= JS_GetPrivate(ctx
, obj
); /* from @form_class */
1099 form
= find_form_by_form_view(doc_view
->document
, fv
);
1102 submit_given_form(ses
, doc_view
, form
, 0);
1104 boolean_to_jsval(ctx
, rval
, 0);
1110 get_form_object(JSContext
*ctx
, JSObject
*jsdoc
, struct form_view
*fv
)
1113 if (fv
->ecmascript_obj
)
1114 return fv
->ecmascript_obj
;
1116 /* jsdoc ('document') is fv's parent */
1117 /* FIXME: That is NOT correct since the real containing element
1118 * should be its parent, but gimme DOM first. --pasky */
1119 JSObject
*jsform
= JS_NewObject(ctx
, (JSClass
*) &form_class
, NULL
, jsdoc
);
1121 JS_DefineProperties(ctx
, jsform
, (JSPropertySpec
*) form_props
);
1122 JS_DefineFunctions(ctx
, jsform
, (JSFunctionSpec
*) form_funcs
);
1123 JS_SetPrivate(ctx
, jsform
, fv
); /* to @form_class */
1124 fv
->ecmascript_obj
= jsform
;
1125 return fv
->ecmascript_obj
;
1127 static JSBool
forms_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
);
1129 /* Each @forms_class object must have a @document_class parent. */
1130 const JSClass forms_class
= {
1132 JSCLASS_HAS_PRIVATE
,
1133 JS_PropertyStub
, JS_PropertyStub
,
1134 forms_get_property
, JS_PropertyStub
,
1135 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
1138 static JSBool
forms_item(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
1139 static JSBool
forms_namedItem(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
1141 const JSFunctionSpec forms_funcs
[] = {
1142 { "item", forms_item
, 1 },
1143 { "namedItem", forms_namedItem
, 1 },
1147 /* Tinyids of properties. Use negative values to distinguish these from
1148 * array indexes (forms[INT] for INT>=0 is equivalent to forms.item(INT)).
1149 * ECMAScript code should not use these directly as in forms[-1];
1150 * future versions of ELinks may change the numbers. */
1152 JSP_FORMS_LENGTH
= -1,
1154 const JSPropertySpec forms_props
[] = {
1155 { "length", JSP_FORMS_LENGTH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
1159 /* @forms_class.getProperty */
1161 forms_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
1163 JSObject
*parent_doc
; /* instance of @document_class */
1164 JSObject
*parent_win
; /* instance of @window_class */
1165 struct view_state
*vs
;
1166 struct document_view
*doc_view
;
1167 struct document
*document
;
1169 /* This can be called if @obj if not itself an instance of the
1170 * appropriate class but has one in its prototype chain. Fail
1172 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &forms_class
, NULL
))
1174 parent_doc
= JS_GetParent(ctx
, obj
);
1175 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
1176 if_assert_failed
return JS_FALSE
;
1177 parent_win
= JS_GetParent(ctx
, parent_doc
);
1178 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
1179 if_assert_failed
return JS_FALSE
;
1181 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
1182 doc_view
= vs
->doc_view
;
1183 document
= doc_view
->document
;
1185 if (JSVAL_IS_STRING(id
)) {
1186 forms_namedItem(ctx
, obj
, 1, &id
, vp
);
1190 if (!JSVAL_IS_INT(id
))
1193 switch (JSVAL_TO_INT(id
)) {
1194 case JSP_FORMS_LENGTH
:
1195 int_to_jsval(ctx
, vp
, list_size(&document
->forms
));
1199 forms_item(ctx
, obj
, 1, &id
, vp
);
1206 /* @forms_funcs{"item"} */
1208 forms_item(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1210 JSObject
*parent_doc
; /* instance of @document_class */
1211 JSObject
*parent_win
; /* instance of @window_class */
1212 struct view_state
*vs
;
1213 struct form_view
*fv
;
1217 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &forms_class
, argv
)) return JS_FALSE
;
1218 parent_doc
= JS_GetParent(ctx
, obj
);
1219 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
1220 if_assert_failed
return JS_FALSE
;
1221 parent_win
= JS_GetParent(ctx
, parent_doc
);
1222 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
1223 if_assert_failed
return JS_FALSE
;
1225 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
1230 JS_ValueToInt32(ctx
, argv
[0], &index
);
1231 undef_to_jsval(ctx
, rval
);
1233 foreach (fv
, vs
->forms
) {
1235 if (counter
== index
) {
1236 object_to_jsval(ctx
, rval
, get_form_object(ctx
, parent_doc
, fv
));
1244 /* @forms_funcs{"namedItem"} */
1246 forms_namedItem(JSContext
*ctx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1248 JSObject
*parent_doc
; /* instance of @document_class */
1249 JSObject
*parent_win
; /* instance of @window_class */
1250 struct view_state
*vs
;
1251 struct document_view
*doc_view
;
1252 struct document
*document
;
1254 unsigned char *string
;
1256 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &forms_class
, argv
)) return JS_FALSE
;
1257 parent_doc
= JS_GetParent(ctx
, obj
);
1258 assert(JS_InstanceOf(ctx
, parent_doc
, (JSClass
*) &document_class
, NULL
));
1259 if_assert_failed
return JS_FALSE
;
1260 parent_win
= JS_GetParent(ctx
, parent_doc
);
1261 assert(JS_InstanceOf(ctx
, parent_win
, (JSClass
*) &window_class
, NULL
));
1262 if_assert_failed
return JS_FALSE
;
1264 vs
= JS_GetPrivate(ctx
, parent_win
); /* from @window_class */
1265 doc_view
= vs
->doc_view
;
1266 document
= doc_view
->document
;
1271 undef_to_jsval(ctx
, rval
);
1273 string
= jsval_to_string(ctx
, &argv
[0]);
1277 foreach (form
, document
->forms
) {
1278 if (form
->name
&& !strcasecmp(string
, form
->name
)) {
1279 object_to_jsval(ctx
, rval
, get_form_object(ctx
, parent_doc
,
1280 find_form_view(doc_view
, form
)));
1290 unicode_to_jsstring(JSContext
*ctx
, unicode_val_T u
)
1294 /* This is supposed to make a string from which
1295 * jsval_to_accesskey() can get the original @u back.
1296 * If @u is a surrogate, then that is not possible, so
1297 * return NULL to indicate an error instead.
1299 * If JS_NewUCStringCopyN hits a null character, it truncates
1300 * the string there and pads it with more nulls. However,
1301 * that is not a problem here, because if there is a null
1302 * character in buf[], then it must be the only character. */
1303 if (u
<= 0xFFFF && !is_utf16_surrogate(u
)) {
1305 return JS_NewUCStringCopyN(ctx
, buf
, 1);
1306 } else if (needs_utf16_surrogates(u
)) {
1307 buf
[0] = get_utf16_high_surrogate(u
);
1308 buf
[1] = get_utf16_low_surrogate(u
);
1309 return JS_NewUCStringCopyN(ctx
, buf
, 2);
1315 /* Convert the string *@vp to an access key. Return 0 for no access
1316 * key, UCS_NO_CHAR on error, or the access key otherwise. */
1317 static unicode_val_T
1318 jsval_to_accesskey(JSContext
*ctx
, jsval
*vp
)
1323 /* Convert the value in place, to protect the result from GC. */
1324 if (JS_ConvertValue(ctx
, *vp
, JSTYPE_STRING
, vp
) == JS_FALSE
)
1326 len
= JS_GetStringLength(JSVAL_TO_STRING(*vp
));
1327 chr
= JS_GetStringChars(JSVAL_TO_STRING(*vp
));
1329 /* This implementation ignores extra characters in the string. */
1331 return 0; /* which means no access key */
1332 if (!is_utf16_surrogate(chr
[0]))
1335 && is_utf16_high_surrogate(chr
[0])
1336 && is_utf16_low_surrogate(chr
[1]))
1337 return join_utf16_surrogates(chr
[0], chr
[1]);
1338 JS_ReportError(ctx
, "Invalid UTF-16 sequence");
1339 return UCS_NO_CHAR
; /* which the caller will reject */