aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/webchannel/shared/qwebchannel.js45
-rw-r--r--src/webchannel/doc/src/javascript.qdoc11
-rw-r--r--tests/auto/qml/data/tst_webchannel.qml59
3 files changed, 112 insertions, 3 deletions
diff --git a/examples/webchannel/shared/qwebchannel.js b/examples/webchannel/shared/qwebchannel.js
index 948c836..56fa66a 100644
--- a/examples/webchannel/shared/qwebchannel.js
+++ b/examples/webchannel/shared/qwebchannel.js
@@ -17,7 +17,7 @@ var QWebChannelMessageTypes = {
response: 10,
};
-var QWebChannel = function(transport, initCallback)
+var QWebChannel = function(transport, initCallback, converters)
{
if (typeof transport !== "object" || typeof transport.send !== "function") {
console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +
@@ -28,6 +28,43 @@ var QWebChannel = function(transport, initCallback)
var channel = this;
this.transport = transport;
+ var converterRegistry =
+ {
+ Date : function(response) {
+ if (typeof response === "string"
+ && response.match(
+ /^-?\d+-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?([-+\u2212](\d{2}):(\d{2})|Z)?$/)) {
+ var date = new Date(response);
+ if (!isNaN(date))
+ return date;
+ }
+ return undefined; // Return undefined if current converter is not applicable
+ }
+ };
+
+ this.usedConverters = [];
+
+ this.addConverter = function(converter)
+ {
+ if (typeof converter === "string") {
+ if (converterRegistry.hasOwnProperty(converter))
+ this.usedConverters.push(converterRegistry[converter]);
+ else
+ console.error("Converter '" + converter + "' not found");
+ } else if (typeof converter === "function") {
+ this.usedConverters.push(converter);
+ } else {
+ console.error("Invalid converter object type " + typeof converter);
+ }
+ }
+
+ if (Array.isArray(converters)) {
+ for (const converter of converters)
+ this.addConverter(converter);
+ } else if (converters !== undefined) {
+ this.addConverter(converters);
+ }
+
this.send = function(data)
{
if (typeof(data) !== "string") {
@@ -154,6 +191,12 @@ function QObject(name, data, webChannel)
this.unwrapQObject = function(response)
{
+ for (const converter of webChannel.usedConverters) {
+ var result = converter(response);
+ if (result !== undefined)
+ return result;
+ }
+
if (response instanceof Array) {
// support list of objects
return response.map(qobj => object.unwrapQObject(qobj))
diff --git a/src/webchannel/doc/src/javascript.qdoc b/src/webchannel/doc/src/javascript.qdoc
index d36476e..0657953 100644
--- a/src/webchannel/doc/src/javascript.qdoc
+++ b/src/webchannel/doc/src/javascript.qdoc
@@ -14,7 +14,8 @@
can load the file via \c qrc:///qtwebchannel/qwebchannel.js. For external clients, you
need to copy the file to your web server. Then instantiate a QWebChannel object and pass
it a transport object and a callback function, which will be invoked once the
- initialization of the channel finishes and the published objects become available.
+ initialization of the channel finishes and the published objects become available. An optional
+ third argument contains an array of converter wrapper functions or a single one.
The transport object implements a minimal message passing interface. It should be an object
with a \c send() function, which takes a stringified JSON message and transmits it to the
@@ -27,6 +28,14 @@
socket's \c onopen handler. Take a look at the \l{Qt WebChannel Standalone Example} to see how
this is done.
+ A converter wrapper function is either a string with the name of a built-in converter or a
+ user supplied function that takes the object to process as an argument and returns the
+ resultant type or undefined if the function does not apply. If undefined is returned the next
+ converter is processed. If there are no converters that returns a value other than undefined,
+ processing proceeds as normal. "Date" is the only currently built-in converter function. It
+ takes a string with an ISO 8601 date and returns a new Date object if the syntax is right and
+ the date is valid.
+
\section1 Interacting with QObjects
Once the callback passed to the QWebChannel object is invoked, the channel has finished
diff --git a/tests/auto/qml/data/tst_webchannel.qml b/tests/auto/qml/data/tst_webchannel.qml
index 6e67dfd..c563155 100644
--- a/tests/auto/qml/data/tst_webchannel.qml
+++ b/tests/auto/qml/data/tst_webchannel.qml
@@ -36,6 +36,11 @@ TestCase {
property var bar: 1
WebChannel.id: "myOtherObj"
}
+ QtObject {
+ id: myValueObj
+ property var value: undefined
+ WebChannel.id: "myValueObj"
+ }
property var lastFactoryObj
QtObject{ id: bar; objectName: "bar" }
QtObject{ id: baz; objectName: "baz" }
@@ -76,7 +81,7 @@ TestCase {
TestWebChannel {
id: webChannel
transports: [client.serverTransport]
- registeredObjects: [myObj, myOtherObj, myFactory, testObject]
+ registeredObjects: [myObj, myOtherObj, myValueObj, myFactory, testObject]
}
function initChannel() {
@@ -686,4 +691,56 @@ TestCase {
compare(success, true);
}
+
+ function test_customUpcaseWrapper()
+ {
+ var channel = client.createChannel(function(channel) {
+ channel.objects.testObject.stringProperty = "foo";
+ }, function(arg) { return (typeof arg === "string") ? arg.toUpperCase() : undefined });
+
+ client.awaitInit();
+ function awaitMessage(type)
+ {
+ var msg = client.awaitMessage();
+ compare(msg.type, type);
+ compare(msg.object, "testObject");
+ }
+ awaitMessage(JSClient.QWebChannelMessageTypes.setProperty);
+ compare(testObject.stringProperty, "foo"); // Don't convert in this direction
+ client.awaitIdle(); // init
+
+ testObject.stringProperty = "bar";
+ compare(testObject.stringProperty, "bar");
+ client.awaitIdle(); // property update
+ compare(channel.objects.testObject.stringProperty, "BAR"); // Case converted
+ }
+
+ function test_dateWrapper()
+ {
+ var channel = client.createChannel(undefined, "Date");
+ client.awaitInit();
+ client.awaitIdle();
+
+ var dateString = "2022-01-01T10:00:00Z";
+ myValueObj.value = dateString;
+ compare(myValueObj.value, dateString);
+ client.awaitIdle(); // property update
+ var value = channel.objects.myValueObj.value;
+ verify(value instanceof Date);
+ verify(!isNaN(value));
+ compare(value.getUTCFullYear(), 2022);
+ compare(value.getUTCMonth(), 0); // 0 = January
+ compare(value.getUTCDate(), 1);
+ compare(value.getUTCHours(), 10);
+ compare(value.getUTCMinutes(), 0);
+ compare(value.getUTCSeconds(), 0);
+
+ var invalidDate = "2022-13-31T10:00:00Z"; // Month after december
+ myValueObj.value = invalidDate;
+ compare(myValueObj.value, invalidDate);
+ client.awaitIdle(); // property update
+ value = channel.objects.myValueObj.value;
+ verify(typeof value === "string"); // Not converted to Date
+ compare(value, invalidDate);
+ }
}