diff options
-rw-r--r-- | doc/api/jsapi.7.txt | 19 | ||||
-rw-r--r-- | doc/api/jsapi.txt | 61 | ||||
-rw-r--r-- | doc/dwb-js.7 | 37 | ||||
-rw-r--r-- | extensions/userscripts | 58 | ||||
-rw-r--r-- | scripts/lib/dwb.js | 9 | ||||
-rw-r--r-- | scripts/lib/util.js | 16 | ||||
-rw-r--r-- | src/js.c | 25 | ||||
-rw-r--r-- | src/js.h | 3 | ||||
-rw-r--r-- | src/scripts.c | 124 |
9 files changed, 257 insertions, 95 deletions
diff --git a/doc/api/jsapi.7.txt b/doc/api/jsapi.7.txt index 21723ea0..7f90a62f 100644 --- a/doc/api/jsapi.7.txt +++ b/doc/api/jsapi.7.txt @@ -930,15 +930,18 @@ _wv.tabLabel (GtkLabel, read)_;; Text label of a tab, child of *wv.tabBox*. -==== String wv.inject(String script, [Object argument], [Boolean global]) +==== String wv.inject([String code|Function code], [Object arg], [Boolean global]) **** Injects a script into a webview -_script_;; The script to inject -_argument_;; If the script isn't injected into the global scope the script is -wrapped inside a function. argument then is accesible via +_code_;; The script to inject, either a string or a function. If it is a +function the body will be wrapped inside a new function. +_arg_;; If the script isn't injected into the global scope the script is +wrapped inside a function. 'arg' then is accesible via 'arguments' in the injected script, optional +_line_;; Starting line number, useful for debugging. If linenumber is +greater than 0 error messages will be printed to stderr, optional. _global_;; true to inject it into the global scope, false to encapsulate it in a function, optional _returns_;; The return value of the script. If the script is injected globally @@ -1789,6 +1792,14 @@ Same as io.debug but also prints additional information, e.g. if the object is an Error, this method will also print the corresponding source of the error. **** +==== String script.generateId() +**** + +Generates a unique id. + +_returns_;; A unique id. +**** + ==== void script.getPrivate(Object object, String key) **** diff --git a/doc/api/jsapi.txt b/doc/api/jsapi.txt index 56bb3edb..debf2a5e 100644 --- a/doc/api/jsapi.txt +++ b/doc/api/jsapi.txt @@ -1848,17 +1848,20 @@ Text label of a tab, child of *wv.tabBox*. [source,javascript] ---- -String wv.inject(String script, [Object argument], [Boolean global]) +String wv.inject([String code|Function code], [Object arg], [Number line], [Boolean global]) ---- Injects a script into a webview :: -_script_;; The script to inject -_argument_;; If the script isn't injected into the global scope the script is -wrapped inside a function. +argument+ then is accesible via +_code_;; The script to inject, either a string or a function. If it is a +function the body will be wrapped inside a new function. +_arg_;; If the script isn't injected into the global scope the script is +wrapped inside a function. +arg+ then is accesible via +arguments+ in the injected script, optional +_line_;; Starting line number, useful for debugging. If linenumber is +greater than 0 error messages will be printed to stderr, optional. _global_;; +true+ to inject it into the global scope, +false+ to encapsulate it in a function, optional _returns_;; The return value of the script. If the script is injected globally @@ -1866,6 +1869,39 @@ inject always returns +null+. The return value is always converted to a string. To return objects call JSON.parse on the return value. **** +==== +.Example +[source,javascript,src_numbered] +------ +//!javascript + +function injectMe() { + var text = arguments[0]; + document.body.innerHTML = text; + text = y; + var d = document.createElement("div"); + document.body.appendChild(d); +} +signals.connect("documentLoaded", function(wv) { + wv.inject(injectMe, "foo", 4); +}); +------ + +The debugging message will be as follows: + +[source,txt] +------ +DWB SCRIPT EXCEPTION: An error occured injecting injectMe. +DWB SCRIPT EXCEPTION: in line 6: Can't find variable: y +==> DEBUG [SOURCE] + ... + 5 > document.body.innerHTML = text; +--> 6 > text = y; + 7 > var d = document.createElement("div"); + ... +------ +==== + **** [float] ==== *history()* ==== @@ -3171,6 +3207,23 @@ an Error, this method will also print the corresponding source of the error. **** **** +[[generateId]] +[float] +==== *generateId()* ==== + +[source,javascript] +---- +String script.generateId() +---- + +Generates a unique id. + + :: + +_returns_;; A unique id. +**** + +**** [[getPrivate]] [float] ==== *getPrivate()* ==== diff --git a/doc/dwb-js.7 b/doc/dwb-js.7 index d69db865..262e63f4 100644 --- a/doc/dwb-js.7 +++ b/doc/dwb-js.7 @@ -2,12 +2,12 @@ .\" Title: dwb-js .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/> -.\" Date: 03/04/2013 +.\" Date: 03/07/2013 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "DWB\-JS" "7" "03/04/2013" "\ \&" "\ \&" +.TH "DWB\-JS" "7" "03/07/2013" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -1845,23 +1845,30 @@ Text label of a tab, child of .nr an-break-flag 1 .br .ps +1 -\fBString wv.inject(String script, [Object argument], [Boolean global])\fR +\fBString wv.inject([String code|Function code], [Object arg], [Boolean global])\fR .RS 4 .sp Injects a script into a webview .PP -\fIscript\fR +\fIcode\fR .RS 4 -The script to inject +The script to inject, either a string or a function\&. If it is a function the body will be wrapped inside a new function\&. .RE .PP -\fIargument\fR +\fIarg\fR .RS 4 -If the script isn\(cqt injected into the global scope the script is wrapped inside a function\&. argument then is accesible via +If the script isn\(cqt injected into the global scope the script is wrapped inside a function\&. +\fIarg\fR +then is accesible via \fIarguments\fR in the injected script, optional .RE .PP +\fIline\fR +.RS 4 +Starting line number, useful for debugging\&. If linenumber is greater than 0 error messages will be printed to stderr, optional\&. +.RE +.PP \fIglobal\fR .RS 4 true to inject it into the global scope, false to encapsulate it in a function, optional @@ -3539,6 +3546,22 @@ Same as io\&.debug but also prints additional information, e\&.g\&. if the objec .nr an-break-flag 1 .br .ps +1 +\fBString script.generateId()\fR +.RS 4 +.sp +Generates a unique id\&. +.PP +\fIreturns\fR +.RS 4 +A unique id\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 \fBvoid script.getPrivate(Object object, String key)\fR .RS 4 .sp diff --git a/extensions/userscripts b/extensions/userscripts index 76709ec3..82a15eb3 100644 --- a/extensions/userscripts +++ b/extensions/userscripts @@ -65,8 +65,6 @@ INFO>*/ var me = "userscripts"; var onStart = []; var onEnd = []; -var sigDocument = -1; -var sigCommitted = -1; /* //<DEFAULT_CONFIG // paths to userscripts, this extension will also load all scripts in from @@ -105,6 +103,7 @@ function UserScript() this.delay = 0; this.noframes = false; this.priority = 0; + this.offset = 0; } // Reused regular expressions @@ -165,21 +164,21 @@ var GM_compatability = function () var GM_info = function () { return undefined; }; var GM_registerMenuCommand = function () { return undefined; }; var GM_openInTab = function (url) { return null; }; - var GM_getResourceText = function (name) - { - // TODO implemnt - return ""; - }; - var GM_getResourceURL = function (name) - { - // TODO implemnt - return ""; - }; - var GM_xmlHttpRequest = function (details) - { - // TODO implemnt - return null; - }; + //var GM_getResourceText = function (name) + //{ + // // TODO implemnt + // return ""; + //}; + //var GM_getResourceURL = function (name) + //{ + // // TODO implemnt + // return ""; + //}; + //var GM_xmlHttpRequest = function (details) + //{ + // // TODO implemnt + // return null; + //}; }; function matchIncludeExclude(frame, items) //{{{ @@ -234,12 +233,12 @@ function doInject(frame, item) if (item.delay > 0) { timerStart(item.delay, function() { - frame.inject(item.script, null, item.unwrap); + frame.inject(item.script, null, item.offset, item.unwrap); return false; }); } else - frame.inject(item.script, null, item.unwrap); + frame.inject(item.script, null, item.offset, item.unwrap); } function handle(frame, array, isMainFrame) //{{{ @@ -393,6 +392,7 @@ function parseScript(path) //{{{ if (metaStart == -1 || metaEnd == -1) { userscript.script = curScript; + userscript.offset = 1; userscript.include = [ { regExp : /.*/, isTld : false} ]; onEnd.push(userscript); return; @@ -464,8 +464,9 @@ function parseScript(path) //{{{ userscript.scriptId = userscript.namespace + "::" + userscript.name; userscript.scriptId = userscript.scriptId.replace(/\s+/g, "_"); userscript.script = "var DWB_scriptId = '" + userscript.scriptId + "';" + - util.getBody(GM_compatability) + curScript.substring(0, metaStart) + - curScript.substring(scriptStart); + curScript.substring(0, metaStart) + + curScript.substring(scriptStart) + util.getBody(GM_compatability); + userscript.offset = meta.length + 1; getRequirements(userscript); @@ -488,13 +489,13 @@ function userscriptsStart() if (onStart.length > 0) { onStart.sort(function(a, b) { return b.priority - a.priority; }); - sigCommitted = signals.connect("loadCommitted", loadCommittedCallback); + signals.connect("loadCommitted", loadCommittedCallback); ret = true; } if (onEnd.length > 0) { onEnd.sort(function(a, b) { return b.priority - a.priority; }); - sigDocument = signals.connect("documentLoaded", loadFinishedCallback); + signals.connect("documentLoaded", loadFinishedCallback); ret = true; } //metaData = {}; @@ -540,15 +541,8 @@ var userscripts = { return parseScripts(c ? c.scripts || [] : []); }, end : function () { - if (sigDocument >= 0) { - signals.disconnect(sigDocument); - sigDocument = -1; - } - if (sigCommitted >= 0) { - signals.disconnect(sigCommitted); - sigCommitted = -1; - } - + signals.disconnect(loadFinishedCallback); + signals.disconnect(loadCommittedCallback); } }; diff --git a/scripts/lib/dwb.js b/scripts/lib/dwb.js index cdb73e62..e36bb1e1 100644 --- a/scripts/lib/dwb.js +++ b/scripts/lib/dwb.js @@ -99,6 +99,15 @@ "path" : { value : path }, "debug" : { value : io.debug.bind(self) }, "_arguments" : { value : arguments }, + "generateId" : { + value : (function() { + var id = 0; + var timeStamp = new Date().getTime(); + return function() { + return checksum(timeStamp + (id++) + this.path, ChecksumType.sha1); + }; + })() + }, "setPrivate" : { value : function(id, object, key, value) diff --git a/scripts/lib/util.js b/scripts/lib/util.js index 991bf067..e99d7a35 100644 --- a/scripts/lib/util.js +++ b/scripts/lib/util.js @@ -1,22 +1,6 @@ (function () { Object.defineProperties(util, { - "getBody" : - { - value : function(f) - { - if (f && f instanceof Function) - { - var m = f.toString().match(/\{([\s\S]*)\}/m)[1]; - m = m.replace(/^[ \t\r\v\f]*/, ''); - if (m[0] == "\n") - return m.substring(1); - else - return m; - } - return null; - } - }, "getSelection" : { value : function() @@ -233,14 +233,9 @@ error_out: return ret; }/*}}}*/ -/*{{{*/ char * -js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc) +js_value_to_string(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc) { - if (value == NULL) - return NULL; - if (! JSValueIsString(ctx, value)) - return NULL; JSStringRef jsstring = JSValueToStringCopy(ctx, value, exc); if (jsstring == NULL) return NULL; @@ -248,11 +243,21 @@ js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *e char *ret = js_string_to_char(ctx, jsstring, limit); JSStringRelease(jsstring); return ret; +} +/*{{{*/ +char * +js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc) +{ + if (value == NULL) + return NULL; + if (! JSValueIsString(ctx, value)) + return NULL; + return js_value_to_string(ctx, value, limit, exc); }/*}}}*/ /* print_exception {{{*/ gboolean -js_print_exception(JSContextRef ctx, JSValueRef exception, char *buffer, size_t bufferSize, int *linenumber) +js_print_exception(JSContextRef ctx, JSValueRef exception, char *buffer, size_t bufferSize, int starting_line, int *linenumber) { if (exception == NULL) return false; @@ -267,7 +272,7 @@ js_print_exception(JSContextRef ctx, JSValueRef exception, char *buffer, size_t char *sourceURL = js_get_string_property(ctx, o, "sourceURL"); if (sourceURL) fprintf(stderr, "DWB SCRIPT EXCEPTION: in file %s\n", sourceURL); - fprintf(stderr, "DWB SCRIPT EXCEPTION: in line %d: %s\n", line, message == NULL ? "unknown" : message); + fprintf(stderr, "DWB SCRIPT EXCEPTION: in line %d: %s\n", line + starting_line, message == NULL ? "unknown" : message); if (sourceURL != NULL && buffer != NULL) { strncpy(buffer, message, bufferSize-1); @@ -296,7 +301,7 @@ js_make_function(JSContextRef ctx, const char *script, const char *sourceurl, in if (function != NULL) ret = function; else - js_print_exception(ctx, exc, NULL, 0, NULL); + js_print_exception(ctx, exc, NULL, 0, 0, NULL); JSStringRelease(body); if (source != NULL) @@ -371,7 +376,7 @@ js_check_syntax(JSContextRef ctx, const char *script, const char *filename, int gboolean correct = JSCheckScriptSyntax(ctx, jsscript, jssource, lineOffset, &exc); if (!correct) { - js_print_exception(ctx, exc, NULL, 0, NULL); + js_print_exception(ctx, exc, NULL, 0, 0, NULL); } JSStringRelease(jsscript); if (jssource != NULL) @@ -23,6 +23,7 @@ void js_make_exception(JSContextRef ctx, JSValueRef *exception, const gchar *format, ...); char * js_string_to_char(JSContextRef ctx, JSStringRef jsstring, size_t ); char * js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *); +char * js_value_to_string(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *); JSObjectRef js_get_object_property(JSContextRef ctx, JSObjectRef arg, const char *name); void js_set_property(JSContextRef ctx, JSObjectRef arg, const char *name, JSValueRef value, JSClassAttributes attr, JSValueRef *); void js_set_object_property(JSContextRef ctx, JSObjectRef arg, const char *name, const char *value, JSValueRef *); @@ -34,7 +35,7 @@ char * js_call_as_function(WebKitWebFrame *, JSObjectRef, const char *string, co JSValueRef js_char_to_value(JSContextRef ctx, const char *text); char * js_value_to_json(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc); JSValueRef js_execute(JSContextRef ctx, const char *, JSValueRef *exc); -gboolean js_print_exception(JSContextRef ctx, JSValueRef exception, char *buffer, size_t bs, int *line); +gboolean js_print_exception(JSContextRef ctx, JSValueRef exception, char *buffer, size_t bs, int starting_line, int *line); JSObjectRef js_make_function(JSContextRef ctx, const char *script, const char *path, int line); JSValueRef js_json_to_value(JSContextRef ctx, const char *text); JSValueRef js_context_change(JSContextRef, JSContextRef, JSValueRef, JSValueRef *); diff --git a/src/scripts.c b/src/scripts.c index 1374728f..f1f7b611 100644 --- a/src/scripts.c +++ b/src/scripts.c @@ -198,6 +198,37 @@ uncamelize(char *uncamel, const char *camel, char rep, size_t length) return ret; }/*}}}*/ +static char * +get_body(JSContextRef ctx, JSObjectRef func, JSValueRef *exc) +{ + char *sfunc = NULL, *result = NULL; + if (func == NULL) + return NULL; + JSStringRef js_string = JSValueToStringCopy(ctx, func, exc); + sfunc = js_string_to_char(ctx, js_string, -1); + if (!sfunc) + goto error_out; + const char *start = strchr(sfunc, '{'); + const char *end = strrchr(sfunc, '}'); + if (!start || !end || start == end) + goto error_out; + if (start) + start++; + + // Skip first empty line, needed for correct line numbers + for (; *start && g_ascii_isspace(*start) && *start != '\n'; start++) + ; + if (*start == '\n') + start++; + + result = g_strndup(start, end - start); + +error_out: + g_free(sfunc); + JSStringRelease(js_string); + return result; +} + static JSValueRef call_as_function_debug(JSContextRef ctx, JSObjectRef func, JSObjectRef this, size_t argc, const JSValueRef argv[]) { @@ -208,7 +239,7 @@ call_as_function_debug(JSContextRef ctx, JSObjectRef func, JSObjectRef this, siz if (exc != NULL) { if (!s_debugging) - js_print_exception(ctx, exc, path, PATH_MAX, &line); + js_print_exception(ctx, exc, path, PATH_MAX, 0, &line); else { //JSObjectRef p = JSObjectMake(ctx, NULL, NULL); @@ -230,7 +261,12 @@ inject(JSContextRef ctx, JSContextRef wctx, JSObjectRef function, JSObjectRef th JSValueRef ret = NIL; gboolean global = false; JSValueRef args[1]; + JSObjectRef f; + JSStringRef script; + char *name = NULL; + char *body = NULL; int count = 0; + double debug = -1; if (argc < 1) { js_make_exception(ctx, exc, EXCEPTION("inject: missing argument")); @@ -241,30 +277,40 @@ inject(JSContextRef ctx, JSContextRef wctx, JSObjectRef function, JSObjectRef th args[0] = js_context_change(ctx, wctx, argv[1], exc); count = 1; } - if (argc > 2 && JSValueIsBoolean(ctx, argv[2])) + if (argc > 2) + debug = JSValueToNumber(ctx, argv[2], exc); + if (argc > 3 && JSValueIsBoolean(ctx, argv[3])) global = JSValueToBoolean(ctx, argv[2]); - JSStringRef script = JSValueToStringCopy(ctx, argv[0], exc); - if (script == NULL) - return NIL; + if (JSValueIsObject(ctx, argv[0]) && (f = js_value_to_function(ctx, argv[0], exc)) != NULL) + { + body = get_body(ctx, f, exc); + if (body == NULL) + return NIL; + script = JSStringCreateWithUTF8CString(body); + name = js_get_string_property(ctx, f, "name"); + } + else + { + script = JSValueToStringCopy(ctx, argv[0], exc); + if (script == NULL) + return NIL; + } + + JSValueRef e = NULL; if (global) - JSEvaluateScript(wctx, script, NULL, NULL, 0, NULL); + JSEvaluateScript(wctx, script, NULL, NULL, 0, &e); else { JSObjectRef func = JSObjectMakeFunction(wctx, NULL, 0, NULL, script, NULL, 0, NULL); if (func != NULL && JSObjectIsFunction(ctx, func)) { - JSValueRef exc = NULL; - JSValueRef wret = JSObjectCallAsFunction(wctx, func, func, count, count == 1 ? args : NULL, &exc) ; + JSValueRef wret = JSObjectCallAsFunction(wctx, func, func, count, count == 1 ? args : NULL, &e) ; if (exc != NULL) { - fputs("DWB SCRIPT EXCEPTION: An error occured injecting a script.\n", stderr); - js_print_exception(wctx, exc, NULL, 0, NULL); - } - else { - // This could be replaced with js_context_change char *retx = js_value_to_json(wctx, wret, -1, NULL); + // This could be replaced with js_context_change if (retx) { ret = js_char_to_value(ctx, retx); @@ -273,6 +319,26 @@ inject(JSContextRef ctx, JSContextRef wctx, JSObjectRef function, JSObjectRef th } } } + if (e != NULL && !isnan(debug) && debug > 0) + { + int line = 0; + fprintf(stderr, "DWB SCRIPT EXCEPTION: An error occured injecting %s.\n", name == NULL || *name == '\0' ? "[anonymous]" : name); + js_print_exception(wctx, e, NULL, 0, (int)(debug-1), &line); + + fputs("==> DEBUG [SOURCE]\n", stderr); + if (body == NULL) + body = js_string_to_char(ctx, script, -1); + char **lines = g_strsplit(body, "\n", -1); + + fprintf(stderr, " %s\n", line < 3 ? "BOF" : "..."); + for (int i=MAX(line-2, 0); lines[i] != NULL && i < line + 1; i++) + fprintf(stderr, "%s %d > %s\n", i == line-1 ? "-->" : " ", i+ ((int) debug), lines[i]); + fprintf(stderr, " %s\n", line + 2 >= g_strv_length(lines) ? "EOF" : "..."); + + g_strfreev(lines); + } + g_free(body); + g_free(name); JSStringRelease(script); return ret; }/*}}}*/ @@ -1567,7 +1633,7 @@ global_timer_start(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size /* UTIL {{{*/ /* util_domain_from_host {{{*/ static JSValueRef -util_domain_from_host(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) +sutil_domain_from_host(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { if (argc < 1) { @@ -1584,7 +1650,7 @@ util_domain_from_host(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, s return ret; }/*}}}*//*}}}*/ static JSValueRef -util_markup_escape(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) +sutil_markup_escape(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { char *string = NULL, *escaped = NULL; if (argc > 0) @@ -1605,13 +1671,28 @@ util_markup_escape(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size return NIL; } static JSValueRef -util_get_mode(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) +sutil_get_mode(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { return JSValueMakeNumber(ctx, BASIC_MODES(dwb.state.mode)); } static JSValueRef -util_dispatch_event(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) +sutil_get_body(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + if (argc == 0) + return NIL; + JSValueRef ret = NIL; + JSObjectRef func = js_value_to_function(ctx, argv[0], exc); + char *body = get_body(ctx, func, exc); + if (body != NULL) + { + ret = js_char_to_value(ctx, body); + g_free(body); + } + return ret; +} +static JSValueRef +sutil_dispatch_event(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { gboolean result = false; if (argc < 3) @@ -3173,10 +3254,11 @@ create_global_object() JSClassRelease(class); JSStaticFunction util_functions[] = { - { "domainFromHost", util_domain_from_host, kJSDefaultAttributes }, - { "markupEscape", util_markup_escape, kJSDefaultAttributes }, - { "getMode", util_get_mode, kJSDefaultAttributes }, - { "dispatchEvent", util_dispatch_event, kJSDefaultAttributes }, + { "domainFromHost", sutil_domain_from_host, kJSDefaultAttributes }, + { "markupEscape", sutil_markup_escape, kJSDefaultAttributes }, + { "getMode", sutil_get_mode, kJSDefaultAttributes }, + { "getBody", sutil_get_body, kJSDefaultAttributes }, + { "dispatchEvent", sutil_dispatch_event, kJSDefaultAttributes }, { 0, 0, 0 }, }; class = create_class("util", util_functions, NULL); |