Bug 846: Separate JS_GetParent & JS_GetPrivate calls from initializations.
[elinks.git] / src / ecmascript / spidermonkey / location.c
blob1f433cc0d0f3b999d56f969eaa85bd360b630331
1 /* The SpiderMonkey location and history objects 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/location.h"
26 #include "intl/gettext/libintl.h"
27 #include "main/select.h"
28 #include "osdep/newwin.h"
29 #include "osdep/sysname.h"
30 #include "protocol/http/http.h"
31 #include "protocol/uri.h"
32 #include "session/history.h"
33 #include "session/location.h"
34 #include "session/session.h"
35 #include "session/task.h"
36 #include "terminal/tab.h"
37 #include "terminal/terminal.h"
38 #include "util/conv.h"
39 #include "util/memory.h"
40 #include "util/string.h"
41 #include "viewer/text/draw.h"
42 #include "viewer/text/form.h"
43 #include "viewer/text/link.h"
44 #include "viewer/text/vs.h"
47 static JSBool history_back(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
48 static JSBool history_forward(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
49 static JSBool history_go(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
51 const JSClass history_class = {
52 "history",
53 JSCLASS_HAS_PRIVATE,
54 JS_PropertyStub, JS_PropertyStub,
55 JS_PropertyStub, JS_PropertyStub,
56 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
59 const JSFunctionSpec history_funcs[] = {
60 { "back", history_back, 0 },
61 { "forward", history_forward, 0 },
62 { "go", history_go, 1 },
63 { NULL }
66 /* @history_funcs{"back"} */
67 static JSBool
68 history_back(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
70 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
71 struct document_view *doc_view = interpreter->vs->doc_view;
72 struct session *ses = doc_view->session;
74 go_back(ses);
76 /* history_back() must return 0 for onClick to cause displaying previous page
77 * and return non zero for <a href="javascript:history.back()"> to prevent
78 * "calculating" new link. Returned value 2 is changed to 0 in function
79 * spidermonkey_eval_boolback */
80 return 2;
83 /* @history_funcs{"forward"} */
84 static JSBool
85 history_forward(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
87 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
88 struct document_view *doc_view = interpreter->vs->doc_view;
89 struct session *ses = doc_view->session;
91 go_unback(ses);
93 return 2;
96 /* @history_funcs{"go"} */
97 static JSBool
98 history_go(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
100 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
101 struct document_view *doc_view = interpreter->vs->doc_view;
102 struct session *ses = doc_view->session;
103 int index;
104 struct location *loc;
106 if (argc != 1)
107 return JS_TRUE;
109 index = atol(jsval_to_string(ctx, &argv[0]));
111 for (loc = cur_loc(ses);
112 loc != (struct location *) &ses->history.history;
113 loc = index > 0 ? loc->next : loc->prev) {
114 if (!index) {
115 go_history(ses, loc);
116 break;
119 index += index > 0 ? -1 : 1;
122 return 2;
126 static JSBool location_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
127 static JSBool location_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
129 /* Each @location_class object must have a @window_class parent. */
130 const JSClass location_class = {
131 "location",
132 JSCLASS_HAS_PRIVATE,
133 JS_PropertyStub, JS_PropertyStub,
134 location_get_property, location_set_property,
135 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
138 enum location_prop { JSP_LOC_HREF };
139 const JSPropertySpec location_props[] = {
140 { "href", JSP_LOC_HREF, JSPROP_ENUMERATE },
141 { NULL }
144 /* @location_class.getProperty */
145 static JSBool
146 location_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
148 JSObject *parent_win; /* instance of @window_class */
149 struct view_state *vs;
151 parent_win = JS_GetParent(ctx, obj);
152 vs = JS_GetPrivate(ctx, parent_win); /* from @window_class */
154 if (!JSVAL_IS_INT(id))
155 return JS_TRUE;
157 undef_to_jsval(ctx, vp);
159 switch (JSVAL_TO_INT(id)) {
160 case JSP_LOC_HREF:
161 astring_to_jsval(ctx, vp, get_uri_string(vs->uri, URI_ORIGINAL));
162 break;
163 default:
164 INTERNAL("Invalid ID %d in location_get_property().", JSVAL_TO_INT(id));
165 break;
168 return JS_TRUE;
171 /* @location_class.setProperty */
172 static JSBool
173 location_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
175 JSObject *parent_win; /* instance of @window_class */
176 struct view_state *vs;
177 struct document_view *doc_view;
179 parent_win = JS_GetParent(ctx, obj);
180 vs = JS_GetPrivate(ctx, parent_win); /* from @window_class */
181 doc_view = vs->doc_view;
183 if (!JSVAL_IS_INT(id))
184 return JS_TRUE;
186 switch (JSVAL_TO_INT(id)) {
187 case JSP_LOC_HREF:
188 location_goto(doc_view, jsval_to_string(ctx, vp));
189 break;
192 return JS_TRUE;
195 static JSBool location_toString(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
197 const JSFunctionSpec location_funcs[] = {
198 { "toString", location_toString, 0 },
199 { "toLocaleString", location_toString, 0 },
200 { NULL }
203 /* @location_funcs{"toString"}, @location_funcs{"toLocaleString"} */
204 static JSBool
205 location_toString(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
207 return JS_GetProperty(ctx, obj, "href", rval);
210 struct delayed_goto {
211 /* It might look more convenient to pass doc_view around but it could
212 * disappear during wild dances inside of frames or so. */
213 struct view_state *vs;
214 struct uri *uri;
217 static void
218 delayed_goto(void *data)
220 struct delayed_goto *deg = data;
222 assert(deg);
223 if (deg->vs->doc_view
224 && deg->vs->doc_view == deg->vs->doc_view->session->doc_view) {
225 goto_uri_frame(deg->vs->doc_view->session, deg->uri,
226 deg->vs->doc_view->name,
227 CACHE_MODE_NORMAL);
229 done_uri(deg->uri);
230 mem_free(deg);
233 void
234 location_goto(struct document_view *doc_view, unsigned char *url)
236 unsigned char *new_abs_url;
237 struct uri *new_uri;
238 struct delayed_goto *deg;
240 /* Workaround for bug 611. Does not crash, but may lead to infinite loop.*/
241 if (!doc_view) return;
242 new_abs_url = join_urls(doc_view->document->uri,
243 trim_chars(url, ' ', 0));
244 if (!new_abs_url)
245 return;
246 new_uri = get_uri(new_abs_url, 0);
247 mem_free(new_abs_url);
248 if (!new_uri)
249 return;
250 deg = mem_calloc(1, sizeof(*deg));
251 if (!deg) {
252 done_uri(new_uri);
253 return;
255 assert(doc_view->vs);
256 deg->vs = doc_view->vs;
257 deg->uri = new_uri;
258 /* It does not seem to be very safe inside of frames to
259 * call goto_uri() right away. */
260 register_bottom_half(delayed_goto, deg);