Friday, February 24, 2012

New widget for HB

There was a time since i wrote my last post, the reason is i wanted to take some time to rethink somethings about the way i did face the project, and take away of it for a while, and dedicate some time for me. I think is time to write a new post and on this time i will show a new HB widget consisting of a music mp3 player. You can see a picture of the component below:


You can see the player on the bottom (the black box). The player has the typical look, with play, stop, repeat, etc controls. The events offered for this widget are the ready and soundLoaded event, and the main methods are set_url,startPlay,setRepeat,stop. You can also change the appearance of the widget using style's properties. :)

Friday, June 3, 2011

Tuesday, May 17, 2011

Creating Windows on HB

i want to dedicate this post to my mother, she was a great women, and she always did support me until the sunday may 15, when the cancer took her life. She was fighting since two and half years against this terrible disease. All i can say is thanks for every thing that you did give me, always waiting nothing in change. You will be always living in my heart and in every thing i make. Thanks and rests in peace.


On this post i will show you the way you can create and manage windows on HB.

Following is the image showing the HB page we will working on at design time:


the components on the page are:

- database7_1, database7_2: are text, when the user click on 'create windows' we will create three windows, and when click on 'close all windows' all the windows opened will be closed.
- database7_3: this widget will allow us to create windows. we will can move the windows on the page dragging with the mouse from the window's title area.
- database7_4: we will use this widget to create a 'canvas' object, then we will load some HB page inside it and finally we will put the canvas inside the window.

following is the page at visit time:


On the next image you can see how we can move the windows on the page using the mouse:


and next is the code for every event to do this page work:

database7_1_onClick event:

// here we create some windows using the widget

var pagesToLoad=new Array();
pagesToLoad.push('jaime2');
pagesToLoad.push('jaime4');
pagesToLoad.push('jaime5');

var o=page.findObject2('/database7_3');
if (o!=null)
{
for (var i = 0 ;i < pagesToLoad.length ; i++)
{
var w=o.content.application.new_window();
w.title='Window '+(i+1);
// si no especificamos el ancho y alto de la ventana, esta se ajustar√° a su contenido
w.closeButton(true,w.constant_remove); // show close button
// we want respond to some events
w.addEvents('close|mouseDownOutside','|','win');
// set some styles for the window
w.setStyle('borderColor',0x0099CC);
w.setStyle('borderThicknessLeft',3);
w.setStyle('borderThicknessRight',3);
// show the window
o.content.application.windowManager.addPopUp(w,page,false);
// center the window on the browser
o.content.application.windowManager.centerPopUp(w);



/*
no we create a canvas object, then add the canvas
to the window and load inside it an HB page
*/
var cw=page.findObject2('/database7_4');
var canvas=cw.content.application.new_canvas();
// si no especificamos el ancho y alto del canvas este se ajustara a su contenido
if (canvas!=null)
{
w.addChild(canvas);
page.cargar_pagina(canvas,pagesToLoad[i],'','');
global.canvasWindow=canvas;
}
} // fin ciclo for

}


database7_2_onClick
event:

// here we close all the popups
ac=page.getAllPopups();
if (ac.length>0)
{
var o=page.findObject2('/database7_3');
for (var i = 0 ; i < ac.length ; i++)
o.content.application.windowManager.removePopUp(ac[i]);
}

win_windowClose
event:

// a window is being closed for the user, you can do something here

win_windowMouseDownOutside event:

// the user clicks outside the window, you can do something here



Thursday, April 28, 2011

Communicating with data services of third party , YouTube sample - II


This is the second part of the YouTube Sample, which shows you how to connect to YouTube's data services. Following is the code of the others script events:

database5_3_ready event:

// create textInput to get the search string from the user
var cw=page.findObject2("/database5_3");
var t=cw.content.application.new_textInput();
t.y=40;t.x=33;t.width=277;
// next line: when user press enter will trigger searchString_textInputEnter event
t.addEvents('enter','|','searchString')
page.content.addChild(t);
global.t=t; // saves reference to the textInput for use it in other events



// CREATE AN IMAGE AND LOAD THE CHROMELESS PLAYER FROM YOUTUBE
var im=cw.content.application.new_image();
im.y=160;im.x=33;
im.width=399;im.height=377;
im.id="player";
im.addEvents("loadComplete",'|','videoPlayer');
im.source="http://www.youtube.com/apiplayer?version=3";
page.content.addChild(im);
global.vidPlayer=im; // saves reference to the player for use it in other events

// create a vertical box which will be the video list container
create_vBox();
// create a vertical box which will be the comments list container
create_vBoxComments();

setButtonMode(); // set button mode for some componentes


