diff options
-rw-r--r-- | api/dwb-js.7 | 391 | ||||
-rw-r--r-- | api/jsapi.7.txt | 248 | ||||
-rw-r--r-- | api/jsapi.txt | 326 | ||||
-rw-r--r-- | extensions/requestpolicy | 624 | ||||
-rw-r--r-- | scripts/base.js | 26 | ||||
-rw-r--r-- | scripts/lib/dwb.js | 34 | ||||
-rw-r--r-- | src/dwb.c | 1 | ||||
-rw-r--r-- | src/js.c | 8 | ||||
-rw-r--r-- | src/js.h | 1 | ||||
-rw-r--r-- | src/scripts.c | 323 | ||||
-rw-r--r-- | src/view.c | 7 |
11 files changed, 1526 insertions, 463 deletions
diff --git a/api/dwb-js.7 b/api/dwb-js.7 index 1c3e07ac..f39a13ea 100644 --- a/api/dwb-js.7 +++ b/api/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.77.1 <http://docbook.sf.net/> -.\" Date: 12/05/2012 +.\" Date: 12/09/2012 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "DWB\-JS" "7" "12/05/2012" "\ \&" "\ \&" +.TH "DWB\-JS" "7" "12/09/2012" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -701,27 +701,6 @@ A string with the file content .nr an-break-flag 1 .br .ps +1 -\fBString io.statusBar(Object text)\fR -.RS 4 -.sp -Sets the statusbar text\&. The statusbar consists of two labels, a \fImiddle\fR label and a \fIright\fR label, on both labels pango markup can be used -.PP -\fItext\&.middle\fR -.RS 4 -Text for the middle label -.RE -.PP -\fItext\&.right\fR -.RS 4 -Text for the right label -.RE -.RE -.sp -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 \fBBoolean io.write(String path, String mode, String text)\fR .RS 4 .sp @@ -1156,6 +1135,241 @@ Label used for displaying uris, third child of Label used for status information, fourth child of \fBgui\&.statusBox\fR\&. .RE +.SS "Deferred" +.sp +Deferred objects can be used to manage asynchronous operations\&. It can trigger a callback function when an asynchrounous operation has finished, and allows chaining of callbacks\&. Deferred basically have 2 callback chains, a \fIdone\fR\-chain and a \fIfail\fR\-chain\&. If a asynchronous operation is successful the deferred should be resolved and the done callback chain of the deferred is called\&. If a asynchronous operation fails the deferred should be rejected and the fail callback chain of the deferred is called\&. +.sp +Deferreds implement the following methods: +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBvoid Deferred.done(Function callback)\fR +.RS 4 +.sp +Registers a function for the done\-chain\&. +.PP +\fIcallback\fR +.RS 4 +A callback function that will be called when the Deferred is resolved\&. If the function returns a deferred the original deferred will be replaced with the new deferred\&. +.RE +.PP +\fIreturns\fR +.RS 4 +A new deferred that can be used to chain callbacks\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBDeferred Deferred.fail(Function callback)\fR +.RS 4 +.sp +Registers a function for the fail\-chain\&. +.PP +\fIcallback\fR +.RS 4 +A callback function that will be called when the deferred is rejected\&. If the function returns a deferred the original deferred will be replaced with the new deferred\&. +.RE +.PP +\fIreturns\fR +.RS 4 +A new deferred that can be used to chain callbacks\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBDeferred Deferred.reject(arguments)\fR +.RS 4 +.sp +Rejects a deferred, the fail\-chain is called when a deferred is rejected\&. +.PP +\fIarguments\fR +.RS 4 +Arguments passed to the +\fIfail\fR +callbacks\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBvoid Deferred.resolve(arguments)\fR +.RS 4 +.sp +Resolves a deferred, the done\-chain is called when a deferred is resolved\&. +.PP +\fIarguments\fR +.RS 4 +Arguments passed to the +\fIdone\fR +callbacks\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBDeferred Deferred.then(Function ondone, Function onfail)\fR +.RS 4 +.sp +Registers a function for the done and fail chain\&. +.PP +\fIondone\fR +.RS 4 +A callback function that will be called when the deferred is resolved\&. If the function returns a deferred the original deferred will be replaced with the new deferred\&. +.RE +.PP +\fIonfail\fR +.RS 4 +A callback function that will be called when the deferred is rejected\&. If the function returns a deferred the original deferred will be replaced with the new deferred\&. +.RE +.PP +\fIreturns\fR +.RS 4 +A new deferred that can be used to chain callbacks\&. +.RE +.sp +Simple usage of a deferred: +.sp +.if n \{\ +.RS 4 +.\} +.nf +function loadUri(uri) { + var d = new Deferred(); + tabs\&.current\&.loadUri(uri, function(wv) { + if (wv\&.loadStatus == LoadStatus\&.finished) + { + d\&.resolve("Finished"); + return true; + } + else if (wv\&.loadStatus == LoadStatus\&.failed) + { + d\&.reject("Failed"); + return true; + } + }); + return d; +} + +loadUri("http://www\&.example\&.com")\&.then( + function(response) { + io\&.print(response); // Finished + }, + function(response) { + io\&.print(response); // Failed + } +); +.fi +.if n \{\ +.RE +.\} +.sp +Chaining of a deferred: +.sp +.if n \{\ +.RS 4 +.\} +.nf +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d\&.reject("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io\&.print(response); +} + +// Will print "rejected" twice to stdout after 2 seconds +foo()\&.fail(onResponse)\&.fail(onResponse); +.fi +.if n \{\ +.RE +.\} +.sp +Note that if the deferred is rejected only the fail chain is called, when it is resolved only the done chain is called\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d\&.reject("rejected"); + // Already rejected, will not execute the done chain + d\&.resolve("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io\&.print(response); +} + +// Only the fail will be executed + +foo()\&.fail(onResponse)\&.done(onResponse); +foo()\&.done(onResponse)\&.fail(onResponse); +.fi +.if n \{\ +.RE +.\} +.sp +Changing the deferred in a callback chain: +.sp +.if n \{\ +.RS 4 +.\} +.nf +function foo(message) +{ + var d = new Deferred(); + timerStart(2000, function() { + d\&.resolve(message); + }); + return d; +} +function callback1(response) +{ + io\&.print(response); // Prints "foo" after 2 seconds + + // Return a new Deferred, will replace the old one\&. + return foo("bar"); +} +function callback2(response) +{ + io\&.print(response); // Prints "bar" after 4 seconds +} + +foo("foo")\&.done(callback1)\&.done(callback2); +.fi +.if n \{\ +.RE +.\} +.RE .SH "WEBKIT OBJECTS" .sp All webkit objects correspond to gobject objects, i\&.e\&. they have the same properties, but the javascript properties are all camelcase\&. For example, a WebKitWebView has the property \fBzoom\-level\fR, the corresponding javascript property is \fBzoomLevel\fR: @@ -1194,6 +1408,23 @@ The following methods are implemented by all Objects derived from GObject .nr an-break-flag 1 .br .ps +1 +\fBvoid object.blockSignal(Number signalid)\fR +.RS 4 +.sp +Blocks emission of a gobect signal\&. +.PP +\fIsignalid\fR +.RS 4 +The signalid returned from +\fBobject\&.connect\fR +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 \fBNumber object.connect(String name, Function callback, [Boolean after])\fR .RS 4 .sp @@ -1225,6 +1456,37 @@ The signal id of the signal\&. .nr an-break-flag 1 .br .ps +1 +\fBNumber object.connectBlocked(String name, Function callback, [Boolean after])\fR +.RS 4 +.sp +Connect to a gobject\-signal but block the emission of the own callback during execution of the callback, useful if the object is connected to a notify event and the the property is changed in the callback function\&. +.PP +\fIname\fR +.RS 4 +The signal name to connect to\&. +.RE +.PP +\fIcallback\fR +.RS 4 +Callback function that will be called when the signal is emitted\&. +.RE +.PP +\fIafter\fR +.RS 4 +Whether to install the handler after the default handler, default false\&. +.RE +.PP +\fIreturns\fR +.RS 4 +The signal id of the signal\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 \fBBoolean object.disconnect(Number id)\fR .RS 4 .sp @@ -1277,6 +1539,37 @@ The signal id of the signal\&. .nr an-break-flag 1 .br .ps +1 +\fBNumber object.notifyBlocked(String name, Function callback, [Boolean after])\fR +.RS 4 +.sp +Wrapper function for property\-change notification, the same as \fIobject\&.connectBlocked("notify::" + name, callback, after);\fR\&. +.PP +\fIname\fR +.RS 4 +The property name to connect to, the name can also be in camelcase\&. +.RE +.PP +\fIcallback\fR +.RS 4 +Callback function that will be called when the property changes\&. +.RE +.PP +\fIafter\fR +.RS 4 +Whether to install the handler after the default handler, default after\&. +.RE +.PP +\fIreturns\fR +.RS 4 +The signal id of the signal\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 \fBObject GObject.getPrivate(String key, Object identifier)\fR .RS 4 .sp @@ -1323,6 +1616,23 @@ The property value A local object to identify the calling script, the identifier must either be of type Object or of type Function\&. .RE .RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBvoid object.unblockSignal(Number signalid)\fR +.RS 4 +.sp +Unblocks a signal previously blocked with \fBobject\&.blockSignal\fR\&. +.PP +\fIsignalid\fR +.RS 4 +The signalid returned from +\fBobject\&.connect\fR +.RE +.RE .SS "webview" .sp The webview object represents the widget that actually displays the site content\&. @@ -1449,7 +1759,7 @@ Number of steps, pass a negative value to go back in history \fBBoolean wv.loadUri(String uri, [Function callback])\fR .RS 4 .sp -Load an uri in a webview\&. +Loads an uri in a webview\&. .PP \fIuri\fR .RS 4 @@ -1472,6 +1782,28 @@ true if the uri is loaded .nr an-break-flag 1 .br .ps +1 +\fBvoid wv.reload(void)\fR +.RS 4 +.sp +Reloads a webview +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBvoid wv.stopLoading()\fR +.RS 4 +.sp +Stops any ongoing loading\&. +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 \fBNumber wv.toPng(String filename, [Number width, Number height], [Boolean keepAspect])\fR .RS 4 .sp @@ -1502,17 +1834,6 @@ Whether to keep the aspect ratio, if set to true the new image will have the sam A cairo_status_t (0 on success) or \-1 if an error occured\&. .RE .RE -.sp -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBvoid wv.reload(void)\fR -.RS 4 -.sp -Reload a webview -.RE .SS "frame" .sp A frame represents a frame or iframe\&. Due to same origin policy it is not possible to inject scripts from a webview into iframes with a different domain\&. For this purpose the frame object can be used\&. diff --git a/api/jsapi.7.txt b/api/jsapi.7.txt index 7c4e132f..a9bfb561 100644 --- a/api/jsapi.7.txt +++ b/api/jsapi.7.txt @@ -323,16 +323,6 @@ _path_;; Path to a file that should be read _returns_;; A string with the file content **** -==== String io.statusBar(Object text) -**** - -Sets the statusbar text. The statusbar consists of two labels, a 'middle' label and -a 'right' label, on both labels pango markup can be used - -_text.middle_;; Text for the middle label -_text.right_;; Text for the right label -**** - ==== Boolean io.write(String path, String mode, String text) **** @@ -523,6 +513,180 @@ _gui.uriLabel (GtkLabel, read)_;; Label used for displaying uris, third child of _gui.statusLabel (GtkLabel, read)_;; Label used for status information, fourth child of *gui.statusBox*. +=== Deferred === + +Deferred objects can be used to manage asynchronous operations. It can trigger a +callback function when an asynchrounous operation has finished, and allows +chaining of callbacks. +Deferred basically have 2 callback chains, a _done_-chain and a _fail_-chain. +If a asynchronous operation is successful the deferred should be resolved and +the done callback chain of the deferred is called. +If a asynchronous operation fails the deferred should be rejected and +the fail callback chain of the deferred is called. + + +Deferreds implement the following methods: + +==== void Deferred.done(Function callback) +**** + +Registers a function for the done-chain. + +_callback_;; A callback function that will be called when the Deferred is +resolved. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + +==== Deferred Deferred.fail(Function callback) +**** + +Registers a function for the fail-chain. + +_callback_;; A callback function that will be called when the deferred is +rejected. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + +==== Deferred Deferred.reject(arguments) +**** + +Rejects a deferred, the fail-chain is called when a deferred is rejected. + +_arguments_;; Arguments passed to the _fail_ callbacks. +**** + +==== void Deferred.resolve(arguments) +**** + +Resolves a deferred, the done-chain is called when a deferred is resolved. + +_arguments_;; Arguments passed to the _done_ callbacks. +**** + +==== Deferred Deferred.then(Function ondone, Function onfail) +**** + +Registers a function for the done and fail chain. + +_ondone_;; A callback function that will be called when the deferred is +resolved. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_onfail_;; A callback function that will be called when the deferred is +rejected. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + + +Simple usage of a deferred: + +[source,javascript] +--------------------------------- +function loadUri(uri) { + var d = new Deferred(); + tabs.current.loadUri(uri, function(wv) { + if (wv.loadStatus == LoadStatus.finished) + { + d.resolve("Finished"); + return true; + } + else if (wv.loadStatus == LoadStatus.failed) + { + d.reject("Failed"); + return true; + } + }); + return d; +} + +loadUri("http://www.example.com").then( + function(response) { + io.print(response); // Finished + }, + function(response) { + io.print(response); // Failed + } +); +--------------------------------- + +Chaining of a deferred: + +[source,javascript] +--------------------------------- +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d.reject("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io.print(response); +} + +// Will print "rejected" twice to stdout after 2 seconds +foo().fail(onResponse).fail(onResponse); +--------------------------------- + +Note that if the deferred is rejected only the fail chain is called, when it is +resolved only the done chain is called. +[source,javascript] +--------------------------------- +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d.reject("rejected"); + // Already rejected, will not execute the done chain + d.resolve("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io.print(response); +} + +// Only the fail will be executed + +foo().fail(onResponse).done(onResponse); +foo().done(onResponse).fail(onResponse); +--------------------------------- + +Changing the deferred in a callback chain: + +[source,javascript] +--------------------------------- +function foo(message) +{ + var d = new Deferred(); + timerStart(2000, function() { + d.resolve(message); + }); + return d; +} +function callback1(response) +{ + io.print(response); // Prints "foo" after 2 seconds + + // Return a new Deferred, will replace the old one. + return foo("bar"); +} +function callback2(response) +{ + io.print(response); // Prints "bar" after 4 seconds +} + +foo("foo").done(callback1).done(callback2); +--------------------------------- + + == WEBKIT OBJECTS == All webkit objects correspond to gobject objects, i.e. they have the same @@ -555,6 +719,14 @@ if (myObject instanceof GObject) The following methods are implemented by all Objects derived from GObject +==== void object.blockSignal(Number signalid) +**** + +Blocks emission of a gobect signal. + +_signalid_;; The signalid returned from *object.connect* +**** + ==== Number object.connect(String name, Function callback, [Boolean after]) **** @@ -572,6 +744,20 @@ false. _returns_;; The signal id of the signal. **** +==== Number object.connectBlocked(String name, Function callback, [Boolean after]) +**** + +Connect to a gobject-signal but block the emission of the own callback during +execution of the callback, useful if the object is connected to a notify event +and the the property is changed in the callback function. + +_name_;; The signal name to connect to. +_callback_;; Callback function that will be called when the signal is emitted. +_after_;; Whether to install the handler after the default handler, default +false. +_returns_;; The signal id of the signal. +**** + ==== Boolean object.disconnect(Number id) **** @@ -594,6 +780,19 @@ after. _returns_;; The signal id of the signal. **** +==== Number object.notifyBlocked(String name, Function callback, [Boolean after]) +**** + +Wrapper function for property-change notification, the same as +_object.connectBlocked("notify::" + name, callback, after);_. + +_name_;; The property name to connect to, the name can also be in camelcase. +_callback_;; Callback function that will be called when the property changes. +_after_;; Whether to install the handler after the default handler, default +after. +_returns_;; The signal id of the signal. +**** + ==== Object GObject.getPrivate(String key, Object identifier) **** @@ -617,6 +816,13 @@ _identifier_;; A local object to identify the calling script, the identifier must either be of type Object or of type Function. **** +==== void object.unblockSignal(Number signalid) +**** + +Unblocks a signal previously blocked with *object.blockSignal*. + +_signalid_;; The signalid returned from *object.connect* +**** === webview === @@ -673,7 +879,7 @@ _steps_;; Number of steps, pass a negative value to go back in history ==== Boolean wv.loadUri(String uri, [Function callback]) **** -Load an uri in a webview. +Loads an uri in a webview. _uri_;; The uri to load _callback_;; A callback function that will be called when the load status @@ -681,6 +887,20 @@ changes, return true to stop the emission, optional _returns_;; true if the uri is loaded **** +==== void wv.reload(void) +**** + +Reloads a webview +**** + + +==== void wv.stopLoading() +**** + +Stops any ongoing loading. +**** + + ==== Number wv.toPng(String filename, [Number width, Number height], [Boolean keepAspect]) **** @@ -699,12 +919,6 @@ _returns_;; A cairo_status_t (0 on success) or -1 if an error occured. **** -==== void wv.reload(void) -**** - -Reload a webview -**** - === frame === A frame represents a frame or iframe. Due to same origin policy it diff --git a/api/jsapi.txt b/api/jsapi.txt index 0e8eda9d..c4972638 100644 --- a/api/jsapi.txt +++ b/api/jsapi.txt @@ -532,25 +532,6 @@ _returns_;; A string with the file content **** **** -[[statusBar]] -[float] -==== *statusBar()* ==== - -[source,javascript] ----- -void io.statusBar(Object text) ----- - -Sets the statusbar text. The statusbar consists of two labels, a 'middle' label and -a 'right' label, on both labels pango markup can be used - - :: - -_text.middle_;; Text for the middle label -_text.right_;; Text for the right label -**** - -**** [[write]] [float] ==== *write()* ==== @@ -1064,6 +1045,221 @@ gui.statusLabel GtkLabel read Label used for status information, fourth child of *gui.statusBox*. **** +[[Deferred]] +=== Deferred === + +Deferred objects can be used to manage asynchronous operations. It can trigger a +callback function when an asynchrounous operation has finished, and allows +chaining of callbacks. +Deferred basically have 2 callback chains, a _done_-chain and a _fail_-chain. +If a asynchronous operation is successful the deferred should be resolved and +the done callback chain of the deferred is called. +If a asynchronous operation fails the deferred should be rejected and +the fail callback chain of the deferred is called. + + +Deferreds implement the following methods: + +**** +[float] +==== *done()* ==== + +[source,javascript] +---- +Deferred Deferred.done(Function callback) +---- + +Registers a function for the done-chain. + + :: + +_callback_;; A callback function that will be called when the Deferred is +resolved. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + +**** +[float] +==== *fail()* ==== + +[source,javascript] +---- +void Deferred.fail(Function callback) +---- + +Registers a function for the fail-chain. + + :: + +_callback_;; A callback function that will be called when the deferred is +rejected. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + +**** +[float] +==== *reject()* ==== + +[source,javascript] +---- +void Deferred.reject(arguments) +---- + +Rejects a deferred, the fail-chain is called when a deferred is rejected. + + :: + +_arguments_;; Arguments passed to the _fail_ callbacks. +**** + +**** +[float] +==== *resolve()* ==== + +[source,javascript] +---- +Deferred Deferred.resolve(arguments) +---- + +Resolves a deferred, the done-chain is called when a deferred is resolved. + + :: + +_arguments_;; Arguments passed to the _done_ callbacks. +**** + +**** +[float] +==== *then()* ==== + +[source,javascript] +---- +Deferred Deferred.then(Function ondone, Function onfail) +---- + +Registers a function for the done and fail chain. + + :: + +_ondone_;; A callback function that will be called when the deferred is +resolved. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_onfail_;; A callback function that will be called when the deferred is +rejected. If the function returns a deferred the original deferred will be replaced with +the new deferred. +_returns_;; A new deferred that can be used to chain callbacks. +**** + +==== *Examples* ==== + +Simple usage of a deferred: + +[source,javascript] +--------------------------------- +function loadUri(uri) { + var d = new Deferred(); + tabs.current.loadUri(uri, function(wv) { + if (wv.loadStatus == LoadStatus.finished) + { + d.resolve("Finished"); + return true; + } + else if (wv.loadStatus == LoadStatus.failed) + { + d.reject("Failed"); + return true; + } + }); + return d; +} + +loadUri("http://www.example.com").then( + function(response) { + io.print(response); // Finished + }, + function(response) { + io.print(response); // Failed + } +); +--------------------------------- + +Chaining of a deferred: + +[source,javascript] +--------------------------------- +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d.reject("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io.print(response); +} + +// Will print "rejected" twice to stdout after 2 seconds +foo().fail(onResponse).fail(onResponse); +--------------------------------- + +Note that if the deferred is rejected only the fail chain is called, when it is +resolved only the done chain is called. +[source,javascript] +--------------------------------- +function foo() +{ + var d = new Deferred(); + timerStart(2000, function() { + d.reject("rejected"); + // Already rejected, will not execute the done chain + d.resolve("rejected"); + }); + return d; +} + +function onResponse(response) +{ + io.print(response); +} + +// Only the fail will be executed + +foo().done(onResponse).fail(onResponse); +foo().fail(onResponse).done(onResponse); +--------------------------------- + +Changing the deferred in a callback chain: + +[source,javascript] +--------------------------------- +function foo(message) +{ + var d = new Deferred(); + timerStart(2000, function() { + d.resolve(message); + }); + return d; +} +function callback1(response) +{ + io.print(response); // Prints "foo" after 2 seconds + + // Return a new Deferred, will replace the old one. + return foo("bar"); +} +function callback2(response) +{ + io.print(response); // Prints "bar" after 4 seconds +} + +foo("foo").done(callback1).done(callback2); +--------------------------------- + [[Webkitobjects]] == Webkit objects == @@ -1120,6 +1316,23 @@ All Objects derived from GObjets implement the following methods. **** [float] +==== *blockSignal()* ==== + +[source,javascript] +---- +Number object.blockSignal(Number signalid) +---- + +Blocks emission of a gobect signal. + + :: + +_signalid_;; The signalid returned from *object.connect* +**** + + +**** +[float] ==== *connect()* ==== [source,javascript] @@ -1145,6 +1358,28 @@ _returns_;; The signal id of the signal. **** [float] +==== *connectBlocked()* ==== + +[source,javascript] +---- +Number object.connectBlocked(String name, Function callback, [Boolean after]) +---- + +Connect to a gobject-signal but block the emission of the own callback during +execution of the callback, useful if the object is connected to a notify event +and the the property is changed in the callback function. + + :: + +_name_;; The signal name to connect to. +_callback_;; Callback function that will be called when the signal is emitted. +_after_;; Whether to install the handler after the default handler, default +false. +_returns_;; The signal id of the signal. +**** + +**** +[float] ==== *disconnect()* ==== [source,javascript] @@ -1169,7 +1404,7 @@ _returns_;; +true+ if the signal was disconnected Number object.notify(String name, Function callback, [Boolean after]) ---- -Wrapper function for property-change notification, the same as +Wrapper function for property-change notification but with signal blocking, same as _object.connect("notify::" + name, callback, after);_. :: @@ -1181,6 +1416,27 @@ _returns_;; The signal id of the signal. **** **** +[float] +==== *notifyBlocked()* ==== + +[source,javascript] +---- +Number object.notifyBlocked(String name, Function callback, [Boolean after]) +---- + +Wrapper function for property-change notification but with signal blocking, same as +_object.connectBlocked("notify::" + name, callback, after);_. + + :: + +_name_;; The property name to connect to, can also be in camelcase. +_callback_;; Callback function that will be called when the property changes. +_after_;; Whether to install the handler after the default handler. +_returns_;; The signal id of the signal. +**** + + +**** [[getPrivate]] [float] ==== *getPrivate()* ==== @@ -1216,6 +1472,22 @@ _identifier_;; A local object to identify the calling script, the identifier must either be of type object or of type function. **** +**** +[float] +==== *unblockSignal()* ==== + +[source,javascript] +---- +Number object.unblockSignal(Number signalid) +---- + +Unblocks a signal previously blocked with *object.blockSignal*. + + :: + +_signalid_;; The signalid returned from *object.connect* +**** + ==== [float] @@ -1439,7 +1711,7 @@ _steps_;; Number of steps, pass a negative value to go back in history Boolean wv.loadUri(String uri, [Function callback]) ---- -Load an uri in a webview. +Loads an uri in a webview. :: @@ -1464,6 +1736,18 @@ Reload a webview **** [float] +==== *stopLoading()* ==== + +[source,javascript] +---- +void wv.stopLoading(void) +---- + +Stops any ongoing loading. +**** + +**** +[float] ==== *toPng()* ==== [source,javascript] diff --git a/extensions/requestpolicy b/extensions/requestpolicy index 5ec6d6d4..f8d6b62e 100644 --- a/extensions/requestpolicy +++ b/extensions/requestpolicy @@ -87,338 +87,380 @@ INFO>*/ var me = "requestpolicy"; var defaultConfig = { -//<DEFAULT_CONFIG - // path to a whitelist - whiteList : data.configDir + "/" + data.profile + "/requestpolicy.json", + //<DEFAULT_CONFIG + // path to a whitelist + whiteList : data.configDir + "/" + data.profile + "/requestpolicy.json", - // shortcut to block/allow requests - shortcut : "erp", + // shortcut to block/allow requests + shortcut : "erp", - // shortcut to unblock requests from current site that are blocked on all - // sites - unblockCurrent : "erC", + // shortcut to unblock requests from current site that are blocked on all + // sites + unblockCurrent : "erC", - // shortcut to unblock requests that are blocked on all sites - unblockAll : "erA", + // shortcut to unblock requests that are blocked on all sites + unblockAll : "erA", - // reload current site after blocking / unblocking a request - autoreload : false, + // reload current site after blocking / unblocking a request + autoreload : false, - // notify about blocked requests - notify : false + // notify about blocked requests + notify : false -//>DEFAULT_CONFIG + //>DEFAULT_CONFIG }; var config = {}; var sigs = { - resource : -1, - navigation : -1, - loadFinished : -1 + resource : -1, + navigation : -1, + loadFinished : -1 }; var persistentList = null; var tmpList = {}; -var getPrivate = (function () { - var identifier = {}; - return function (wv) { - var p = wv.getPrivate("foo", identifier); - if (p === null) { - p = { domains : [], blocked : 0 }; - wv.setPrivate("foo", p, identifier); - } - return p; - }; +var getPrivate = (function () +{ + var identifier = {}; + return function (wv) { + var p = wv.getPrivate("foo", identifier); + if (!p) + { + p = { domains : [], blocked : 0 }; + wv.setPrivate("foo", p, identifier); + } + return p; + }; })(); -function listAdd(o, key, value, doWrite) { - if (!o[key]) - o[key] = []; - if (o[key].fastIndexOf(value) == -1) - o[key].push(value); - if (doWrite) - io.write(config.whiteList, "w", JSON.stringify(persistentList)); -} -function listRemove(o, firstParty, domain, doWrite) { - var idx; - if (o[firstParty] && (idx = o[firstParty].fastIndexOf(domain)) != -1) { - o[firstParty].splice(idx, 1); - if (o[firstParty].length === 0) - delete o[firstParty]; +function listAdd(o, key, value, doWrite) +{ + if (!o[key]) + o[key] = []; + if (o[key].fastIndexOf(value) == -1) + o[key].push(value); if (doWrite) - io.write(config.whiteList, "w", JSON.stringify(persistentList)); - return true; - } - return false; + io.write(config.whiteList, "w", JSON.stringify(persistentList)); +} +function listRemove(o, firstParty, domain, doWrite) +{ + var idx; + if (o[firstParty] && (idx = o[firstParty].fastIndexOf(domain)) != -1) + { + o[firstParty].splice(idx, 1); + if (o[firstParty].length === 0) + delete o[firstParty]; + if (doWrite) + io.write(config.whiteList, "w", JSON.stringify(persistentList)); + return true; + } + return false; } // MENU {{{ -function showMenu() { - var tmpWhiteListed, whiteListed; - var isWhiteListed = false; - var dom, i, l, domains, labels, currentDomain; - - var domain = tabs.current.mainFrame.domain; - if (domain === null) - return; - - domains = getPrivate(tabs.current).domains; - labels = []; - currentDomain = tabs.current.mainFrame.domain; - - for (i=0, l=domains.length; i<l; ++i){ - (function(dom) { - if (persistentList._alwaysBlock && persistentList._alwaysBlock.fastIndexOf(dom) != -1) - return; - whiteListed = persistentList[domain] && persistentList[domain].fastIndexOf(dom) != -1; - tmpWhiteListed = tmpList[domain] && tmpList[domain].fastIndexOf(dom) != -1; - if (!persistentList._always || persistentList._always.fastIndexOf(dom) == -1) { - if (!whiteListed && !tmpWhiteListed) { - labels.push({ - left : "[" + dom + "] allow", +function showMenu() +{ + var tmpWhiteListed, whiteListed; + var isWhiteListed = false; + var dom, i, l, domains, labels, currentDomain; + + var domain = tabs.current.mainFrame.domain; + if (domain === null) + return; + + domains = getPrivate(tabs.current).domains; + labels = []; + currentDomain = tabs.current.mainFrame.domain; + + for (i=0, l=domains.length; i<l; ++i) + { + (function(dom) + { + if (persistentList._alwaysBlock && persistentList._alwaysBlock.fastIndexOf(dom) != -1) + return; + + whiteListed = persistentList[domain] && persistentList[domain].fastIndexOf(dom) != -1; + tmpWhiteListed = tmpList[domain] && tmpList[domain].fastIndexOf(dom) != -1; + if (!persistentList._always || persistentList._always.fastIndexOf(dom) == -1) + { + if (!whiteListed && !tmpWhiteListed) + { + labels.push({ + left : "[" + dom + "] allow", + action : function () { + listAdd(persistentList, currentDomain, dom, true); + } + }); + labels.push({ + left : "[" + dom + "] allow temporarily", + action : function() { + listAdd(tmpList, currentDomain, dom, false); + } + }); + } + + else + { + labels.push({ + left : "[" + dom + "] block", + action : function() { + listRemove(persistentList, currentDomain, dom, true); + listRemove(tmpList, currentDomain, dom, false); + } + }); + } + } + isWhiteListed = isWhiteListed || whiteListed || tmpWhiteListed; + if (!persistentList._always || persistentList._always.fastIndexOf(dom) == -1) + { + labels.push({ + left : "[" + dom + "] allow on all sites", + action : function() { + listAdd(persistentList, "_always", dom, true); + } + }); + } + else + { + labels.push({ + left : "[" + dom + "] don't allow on all sites", + action : function() { + listRemove(persistentList, "_always", dom, true); + } + }); + } + labels.push({ + left : "[" + dom + "] block on all sites", + action : function () { + listAdd(persistentList, "_alwaysBlock", dom, true); + } + }); + })(domains[i]); + } + var allAllowed = (persistentList._all && persistentList._all.fastIndexOf(domain) != -1) || + (tmpList._all && tmpList._all.fastIndexOf(domain) != -1); + if (isWhiteListed || allAllowed) + { + labels.unshift({ + left : "Block all requests on " + domain, action : function () { - listAdd(persistentList, currentDomain, dom, true); + delete persistentList[currentDomain]; + listRemove(persistentList, "_all", currentDomain, false); + // necessary if persistentList.currentDomain exists + io.write(config.whiteList, "w", JSON.stringify(persistentList)); + delete tmpList[currentDomain]; + listRemove(tmpList, "_all", currentDomain, false); } - }); - labels.push({ - left : "[" + dom + "] allow temporarily", + }); + } + if (allAllowed) + { + labels.unshift({ + left : "Don't allow all requests on " + domain, action : function() { - listAdd(tmpList, currentDomain, dom, false); + listRemove(tmpList, "_all", currentDomain, false); + listRemove(persistentList, "_all", currentDomain, true); } - }); - } - - else { - labels.push({ - left : "[" + dom + "] block", + }); + } + else + { + labels.unshift({ + left : "Temporarily allow all requests on " + domain, action : function() { - listRemove(persistentList, currentDomain, dom, true); - listRemove(tmpList, currentDomain, dom, false); + listAdd(tmpList, "_all", currentDomain, false); + } + }); + labels.unshift({ + left : "Allow all requests on " + domain, + action : function() { + listAdd(persistentList, "_all", currentDomain, true); } - }); - } - } - isWhiteListed = isWhiteListed || whiteListed || tmpWhiteListed; - if (!persistentList._always || persistentList._always.fastIndexOf(dom) == -1) { - labels.push({ - left : "[" + dom + "] allow on all sites", - action : function() { - listAdd(persistentList, "_always", dom, true); - } - }); - } - else { - labels.push({ - left : "[" + dom + "] don't allow on all sites", - action : function() { - listRemove(persistentList, "_always", dom, true); - } - }); - } - labels.push({ - left : "[" + dom + "] block on all sites", - action : function () { - listAdd(persistentList, "_alwaysBlock", dom, true); - } }); - })(domains[i]); - } - var allAllowed = (persistentList._all && persistentList._all.fastIndexOf(domain) != -1) || - (tmpList._all && tmpList._all.fastIndexOf(domain) != -1); - if (isWhiteListed || allAllowed) { - labels.unshift({ - left : "Block all requests on " + domain, - action : function () { - delete persistentList[currentDomain]; - listRemove(persistentList, "_all", currentDomain, false); - // necessary if persistentList.currentDomain exists - io.write(config.whiteList, "w", JSON.stringify(persistentList)); - delete tmpList[currentDomain]; - listRemove(tmpList, "_all", currentDomain, false); - } - }); - } - if (allAllowed) { - labels.unshift({ - left : "Don't allow all requests on " + domain, - action : function() { - listRemove(tmpList, "_all", currentDomain, false); - listRemove(persistentList, "_all", currentDomain, true); - } - }); - } - else { - labels.unshift({ - left : "Temporarily allow all requests on " + domain, - action : function() { - listAdd(tmpList, "_all", currentDomain, false); - } - }); - labels.unshift({ - left : "Allow all requests on " + domain, - action : function() { - listAdd(persistentList, "_all", currentDomain, true); - } - }); - } - - tabComplete("Requestpolicy:", labels, function (response) { - var i, l, len; - for (i=0, len = labels.length; i<len; ++i) { - l = labels[i]; - if (l.left == response) { - l.action(); - if (config.autoreload) { - tabs.current.reload(); - } - } } - }, true); + + tabComplete("Requestpolicy:", labels, function (response) { + var i, l, len; + for (i=0, len = labels.length; i<len; ++i) + { + l = labels[i]; + if (l.left == response) + { + l.action(); + if (config.autoreload) + tabs.current.reload(); + } + } + }, true); }//}}} -function unblockCurrent() { - if (!persistentList._alwaysBlock) { - io.notify("No domains to unblock"); - return; - } - var domains = getPrivate(tabs.current).domains; - //var domains = persistentList._alwaysBlock; - var labels = [], i, l; - for (i=0, l = domains.length; i<l; i++) { - if (persistentList._alwaysBlock.fastIndexOf(domains[i]) != -1) { - labels.push({ left : domains[i] }); + +function unblockCurrent() +{ + if (!persistentList._alwaysBlock) + { + io.notify("No domains to unblock"); + return; } - } - if (labels.length > 0) { - tabComplete("Unblock:", labels, function(response) { - listRemove(persistentList, "_alwaysBlock", response, true); - if (config.autoreload) - tabs.current.reload(); - }, true); - } - else { - io.notify("No domains to unblock"); - } + var domains = getPrivate(tabs.current).domains; + //var domains = persistentList._alwaysBlock; + var labels = [], i, l; + for (i=0, l = domains.length; i<l; i++) + { + if (persistentList._alwaysBlock.fastIndexOf(domains[i]) != -1) + labels.push({ left : domains[i] }); + } + if (labels.length > 0) + { + tabComplete("Unblock:", labels, function(response) { + listRemove(persistentList, "_alwaysBlock", response, true); + if (config.autoreload) + tabs.current.reload(); + }, true); + } + else + io.notify("No domains to unblock"); } -function unblockAll() { - if (!persistentList._alwaysBlock) { - io.notify("No domains to unblock"); - return; - } - var i, l, labels = []; - var domains = persistentList._alwaysBlock; - for (i=0, l=domains.length; i<l; ++i) { - labels.push({ left : domains[i] }); - } - if (labels.length > 0) { - tabComplete("Unblock:", labels, function(response) { - listRemove(persistentList, "_alwaysBlock", response, true); - if (config.autoreload) - tabs.current.reload(); - }, true); - } + +function unblockAll() +{ + if (!persistentList._alwaysBlock) + { + io.notify("No domains to unblock"); + return; + } + var i, l, labels = []; + var domains = persistentList._alwaysBlock; + for (i=0, l=domains.length; i<l; ++i) + labels.push({ left : domains[i] }); + + if (labels.length > 0) + { + tabComplete("Unblock:", labels, function(response) { + listRemove(persistentList, "_alwaysBlock", response, true); + if (config.autoreload) + tabs.current.reload(); + }, true); + } } -function blockRequest(wv, request, priv, domain) { - request.uri = "about:blank"; - priv.blocked++; - if (config.notify && wv == tabs.current) - io.notify("RP: blocked " + domain); - return true; + +function blockRequest(wv, request, priv, domain) +{ + request.uri = "about:blank"; + priv.blocked++; + if (config.notify && wv == tabs.current) + io.notify("RP: blocked " + domain); + return true; } // SIGNALS {{{ -var resourceCB = (function () { - var regexEmpty = /^\s*$/; - return function resourceCB(wv, frame, request, response) { - var o, message, domain, firstParty; - if (regexEmpty.test(request.uri)) - return false; - - message = request.message; - if (!message) - return false; - - firstParty = util.domainFromHost(message.firstParty.host); - domain = util.domainFromHost(message.uri.host); - if (firstParty == domain) - return false; - - o = getPrivate(wv); - if (o.domains.fastIndexOf(domain) == -1) - o.domains.push(domain); - - // Check for requests that are always blocked - if (persistentList._alwaysBlock && persistentList._alwaysBlock.fastIndexOf(domain) != -1) - return blockRequest(wv, request, o, domain); - - // Check if domain is always allowed - if ((persistentList._all && persistentList._all.fastIndexOf(firstParty) != -1) || - (tmpList._all && tmpList._all.fastIndexOf(firstParty) != -1)) - return false; - - // Check request is always allowed - if (persistentList._always && persistentList._always.fastIndexOf(domain) != -1) - return false; - - // Check if request is whitelisted - if ( (!persistentList[firstParty] || persistentList[firstParty].fastIndexOf(domain) == -1) && - (!tmpList[firstParty] || tmpList[firstParty].fastIndexOf(domain) == -1)) - return blockRequest(wv, request, o, domain); - }; +var resourceCB = (function () +{ + var regexEmpty = /^\s*$/; + return function resourceCB(wv, frame, request, response) + { + var o, message, domain, firstParty; + if (regexEmpty.test(request.uri)) + return false; + + message = request.message; + if (!message) + return false; + + firstParty = util.domainFromHost(message.firstParty.host); + domain = util.domainFromHost(message.uri.host); + if (firstParty == domain) + return false; + + o = getPrivate(wv); + if (o.domains.fastIndexOf(domain) == -1) + o.domains.push(domain); + + // Check for requests that are always blocked + if (persistentList._alwaysBlock && persistentList._alwaysBlock.fastIndexOf(domain) != -1) + return blockRequest(wv, request, o, domain); + + // Check if domain is always allowed + if ((persistentList._all && persistentList._all.fastIndexOf(firstParty) != -1) || + (tmpList._all && tmpList._all.fastIndexOf(firstParty) != -1)) + return false; + + // Check request is always allowed + if (persistentList._always && persistentList._always.fastIndexOf(domain) != -1) + return false; + + // Check if request is whitelisted + if ( (!persistentList[firstParty] || persistentList[firstParty].fastIndexOf(domain) == -1) && + (!tmpList[firstParty] || tmpList[firstParty].fastIndexOf(domain) == -1)) + return blockRequest(wv, request, o, domain); + }; })(); -function navigationCB(wv, frame) { - if (frame == wv.mainFrame) { - var o = getPrivate(wv); - o.domains = []; - o.blocked = 0; - } -} -function loadFinishedCB(wv) { - if (wv != tabs.current) - return; +function navigationCB(wv, frame) +{ + if (frame == wv.mainFrame) + { + var o = getPrivate(wv); + o.domains = []; + o.blocked = 0; + } + } - var blocked = getPrivate(wv).blocked; - if (blocked > 0) - io.notify("RP: blocked " + blocked + " requests"); +function loadFinishedCB(wv) +{ + if (wv != tabs.current) + return; + + var blocked = getPrivate(wv).blocked; + if (blocked > 0) + io.notify("RP: blocked " + blocked + " requests"); } -function connect() { - sigs.resource = signals.connect("resource", resourceCB); - sigs.navigation = signals.connect("navigation", navigationCB); - if (config.notify) - sigs.loadFinished = signals.connect("loadFinished", loadFinishedCB); +function connect() +{ + sigs.resource = signals.connect("resource", resourceCB); + sigs.navigation = signals.connect("navigation", navigationCB); + if (config.notify) + sigs.loadFinished = signals.connect("loadFinished", loadFinishedCB); } -function disconnect() { - sigs.forEach(function (key, value) { - if (value != -1) { - signals.disconnect(value); - sigs[key] = -1; - } - }); +function disconnect() +{ + sigs.forEach(function (key, value) { + if (value != -1) + { + signals.disconnect(value); + sigs[key] = -1; + } + }); }//}}} return { - init : function(c) { - config = extensions.getConfig(c, defaultConfig); - if (system.fileTest(config.whiteList, FileTest.regular | FileTest.symlink)) { - var rawWhiteList = io.read(config.whiteList); - try { - persistentList = JSON.parse(rawWhiteList); - } - catch (e) { - extensions.debug(me, e, "Error parsing persistentList"); - } + defaultConfig : defaultConfig, + init : function(c) + { + config = c; + if (system.fileTest(config.whiteList, FileTest.regular | FileTest.symlink)) + { + var rawWhiteList = io.read(config.whiteList); + try + { + persistentList = JSON.parse(rawWhiteList); + } + catch (e) + { + extensions.debug(me, e, "Error parsing persistentList"); + } + } + persistentList = persistentList || {}; + connect(); + bind(config.shortcut, showMenu, "requestpolicy"); + bind(config.unblockCurrent, unblockCurrent, "requestpolicyUnblockCurrent"); + bind(config.unblockAll, unblockAll, "requestpolicyUnblockAll"); + return true; + }, + end : function () + { + disconnect(); + unbind("requestpolicy"); + unbind("requestpolicyUnblockCurrent"); + unbind("requestpolicyUnblockAll"); } - persistentList = persistentList || {}; - connect(); - bind(config.shortcut, showMenu, "requestpolicy"); - bind(config.unblockCurrent, unblockCurrent, "requestpolicyUnblockCurrent"); - bind(config.unblockAll, unblockAll, "requestpolicyUnblockAll"); - return true; - }, - end : function () { - disconnect(); - unbind("requestpolicy"); - unbind("requestpolicyUnblockCurrent"); - unbind("requestpolicyUnblockAll"); - } -} +}; // vim: set ft=javascript: diff --git a/scripts/base.js b/scripts/base.js index 0fd8dfd0..280d6d03 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -16,6 +16,7 @@ Object.freeze((function () { lastInput : null, lastPosition : 0, newTab : false, + notify : null, hintTypes : [ "a, textarea, select, input:not([type=hidden]), button, frame, iframe, [onclick], [onmousedown]," + "[role=link], [role=option], [role=button], [role=option], img", // HINT_T_ALL //[ "iframe", @@ -278,7 +279,6 @@ Object.freeze((function () { active.overlay.parentNode.removeChild(active.overlay); active.hint.style.font = globals.font; - } globals.active = element; if (!globals.active.overlay) @@ -287,6 +287,16 @@ Object.freeze((function () { if (!globals.markHints) globals.active.hint.parentNode.appendChild(globals.active.overlay); + var e = element.element; + if (e.href || e.src) + globals.notify.innerText = encodeURI(e.href || e.ret); + else if (e.name) + globals.notify.innerText = e.tagName.toLowerCase() + ", name=" + e.name; + else if (e.innerText && e.innerText.trim().length > 0) + globals.notify.innerText = e.tagName.toLowerCase() + ": " + e.innerText.replace("\n\r", "").trim(); + else + globals.notify.innerText = e.tagName.toLowerCase(); + globals.active.overlay.style.background = globals.activeColor; globals.active.hint.style.fontSize = globals.bigFont; }; @@ -448,6 +458,18 @@ Object.freeze((function () { return __evaluate(globals.elements[0].element, type); } + globals.notify = document.createElement("div"); + globals.notify.style.cssText = + "bottom:0px;left:0px;position:fixed;z-index:1000;" + + "text-overflow:ellipsis;white-space:nowrap;overflow:hidden;max-width:100%;" + + "border-right:1px solid #555;" + + "border-top:1px solid #555;" + + "padding-right:2px;" + + "border-radius:0px 5px 0px 0px;letter-spacing:0px;background:" + globals.bgColor + ";" + + "color:" + globals.fgColor + ";font:" + globals.font + ";font-size:" + globals.fontSize + ";"; + globals.notify.id = "dwb_hint_notifier"; + document.body.appendChild(globals.notify); + __getTextHints(globals.elements); globals.activeArr = globals.elements; __setActive(globals.elements[0]); @@ -569,6 +591,8 @@ Object.freeze((function () { globals.lastPosition = 0; globals.lastInput = null; globals.positions = []; + globals.notify.parentNode.removeChild(globals.notify); + globals.notify = null; }; var __evaluate = function (e, type) { diff --git a/scripts/lib/dwb.js b/scripts/lib/dwb.js index a66afb67..b0cd86a7 100644 --- a/scripts/lib/dwb.js +++ b/scripts/lib/dwb.js @@ -155,7 +155,7 @@ var i = _getPrivateIdx(this, key, identifier); if (i !== -1) return _privProps[i].value; - return null; + return undefined; } }, "notify" : @@ -164,6 +164,38 @@ { return this.connect("notify::" + util.uncamelize(name), callback, after || false); } + }, + "connectBlocked" : + { + value : function(name, callback, after) + { + var self = this; + var sig = self.connect(name, function() { + self.blockSignal(sig); + callback.apply(null, arguments); + self.unblockSignal(sig); + }); + return sig; + } + }, + "notifyBlocked" : + { + value : function(name, callback, after) + { + return this.connectBlocked("notify::" + util.uncamelize(name), callback, after || false); + } + } + }); + Object.defineProperties(Deferred.prototype, { + "done" : { + value : function(method) { + return this.then(method); + } + }, + "fail" : { + value : function(method) { + return this.then(null, method); + } } }); })(); @@ -4210,7 +4210,6 @@ dwb_init_gui() /* entry */ dwb.gui.entry = gtk_entry_new(); - gtk_entry_set_inner_border(GTK_ENTRY(dwb.gui.entry), NULL); gtk_entry_set_has_frame(GTK_ENTRY(dwb.gui.entry), false); gtk_entry_set_inner_border(GTK_ENTRY(dwb.gui.entry), false); @@ -332,4 +332,12 @@ js_array_iterator_next(js_array_iterator *iter, JSValueRef *exc) return JSObjectGetPropertyAtIndex(iter->ctx, iter->array, iter->current_index++, exc); } +JSObjectRef +js_value_to_function(JSContextRef ctx, JSValueRef val, JSValueRef *exc) +{ + JSObjectRef ret = JSValueToObject(ctx, val, exc); + if (ret != NULL && JSObjectIsFunction(ctx, ret)) + return ret; + return NULL; +} @@ -38,6 +38,7 @@ gboolean js_print_exception(JSContextRef ctx, JSValueRef exception); JSObjectRef js_make_function(JSContextRef ctx, const char *script); JSValueRef js_json_to_value(JSContextRef ctx, const char *text); JSValueRef js_context_change(JSContextRef, JSContextRef, JSValueRef, JSValueRef *); +JSObjectRef js_value_to_function(JSContextRef, JSValueRef, JSValueRef *); typedef struct _js_array_iterator { JSContextRef ctx; diff --git a/src/scripts.c b/src/scripts.c index ec1a6ede..95e2158e 100644 --- a/src/scripts.c +++ b/src/scripts.c @@ -62,6 +62,12 @@ struct _SSignal { GObject *object; JSObjectRef func; }; +typedef struct DeferredPriv_s +{ + JSObjectRef reject; + JSObjectRef resolve; + JSObjectRef next; +} DeferredPriv; //static GSList *s_signals; #define S_SIGNAL(X) ((SSignal*)X->data) @@ -97,10 +103,13 @@ static Sigmap s_sigmap[] = { static JSObjectRef make_object_for_class(JSContextRef ctx, JSClassRef class, GObject *o, gboolean); -static JSValueRef connect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); -static JSValueRef disconnect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); +static JSValueRef gobject_connect(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); +static JSValueRef gobject_block_signal(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); +static JSValueRef gobject_unblock_signal(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); +static JSValueRef gobject_disconnect(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); static JSValueRef wv_load_uri(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); +static JSValueRef wv_stop_loading(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); static JSValueRef wv_history(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); static JSValueRef wv_reload(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); static JSValueRef wv_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); @@ -108,12 +117,15 @@ static JSValueRef wv_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef static JSValueRef wv_to_png(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc); #endif static JSStaticFunction default_functions[] = { - { "connect", connect_object, kJSDefaultAttributes }, - { "disconnect", disconnect_object, kJSDefaultAttributes }, + { "connect", gobject_connect, kJSDefaultAttributes }, + { "blockSignal", gobject_block_signal, kJSDefaultAttributes }, + { "unblockSignal", gobject_unblock_signal, kJSDefaultAttributes }, + { "disconnect", gobject_disconnect, kJSDefaultAttributes }, { 0, 0, 0 }, }; static JSStaticFunction wv_functions[] = { { "loadUri", wv_load_uri, kJSDefaultAttributes }, + { "stopLoading", wv_stop_loading, kJSDefaultAttributes }, { "history", wv_history, kJSDefaultAttributes }, { "reload", wv_reload, kJSDefaultAttributes }, { "inject", wv_inject, kJSDefaultAttributes }, @@ -190,6 +202,7 @@ enum { CONSTRUCTOR_DOWNLOAD, CONSTRUCTOR_FRAME, CONSTRUCTOR_SOUP_MESSAGE, + CONSTRUCTOR_DEFERRED, CONSTRUCTOR_LAST, }; @@ -203,7 +216,7 @@ static JSObjectRef make_object(JSContextRef ctx, GObject *o); static JSObjectRef s_sig_objects[SCRIPTS_SIG_LAST]; static JSGlobalContextRef s_global_context; static GSList *s_script_list; -static JSClassRef s_gobject_class, s_webview_class, s_frame_class, s_download_class, s_download_class, s_message_class; +static JSClassRef s_gobject_class, s_webview_class, s_frame_class, s_download_class, s_download_class, s_message_class, s_deferred_class; static gboolean s_commandline = false; static JSObjectRef s_array_contructor; static JSObjectRef s_completion_callback; @@ -277,6 +290,7 @@ inject(JSContextRef ctx, JSContextRef wctx, JSObjectRef function, JSObjectRef th if (func != NULL && JSObjectIsFunction(ctx, func)) { JSValueRef wret = JSObjectCallAsFunction(wctx, func, NULL, count, count == 1 ? args : NULL, NULL) ; + // This could be replaced with js_context_change char *retx = js_value_to_json(wctx, wret, -1, NULL); if (retx) { @@ -356,8 +370,8 @@ ssignal_new() static void make_callback(JSContextRef ctx, JSObjectRef this, GObject *gobject, const char *signalname, JSValueRef value, StopCallbackNotify notify, JSValueRef *exception) { - JSObjectRef func = JSValueToObject(ctx, value, exception); - if (func != NULL && JSObjectIsFunction(ctx, func)) + JSObjectRef func = js_value_to_function(ctx, value, exception); + if (func != NULL) { CallbackData *c = callback_data_new(gobject, this, func, notify); g_signal_connect_swapped(gobject, signalname, G_CALLBACK(callback), c); @@ -430,9 +444,13 @@ tabs_get_nth(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz static GList * find_webview(JSObjectRef o) { - GList *r = NULL; - for (r = dwb.state.views; r && VIEW(r)->script_wv != o; r=r->next); - return r; + for (GList *r = dwb.state.fview; r; r=r->next) + if (VIEW(r)->script_wv == o) + return r; + for (GList *r = dwb.state.fview->prev; r; r=r->prev) + if (VIEW(r)->script_wv == o) + return r; + return NULL; } /* wv_status_cb {{{*/ static gboolean @@ -470,6 +488,15 @@ wv_load_uri(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t arg return false; }/*}}}*/ +static JSValueRef +wv_stop_loading(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + WebKitWebView *wv = JSObjectGetPrivate(this); + if (wv != NULL) + webkit_web_view_stop_loading(wv); + return UNDEFINED; +} + /* wv_history {{{*/ static JSValueRef wv_history(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) @@ -729,11 +756,9 @@ static JSObjectRef sp_callback_create(JSContextRef ctx, size_t argc, const JSValueRef argv[], JSValueRef *exc) { JSObjectRef ret = NULL; - if (argc > 0) + if (argc > 0) { - ret = JSValueToObject(ctx, argv[0], exc); - if (ret == NULL || !JSObjectIsFunction(ctx, ret)) - ret = NULL; + ret = js_value_to_function(ctx, argv[0], exc); } return ret; } @@ -970,15 +995,11 @@ global_bind(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size return JSValueMakeBoolean(ctx, false); } keystr = js_value_to_char(ctx, argv[0], JS_STRING_MAX, exc); - JSObjectRef func = JSValueToObject(ctx, argv[1], exc); + + JSObjectRef func = js_value_to_function(ctx, argv[1], exc); if (func == NULL) goto error_out; - if (!JSObjectIsFunction(ctx, func)) - { - js_make_exception(ctx, exc, EXCEPTION("bind: not a function.")); - goto error_out; - } if (argc > 2) { name = js_value_to_char(ctx, argv[2], JS_STRING_MAX, exc); @@ -1147,8 +1168,8 @@ global_send_request(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, siz if (uri == NULL) return JSValueMakeNumber(ctx, -1); - function = JSValueToObject(ctx, argv[1], exc); - if (function == NULL || !JSObjectIsFunction(ctx, function)) + function = js_value_to_function(ctx, argv[1], exc); + if (function == NULL) goto error_out; if (argc > 2) @@ -1219,14 +1240,10 @@ global_tab_complete(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, siz js_make_exception(ctx, exc, EXCEPTION("tabComplete: invalid argument.")); return UNDEFINED; } - s_completion_callback = JSValueToObject(ctx, argv[2], exc); + s_completion_callback = js_value_to_function(ctx, argv[2], exc); if (s_completion_callback == NULL) return UNDEFINED; - if (!JSObjectIsFunction(ctx, s_completion_callback)) - { - js_make_exception(ctx, exc, EXCEPTION("tabComplete: arguments[2] is not a function.")); - return UNDEFINED; - } + dwb.state.script_comp_readonly = false; if (argc > 3 && JSValueIsBoolean(ctx, argv[3])) { @@ -1320,12 +1337,10 @@ global_timer_start(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size if ((msec = JSValueToNumber(ctx, argv[0], exc)) == NAN ) return JSValueMakeNumber(ctx, -1); - JSObjectRef func = JSValueToObject(ctx, argv[1], exc); - if (func == NULL || !JSObjectIsFunction(ctx, func)) - { - js_make_exception(ctx, exc, EXCEPTION("timerStart: argument 2 is not a function.")); + JSObjectRef func = js_value_to_function(ctx, argv[1], exc); + if (func == NULL) return JSValueMakeNumber(ctx, -1); - } + JSValueProtect(ctx, func); int ret = g_timeout_add((int)msec, (GSourceFunc)timeout_callback, func); @@ -1379,6 +1394,116 @@ util_get_mode(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t ar { return JSValueMakeNumber(ctx, BASIC_MODES(dwb.state.mode)); } + +void +deferred_destroy(JSContextRef ctx, JSObjectRef this, DeferredPriv *priv) +{ + g_return_if_fail(this != NULL); + + if (priv == NULL) + priv = JSObjectGetPrivate(this); + JSObjectSetPrivate(this, NULL); + + g_free(priv); + + JSValueUnprotect(ctx, this); +} + +static JSObjectRef +deferred_new(JSContextRef ctx) +{ + DeferredPriv *priv = g_malloc(sizeof(DeferredPriv)); + priv->resolve = priv->reject = priv->next = NULL; + + JSObjectRef ret = JSObjectMake(ctx, s_deferred_class, priv); + JSValueProtect(ctx, ret); + + return ret; +} +static JSValueRef +deferred_then(JSContextRef ctx, JSObjectRef f, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + DeferredPriv *priv = JSObjectGetPrivate(this); + if (priv == NULL) + return NIL; + + if (argc > 0) + priv->resolve = js_value_to_function(ctx, argv[0], NULL); + if (argc > 1) + priv->reject = js_value_to_function(ctx, argv[1], NULL); + + priv->next = deferred_new(ctx); + + return priv->next; +} +static DeferredPriv * +deferred_transition(JSContextRef ctx, JSObjectRef old, JSObjectRef new) +{ + DeferredPriv *opriv = JSObjectGetPrivate(old); + DeferredPriv *npriv = JSObjectGetPrivate(new); + + npriv->resolve = opriv->resolve; + npriv->reject = opriv->reject; + npriv->next = opriv->next; + + deferred_destroy(ctx, old, opriv); + return npriv; +} +static JSValueRef +deferred_resolve(JSContextRef ctx, JSObjectRef f, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + JSValueRef ret = NULL; + + DeferredPriv *priv = JSObjectGetPrivate(this); + if (priv == NULL) + return UNDEFINED; + + if (priv->resolve) + ret = JSObjectCallAsFunction(ctx, priv->resolve, NULL, argc, argv, exc); + + JSObjectRef next = priv->next; + deferred_destroy(ctx, this, priv); + + if (next) + { + if ( ret && JSValueIsObjectOfClass(ctx, ret, s_deferred_class) ) + { + JSObjectRef o = JSValueToObject(ctx, ret, NULL); + deferred_transition(ctx, next, o)->reject = NULL; + } + else + deferred_resolve(ctx, f, next, argc, argv, exc); + } + return UNDEFINED; +} +static JSValueRef +deferred_reject(JSContextRef ctx, JSObjectRef f, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + JSValueRef ret = NULL; + + DeferredPriv *priv = JSObjectGetPrivate(this); + if (priv == NULL) + return UNDEFINED; + + if (priv->reject) + ret = JSObjectCallAsFunction(ctx, priv->reject, NULL, argc, argv, exc); + + JSObjectRef next = priv->next; + deferred_destroy(ctx, this, priv); + + if (next) + { + if ( ret && JSValueIsObjectOfClass(ctx, ret, s_deferred_class) ) + { + JSObjectRef o = JSValueToObject(ctx, ret, NULL); + deferred_transition(ctx, next, o)->resolve = NULL; + } + else + deferred_reject(ctx, f, next, argc, argv, exc); + } + return UNDEFINED; +} + /* DATA {{{*/ /* data_get_profile {{{*/ static JSValueRef @@ -1532,8 +1657,8 @@ system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz } if (argc > 1) { - oc = JSValueToObject(ctx, argv[1], NULL); - if ( oc == NULL || !JSObjectIsFunction(ctx, oc) ) + oc = js_value_to_function(ctx, argv[1], NULL); + if ( oc == NULL ) { if (!JSValueIsNull(ctx, argv[1])) ret |= SPAWN_STDOUT_FAILED; @@ -1541,8 +1666,8 @@ system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz } } if (argc > 2) { - ec = JSValueToObject(ctx, argv[2], NULL); - if ( ec == NULL || !JSObjectIsFunction(ctx, ec) ) + ec = js_value_to_function(ctx, argv[2], NULL); + if ( ec == NULL ) { if (!JSValueIsNull(ctx, argv[2])) ret |= SPAWN_STDERR_FAILED; @@ -1557,7 +1682,9 @@ system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz } if (!g_shell_parse_argv(cmdline, &srgc, &srgv, NULL) || - !g_spawn_async_with_pipes(NULL, srgv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, oc != NULL ? &outfd : NULL, ec != NULL ? &errfd : NULL, NULL)) + !g_spawn_async_with_pipes(NULL, srgv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, + oc != NULL ? &outfd : NULL, + ec != NULL ? &errfd : NULL, NULL)) { js_make_exception(ctx, exc, EXCEPTION("spawning %s failed."), cmdline); ret |= SPAWN_FAILED; @@ -1709,38 +1836,13 @@ io_error(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t } return UNDEFINED; }/*}}}*/ -static JSValueRef -io_status_bar(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) -{ - if (argc < 1) - return UNDEFINED; - - JSObjectRef o = JSValueToObject(ctx, argv[0], exc); - if (o == NULL) - return UNDEFINED; - - char *middle = js_get_string_property(ctx, o, "middle"); - char *right = js_get_string_property(ctx, o, "right"); - - if (middle != NULL) - gtk_label_set_markup(GTK_LABEL(dwb.gui.urilabel), middle); - - if (right != NULL) - gtk_label_set_markup(GTK_LABEL(dwb.gui.rstatus), right); - - g_free(middle); - g_free(right); - return UNDEFINED; -} static JSValueRef io_dir_names(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { if (argc < 1) - { - js_make_exception(ctx, exc, EXCEPTION("io.dirNames: missing argument.")); return NIL; - } + JSValueRef ret; GDir *dir; char *dir_name = js_value_to_char(ctx, argv[0], PATH_MAX, exc); @@ -1752,7 +1854,8 @@ io_dir_names(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz if ((dir = g_dir_open(dir_name, 0, NULL)) != NULL) { GSList *list = NULL; - while ((name = g_dir_read_name(dir)) != NULL) { + while ((name = g_dir_read_name(dir)) != NULL) + { list = g_slist_prepend(list, (gpointer)js_char_to_value(ctx, name)); } g_dir_close(dir); @@ -1820,10 +1923,7 @@ static JSValueRef io_print(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) { if (argc == 0) - { - js_make_exception(ctx, exc, EXCEPTION("io.print needs an argument.")); return UNDEFINED; - } FILE *stream = stdout; if (argc >= 2) @@ -1884,10 +1984,7 @@ static JSObjectRef download_constructor_cb(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef argv[], JSValueRef* exception) { if (argc<1) - { - js_make_exception(ctx, exception, EXCEPTION("Download constructor: missing argument")); return JSValueToObject(ctx, NIL, NULL); - } char *uri = js_value_to_char(ctx, argv[0], -1, exception); if (uri == NULL) @@ -1907,6 +2004,11 @@ download_constructor_cb(JSContextRef ctx, JSObjectRef constructor, size_t argc, WebKitDownload *download = webkit_download_new(request); return JSObjectMake(ctx, s_download_class, download); }/*}}}*/ +static JSObjectRef +deferred_constructor_cb(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef argv[], JSValueRef* exception) +{ + return deferred_new(ctx); +} /* stop_download_notify {{{*/ static gboolean @@ -1955,57 +2057,57 @@ download_cancel(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t static JSValueRef gui_get_window(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.window), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.window), true); } static JSValueRef gui_get_main_box(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.vbox), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.vbox), true); } static JSValueRef gui_get_tab_box(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.topbox), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.topbox), true); } static JSValueRef gui_get_content_box(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.mainbox), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.mainbox), true); } static JSValueRef gui_get_status_widget(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.statusbox), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.statusbox), true); } static JSValueRef gui_get_status_alignment(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.alignment), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.alignment), true); } static JSValueRef gui_get_status_box(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.status_hbox), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.status_hbox), true); } static JSValueRef gui_get_message_label(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.lstatus), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.lstatus), true); } static JSValueRef gui_get_entry(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.entry), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.entry), true); } static JSValueRef gui_get_uri_label(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.urilabel), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.urilabel), true); } static JSValueRef gui_get_status_label(JSContextRef ctx, JSObjectRef object, JSStringRef property, JSValueRef* exception) { - return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.rstatus), false); + return make_object_for_class(ctx, s_gobject_class, G_OBJECT(dwb.gui.rstatus), true); } /*}}}*/ @@ -2030,7 +2132,7 @@ signal_set(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef s_sig_objects[i] = NULL; dwb.misc.script_signals &= ~(1<<i); } - else if ( (o = JSValueToObject(ctx, value, exception)) != NULL && JSObjectIsFunction(ctx, o)) + else if ( (o = js_value_to_function(ctx, value, exception)) != NULL) { s_sig_objects[i] = o; dwb.misc.script_signals |= (1<<i); @@ -2197,11 +2299,12 @@ on_disconnect_object(SSignal *sig, GClosure *closure) static void notify_callback(GObject *o, GParamSpec *param, JSObjectRef func) { - JSValueRef argv[] = { make_object(s_global_context, o) }; + JSObjectRef jso = make_object(s_global_context, o); + JSValueRef argv[] = { jso }; JSObjectCallAsFunction(s_global_context, func, NULL, 1, argv, NULL); } static JSValueRef -connect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +gobject_connect(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) { GConnectFlags flags = 0; gulong id = 0; @@ -2216,8 +2319,8 @@ connect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t if (name == NULL) goto error_out; - JSObjectRef func = JSValueToObject(ctx, argv[1], exc); - if (func == NULL || !JSObjectIsFunction(ctx, func)) + JSObjectRef func = js_value_to_function(ctx, argv[1], exc); + if (func == NULL) goto error_out; GObject *o = JSObjectGetPrivate(this); @@ -2229,7 +2332,7 @@ connect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t if (strncmp(name, "notify::", 8) == 0) { - g_signal_connect_data(o, name, G_CALLBACK(notify_callback), func, NULL, flags); + id = g_signal_connect_data(o, name, G_CALLBACK(notify_callback), func, NULL, flags); } else { @@ -2266,8 +2369,33 @@ error_out: g_free(name); return JSValueMakeNumber(ctx, id); } + static JSValueRef -disconnect_object(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +gobject_block_signal(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + double sigid; + if (argc > 0 && (sigid = JSValueToNumber(ctx, argv[0], exc)) != NAN) + { + GObject *o = JSObjectGetPrivate(this); + if (o != NULL) + g_signal_handler_block(o, (int)sigid); + } + return UNDEFINED; +} +static JSValueRef +gobject_unblock_signal(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) +{ + double sigid; + if (argc > 0 && (sigid = JSValueToNumber(ctx, argv[0], exc)) != NAN) + { + GObject *o = JSObjectGetPrivate(this); + if (o != NULL) + g_signal_handler_unblock(o, (int)sigid); + } + return UNDEFINED; +} +static JSValueRef +gobject_disconnect(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) { int id; if (argc > 0 && JSValueIsNumber(ctx, argv[0]) && (id = JSValueToNumber(ctx, argv[0], exc)) != NAN) @@ -2515,7 +2643,6 @@ create_global_object() { "dirNames", io_dir_names, kJSDefaultAttributes }, { "notify", io_notify, kJSDefaultAttributes }, { "error", io_error, kJSDefaultAttributes }, - { "statusBar", io_status_bar, kJSDefaultAttributes }, { 0, 0, 0 }, }; class = create_class("io", io_functions, NULL); @@ -2607,6 +2734,18 @@ create_global_object() s_constructors[CONSTRUCTOR_SOUP_MESSAGE] = create_constructor(s_global_context, "SoupMessage", s_message_class, NULL, NULL); + JSStaticFunction deferred_functions[] = { + { "then", deferred_then, kJSDefaultAttributes }, + { "resolve", deferred_resolve, kJSDefaultAttributes }, + { "reject", deferred_reject, kJSDefaultAttributes }, + { 0, 0, 0 }, + }; + cd = kJSClassDefinitionEmpty; + cd.className = "Deferred"; + cd.staticFunctions = deferred_functions; + s_deferred_class = JSClassCreate(&cd); + s_constructors[CONSTRUCTOR_DEFERRED] = create_constructor(s_global_context, "Deferred", s_deferred_class, deferred_constructor_cb, NULL); + JSStaticValue gui_values[] = { { "window", gui_get_window, NULL, kJSDefaultAttributes }, { "mainBox", gui_get_main_box, NULL, kJSDefaultAttributes }, @@ -2666,8 +2805,8 @@ apply_scripts() int i=0; // XXX Not needed? - JSValueRef *scripts = g_try_malloc(length * sizeof(JSValueRef)); - JSObjectRef *objects = g_try_malloc(length * sizeof(JSObjectRef)); + JSValueRef *scripts = g_malloc(length * sizeof(JSValueRef)); + JSObjectRef *objects = g_malloc(length * sizeof(JSObjectRef)); for (GSList *l=s_script_list; l; l=l->next, i++) { scripts[i] = JSObjectMake(s_global_context, NULL, NULL); @@ -423,6 +423,7 @@ view_hovering_over_link_cb(WebKitWebView *web, char *title, char *uri, GList *gl } }/*}}}*/ + /* view_mime_type_policy_cb {{{*/ static gboolean view_mime_type_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetworkRequest *request, char *mimetype, WebKitWebPolicyDecision *policy, GList *gl) @@ -453,8 +454,6 @@ view_mime_type_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetwor return false; }/*}}}*/ - - /* view_navigation_policy_cb {{{*/ static gboolean view_navigation_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *action, @@ -990,9 +989,9 @@ view_init_signals(GList *gl) v->status->signals[SIG_LOAD_STATUS] = g_signal_connect(v->web, "notify::load-status", G_CALLBACK(view_load_status_cb), gl); v->status->signals[SIG_LOAD_ERROR] = g_signal_connect(v->web, "load-error", G_CALLBACK(view_load_error_cb), gl); - v->status->signals[SIG_LOAD_STATUS_AFTER] = g_signal_connect_after(v->web, "notify::load-status", G_CALLBACK(view_load_status_after_cb), gl); + v->status->signals[SIG_LOAD_STATUS_AFTER] = g_signal_connect(v->web, "notify::load-status", G_CALLBACK(view_load_status_after_cb), gl); v->status->signals[SIG_POPULATE_POPUP] = g_signal_connect(v->web, "populate-popup", G_CALLBACK(view_populate_popup_cb), gl); - v->status->signals[SIG_PROGRESS] = g_signal_connect(v->web, "notify::progress", G_CALLBACK(view_progress_cb), gl); + v->status->signals[SIG_PROGRESS] = g_signal_connect(v->web, "notify::progress", G_CALLBACK(view_progress_cb), gl); v->status->signals[SIG_TITLE] = g_signal_connect(v->web, "notify::title", G_CALLBACK(view_title_cb), gl); v->status->signals[SIG_URI] = g_signal_connect(v->web, "notify::uri", G_CALLBACK(view_uri_cb), gl); v->status->signals[SIG_SCROLL] = g_signal_connect(v->web, "scroll-event", G_CALLBACK(view_scroll_cb), gl); |