This Javascript tutorial describes the basic steps to compile and run a Javascript example using EFL with Node.Js
Before you start you may want to read about how to compile the EFL:
You will need additional dependencies to Javascript Bindings:
To configure efl sources with nodejs bindings add ––with-js=nodejs
to the configure flags:
./configure --with-js=nodejs #in efl source path
After that, you can compile normally with:
make make install
EFL will install its nodejs modules - named efl.node
- under the <prefix>/lib
path. The default prefix, if not explicitly defined, is /usr/local
. In order to nodejs discover these modules, add the previously cited folder to the NODE_PATH
environment variable:
export NODE_PATH=/usr/local/lib:$NODE_PATH #if necessary replace with your prefix path
To check if the path is correctly set, use require
inside nodejs to import the module:
~$ node > efl = require("efl")
<efl_source>/src/examples/elementary/button_example_00.js
Import Efl module
efl = require('efl');
Create a new Window with auto hide (the window is automatically hidden when the close button is clicked):
win = new efl.Efl.Ui.Win.Standard(null); win.setText("Hello, World!"); // Sets the title win.setAutohide(true);
Create a new Button (passing the newly created window as parent) and set new label text to button:
btn = new efl.Elm.Button(win); btn.setText(null, "Good-Bye, World!");
Set button basic size and positions:
btn.setSize(120, 30); btn.setPosition(60, 15); btn.setHintWeight(1.0, 1.0); btn.setHintAlign(1.0, 1.0);
The method on
is used to register callback on events. In this case we need to catch the clicked
event, so we register a function (second argument) to print a log message when the button btn
is clicked:
btn.on('clicked', function () { console.log('clicked'); } );
To finish, it is necessary to show all elements, using the setVisible(true)
method:
btn.setVisible(true); win.setSize(240, 60); win.setVisible(true);
Once finished this setup, the efl.node
module automatically integrates with the nodejs main loop without requiring you to call it explicitly.
<efl_source>/src/examples/twitter_example_01.js
This is a more complex example, with edje theming and some external requirements. We need to install the request
and twitter
nodejs modules, using the npm
(node.js package manager) to automatically download and install all necessary files:
npm install request npm install twitter
npm
is installed by default with Node.js
Import all modules and initialize the necessary variables to connect to the twitter API
efl = require('efl'); // Standard node modules util = require('util'); fs = require('fs'); path = require('path'); // 3rd pardy modules, requiring install with npm request = require('request'); //need "npm install request" twitter = require('twitter'); //need "npm install twitter" // Twitter access keys var twit = new twitter({ consumer_key: 'ZbSM93w5Sp2cyZ2SG0XuCvoHV', consumer_secret: 'g8N7EEQLpdKPnAsS9hWuQV29FYjBkhH62jhZzXyYymDw87DKye', access_token_key: '222611263-pPhKKjYh59uuNLP0b86sP7aAtLhdecjVQaEsCDCv', access_token_secret: 'l7ccNKXTVv6cymfSD1gQH61tmfixkdna2QmOjPtpVxSHD' }); user_acount = 'EnlightenmentKo' // our target twitter account to be shown
Create a new Window (as in the previous example):
win = new efl.Efl.Ui.Win.Standard(null); win.setText("Twitter App"); win.setAutohide(true);
Create and show two boxes widget containers, one to be the top level box and another to work like a list, with the individual tweets.
box = new efl.Efl.Ui.Box(win); box.setHintWeight(1.0, 1.0); win.setContent(box); box.setVisible(true); tweet_box = new efl.Efl.Ui.Box(win); tweet_box.setHintWeight(1.0, 1.0); tweet_box.setHintAlign(-1.0, -1.0); tweet_box.setPackPadding(0.0, 30.0, true); // Give some space between the tweets box.packEnd(tweet_box);
The default box orientation is horizontal. In order to resemble the original timeline appearance, we need to make it horizontal. This is made in two steps, first we “cast” the box to an Efl.Orientation
object and then we actually set the orientation.
Efl.Ui.Box
inherits from both Elm.Widget
and the interface Efl.Orientation
. These two classes/interfaces define a method called setOrientation
. In C you can specify which one you want by calling the respective function, e.g. elm_widget_orientation_set
or efl_orientation_orientation_set
. In the Javascript bindings, the current approach is using these explicit casts.
tweet_box_orient = tweet_box.cast("Efl.Orientation"); tweet_box_orient.setOrientation(efl.Efl.Orient.VERTICAL);
Now we are ready to ask the twitter module to get the timeline of the target user. The 'get' function will be passed a callback that will be called when the data is ready. Inside it, we will start building the tweet list.
Also, we create an array to store the icon widgets to be filled when the icon finish downloading.
icon_array = new Array(); // To store the icons twit.get('statuses/user_timeline', {screen_name: user_acount, count:10}, function(error, tweets, response) { if (error) return; // Begin building the tweets
For each tweet, we make a new Elm.Layout
and set various components, or, in efl jargon, “parts”, using the set*
family of methods.
First, we set a base theme using setFile
. The layout will load the given file and setup the internal layout structure, etc. This will allow us to refer the individual tweet's parts by name on the following methods.
The edj file used was compiled from a source edc file. For more information, see the next section.
// continuing the previous callback for(i=0; i < tweets.length; i++){ // extract the data we got from the twitter api var user_name = tweets[i].user.name; var screen_name = tweets[i].user.screen_name; var text = tweets[i].text; var layout = new efl.Elm.Layout(win); // Use __dirname to get the file from the same folder of this .js var filename = path.join(__dirname, "twitter_example_01.edj"); layout.setFile(filename, "tweet"); // Load the 'tweet' group from theme file
Once we have the theme loaded, we can use setText
to set a new text to the related Edje parts in the theme, referring them on each call by using the name of the part as the first argument.
// Continuing the previous for loop layout.setText("user_name", screen_name); layout.setText("screen_name", " - @"+screen_name);
To have a formatted text, we use an Elm.Entry
to show the main tweet text and add this widget into the theme using the setContent
layout method. This allows us to inject full widgets into the layout, besides the basic stuff. Like setText
, setContent
also receives the name of the target part as the first argument.
// continuing the previous for loop var entry = new efl.Elm.Entry(win); entry.setText("elm.text", text); entry.setEditable(false); // We have to cast to the proper type, like in the previous box orientation // case part = layout.part("tweet_text").cast("Efl.Container"); part.setContent(entry); // Some sizing details for better looking layout.setHintMin(127, 96); layout.setHintWeight(1.0, 1.0); layout.setHintAlign(-1.0, -1.0);
Now, for the icon, we use an efl.Efl.Ui.Image
. It'll be set to display the downloaded icon. Like the entry above, it will be placed in a swallow part of the theme.
// continuing the for loop var icon = new efl.Efl.Ui.Image(win); icon.fillInside = true; icon_array.push(icon); user_icon = layout.part("user_icon").cast("Efl.Container"); user_icon.setContent(icon); // Pack the tweet into the box. item = tweet_box.packEnd(layout); layout.setVisible(true); } // Finished the for loop
To show the tweet image, we need to download it. We can accomplish this creating a new file stream with fs.createWriteStream
and download the image to this file stream using the request
module. Once the download is finished, we iterate through the list of icons widgets and tell them to display the downloaded file. We also tell the tweet box and the window to show themselves.
if (tweets.length > 0) { var icon_filename = '/tmp/twitter_pic.jpg'; var file = fs.createWriteStream(icon_filename); file.on('finish', function() { console.log("finished loading the icon file."); for (i=0; i < icon_array.length; i++) { icon_array[i].setFile(icon_filename, null); } }); request(tweets[0].user.profile_image_url).pipe(file); } tweet_box.setVisible(true); }); win.setSize(380, 400); win.setVisible(true);
You will find these and more examples in directory src/examples
in the efl source code.
All you need to run is:
node <example_file_name>
Theming the tweet in edj allows you to separate presentation details from the code. In a nutshell, you create themes in edje by creating “parts” inside groups, the basic elements of an edje theme. For example, you can create text parts to hold text and rectangles. For traditional widgets, you can create “swallow” parts that the application can use to show buttons, text entry, etc. For more information, check the EDJE tutorial here.
For now, first create an edc - the EDJE source format - file with the following contents:
collections { group { name: "tweet"; parts { part { name: "user_icon"; type: SWALLOW; description { rel1 { relative: 0.0 0.0; offset: 2 2; } rel2 { relative: 0.0 0.0; offset: 50 50 ; } } } part { name: "user_name"; type: TEXT; effect: SOFT_SHADOW; description { color: 0 190 255 255; rel1 { relative: 1.0 0.0; to_x: "user_icon"; offset: 7 4; } rel2 { relative: 1.0 0.0; to_x: "user_icon"; offset: 120 30; } text { text: "User Name"; size: 12; font: "sans:style=Bold"; min: 1 1; ellipsis: -1; align: 0.0 0.0; } } } part { name: "screen_name"; type: TEXT; description { rel1 { relative: 1.0 0.0; to: "user_name"; offset: 15 4; } rel2 { relative: 1.0 1.0; to: "user_name"; offset: 75 10; } text { text: "scname"; size: 10; font: "sans"; min: 1 1; ellipsis: -1; align: 0.0 0.0; } } } part { name: "tweet_text"; type: SWALLOW; description { rel1 { relative: 0.0 1.0; to: "user_name"; offset: 0 0; } rel2 { relative: 0.0 1.0; to: "user_name"; offset: 250 80; } } } } } }
Then compile it to the .edj format that your app will load:
~$ edje_cc your_edc_file.edc # Will generate your_edc_file.edj