videoPlayer_imageLoadComplete event:


if (me.id="player")
{
// set a listener to 'watch' when the chromeless player contained
// inside this component is ready to interaction
me.content.addEventListener("onReady",page.g_scripts.listener);
}



listener event:

if (event.currentTarget==global.vidPlayer.content && event.type=='onReady')
{
/*
the chromeless video player triggered the onReadyEvent,
signaling is ready to be used
*/
var w=500;
var h=400; //w*3/4;
event.currentTarget.setSize(w, h);
}

searchString_textInputEnter event:

/*
here we send the search request to youtube
*/
searchVideos();

database5_1_onClick event:

/*
here we send the search request to youtube
*/
searchVideos();


serverResponse event:


// prepare some variables to store the video data
var videos=new ArrayCollection();
var video=null;

// get some namespaces from the xml data

var os = result.result.namespace("openSearch");//::totalResults;
global.totalResults=result.result.os::totalResults;


var ns= result.result.namespace("");
var gd = result.result.namespace("gd");
var media = result.result.namespace("media");
var yt = result.result.namespace("yt");

var vList=null;
vList = result.result.ns::entry;


for each(var vElement in vList)
{

video=new Object();
if (video!=null)
{
video.title = vElement.ns::title;
video.published = vElement.ns::published;
video.rating = Number(vElement.gd::rating.@average);
video.description = vElement.media::group.media::description;
video.keywords = vElement.media::group.media::keywords;
video.category = vElement.media::group.media::category;
video.thumbnail = vElement.media::group.media::thumbnail[0].@url;
video.duration = Number(vElement.media::group.yt::duration.@seconds);
//video.url = vElement.media::group.media::content.(@type == "application/x-shockwave-flash").@url;
video.url = vElement.media::group.media::content.(String(@url).substr(0,4) == "http").@url;
video.urlComments=vElement.gd::comments.gd::feedLink.@href;
//if(video.url != null && video.url.length > 0)
{
videos.addItem(video);
}
}

} // end of for each

global.videos=videos; // save the videos in the global variable

// now we build the videoList from the video list
buildVideoList();

showOneOf();


serverError event:

Alert.show('error calling video search');


serverResponseComments event:


// prepare some variables to store the comments
var comments=new ArrayCollection();
var comment=null;

// get some namespaces from the xml data

var os = result.result.namespace("openSearch");
global.totalResultsComments=result.result.os::totalResults;

var ns= result.result.namespace("");


var vList=null;
vList = result.result.ns::entry;


for each(var vElement in vList)
{

comment=new Object();
if (comment!=null)
{
comment.title = vElement.ns::title;
comment.published = vElement.ns::published;
comment.updated = vElement.ns::updated;
comment.content = vElement.ns::content;
comment.authorName = vElement.ns::author.ns::name;

{
comments.addItem(comment);
}
}

} // end of for each

global.comments=comments; // save the comments in the global variable

// now we build the commentsList from the comments list
buildCommentsList();

showOneOfComments();


serverErrorComments event:

Alert.show('error calling comments for video');


database5_5_onClick event:

// user click the play video button
if (global.vidPlayer==null)
{
// cromeless video player not instantiated
return;
}
global.vidPlayer.content.playVideo();


database5_6_onClick event:

// user click the pause video button
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.pauseVideo();


database5_8_onClick event:

// user click the rewind video button
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.seekTo(0, true);


database5_9_onClick event:

// back the video list to the previous page
if (global.startIndex-global.maxResults>=1)
global.startIndex=global.startIndex-global.maxResults;
else
global.startIndex=1;

searchVideos();


database5_10_onClick event:

// forward the video list to the next page
if (global.startIndex+global.maxResults<=global.totalResults)
global.startIndex=global.startIndex+global.maxResults;
else
{
global.startIndex=global.totalResults-global.maxResults;
if (global.startIndex<1) global.startIndex=1;
}

searchVideos();

database5_17_onClick event:

// back the comments list to the previous page
if (global.startIndexComments-global.maxResultsComments>=1)
global.startIndexComments=global.startIndexComments-global.maxResultsComments;
else
global.startIndexComments=1;

searchComments();


database5_18_onClick event:

// forward the video list to the next page
if (global.startIndexComments+global.maxResultsComments<=global.totalResultsComments)
global.startIndexComments=global.startIndexComments+global.maxResultsComments;
else
{
global.startIndexComments=global.totalResultsComments-global.maxResultsComments;
if (global.startIndexComments<1) global.startIndexComments=1;
}

searchComments();


videoList_canvasClick event:

if (me.id.indexOf('_')==-1) // name does not adjust to name convention of name_n
return;

