1 /* "elinks.bookmarks" */
9 #include "bookmarks/bookmarks.h"
10 #include "ecmascript/spidermonkey-shared.h"
11 #include "intl/charsets.h"
12 #include "main/event.h"
13 #include "scripting/smjs/core.h"
14 #include "scripting/smjs/elinks_object.h"
15 #include "util/memory.h"
18 static const JSClass bookmark_class
, bookmark_folder_class
; /* defined below */
24 smjs_get_bookmark_generic_object(struct bookmark
*bookmark
, JSClass
*clasp
)
28 assert(clasp
== &bookmark_class
|| clasp
== &bookmark_folder_class
);
29 if_assert_failed
return NULL
;
31 jsobj
= JS_NewObject(smjs_ctx
, clasp
, NULL
, NULL
);
32 if (!jsobj
) return NULL
;
34 if (!bookmark
) return jsobj
;
36 if (JS_TRUE
== JS_SetPrivate(smjs_ctx
, jsobj
, bookmark
)) { /* to @bookmark_class or @bookmark_folder_class */
37 object_lock(bookmark
);
45 /* @bookmark_class.finalize, @bookmark_folder_class.finalize */
47 bookmark_finalize(JSContext
*ctx
, JSObject
*obj
)
49 struct bookmark
*bookmark
;
51 assert(JS_InstanceOf(ctx
, obj
, (JSClass
*) &bookmark_class
, NULL
)
52 || JS_InstanceOf(ctx
, obj
, (JSClass
*) &bookmark_folder_class
, NULL
));
53 if_assert_failed
return;
55 bookmark
= JS_GetPrivate(ctx
, obj
); /* from @bookmark_class or @bookmark_folder_class */
57 if (bookmark
) object_unlock(bookmark
);
61 /*** bookmark object ***/
63 /* Tinyids of properties. Use negative values to distinguish these
64 * from array indexes (even though this object has no array elements).
65 * ECMAScript code should not use these directly as in bookmark[-1];
66 * future versions of ELinks may change the numbers. */
70 BOOKMARK_CHILDREN
= -3,
73 static const JSPropertySpec bookmark_props
[] = {
74 { "title", BOOKMARK_TITLE
, JSPROP_ENUMERATE
},
75 { "url", BOOKMARK_URL
, JSPROP_ENUMERATE
},
76 { "children", BOOKMARK_CHILDREN
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
80 static JSObject
*smjs_get_bookmark_folder_object(struct bookmark
*bookmark
);
82 /** Convert a string retrieved from struct bookmark to a jsval.
84 * @return JS_TRUE if successful. On error, report the error and
87 bookmark_string_to_jsval(JSContext
*ctx
, const unsigned char *str
, jsval
*vp
)
89 JSString
*jsstr
= utf8_to_jsstring(ctx
, str
, -1);
93 *vp
= STRING_TO_JSVAL(jsstr
);
97 /** Convert a jsval to a string and store it in struct bookmark.
100 * Context for memory allocations and error reports.
102 * The @c jsval that should be converted.
103 * @param[in,out] result
104 * A string allocated with mem_alloc().
105 * On success, this function frees the original string, if any.
107 * @return JS_TRUE if successful. On error, report the error to
108 * SpiderMonkey and return JS_FALSE. */
110 jsval_to_bookmark_string(JSContext
*ctx
, jsval val
, unsigned char **result
)
112 JSString
*jsstr
= NULL
;
115 /* jsstring_to_utf8() might GC; protect the string to come. */
116 if (!JS_AddNamedRoot(ctx
, &jsstr
, "jsval_to_bookmark_string"))
119 jsstr
= JS_ValueToString(ctx
, val
);
121 JS_RemoveRoot(ctx
, &jsstr
);
125 str
= jsstring_to_utf8(ctx
, jsstr
, NULL
);
127 JS_RemoveRoot(ctx
, &jsstr
);
131 JS_RemoveRoot(ctx
, &jsstr
);
132 mem_free_set(result
, str
);
136 /* @bookmark_class.getProperty */
138 bookmark_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
140 struct bookmark
*bookmark
;
142 /* This can be called if @obj if not itself an instance of the
143 * appropriate class but has one in its prototype chain. Fail
145 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &bookmark_class
, NULL
))
148 bookmark
= JS_GetInstancePrivate(ctx
, obj
,
149 (JSClass
*) &bookmark_class
, NULL
);
151 if (!bookmark
) return JS_FALSE
;
153 undef_to_jsval(ctx
, vp
);
155 if (!JSVAL_IS_INT(id
))
158 switch (JSVAL_TO_INT(id
)) {
160 return bookmark_string_to_jsval(ctx
, bookmark
->title
, vp
);
162 return bookmark_string_to_jsval(ctx
, bookmark
->url
, vp
);
163 case BOOKMARK_CHILDREN
:
164 *vp
= OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark
));
168 /* Unrecognized integer property ID; someone is using
169 * the object as an array. SMJS builtin classes (e.g.
170 * js_RegExpClass) just return JS_TRUE in this case
171 * and leave *@vp unchanged. Do the same here.
172 * (Actually not quite the same, as we already used
173 * @undef_to_jsval.) */
178 /* @bookmark_class.setProperty */
180 bookmark_set_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
182 struct bookmark
*bookmark
;
183 unsigned char *title
= NULL
;
184 unsigned char *url
= NULL
;
187 /* This can be called if @obj if not itself an instance of the
188 * appropriate class but has one in its prototype chain. Fail
190 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &bookmark_class
, NULL
))
193 bookmark
= JS_GetInstancePrivate(ctx
, obj
,
194 (JSClass
*) &bookmark_class
, NULL
);
196 if (!bookmark
) return JS_FALSE
;
198 if (!JSVAL_IS_INT(id
))
201 switch (JSVAL_TO_INT(id
)) {
203 if (!jsval_to_bookmark_string(ctx
, *vp
, &title
))
207 if (!jsval_to_bookmark_string(ctx
, *vp
, &url
))
211 /* Unrecognized integer property ID; someone is using
212 * the object as an array. SMJS builtin classes (e.g.
213 * js_RegExpClass) just return JS_TRUE in this case.
214 * Do the same here. */
218 ok
= update_bookmark(bookmark
, get_cp_index("UTF-8"), title
, url
);
221 return ok
? JS_TRUE
: JS_FALSE
;
224 static const JSClass bookmark_class
= {
226 JSCLASS_HAS_PRIVATE
, /* struct bookmark * */
227 JS_PropertyStub
, JS_PropertyStub
,
228 bookmark_get_property
, bookmark_set_property
,
229 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, bookmark_finalize
,
233 smjs_get_bookmark_object(struct bookmark
*bookmark
)
237 jsobj
= smjs_get_bookmark_generic_object(bookmark
,
238 (JSClass
*) &bookmark_class
);
241 && JS_TRUE
== JS_DefineProperties(smjs_ctx
, jsobj
,
242 (JSPropertySpec
*) bookmark_props
))
249 /*** bookmark folder object ***/
251 /* @bookmark_folder_class.getProperty */
253 bookmark_folder_get_property(JSContext
*ctx
, JSObject
*obj
, jsval id
, jsval
*vp
)
255 struct bookmark
*bookmark
;
256 struct bookmark
*folder
;
257 unsigned char *title
= NULL
;
259 /* This can be called if @obj if not itself an instance of the
260 * appropriate class but has one in its prototype chain. Fail
262 if (!JS_InstanceOf(ctx
, obj
, (JSClass
*) &bookmark_folder_class
, NULL
))
265 folder
= JS_GetInstancePrivate(ctx
, obj
,
266 (JSClass
*) &bookmark_folder_class
, NULL
);
270 if (!jsval_to_bookmark_string(ctx
, id
, &title
))
273 bookmark
= get_bookmark_by_name(folder
, title
);
275 *vp
= OBJECT_TO_JSVAL(smjs_get_bookmark_object(bookmark
));
282 static const JSClass bookmark_folder_class
= {
284 JSCLASS_HAS_PRIVATE
, /* struct bookmark * */
285 JS_PropertyStub
, JS_PropertyStub
,
286 bookmark_folder_get_property
, JS_PropertyStub
,
287 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, bookmark_finalize
,
291 smjs_get_bookmark_folder_object(struct bookmark
*bookmark
)
293 return smjs_get_bookmark_generic_object(bookmark
,
294 (JSClass
*) &bookmark_folder_class
);
298 smjs_init_bookmarks_interface(void)
301 struct JSObject
*bookmarks_object
;
303 if (!smjs_ctx
|| !smjs_elinks_object
)
306 bookmarks_object
= smjs_get_bookmark_folder_object(NULL
);
307 if (!bookmarks_object
) return;
309 val
= OBJECT_TO_JSVAL(bookmarks_object
);
311 JS_SetProperty(smjs_ctx
, smjs_elinks_object
, "bookmarks", &val
);