Bug 846: Separate JS_GetParent & JS_GetPrivate calls from initializations.
[elinks.git] / src / ecmascript / spidermonkey / document.c
blob589118ebce6ac874366e5cb8e0663ddc165e1438
1 /* The SpiderMonkey document 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/form.h"
26 #include "ecmascript/spidermonkey/location.h"
27 #include "ecmascript/spidermonkey/document.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 JSBool document_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
50 static JSBool document_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
52 /* Each @document_class object must have a @window_class parent. */
53 const JSClass document_class = {
54 "document",
55 JSCLASS_HAS_PRIVATE,
56 JS_PropertyStub, JS_PropertyStub,
57 document_get_property, document_set_property,
58 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
61 enum document_prop { JSP_DOC_LOC, JSP_DOC_REF, JSP_DOC_TITLE, JSP_DOC_URL };
62 /* "cookie" is special; it isn't a regular property but we channel it to the
63 * cookie-module. XXX: Would it work if "cookie" was defined in this array? */
64 const JSPropertySpec document_props[] = {
65 { "location", JSP_DOC_LOC, JSPROP_ENUMERATE },
66 { "referrer", JSP_DOC_REF, JSPROP_ENUMERATE | JSPROP_READONLY },
67 { "title", JSP_DOC_TITLE, JSPROP_ENUMERATE }, /* TODO: Charset? */
68 { "url", JSP_DOC_URL, JSPROP_ENUMERATE },
69 { NULL }
72 /* @document_class.getProperty */
73 static JSBool
74 document_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
76 JSObject *parent_win; /* instance of @window_class */
77 struct view_state *vs;
78 struct document_view *doc_view;
79 struct document *document;
80 struct session *ses;
82 parent_win = JS_GetParent(ctx, obj);
83 vs = JS_GetPrivate(ctx, parent_win); /* from @window_class */
84 doc_view = vs->doc_view;
85 document = doc_view->document;
86 ses = doc_view->session;
88 if (JSVAL_IS_STRING(id)) {
89 struct form *form;
90 unsigned char *string = jsval_to_string(ctx, &id);
92 #ifdef CONFIG_COOKIES
93 if (!strcmp(string, "cookie")) {
94 struct string *cookies = send_cookies(vs->uri);
96 if (cookies) {
97 static unsigned char cookiestr[1024];
99 strncpy(cookiestr, cookies->source, 1024);
100 done_string(cookies);
102 string_to_jsval(ctx, vp, cookiestr);
103 } else {
104 string_to_jsval(ctx, vp, "");
106 return JS_TRUE;
108 #endif
109 foreach (form, document->forms) {
110 if (!form->name || strcasecmp(string, form->name))
111 continue;
113 object_to_jsval(ctx, vp, get_form_object(ctx, obj, find_form_view(doc_view, form)));
114 break;
116 return JS_TRUE;
119 if (!JSVAL_IS_INT(id))
120 return JS_TRUE;
122 undef_to_jsval(ctx, vp);
124 switch (JSVAL_TO_INT(id)) {
125 case JSP_DOC_LOC:
126 JS_GetProperty(ctx, parent_win, "location", vp);
127 break;
128 case JSP_DOC_REF:
129 switch (get_opt_int("protocol.http.referer.policy")) {
130 case REFERER_NONE:
131 /* oh well */
132 undef_to_jsval(ctx, vp);
133 break;
135 case REFERER_FAKE:
136 string_to_jsval(ctx, vp, get_opt_str("protocol.http.referer.fake"));
137 break;
139 case REFERER_TRUE:
140 /* XXX: Encode as in add_url_to_httset_prop_string(&prop, ) ? --pasky */
141 if (ses->referrer) {
142 astring_to_jsval(ctx, vp, get_uri_string(ses->referrer, URI_HTTP_REFERRER));
144 break;
146 case REFERER_SAME_URL:
147 astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_HTTP_REFERRER));
148 break;
150 break;
151 case JSP_DOC_TITLE:
152 string_to_jsval(ctx, vp, document->title);
153 break;
154 case JSP_DOC_URL:
155 astring_to_jsval(ctx, vp, get_uri_string(document->uri, URI_ORIGINAL));
156 break;
157 default:
158 INTERNAL("Invalid ID %d in document_get_property().", JSVAL_TO_INT(id));
159 break;
162 return JS_TRUE;
165 /* @document_class.setProperty */
166 static JSBool
167 document_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
169 JSObject *parent_win; /* instance of @window_class */
170 struct view_state *vs;
171 struct document_view *doc_view;
172 struct document *document;
174 parent_win = JS_GetParent(ctx, obj);
175 vs = JS_GetPrivate(ctx, parent_win); /* from @window_class */
176 doc_view = vs->doc_view;
177 document = doc_view->document;
179 if (JSVAL_IS_STRING(id)) {
180 #ifdef CONFIG_COOKIES
181 if (!strcmp(jsval_to_string(ctx, &id), "cookie")) {
182 set_cookie(vs->uri, jsval_to_string(ctx, vp));
183 /* Do NOT touch our .cookie property, evil
184 * SpiderMonkey!! */
185 return JS_FALSE;
187 #endif
188 return JS_TRUE;
191 if (!JSVAL_IS_INT(id))
192 return JS_TRUE;
194 switch (JSVAL_TO_INT(id)) {
195 case JSP_DOC_TITLE:
196 mem_free_set(&document->title, stracpy(jsval_to_string(ctx, vp)));
197 print_screen_status(doc_view->session);
198 break;
199 case JSP_DOC_LOC:
200 case JSP_DOC_URL:
201 /* According to the specs this should be readonly but some
202 * broken sites still assign to it (i.e.
203 * http://www.e-handelsfonden.dk/validering.asp?URL=www.polyteknisk.dk).
204 * So emulate window.location. */
205 location_goto(doc_view, jsval_to_string(ctx, vp));
206 break;
209 return JS_TRUE;
212 static JSBool document_write(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
213 static JSBool document_writeln(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
215 const JSFunctionSpec document_funcs[] = {
216 { "write", document_write, 1 },
217 { "writeln", document_writeln, 1 },
218 { NULL }
221 static JSBool
222 document_write_do(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
223 jsval *rval, int newline)
225 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
226 struct string *ret = interpreter->ret;
228 if (argc >= 1 && ret) {
229 int i = 0;
231 for (; i < argc; ++i) {
232 unsigned char *code = jsval_to_string(ctx, &argv[i]);
234 add_to_string(ret, code);
237 if (newline)
238 add_char_to_string(ret, '\n');
240 /* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined
241 * function' errors, I want to see just the useful ones. So just
242 * lighting a led and going away, no muss, no fuss. --pasky */
243 /* TODO: Perhaps we can introduce ecmascript.error_report_unsupported
244 * -> "Show information about the document using some valid,
245 * nevertheless unsupported methods/properties." --pasky too */
247 #ifdef CONFIG_LEDS
248 set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J');
249 #endif
251 boolean_to_jsval(ctx, rval, 0);
253 return JS_TRUE;
256 /* @document_funcs{"write"} */
257 static JSBool
258 document_write(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
261 return document_write_do(ctx, obj, argc, argv, rval, 0);
264 /* @document_funcs{"writeln"} */
265 static JSBool
266 document_writeln(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
268 return document_write_do(ctx, obj, argc, argv, rval, 1);