var arrName=me.id.split('_'); // separate name from number of component
var nameComponent=arrName[0];
var numComponent=arrName[1];

if (nameComponent=='canvVideoList')
{
// the user click on a video of the video list, so we start to play the
// selected video in the chromeless player
if (global.vidPlayer==null)
{
// cromeless video player not instatiated
return;
}
global.vidPlayer.content.loadVideoByUrl(global.videos[numComponent].url);

// set the title and description in the text above of the chromeless player
var t=page.findObject2("/database5_2");
if (t!=null)
{
t.htmlText=""+global.videos[numComponent].title+""+"\n"+global.videos[numComponent].description;
}

// search and display the comments for this video
global.startIndexComments=1;
global.totalResultsComments=0;
global.urlComments=global.videos[numComponent].urlComments;
searchComments();
}


videoList_canvasMouseWheel event:

// highlight the item of the video list where is the mouse pointer
if (global.lastCanvas!=null)
if (global.lastCanvas!=me)
{
global.lastCanvas.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvas=me;


videoList_canvasRollOut event:

// restore the blank color of the item of the video list
me.setStyle("backgroundColor", 0xffffff);


videoList_canvasRollOver event:

// highlight the item of the video list where is the mouse pointer
if (global.lastCanvas!=null)
if (global.lastCanvas!=me)
{
global.lastCanvas.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvas=me;


commentsList_canvasClick event:

// do nothing (for the moment)

commentsList_canvasMouseWheel event:

// highlight the item of the comments list where is the mouse pointer
if (global.lastCanvasComments!=null)
if (global.lastCanvasComments!=me)
{
global.lastCanvasComments.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvasComments=me;


commentsList_canvasRollOut event:

// restore the blank color of the item of the comments list
me.setStyle("backgroundColor", 0xffffff);


commentsList_canvasRollOver event:

// highlight the item of the comments list where is the mouse pointer
if (global.lastCanvasComments!=null)
if (global.lastCanvasComments!=me)
{
global.lastCanvasComments.setStyle("backgroundColor", 0xffffff);
}

me.setStyle("backgroundColor", 0xaaaaff);
global.lastCanvasComments=me;


That's all the events for the YouTube sample. You could enhanced the page adding many more controls to the video player, etc. Because with HB you can make that very easily.

On this post you had learn how to connect to a third party data service, how to send and get data to/from the data service using the httpService object and how to create a user interface dynamically to show the data (on this case video data). You now could use this sample like a starting point to connect to others data services like FaceBook, Flickr, etc. :)


Monday, April 18, 2011

Communicating with data services of third party , YouTube sample - I

Hummingbird allow you communicate with external data services. you can do so, using the http services objects provided by HB. On this post i will show you how to communicate with the data services offered by Youtube, but you could adapt the sample to communicate with others services like the one offered for flickr, panoramio, facebook, etc.
following are two images showing the HB page at design time, with the elements needed to do the sample:




The elements found on the page are:

1. commonWidgets: this widget will allow us create the elements 3,5 and 9. id: database5_3
2. search videos: is a text component, when the user click on it, access the youtube data services, and get a video list corresponding to the words in the element 3 (textInput). id: database5_1
3. textInput: here you enter the words corresponding to the videos you want to get from youtube.
4. text: it show you the title and description of the video you are watching currently. id: database5_2
5. video player: it is the chromeless video player provided by youtube. it allow us play streamed videos directly from the YouTube's servers.
6. play button: play the video. id: database5_5
7. stop button: stop the video you are watching. id: database5_6
8. rewind button: rewind the video. id: database5_8
9. video list: this is an vBox component generated using the cwidgets, it shows you the video list corresponding to the videos that match your search criteria. it show you the videos in a paged way, and you can use the buttons below it to move between pages. When you click on a video on this list the video begins to play.
10. back video list: allow you get the previous video list page. id: database5_9
11. forward video list: allow you get the next video list page. id: database5_10
12. text: shows you the start and end videos showed on the video list, and the total of videos. id: database5_12
13. comments list: this is an vBox component generated using the cwidgets, it shows you the comments list corresponding to the video that is being played. it show you the comments in a paged way, and you can use the buttons below it to move between pages.
14. back comments list: allow you get the previous comments list page. id: database5_17
15. forward comments list: allow you get the next comments list page. id: database5_18
16. text: shows you the start and end comments showed on the comments list, and the total of comments. id: database5_19

The next pictures show you the HB page in action (on visit mode):



One of the things you must know when you try to use data services of third party is the way you will communicate with the data services and the format of the returned data. On this case we will get data from Youtube, so you will have to understand how works the YouTube API, so you must read this:

YouTube API protocol
YouTube API player

The above links will provide you with useful info in order to understand what we will do next.

A first question you could be asking yourself is ¿ why use the YouTube's video player instead the HB video player ? Youtube don't allow you access flv videos directly, instead they provides two video players which allow us play the videos. Maybe by googling sometime you could find some hacks to access flv videos directly from YouTube, but there is not guarantee it keep working , because YouTube is constantly closing that hacks.

Following you can see the scripts of the page in the scripts editor:


and next is the code of every event script:

imports event:

import mx.controls.Alert;
import mx.collections.ArrayCollection;


// create our webService object
global.serv=page.newHttpService();
global.serv.service.url="http://gdata.youtube.com/feeds/api/videos";
global.serv.service.resultFormat="e4x";
global.serv.service.method = "GET";

// the next webservice will be used to retrieve the comments for the played video
global.servComments=page.newHttpService();
global.servComments.service.resultFormat="e4x";
global.servComments.service.method = "GET";

/*
every time a search is made we will save
the results videos in the next variable
*/
global.videos=null;
// the next variable will be our video list component container
global.vb=null;
// the next variable will show us the last canvas of the video list that was higlighted
global.lastCanvas=null;
// the next 3 variables will be used to control the movement of the video list pages
global.startIndex=1;
global.maxResults=10;
global.totalResults=0; // when searching this will be filled with the total numbers of videos



// the next 3 variables will be used to control the movement of the comments list pages
global.startIndexComments=1;
global.maxResultsComments=30;
global.totalResultsComments=0; // when searching this will be filled with the total numbers of comments for the selected video
// the next variable will save the comments for a video
global.comments=null;
// the next variable will be our comments list container
global.vbComments=null;
// the next variable will show us the last canvas of the comments list that was higlighted
global.lastCanvasComments=null;
// the next variable will save the url of the comments for the video being played
global.urlComments=null;

// needed to use the chromeless player of youtube
page.allowDomain("www.youtube.com"); // this allows HB access the chromeless YouTube video player

global.vidPlayer=null; // this will be the chromeless videoPlayer Object

functions event:


function clearCommentsList()
{
if (global.vbComments!=null)
global.vbComments.removeAllChildren();


}



function buildCommentsList()
{
/*
this function take the data of the comments and build a nice
comments list
*/

clearCommentsList();

// get a reference to the cWidget
var cw=page.findObject2("/database5_3");

// get a reference to the vertical box created
var vb=global.vbComments;
if (vb==null)
{
Alert.show("vbox for comments list not created");
return;
}


// loop over our comments list
for (var i = 0 ; i < global.comments.length ; i++)
{
// this is the i-esimal comment of the list


/* the data fields for a comment are:
comment.title
comment.published
comment.updated
comment.content
comment.authorName
*/



// create a text object to show some text of the video
var text=cw.content.application.new_text();
text.y=6;text.x=4;
text.width=vb.width-24;
//text.height=100; // component will be autosized according content
text.autoResize=true;
text.htmlText="TITLE: "+global.comments[i].title+"\nAUTHOR: "+global.comments[i].authorName+"\n"+global.comments[i].content;
text.setStyle("color", 0x000000);
text.id="text"+i;
//text.truncateToFit=true; // dont need truncateToFit
//text.addEvents("click");
text.toolTip=global.comments[i].content;
text.mouseChildren=false;



// create a canvas an locate every above object inside it
var can=cw.content.application.new_canvas();
can.setStyle("backgroundColor", 0xffffff);
can.setStyle("borderStyle", "solid");
can.setStyle("borderColor", 0x000000);
can.setStyle("borderThickness", 1);
can.autoLayout=true;
can.addChild(text);

//can.height=text.y+text.height+4; // canvas will be autoLayout
//can.width=text.x+text.width+4; // canvas will be autoLayout
can.id="canvCommentsList_"+i;
/*
next line: the events of the canvas (rollover,rollOut, etc.) will begin with commentsList prefix
*/
can.addEvents("rollOver|rollOut|click|mouseWheel",'|','commentsList');
can.hScrollPolicy("off");
can.vScrollPolicy("off");
can.buttonMode=true;

// add the canvas with its childrens to the container vBox
vb.addChild(can);

}

} // end of function buildCommentsList




function showOneOfComments()
{
// set the a message like this: 1-10 of 123
var c=page.findObject2("/database5_19");
if (c!=null)
{
c.text=global.startIndexComments+"-"+(global.startIndexComments+global.maxResultsComments-1)+" of "+global.totalResultsComments;
}
}


function searchComments()
{
// this function search for the comments of a video
if (global.urlComments==null)
return;

var startIndex=global.startIndexComments;
var maxResults=global.maxResultsComments;

global.servComments.service.url=global.urlComments;
var params=new Object();
params["max-results"]=maxResults;
params["start-index"]=startIndex;

global.servComments.call(params,"serverResponseComments","serverErrorComments");

}

function create_vBoxComments()
{
var cw=page.findObject2("/database5_3");

// creates a vBox which will be the container for the comments list
var vb=cw.content.application.new_vBox();
// set styles for vBox
vb.setStyle("borderStyle", "solid");
vb.setStyle("borderColor", 0x000000);
vb.setStyle("borderThickness", 1);
vb.setStyle("verticalGap", 0); // vertical space between childrens

vb.height=473;
vb.width=397;
vb.x=34;vb.y=544;
vb.setStyle("backgroundColor", 0xffffff);
page.content.addChild(vb);
global.vbComments=vb;

} // end of function vBoxComments



function setButtonMode()
{
// set buttonMode for search videos button
var pb=page.findObject2("/database5_1");
pb.buttonMode=true;
pb.mouseChildren=false; // this is a text so we need this too

// set buttonMode for the player buttons (play,stop,rewind)
var pb=page.findObject2("/database5_5");
pb.buttonMode=true;
var pb=page.findObject2("/database5_6");
pb.buttonMode=true;
var pb=page.findObject2("/database5_8");
pb.buttonMode=true;

// set button mode for videolist buttons (back video list,forward video list)
var pb=page.findObject2("/database5_9");
pb.buttonMode=true;
var pb=page.findObject2("/database5_10");
pb.buttonMode=true;

// set button mode for commentslist buttons (back comments list,forward comments list)
var pb=page.findObject2("/database5_17");
pb.buttonMode=true;
var pb=page.findObject2("/database5_18");
pb.buttonMode=true;

}

function showOneOf()
{
// set the a message like this: 1-10 of 32456
var c=page.findObject2("/database5_12");
if (c!=null)
{
c.text=global.startIndex+"-"+(global.startIndex+global.maxResults-1)+" of "+global.totalResults;
}
}


function searchVideos()
{
/*
here we send the search request to youtube
*/

//Alert.show(global.serv);

var searchString=global.t.text;
var startIndex=global.startIndex;
var maxResults=global.maxResults;

//global.serv.service.url=global.serv.service.url + "?vq=" + searchString + "&max-results=10";
//global.serv.call(null,"serverResponse","serverError");

var params=new Object();
params["vq"]=searchString;
params["max-results"]=maxResults;
params["format"]=5; // check this video format
params["start-index"]=startIndex;
global.serv.call(params,"serverResponse","serverError");

} // end of search videos function


function create_vBox()
{
var cw=page.findObject2("/database5_3");

// creates a vBox which will be the container for the video list
var vb=cw.content.application.new_vBox();
// set styles for vBox
vb.setStyle("borderStyle", "solid");
vb.setStyle("borderColor", 0x000000);
vb.setStyle("borderThickness", 1);
vb.setStyle("verticalGap", 1); // vertical space between childrens

vb.height=919;
vb.width=430;
vb.x=463;vb.y=97;
vb.setStyle("backgroundColor", 0xffffff);
page.content.addChild(vb);
global.vb=vb;


} // end of function create_vBox


function clearVideoList()
{
if (global.vb!=null)
global.vb.removeAllChildren();


}


function buildVideoList()
{
/*
this function take the data of the videos and build a nice
video list
*/

clearVideoList();

// get a reference to the cWidget
var cw=page.findObject2("/database5_3");

// get a reference to the vertical box created
var vb=global.vb;
if (vb==null)
{
Alert.show("vbox for video list not created");
return;
}

// loop over our video list
for (var i=0; i < global.videos.length ; i++)
{
// this is the i-esimal video of the list

// creates an image object to show a thumbnail for the video
var im=cw.content.application.new_image();
im.source=global.videos[i].thumbnail;
im.id="im"+i;
//im.addEvents("click");
im.y=6;im.x=4;
im.height=150;im.width=150;

// create a text object to show some text of the video
var text=cw.content.application.new_text();
text.htmlText=""+global.videos[i].title+""+"\n"+global.videos[i].description;
text.y=im.y;text.x=im.x+im.width+2;
text.height=100;
text.width=250;
text.setStyle("color", 0x000000);
text.id="text"+i;
text.truncateToFit=true;
//text.addEvents("click");
text.toolTip=global.videos[i].title+"\n"+global.videos[i].description;
text.mouseChildren=false;

/*
// create a play button
var but=cw.content.application.new_button();
but.label="play";
but.height=15;
but.x=90;but.y=140;
but.id="button"+i;
but.visible=false;
but.addEvents("click");
but.data=i;
*/

// create a canvas an locate every above object inside it
var can=cw.content.application.new_canvas();
can.setStyle("backgroundColor", 0xffffff);
can.setStyle("borderStyle", "none");
can.setStyle("borderColor", 0x000000);
can.setStyle("borderThickness", 1);
can.addChild(im);
//can.addChild(but); // si el boton es agregado despues del text inhibe el funcionamiento de los hyperlinks.
can.addChild(text);

can.height=im.y+im.height-30;
can.width=text.x+text.width+4;
can.id="canvVideoList_"+i;
// next line: the events of the canvas (rollover,rollOut, etc.) will begin with videoList prefix
can.addEvents("rollOver|rollOut|click|mouseWheel",'|','videoList');
can.hScrollPolicy("off");
can.vScrollPolicy("off");
can.buttonMode=true;

// add the canvas with its childrens to the container vBox
vb.addChild(can);
}


} // end of function buildVideoList


Friday, March 25, 2011

Creating dynamically user interfaces with the cWidgets widget

This post will show you: how to create dynamically user's interfaces using the cWidgets widget. This widget will let you create various different widgets like text inputs, buttons, combo boxes , check boxes, option buttons, radio buttons, etc.


The first step to use the cWidgets widget is ensure it is in the HB server. for more info about this read the post titled 'accessing databases with Hummingbird and scripting, part I', section 'uploading a widget to the hummingbird server'.
The cWidgets is visible only at design time.
On this case the page we are working on has the name database4. following is at design time:



database4_1 corresponds to the cWidget and database4_2 is a panel component. The code for the different events next:

imports event:

import mx.collections.ArrayCollection; // we need this to use ArrayCollections
import mx.controls.Alert; // needed if we want to show messages alerts

/*
we will use the next variable to syncronize the creation of
the widget cWidget in database4_1 with the creation of
the panel database4_2
*/
global.flag=0; // this variable will allow us to detect when the widget and the panel are created


// The next are needed for communication with the midleware
import Connection; // needed to connect with the midleware
/*
next we create an connection object and stored it in a global variable (con)
for later use
*/
global.con=page.newConnection();
// loading of the loadPolicy file in order to have acces to the remote call procedures
global.con.loadPolicyFile("http://alex.cl/WebServPortalFlex/crossdomain.xml");
// open the connection to the midleware (made with asp.net)
global.con.openConnection("http://alex.cl/WebServPortalFlex/Gateway.aspx");


database4_1_ready event:

global.flag++;
if (global.flag==2) // the widget and the panel are ready, so we create our interface
create_interface();

database4_2_onCreated event:

global.flag++;
if (global.flag==2) // the widget and the panel are ready, so we create our interface
create_interface();

functions event:

function create_interface()
{
/*
this function create our interface dynamically
*/

// get a reference to the cWidget
var o=page.findObject2("/database4_1");
if (o!=null)
{
// use the cWidget reference to create some objects

// create label 'name' and a textInput
var l1=o.content.application.new_label();
l1.text='Name';l1.x=10;l1.y=10;

var t1=o.content.application.new_textInput();
t1.x=60;t1.y=10;t1.width=150;

// create label 'email' and a textInput
var l2=o.content.application.new_label();
l2.text='Email';l2.x=10;l2.y=40;

var t2=o.content.application.new_textInput();
t2.x=60;t2.y=40;t2.width=150;

// create label 'subject' and a textInput
var l3=o.content.application.new_label();
l3.text='Subject';l3.x=10;l3.y=70;

var t3=o.content.application.new_textInput();
t3.x=60;t3.y=70;t3.width=150;

// create label 'recipient' and a comboBox
var l4=o.content.application.new_label();
l4.text="Recipient";l4.x=10;l4.y=110;

var c1=o.content.application.new_comboBox();
c1.editable=false;
c1.x=70;c1.y=110
var dataP=new ArrayCollection();
dataP.addItem({label:'General',data:'0'});
dataP.addItem({label:'Clients',data:'1'});
dataP.addItem({label:'IT dept.',data:'2'});
c1.dataProvider=dataP;
c1.addEvents("change");
c1.toolTip='select the recipient';
c1.height=20;
// apply some styles to the combo

c1.setStyle("cornerRadius", 4);
c1.setStyle("selectionColor", 0xffcc99);
c1.setStyle("rollOverColor", 0xffcc66);


//pa.addChild(o.content.application.new_checkBox());

// create textArea for the message
var t4=o.content.application.new_textArea();
t4.x=10;t4.y=140;t4.width=200;t4.height=100;

// create a 'send' button
var b1=o.content.application.new_button();
b1.label="Send";
b1.x=10;b1.y=260;
b1.toolTip='press this button to send the message';
b1.id="send";
b1.addEvents("click");

// create a 'clear' button
var b2=o.content.application.new_button();
b2.label="Clear";
b2.x=100;b2.y=260;
b2.toolTip='press this button to clear all the data';
b2.id="clear";
b2.addEvents("click");

// we will add the above objects inside a panel
// we get a reference to the panel
var pa=page.findObject2("/database4_2");
if (pa!=null)
{
// now we add the just created objects to the panel
pa.addChild(l1);
pa.addChild(l2);
pa.addChild(l3);

pa.addChild(t1);
pa.addChild(t2);
pa.addChild(t3);
pa.addChild(l4);
pa.addChild(c1);
pa.addChild(t4);


pa.addChild(b1);
pa.addChild(b2);

/*
save references to texinputs, combobox and textarea into
global variables for use in others events
*/
global.t1=t1;
global.t2=t2;
global.t3=t3;
global.c1=c1;
global.t4=t4;

}

}


} // end of function create_interface


On the above script you must notice the line where i put an id to the buttons and the line using the addEvents method. These lines will allow us work with the click events of the both buttons in order to detect when the user click the 'send' or 'clear' button, like you will see later.

These are all our events for the moment. you can see them on the scripts window next:






At this point you will have the interface, but it don't make anything when the user press the buttons, for that you will need add the next event:

database4_1_buttonClick event:

/*
this event script will be called for all the click events of the
buttons created with the cWidget database4_1
you can identify every button for its id property like showed below
*/

switch(me.id)
{
case 'send':
// send button pressed

var name=global.t1.text;
var email=global.t2.text;
var subject=global.t3.text;
var recipient=global.c1.selectedLabel;
var message=global.t4.text;

// you must validate the data according some criteria

// after validation you proceed to send the message
global.con.call("WebServPortalFlex.servicios.sendMail","serverResponse","serverError",name,email,subject,recipient,message);
break;
case 'clear':
// clear button pressed
global.t1.text="";
global.t2.text="";
global.t3.text=""
global.c1.selectedIndex=0;
global.t4.text="";
break;
}

serverResponse event:

Alert.message("your message was sended");

serverError event:

Alert.message("there was an error trying to send your message");


On the sample showed on this post you must create the midleware code that receive the data from the HB page and send the email, using (on this case) asp.net. if you need more info about creating the midleware layer with asp.net read the post titled "Accessing databases with hummingbird and scripting part II".
A nice thing about locate the interface inside the panel is that you can move the panel with the mouse on the designer, in order to locate all the interface inside it where you want. :)


Wednesday, March 9, 2011

Creating menus with the hb_menuBar widget

This post will show you: how to create dinamically menus using the hb_menuBar widget like showed on the next picture:


The hb_menuBar widget let you create menu bars which contains drop down menus. This menus are defined using a simple xml syntax, and you can control the appearance of the menu using styles.
You can create as many menuBars like you need using the same hb_menuBar widget.

The first step is upload the hb_menuBar widget to the HB server, for an explanation about how to upload a widget read the post entitled 'Accessing databases with Hummingbird and scripting part I' and the section entitled 'Uploading a widget to the Hummingbird server'.

Once you have upload the hb_menuBar widget to the HB server. you must put the widget onto a HB page, like showed on this picture:


On the above image you can see the widget on the upper right corner. This widget is only visible at design time.
The steps to create a menuBar using the hb_menuBar widget:
- get access to the instance of hb_menuBar widget.
- create a new instance of a menu using the instance of the hb_menuBar.
- set the options of the menu with xml using the setXml method of the widget.
- set some properties like the width, height, etc.
- set some styles for the menu in order to change its appearance.
- add the menu instance to a container (using the addChild method) in order to make it visible to the user. this container could be the page object (page.content.addChild) or a panel object that is visible to the user.

following is the code corresponding to every step described:

// get access to the menuBar widget instance
var mb=page.findObject2("/database2_2");
// create a new menu using the hb_menuBar instance
var m=mb.content.application.new_menu();
/*
set the options of the menu into a string variable with xml
in the xml string the 'label' attribute is the text for the menu's option and the 'data' attribute is used to identify the option selected for the user
*/
var menus=''+
' <root>'+
' <menuitem label="Home" data="1"/>'+
' <menuitem label="Products" data="0">'+
' <menuitem label="Cms software" data="2"/>'+
' <menuitem label="CMR" data="3"/>'+
' </menuitem>'+
' <menuitem label="About us" data="0">'+
' <menuitem label="Who we are" data="4"/>'+
' <menuitem label="Clients" data="5"/>'+
' <menuitem label="Partners" data="6"/>'+
' </menuitem>'+
' <menuitem label="Contact" data="0"> '+
' <menuitem label="Send us a message" data="7"/>'+
' <menuitem label="Address" data="8"/>'+
' </menuitem>'+
' </root>';


m.setXml(menus); // pass the xml with the options to the widget

// set the width of the menu to 100 percent of its container
m.percentWidth='100';
//m.height=30; // set the height of the menu

// set some styles for the menu
m.setStyle('cornerRadius', 0);
m.setStyle('letterSpacing', 1);
m.setStyle('fillColors',[0x3333ff, 0x0066ff]);
m.setStyle('rollOverColor',0x0033cc);
m.setStyle('color', 0xffffff);
m.setStyle('textRollOverColor', 0xffffff);
m.setStyle('themeColor', 0x0066ff);
m.setStyle('fontFamily', 'Times New Roman');;
m.setStyle('fontSize', 20);
m.setStyle('fontWeight', 'normal');
m.setStyle('fontStyle', 'italic');
m.setStyle('textIndent', 0);
m.setStyle('borderColor', 0x333399);
m.setStyle('borderStyle','none');
m.setStyle('fillAlphas',[1, 1]);
// we set the background color for the dropdown menus
var ms=new CSSStyleDeclaration(".myMenuBar"); // we create a CSS
ms.setStyle("backgroundColor",0x000000);
//ms.setStyle("backgroundAlpha",0.5);
m.setStyle('menuStyleName',"myMenuBar");


/*
add the menu to a panel, remember that the menu width
will be 100 percent of the width of its container, on this case
the container is the panel
*/
var o=page.findObject2("/database2_3"); // get a reference to the panel
if (o!=null)
{
// if you need center the menu onto the page uncomment the next line
//o.parent.x=page.content.width/2-o.parent.width/2;
o.addChild(m); // add the menuBar to the panel

}


we write the above code in the ready event of the hb_menuBar widget, like showed here:


The reason why we put the above code on the ready event of the widget is this:
Every widget triggers a 'ready' event when is initialized, let say when is just created, so this event is the ideal place to put our code in order to create a widget's instance when the page is just loaded into the user's browser, because that will be the moment when our widget will be created and the 'ready' event will be triggered. You must take into account that the video, the text, the panel and the picture are not widgets, they are built-in components and they don't trigger a 'ready' event, but if you need to execute some code when these built-in components are just created you can use the 'onCreated' event of the built-in component.

after follow the steps described above you will have a nice menuBar on your HB page. But there is a question for resolve and is ¿ how do you execute an action when the user selects an option ?.
This is simple: when the user selects an option the widget will trigger and event called 'menuClick' and it passes to the event a parameter called 'data' which corresponds to the 'data' attribute defined for you on the xml string for the menu. watch the following code located in the menuClick event of the hb_menuBar widget:

/*
this event is triggered when a user makes click on some option
of the menu, every option must have a data property which is passed
to this event in the info.data parameter, so you will know what option
was clicked by watching for this data
*/

if (info.data==0)
return;
// show a little message with the data attribute of the option selected
Alert.show("option choosed:"+info.data);
// now you must exec some action in response to the selected option
switch (info.data)
{
case '1': // home

break;
case '2': // cms software

break;
case '3': // cmr

break;
case '4': // who we are

break;
default: // others options

break;
};

you will see the above code on this picture:


That is, now you have completed all the steps to have a nice menuBar on your page. :)

a nice feature about the menuBar widget is that you can change the options of the menu at runtime, lets say you can add, replace o remove any option of the menu to adapt the menu according some criteria, like for example the perfil of the user that visits the page. You can disable an option using the 'enabled' attribute with a value of false.
On the next picture you can see how using a button labeled 'change menu' we change the options of the menu when the visitor click on the button:


On the above picture you see how we added a last line of code to the 'ready' event of the hb_menuBar widget (database2_2_ready) in order to store a reference to the menu. this reference will allow us modify the menu in other events. On this case we will change the menu's options in the click event of the button 'database2_4' . you can see the code of the event on the next picture:



On the image you can see that using the setXml method of the menuBar with a new set of options the menu is refreshed automatically on the page. watch that we are using the 'enabled' attribute with a value of false to disable the option labeled 'CMR'.
On the next image you can see the menu with the new options set, just after we clicked the 'change menu' button:


A last note above the hb_menuBar widget: you can control the transparency level of the drop down menus, like you see on this picture:



nice :)