Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Sunday, April 14, 2013

Emitting signal from Javascript in QML application

While I was working on Ubuntu-Touch core app calendar, I wanted to emit signal from java script to QML code.

As such there is no official way provided by Qt framework, but we can try some workaround for this. Initially I used observer pattern to notify QML code from javascript. but I needed to wrote quite handful of code, and I did not liked the solution, I asked my team mates in calendar team and Frank suggested quite neat solution for this.

His suggestion was to create a temporary QtObject in javascript and use it for notification. Following is code for the same.

In following code, I created a QtObject in javascript with dataChanged signal defined in it.

eventsNotifier = Qt.createQmlObject('import QtQuick 2.0; QtObject { signal dataChanged }', Qt.application, 'EventsNotifier');
Now, we can use this object to emit signal to QML code, like this.

function someFunc() {
 ...
 ...
 eventsNotifier.dataChanged();
}
In QML code, we need to attach slot to dataChanged signal,like below.

    import "test.js" as TestJS

    function reload() {
        ...
        ...
    }
    Component.onCompleted: {
        TestJS.eventsNotifier.dataChanged.connect(reload);
    }
This is all, simple and neat.

Thursday, April 4, 2013

Accessing Amazon AWS service from QML/Javascript

Sometime back I published a post that shows how to access Amazon Web Service using Qt. You can find original post here. Now that trend is to code everything from QML and Javascript ( at-least Ubuntu Touch is following that path to make it as device independent as possible), I tired to access AWS service from using pure QML and Javascript.

I required to use external Crypto library for HMACSHA1 algorithm but everything else can easily be done with pure QML/Javascript.

Following is code i used for downloading Book cover image from Amazon AWS.

First all to communicate with AWS you required to have AWS access key id and Secret Access key. You can get it from here. I am also importing the Crypto library, for using HmacSHA1 implementation. I am using crypto-js Library. You can download required the same from here.

.import "JSLib/rollups/hmac-sha1.js" as Crypto

//key and password, required to sign the request using HMACSHA1
var AWS_KEY = "KEY";
var AWS_PASS = "PASSWORD";
var END_POINT = "http://ecs.amazonaws.com/onca/xml";
var AWS_TAG = "TAG"

Now we have required information, we can are ready to create request. In following code, I am putting all required parameter in a map and then using it to create signature and URL. We also need to encode parameter, I am using encodeURIComponent for encoding required parameter.
function downloadCover( author,bookName,callback) {

    var queryItems = {};
    queryItems["AWSAccessKeyId"] = AWS_KEY;
    queryItems["AssociateTag"] = AWS_TAG;
    queryItems["Author"] = encodeURIComponent(author);
    queryItems["Keywords"] = encodeURIComponent(bookName);
    queryItems["Operation"] = "ItemSearch";
    queryItems["ResponseGroup"] = "Images";       
    queryItems["SearchIndex"] = "Books";
    queryItems["Service"] = "AWSECommerceService";
    queryItems["SignatureMethod"] = "HmacSHA1";
    queryItems["Timestamp"] = encodeURIComponent( new Date().toISOString());
    queryItems["Signature"] = createSignature(queryItems);


    var downloadUrl = createUrl(queryItems);
    sendNetworkRequest(downloadUrl,callback);
}
Following is code for creating signature. Creating signature is the only tricky part to make code works as expected. I am using HmacSHA1 from Crypto-JS lib. This function return WordArray object, which can be converted to HEX string, binary string or base64. Once we have HmacSHA1 hash of request, we need to convert it to Base64. I was not able to use base64 function from Crypto-JS library due to some error. I decided to copy base64 function from library directly to my js file and use it. Then finally we need to encode this base64 output, which we can be used as signature while sending request.
function createSignature(queryItems) {
    var strToSign = "GET\n";
    strToSign += "ecs.amazonaws.com\n";
    strToSign += "/onca/xml\n"

    for( var prop in queryItems ) {
        if( prop === "Signature") {
            continue;
        }

        strToSign += ( prop+"="+ queryItems[prop]);
        strToSign += "&"
    }
    //removing last &
    strToSign = strToSign.slice(0,strToSign.length-1)


    var signature = Crypto.CryptoJS.HmacSHA1(strToSign, AWS_PASS);
    signature = base64(signature);

    return encodeURIComponent(signature);
}

Now we are almost done, all we need to do is to use created signature and make HTTP request. Following code shows how. There is nothing new here. I am creating complete URL from all required parameter and making request using this URL by XMLHttpRequest object.

function createUrl(queryItems )
{
    var url = END_POINT+"?";

    for( var prop in queryItems ) {
        url += ( prop+"="+ queryItems[prop]);
        url += "&"
    }
    //removing last &
    url = url.slice(0,url.length-1);
    return url;
}

function sendNetworkRequest(url,callback) {
    var http = new XMLHttpRequest();
    http.onreadystatechange = function() {
        if (http.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
            console.log("Headers -->");
            console.log(http.getAllResponseHeaders ());
            console.log("Last modified -->");
            console.log(http.getResponseHeader ("Last-Modified"));

        } else if (http.readyState === XMLHttpRequest.DONE) {
            console.log(http.responseText);
            callback(http.responseText);
        }
    }

    http.open("GET", url);
    http.send();
}

Friday, March 1, 2013

Using LocalStorage API from javascipt in QML application

Recently I needed to create database from QML application on which I am working. I wanted to separate database related code from QML and created javascript file to handle database related work. I had to struggle a little to make storage API work from javascript, below are my findings.

As you might already know to use sqllite database in QML you will need to import LocalStorage API.
import QtQuick.LocalStorage 2.0 as Sql
This will work for QML but if you want to use it from javascript then you will need to use following syntax.
.import QtQuick.LocalStorage 2.0 as Sql
Now you should be able to use LocalStorage API in javascript. LocalStorage related API can be accessed by using LocalStorage object and we imported LocalStorage module as Sql, we will need to use access LocalStorage object from Sql scope. Like below.
var db = 
   Sql.LocalStorage.openDatabaseSync("TestDB", "1.0", "Description", 100000);
Now you can use this db object to create table and select values from it just like you do in QML. Following is sample example.
function getDatabase() {
     var db = 
     Sql.LocalStorage.openDatabaseSync("TestDB", "1.0", "Description", 100000);

     //create table
     db.transaction(
        function(tx) {    
var query="CREATE TABLE IF NOT EXISTS TEST(Id INTEGER PRIMARY KEY, Title TEXT)";                   
            tx.executeSql(query);
      });

     return db;
}

function printValues() {

    var db = getDatabase();
    db.transaction( function(tx) {
        var rs = tx.executeSql("SELECT * FROM TEST");
        for(var i = 0; i < rs.rows.length; i++) {
            var dbItem = rs.rows.item(i);
            console.log("ID:"+ dbItem.Id + ", TITLE:"+dbItem.Title);
        }
    });
}