= dwb's JavaScript API documentation = == Abstract == *dwb* can be extended with different types of userscripts. This api documentation describes the javascript interface. == Getting Started == Scripts that use the javascript api must be located in +$XDG_CONFIG_HOME/dwb/userscripts+ like any other script. To include a userscript put a script with shebang ------- #!javascript ------- in the userscripts directory. All native javascript methods can be used in scripts, however there are limitations: * The execution context of userscripts is completely seperated from the web execution context. Due to security concerns it is not possible to communicate with the web execution context, it is only possible to inject scripts into the web context. * In contrast to the global +window+ object in the web execution context, the global object is a readonly object, i.e. it is not possible to set properties on the global object, see also <> for details. :numbered!: :caption: == Signals == With the +signals+ object *dwb* communicates with the script on certain events. To connect to a signal one can call the connect function that is implemented by the signals object, that takes 2 arguments, the name of the signal and a callback function. The callback function has a varying number of parameters, the first paramteter is always the <> which received the signal or the focused <>. The last paramter is always a json-object which might be empty or contain additional data relevant to the signal. A callback function should either return +true+ or +false+ or nothing which is equivalent to +false+. If multiple callbacks are connected to the same signal and one callback function returns +true+ the overall return value will be +true+. *dwb* only emits signals as long as one callback is connected to a signal. To reduce overhead one should disconnect from signals when no longer needed. The signals object implements the following functions === Functions === [[connect]] .connect() [source,javascript] ---- Number connect(String signal, Function callback) ---- Connect to a signal :: _signal_;; The signal to connect to _callback_;; The callback function which will be called when the signal is emitted _returns_;; Unique id for this connection, can be passed to <> [[emit]] .emit() [source,javascript] ---- Boolean emit(String signal, ...) ---- Emits a signal with a variable number of arguments passed to the callback function :: _signal_;; The signal to emit _..._;; Objects passed to the callback function _returns_;; Overall return value from all connected callback functions [[disconnect]] .disconnect() [source,javascript] ---- Boolean disconnect(Number id) ---- disconnect from a signal :: _id_;; The id returned from <> _returns_;; +true+ if the signal was disconnected, +false+ if the signal wasn't found or was already disconnected. [[disconnectByFunction]] .disconnectByFunction() [source,javascript] ---- Boolean disconnectByFunction(Function callback) ---- disconnect from all signals with matching callback function :: _callback_;; The callback function passed to <> _returns_;; +true+ if signals were disconnected, +false+ if no signal was [[disconnectByName]] .disconnectByName() [source,javascript] ---- Boolean disconnectByName(String signal) ---- disconnect from all signals with matching name :: _signal_;; The callback function passed to <> _returns_;; +true+ if signals were disconnected, +false+ if no signal was disconnected //[options="header", cols="1s,1m,3,2,2"] //|============================================= //|function 2+| parameter | returns | description // //.2+|connect //|String |The signal to connect to; *required* .2+| The //signal id of the signal or +-1+ if the signal was not connected. //.2+| Connects to a signal. // //|Function(+Object+, +Object+) | The callback to call when the signal is emitted; *required* // //|disconnect //|Number |The signal id of the signal; *required* | - //| Disconnects from a signal, the id is the id returned by //+connect+. // // //.2+|emit //|String |The signal to emit; *required* .2+| - //.2+| Emits a signal. //|Objects |Objects passed to the callback function; *optional* // // //|============================================= === Internal signals === Internal signals are signals implemented by dwb. It should be avoided to call <> on signals implemented by dwb since it will completely stop the emission of the signal in all scripts. [[buttonPress]] .buttonPress [source,javascript] ---- Boolean callback(webview, hittestresult, json) ---- Emitted when a button is pressed on the <>, return +true+ to prevent the default action :: _webview_;; The <> which received the signal _hittestresult_;; Hittestresult under the cursor _json.button_;; The button that is pressed, usually a value between 1 and 5 _json.state_;; A bitmap of modifiers pressed, see <> _json.time_;; The time in milliseconds when the button was pressed _json.type_;; A <> _json.x_;; x-position relative to the window _json.xRoot_;; x-position relative to the screen _json.y_;; y-position relative to the window _json.yRoot_;; y-position relative to the screen [[buttonRelease]] .buttonRelease [source,javascript] ---- Boolean callback(webview, hittestresult, json) ---- Emitted when a button is released, return +true+ to prevent the default action :: _webview_;; The <> which received the signal _hittestresult_;; Hittestresult under the cursor _json_;; Same as <> but without _json.type_ [[frameStatus]] .frameStatus [source,javascript] ---- void callback(webview, frame) ---- Emitted when the <> of a frame changes :: _webview_;; The webview the frame belongs to _frame_;; The frame [[keyPress]] .keyPress [source,javascript] ---- Boolean callback(webview, json) ---- Emitted when a key is pressed, return +true+ to prevent the default action :: _webview_;; The focused webview _json.isModifier_;; Whether or not the key is a modifier _json.keyCode_;; Hardware keycode _json.keyVal_;; Keycode as listed in gdkkeysyms.h _json.name_;; A string represantation of the key _json.state_;; A bitmap of modifiers pressed, see <> [[keyRelease]] .keyRelease [source,javascript] ---- Boolean callback(webview, json) ---- Emitted when a key is released, return +true+ to prevent the default action :: _webview_;; The focused webview _json_;; Same as <> [[loadCommitted]] .loadCommitted [source,javascript] ---- void callback(webview) ---- Emitted when the load has just commited, no data has been loaded when this signal is emitted. This is the preferred signal for injected scripts that do not manipulate the DOM. :: _webview_;; The webview that emitted the signal [[loadFinished]] .loadFinished [source,javascript] ---- Boolean callback(webview) ---- Emitted when the site has completely loaded. :: _webview_;; The webview that emitted the signal [[loadStatus]] .loadStatus [source,javascript] ---- void callback(webview) ---- Emitted when the load status changes :: _webview_;; The webview that emitted the signal [[mimeType]] .mimeType [source,javascript] ---- Boolean callback(webview, frame, request, json) ---- Decide whether or not to show a given mimetype. Return +true+ to stop the request. :: _webview_;; The webview that emitted the signal _frame_;; The frames requires the decision _request_;; The network request _json.mimeType_;; The mimetype [[navigation]] .navigation [source,javascript] ---- Boolean callback(webview, frame, request, action) ---- Emitted before a new site is loaded, return +true+ to stop the request. :: _webview_;; The webview that emitted the signal _frame_;; The frame that requires the navigation _request_;; The network request _action_;; The navigation action [[resource]] .resource [source,javascript] ---- Boolean callback(webview, frame, request, response) ---- Emitted before a new resource is going to be loaded :: _webview_;; The webview that emitted the signal _frame_;; The frame that dispatched the request _request_;; The network request _response_;; The network response [[tabFocus]] .tabFocus [source,javascript] ---- Boolean callback(webview, json) ---- Emitted when another tab gets focus, return +true+ to stop the event :: _webview_;; The new tab _json.last_;; The number of the previously focused tab //[options="header", cols="2s,2m,4,4"] //|============================================= //|signal 2+|parameter |description // //.3+|buttonPress //| <> | currently focused webview //.3+|Emitted when a button is pressed, only clicks on the webview are noticed; //return +true+ to stop the default action //| <> | the hit test result under the cursor //|json | // //* button The button that is pressed, usually a value between 1 and 5 //* state A bitmap of modifiers pressed, see <> //time:: The time in milliseconds when the button was pressed //type:: A <> //x:: x-position relative to the window //xRoot:: x-position relative to the screen //y:: y-position relative to the window //yRoot:: y-position relative to the screen // //|============================================= //|buttonRelease | focused <> //2+d|Same as *buttonPress* but without +type+ //|Emitted when a button is released, only clicks on the webview are noticed; //return +true+ to stop the default action // //.5+|download .5+| focused <> //|filename|The suggested filename //.5+|Emitted before a download starts. Return +true+ to handle the signal or +false+ to let *dwb* handle the signal. //|mimeType|The mimetype of the file or +unknown+ //|referer|The referer of the request //|uri|The uri of the file to download //|totalSize|The total size of the file // //.4+|downloadStatus .4+| focused <> //|filename|The filename //.4+|Emitted when the download status changes //|mimeType|Mimetype of the file or +unknown+ //|status|A <> //|uri|Original uri of the file // //.5+|keyPress .5+| focused <> //|isModifier | Whether or not the key is a modifier //.5+|Emitted when a key is pressed, the first parameter of the callback function //will always be the currently focued <>; return +true+ to stop the //default action //|keyCode | Hardware keycode //|keyVal | Keycode as listed in gdkkeysyms.h //|name | A string represantation of the key //|state | A bitmap of modifiers pressed, see <> // //|keyRelease | focused <> //2+d|Same as *keyPress* //|Emitted when a key is released; return +true+ to stop the //default action // // //|tabFocus | focused <> //|last| Number of the previously focused tab //|Emitted when a new tab gets focus, the first parameter will be the new //<>; return +true+ to prevent the tab being changed .Example [source,javascript] ------ // Prevent example.com from being loaded function navigationCallback(wv, frame, request, action) { if (/.*\.example\.com.*/.test(request.uri)) { return true; } } signals.connect("navigation", navigationCallback); ------ == Global == Functions from the global object. === Functions === [[execute]] .execute() [source,javascript] ---- Boolean execute(String command) ---- [source,javascript] ---- Boolean execute(String command) ---- Executes a dwb command :: _command_;; a dwb command to execute, will be parsed the same way as if executed from commandline _returns_;; +true+ if execution was successful [[include]] .include() [source,javascript] ---- Boolean include(String path, [Boolean global]) ---- Includes a file. Note that there is only one context, all scripts are executed in this context. Included files are not visible in other scripts unless +true+ is passed as second parameter. :: _path_;; Path to a file to include _global_;; Whether to include the script into the global scope, optional _returns_;; The return value of the included file [[timerStart]] .timerStart() [source,javascript] ---- Number timerStart(Number interval, Function func) ---- Executes a function repeatedly until the function returns +false+ or <> is called on the +id+ returned from this function :: _interval_;; Interval in milliseconds _func_;; Function to execute _returns_;; An id that can be passed to timerStop [[timerStop]] .timerStop() [source,javascript] ---- Number timerStop(Number id) ---- Stops a timer started by <> :: _id_;; The id returned from <> _returns_;; +true+ if the timer was stopped [[domainFromHost]] .domainFromHost() [source,javascript] ---- String domainFromHost(String hostname) ---- Gets the base domain name from a hostname where the base domain name is the effective second level domain name, e.g. for www.example.com it will be example.com, for www.example.co.uk it will be example.co.uk. :: _hostname_;; a hostname _returns_;; the base domain //[options="header", cols="1s,1m,3,3,3"] //|============================================= //|function 2+| parameter | returns |description // //|execute //|String //| dwb-command to execute; *required* | //+true+ if successfull, +false+ otherwise | //Executes a dwb-command in the focused tab. // //[[include]] //.2+|include //|String| Path to a file to include; *required* //.2+| The value returned from the script. Note that a value can only be returned //from a script that is encapsulated either by encapsulating the script yourself, //or by omitting or passing +false+ to the second parameter. //.2+| Includes a file. Note that there is only one context, all scripts are //executed in this context. Included files are always included in the global //scope but encapsulated in a function unless you pass +true+ as the second //parameter. //|Boolean| +true+ if the script should be applied to the global scope, objects in //the script will be visible in all scripts, +false+ to encapsulate the script; //*optional*, default +false+ // //.2+|timerStart //|Number |Interval in milliseconds; *required* //.2+|An +id+ for the timeout or -1 if an error occured //.2+|Executes a function repeatedly until the function returns false or //*timerStop* is called on the +id+ returned from *timerStart* //|Function() |Function to execute; *required* // //|timerStop //|Number |The +id+ returned from *timerStart*; *required* //|+true+ if the timeout was stopped //|Stops execution of a function started by timoutStart // //|domainFromHost |String | Host name | The domain name //|Returns the domain part of a hostname. // //|============================================= .Example [source,javascript] --------------------------------- execute("tabopen ixquick.com"); // Execute a function once, similar to window.setTimeout() timerStart(2000, function() { tabs.current.inject("alert('Hello world')"); return false; }); --------------------------------- NOTE: Scripts included with +include+ are either visible in the global scope or invisible, even in the including script. To use an included script it can return an object with its public objects: [source,javascript] --------------------------------- // included script var private = 37; return { getPrivate : function () { return private; } }; // Scripts that includes the above var i = include("/path/to/script"); var p = i.getPrivate(); // 37 --------------------------------- [[Globalobjects]] == Global Objects == [[data]] === data === The +data+ object can be used to determine internally used data securely. All properties are readonly Strings. :: _data.bookmarks_;; Bookmark file _data.cacheDir_;; Cache directory _data.configDir_;; Config directory _data.cookies_;; Cookie file _data.cookiesWhitelist_;; Whitelist for persistent cookies _data.customKeys_;; Custom keyboard shortcuts _data.history_;; History file _data.keys_;; Shortcuts configuration file _data.pluginsWhitelist_;; Whitelist for the plugin blocker _data.profile_;; Profile which will be +default+ unless another profile is specified on command line _data.quickmarks_;; Quickmark file _data.scriptWhitelist_;; Whitelist for scripts _data.session_;; File with stored sessions for this profile _data.sessionCookiesWhitelist_;; Whitelist for session cookies _data.settings_;; Settings configuration file _data.searchEngines_;; Searchengines //.Properties //[options="header", cols="2s,10"] //|============================================= //|bookmarks |Bookmark file //|cacheDir |Cache directory //|configDir |Config directory //|cookies |Cookie file //|cookiesWhitelist |Whitelist for persistent cookies //|customKeys |Custom keyboard shortcuts //|history |History file //|keys |Shortcuts configuration file //|pluginsWhitelist |Whitelist for the plugin blocker //|profile |Profile which will be +default+ unless another profile is specified on command line //|quickmarks |Quickmark file //|scriptWhitelist |Whitelist for scripts //|session |File with stored sessions for this profile //|sessionCookiesWhitelist |Whitelist for session cookies //|settings |Settings configuration file //|searchEngines |Searchengines //|============================================= .Example [source,javascript] --------------------------------- // Get contents of the currently used bookmark file var bookmarks = io.read(data.bookmarks); -------------------------------- [[io]] === io === The +io+ object implements functions for input and output. [[print]] .print() [source,javascript] ---- void io.print(String text, [String stream]) ---- Print text to +stdout+ or +stderr+ :: _text_;; the text to print _stream_;; pass +"stderr"+ to print to stderr, optional [[write]] .write() [source,javascript] ---- Boolean io.write(String path, String mode, String text) ---- Write to a file :: _path_;; Path to a file to write to _mode_;; Either +"a"+ to append to the file, or +"w"+ to strip the file or create a new file. _text_;; The text that should be written to the file _returns_;; +true+ if writing was successful [[read]] .read() [source,javascript] ---- String io.read(String path) ---- Read from a file. :: _path_;; Path to a file that should be read _returns_;; A string with the file content //[options="header", cols="1s,1m,3,2,2"] //|============================================= //|function 2+| parameter | returns |description //.2+|print //|String | Text to print; *required* //.2+| - //.2+|Print text to +stdout+ or +stderr+ //|String | Pass +"stderr"+ to print to stderr; *optional* // //.3+|write | //String| Path to a file to write to; *required* .3+| //+true+ if successfull, +false+ otherwise .3+| //Write text to a local file //|String|Either +"a"+ if the text should be appended or +"w"+ to create a new file; *required* //|String | Text that should be written to the file; *required* // //| read //| String | A path to a file to read; *required* //| A string with the content of the file if reading was successfull, +null+ //otherwise.|Get content of a local file // //|============================================= .Example [source,javascript] --------------------------------- var text = io.read("/home/foo/textfile.txt"); io.print(text); -------------------------------- [[system]] === system === The +system+ object implements system functions. [[spawn]] .spawn() [source,javascript] ---- SpawnError system.spawn(String command, [Function stdin], [Function stderr]) ---- Executes a shell command using the default search path :: _command_;; The command to execute _stdin(String)_;; Callback function for stdin, pass +null+ if only stderr is needed, optional _stderr(String)_;; Callback function for stderr, optional _returns_;; <> if an error occured, 0 otherwise [[getEnv]] .getEnv() [source,javascript] ---- String system.getEnv(String name) ---- Get a system environment variable :: _name_;; Name of the variable _returns_;; The variable or +null+ if the variable wasn't found //[options="header", cols="1s,1m,2,2,2"] //|============================================= //|function 2+| parameter | returns |description //.3+|spawn //|String | Command to execute; *required* //.3+|Returns <> //.3+|Executes a shell command using the default searchpath //|Function(+String+) | callback for stdout, pass +null+ if only stderr is needed; *optional* //|Function(+String+) | callback for stderr; *optional* // //|getEnv //|String | Name of the variable; *required* //|String containing the variable or +null+ if the variable was not found //|Get a system environment variable. //|============================================= .Example [source,javascript] ------------ var home = system.getEnv("HOME"); // asynchronous wrapped read function asyncread(filename) { system.spawn("cat " + filename, function (response) { ... }); } asyncread(home + "/.bashrc"); ------------ [[tabs]] === tabs === The +tabs+ object implements functions and properties to get +webview+ objects. ==== Properties ==== .current [source,javascript] ---- tabs.current webview read ---- The currently focused webview .length [source,javascript] ---- tabs.length Number read ---- Total number of tabs .number [source,javascript] ---- tabs.number Number read ---- Number of the currently focused tab //[options="header", cols="2s,2m,1s,10"] //|============================================= //|name |type|mode| description //|current |<>| ro |The currently focused tab //|length |Number |ro| The total number of tabs //|number |Number |ro| The number of the currently focused tab // //|============================================= ==== Functions ==== .nth() [source,javascript] ---- webview tabs.nth(Number n) ---- Gets the webview object of the nth tab :: _n_;; Number of the tab _returns_;; The corresponding <> //[options="header", cols="1s,1m,3,2,2"] //|============================================= //|function 2+| parameter | returns |description //|nth |Number |Number of the tab, counting from 0; *required* | A <> object or +null+ if //an error occured | Gets the webview object of the nth tab. // //|============================================= .Example [source,javascript] ---- var c = tabs.current; tabs.nth(2).uri = c.uri; ---- [[Webkitobjects]] == Webkit objects == [[webview]] === webview === The +webview+ object represents the widget that actually displays the site content. ==== Properties ==== The properties correspond to the gobject properties in camelcase ==== Functions ==== .inject() [source,javascript] ---- Boolean wv.inject(String script, [Boolean global]) ---- Injects a script into a webview :: _script_;; the script to inject _global_;; +true+ to inject it into the global scope, +false+ to encapsulate it in a function, optional _returns_;; +true+ if the script was injected, +false+ if an error occured .history() [source,javascript] ---- void wv.history(Number steps) ---- Loads a history item +steps+ away from the current history item :: _steps_;; Number of steps, pass a negative value to go back in history .loadUri() [source,javascript] ---- Boolean wv.loadUri(String uri, [Function callback]) ---- Load an uri in a webview. :: _uri_;; The uri to load _callback_;; A callback function that will be called when the load status changes, return +true+ to stop the emission, optional _returns_;; +true+ if the uri is loaded .reload() [source,javascript] ---- void wv.reload(void) ---- Reload a webview .Example [source,javascript] ------------ var wv = tabs.current; wv.loadUri("http://www.example.com", function() { if (wv.loadStatus == LoadStatus.finished) { wv.inject("alert('Hello ' + wv.uri + "!!!"); return true; } }); ------------ //.Functions // //[options="header", cols="1s,1m,2,2,4"] //|============================================= //|function 2+| parameter | returns |description //|set //|Object |An object with properties to set; *required* //|+false+ if an error occurs, +true+ otherwise //|Sets the webviews properties, valid properties are the properties of //http://webkitgtk.org/reference/webkitgtk/stable/WebKitWebSettings.html[WebKitWebSettings]. // //|get //|String |The name of the property to get; *required* //|A String containing the property value //|Sets the webviews properties, valid properties are the properties of //http://webkitgtk.org/reference/webkitgtk/stable/WebKitWebSettings.html[WebKitWebSettings]. //Note that this function always returns a String, for boolean values it returns //+TRUE+ or +FALSE+. // //.2+|inject //|String | Script to inject //.2+|+true+ if the script was injected, +false+ otherwise. //.2+|Injects a script into the +webview+ //|Boolean | +true+ to inject the script in the global scope, +false+ to encapsulate it //in a function; *optional*, default +false+ // //|history //|Number |Number of steps; *required* //|- //|Loads the history item +steps+ away from the current item. // //|reload //|- | //|- //|Reload the +webview+ // //|============================================= //.Signals //[options="header", cols="2s,2m,2m,4,4"] //|============================================= //|signal |first parameter 2+|object properties |description //.2+|[[loadStatus]]loadStatus .2+| <> //|status|The <> //.2+|Emitted when the load status changes. //|uri|Uri that is currently loaded // //|[[loadCommitted]]loadCommitted | <> //|uri|Uri that will be loaded //|Emitted when the load has just commited, no data has been loaded when this //signal is emitted. This //is the preferred signal for injected scripts that do not manipulate the DOM. // //|[[loadFinished]]loadFinished | <> //|uri|Uri that is has been loaded //|Emitted when the site has completely loaded. // //.2+|mimeType .2+| <> //|mimeType| The mime-type //.2+|Decide whether or not to show a given mimetype. Return true to stop the request. //|uri| Uri of the request // //.2+|navigation .2+| <> //|uri | Uri of the request //.2+| Emitted before a new site is loaded, return +true+ to stop the request. //|reason | Reason for the request where +reason+ is a <> // // //|resource | <> //|uri | Uri of the request //|Emitted before a new resource is loaded, return +true+ to stop the request. //|============================================= //.Example //[source,javascript] //------------ //signals.connect("navigation", function (wv, frame, navigation, action) { // if (/.*youtube.*/.test(navigation.uri)) { // o.set({ // "enable-plugins" : true, // "enable-scripts" : true // }); // } //}); //------------ NOTE: If a script is injected from a <>-callback the script must be injected after +LoadStatus.committed+ has been emitted. On +LoadStatus.committed+ the document hasn't been created, if the script modifies the DOM it should be injected on +LoadStatus.finished+. If only +LoadStatus.committed+ or +loadFinished.committed+ are used it is better to use the corresponding signals instead to reduce overhead. [[frame]] === frame === A frame represents a +frame+ or +iframe+. Due to same origin policy it is not possible to inject scripts from a <> into iframes with a different domain. For this purpose the +frame+ object can be used. ==== Properties ==== The properties correspond to the gobject properties in camelcase. ==== Functions ==== .inject() [source,javascript] ---- Boolean frame.inject(String script, [Boolean global]) ---- Injects a script into a frame :: _script_;; the script to inject _global_;; +true+ to inject it into the global scope, +false+ to encapsulate it in a function, optional _returns_;; +true+ if the script was injected, +false+ if an error occured //[options="header", cols="1s,1m,3,2,2"] //|============================================= //|function 2+| parameter | returns |description //.2+|inject //|String | Script to inject //.2+|+true+ if the script was injected, +false+ otherwise. //.2+|Injects a script into the +frame+, see also <> //|Boolean | +true+ to inject the script in the global scope, +false+ to encapsulate it //in a function; *optional*, default +false+ //|============================================= //.Signals //[options="header", cols="2s,2m,2m,4,4"] //|============================================= //|signal |first parameter 2+|object properties |description //|frameStatus[[frameStatus]] | <> //|status |<> //| Emitted when the load status of a frame changes changes, scripts should be //injected into a frame either on +LoadStatus.committed+ or +LoadStatus.finished+ // //|============================================= // //.Example //[source,javascript] //-------- //signals.connect("frameStatus", function(frame, o) { // if (o.status == LoadStatus.finished) { // frame.inject("document.body.innerHTML = '';"); // } //}); //-------- [[request]] === request === Corresponds to a +WebKitNavigationRequest+. [[navigationAction]] === navigationAction === Corresponds to a +WebKitWebNavigationAction+. == Enum objects == Enum objects are objects that have only readonly properties, mapping gtk/webkit enums to javascript objects. [[ButtonContext]] .ButtonContext [source,javascript] -------- const ButtonContext = { document : 1 << 1, link : 1 << 2, image : 1 << 3, media : 1 << 4, selection : 1 << 5, editable : 1 << 6 }; -------- [[ClickType]] .ClickType [source,javascript] -------- const ClickType = { click : 4, doubleClick : 5, tripleClick : 6 }; -------- [[DownloadStatus]] .DownloadStatus [source,javascript] ------- const DownloadStatus = { error : -1, created : 0, started : 1, cancelled : 2, finished : 3 }; ------- [[LoadStatus]] .LoadStatus [source,javascript] --------- const LoadStatus = { provisional : 0, committed : 1, finished : 2, firstVisualLayout : 3, failed : 4 }; --------- [[Modifier]] .Modifier [source,javascript] -------- const Modifier = { Shift : 1 << 0, Lock : 1 << 1, Control : 1 << 2, Mod1 : 1 << 3, Mod2 : 1 << 4, Mod3 : 1 << 5, Mod4 : 1 << 6, Mod5 : 1 << 7, Button1 : 1 << 8, Button2 : 1 << 9, Button3 : 1 << 10, Button4 : 1 << 11, Button5 : 1 << 12, Super : 1 << 26, Hyper : 1 << 27, Meta : 1 << 28, Release : 1 << 30, Modifier : 0x5c001fff }; -------- [[NavigationReason]] .NavigationReason [source,javascript] -------- const NavigationReason = { linkClicked : 0, formSubmitted : 1, backForward : 2, reload : 3, formResubmitted : 4, other : 5 }; -------- [[SpawnError]] .SpawnError [source,javascript] -------- const SpawnError = { success : 0, spawnFailed : 1<<0, stdoutFailed : 1<<1, stderrFailed : 1<<2 }; -------- [[Globaldata]] == Global data == Since all scripts share the same execution context, they are encapsulated in a function. To avoid conflicts with other scripts it is not allowed to set properties on the global object, i.e. [source,javascript] ------- #!javascript // not allowed, the global object is readonly number = 0; io.print(number); // undefined // always you var instead var number = 0; io.print(number2); // 0 // won't work either function foo() { bar = 1; } foo(); io.print(bar); // undefined ------- For sharing data between scripts either signals can be created or the +globals+-object can be used. To share data with the globals object securely when the scripts are loaded the script can return an +init+ function that will be called after all scripts have been initialized: .Script 1 [source,javascript] ------- #!javascript // set when the script is initialized. globals.foo = "bar"; ------- .Script 2 [source,javascript] ------- #!javascript // The behaviour is undefined, depending on if Script 1 was initialized before // Script 2 or the other way round. io.print(globals.foo) // undefined or "bar" // Will be called after all scripts have been initialized return { init : function () { // globals.foo has been initialized io.print(globals.foo); // "bar" } }; ------- One exception is <>, scripts that are explicitly included into the global scope setting the second parameter to true are visible in every script. .foo [source,javascript] ------- var foo = "bar"; ------- .Script 1 [source,javascript] ------- #!javascript include("/path/to/foo", true); // visible in every script ------- .Script 2 [source,javascript] ------- #!javascript // Make sure Script 1 has been initialized return { init : function() { io.print(foo); // "bar"; } }; ------- [[Extensions]] == Extensions == *dwb* provides the possibility to load extensions. It is recommended to implement javascript-userscripts as an extension to have consistent configuration locations for scripts. The +extensions+ object has the following properties and functions === Functions === [[extensionload,load]] .load() [source,javascript] ---- Boolean extensions.load(String name) ---- Loads an extension :: _name_;; Name of the extension _returns_;; True if the extension was loaded [[error]] .error() [source,javascript] ---- void extensions.error(String name, String message) ---- Print a consistent error to stderr :: _name_;; Name of the extension _message_;; The error message [[message]] .message() [source,javascript] ---- void extensions.message(String name, String message) ---- Print a consistent message to stderr :: _name_;; Name of the extension _message_;; The message [[warning]] .warning() [source,javascript] ---- void extensions.warning(String name, String message) ---- Print a consistent warning to stderr :: _name_;; Name of the extension _message_;; The warning message .Example [source,javascript] -------- #!javascript extensions.load("foobar"); -------- .Writing extensions The default searchpath for extensions isn +$XDG_DATA_HOME/dwb/extensions+ and +SHARE_DIR/dwb/extensions+ where the +SHARE_DIR+ with sharedirectory being the share-dir of the installation. The configuration for extensions is in +$XDG_CONFIG_HOME/dwb/extensionsrc+ and should return a javascript object. Every extension must implement one function named +init+ that takes one argument, the config for the extension. The function should return +true+ if the extension was successfully loaded, +false+ otherwise. +init+ should be returned from the extension. .Example A extension called *foobar* in +$HOME/.local/share/dwb/extensions/foobar+. [source,javascript] -------- function foo(val) { .... } function bar(val) { .... } return { init : function (config) { if (config.foo > 36) { bar(config.foo); foo(config.bar); return true; } return false; } }; -------- .Example extensionrc [source,javascript] -------- return { foobar : { bar : "X", foo : 37 }, // config for extension foobar barfoo : { } // config for extension barfoo }; -------- // vim: set ft=asciidoc: