Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Front-End Web Development

341 Articles
article-image-user-authentication-codeigniter-17-using-facebook-connect
Packt
21 May 2010
8 min read
Save for later

User Authentication with Codeigniter 1.7 using Facebook Connect

Packt
21 May 2010
8 min read
(Read more interesting articles on CodeIgniter 1.7 Professional Development here.) Registering a Facebook application You need to register a new Facebook Application so that you can get an API key and an Application Secret Key. Head on over to www.facebook.com/developers/ and click on the Set up New Application button in the upper right–hand corner. This process is very similar to setting up a new Twitter application which we covered in the previous article, so I won't bore you with all of the details. Once you've done that, you should have your API key and Application Secret Key. These two things will enable Facebook to recognize your application. Download the Client library When you are on your applications page showing all your applications' information, scroll down the page to see a link to download the Client Library. Once you've downloaded it, simply untar it. There are two folders inside the facebook-platform folder, footprints and php. We are only going to be using the php folder. Open up the php folder; there are two files here that we don't need, facebook_desktop.php and facebook_mobile.php—you can delete them. Finally, we can copy this folder into our application. Place it in the system/application/libraries folder, and then rename the folder to facebook. This helps us to keep our code tidy and properly sorted. Our CodeIgniter Wrapper Before we start coding, we need to know what we need to code in order to make the Facebook Client Library work with our CodeIgniter installation. Our Wrapper library needs to instantiate the Facebook class with our API Key and Secret Application Key. We'll also want it to create a session for the user when they are logged in. If a session is found but the user is not authenticated, we will need to destroy the session. You should create a new file in the system/application/libraries/ folder, called Facebook_connect.php. This is where the Library code given next should be placed. Base class The Base Class for our Facebook Connect Wrapper Library is very simple: <?phprequire_once(APPPATH . 'libraries/facebook/facebook.php');class Facebook_connect{ var $CI; var $connection; var $api_key; var $secret_key; var $user; var $user_id; var $client;}?> The first thing that our Library needs to do is to load the Facebook library—the one we downloaded from facebook.com. We build the path for this by using APPPATH, a constant defined by CodeIgniter to be the path of the application folder. Then, in our Class we have a set of variables. The $CI variable is the variable in which we will store the CodeIgniter super object; this allows us to load CodeIgniter resources (libraries, models, views, and so on) in our library. We'll only be using this to load and use the CodeIgniter Session library, however. The $connection variable will contain the instance of the Facebook class. This will allow us to grab any necessary user data and perform any operations that we like, such as updating a user's status or sending a message to one of their friends. The next few variables are pretty self-explanatory—they will hold our API Key and Secret Key. The $user variable will be used to store all of the information about our user, including general details about the user such as their profile URL and their name. The $user_id variable will be used to store the user ID of our user. Finally, the $client variable is used to store general information about our connection to Facebook, including the username of the user currently using the connection, amongst other things such as server addresses to query for things like photos. Class constructor Our class constructor has to do a few things in order to allow us to authenticate our users using Facebook Connect. Here's the code: function Facebook_connect($data){ $this->CI =& get_instance(); $this->CI->load->library('session'); $this->api_key = $data['api_key']; $this->secret_key = $data['secret_key']; $this->connection = new Facebook($this->api_key, $this->secret_key); $this->client = $this->connection->api_client; $this->user_id = $this->connection->get_loggedin_user(); $this->_session();} The first line in our function should be new to everyone reading this article. The function get_instance() allows us to assign the CodeIgniter super object by reference to a local variable. This allows us to use all of CodeIgniter's syntax for loading libraries, and so on; but instead of using $this->load we would use $this->CI->load. But of course it doesn't just allow us to use the Loader—it allows us to use any CodeIgniter resource, as we normally would inside a Controller or a Model. The next line of code gives us a brilliant example of this: we're loading the session library using the variable $this->CI rather than the usual $this. The next two lines simply set the values of the API key and Secret Application Key into a class variable so that we can reference it throughout the whole class. The $data array is passed into the constructor when we load the library in our Controller. More on that when we get there. Next up, we create a new instance of the Facebook Class (this is contained within the Facebook library that we include before our own class code) and we pass the API Key and Secret Application Key through to the class instance. This is all assigned to the class variable $this->connection, so that we can easily refer to it anywhere in the class. The next two lines are specific parts of the overall Facebook instance. All of the client details and the data that helps us when using the connection are stored in a class variable, in order to make it more accessible. We store the client details in the variable $this->client. The next line of code stores all of the details about the user that were provided to us by the Facebook class. We store this in a class variable for the same reason as storing the client data: it makes it easier to get to. We store this data in $this->user_id. The next line of code calls upon a function inside our class. The underscore at the beginning tells CodeIgniter that we only want to be able to use this function inside this class; so you couldn't use it in a Controller, for example. I'll go over this function shortly. _session(); This function manages the user's CodeIgniter session. Take a look at the following code: function _session(){ $user = $this->CI->session->userdata('facebook_user'); if($user === FALSE && $this->user_id !== NULL) { $profile_data = array('uid','first_name', 'last_name', 'name', 'locale', 'pic_square', 'profile_url'); $info = $this->connection->api_client-> users_getInfo($this->user_id, $profile_data); $user = $info[0]; $this->CI->session->set_userdata('facebook_user', $user); } elseif($user !== FALSE && $this->user_id === NULL) { $this->CI->session->sess_destroy(); } if($user !== FALSE) { $this->user = $user; }} This function initially creates a variable and sets its value to that of the session data from the CodeIgniter session library. Then we go through a check to see if the session is empty and the $this->user_id variable is false. This means that the user has not yet logged in using Facebook Connect. So we create an array of the data that we want to get back from the Facebook class, and then use the function users_getInfo() provided by the class to get the information in the array that we created. Then we store this data into the $user variable and create a new session for the user. The next check that we do is that if the $user variable is not empty, but the $this->user_id variable is empty, then the user is not authenticated on Facebook's side so we should destroy the session. We do this by using a function built in to the Session Library sess_destroy(); Finally, we check to see if the $user variable is not equal to FALSE. If it passes this check, we set the $this->user class variable to that of the local $user variable.
Read more
  • 0
  • 0
  • 1829

article-image-user-authentication-codeigniter-17-using-twitter-oauth
Packt
21 May 2010
6 min read
Save for later

User Authentication with Codeigniter 1.7 using Twitter oAuth

Packt
21 May 2010
6 min read
(Read more interesting articles on CodeIgniter 1.7 Professional Development here.) How oAuth works Getting used to how Twitter oAuth works takes a little time. When a user comes to your login page, you send a GET request to Twitter for a set of request codes. These request codes are used to verify the user on the Twitter website. The user then goes through to Twitter to either allow or deny your application access to their account. If they allow the application access, they will be taken back to your application. The URL they get sent to will have an oAuth token appended to the end. This is used in the next step. Back at your application, you then send another GET request for some access codes from Twitter. These access codes are used to verify that the user has come directly from Twitter, and has not tried to spoof an oAuth token in their web browser. Registering a Twitter application Before we write any code, we need to register an application with Twitter. This will give us the two access codes that we need. The first is a consumer key, and the second is a secret key. Both are used to identify our application, so if someone posts a message to Twitter through our application, our application name will show up alongside the user's tweet. To register a new application with Twitter, you need to go to http://www.twitter.com/apps/new. You'll be asked for a photo for your application and other information, such as website URL, callback URL, and a description, among other things. You must select the checkbox that reads Yes, use Twitter for login or you will not be able to authenticate any accounts with your application keys. Once you've filled out the form, you'll be able to see your consumer key and consumer secret code. You'll need these later. Don't worry though; you'll be able to get to these at any time so there's no need to save them to your hard drive. Here's a screenshot of my application: Downloading the oAuth library Before we get to write any of our CodeIgniter wrapper library, we need to download the oAuth PHP library. This allows us to use the oAuth protocol without writing the code from scratch ourselves. You can find the PHP Library on the oAuth website at www.oauth.net/code. Scroll down to PHP and click on the link to download the basic PHP Library; or just visit: http://oauth.googlecode.com/svn/code/php/—the file you need is named OAuth.php. Download this file and save it in the folder system/application/libraries/twitter/—you'll need to create the twitter folder. We're simply going to create a folder for each different protocol so that we can easily distinguish between them. Once you've done that, we'll create our Library file. Create a new file in the system/application/libraries/ folder, called Twitter_oauth.php. This is the file that will contain functions to obtain both request and access tokens from Twitter, and verify the user credentials. The next section of the article will go through the process of creating this library alongside the Controller implementation; this is because the whole process requires work on both the front-end and the back-end. Bear with me, as it could get a little confusing, especially when trying to implement a brand new type of system such as Twitter oAuth. Library base class Let's break things down into small sections. The following code is a version of the base class with all its guts pulled out. It simply loads the oAuth library and sets up a set of variables for us to store certain information in. Below this, I'll go over what each of the variables are there for. <?phprequire_once(APPPATH . 'libraries/twitter/OAuth.php');class Twitter_oauth{ var $consumer; var $token; var $method; var $http_status; var $last_api_call;}?> The first variable you'll see is $consumer—it is used to store the credentials for our application keys and the user tokens as and when we get them. The second variable you see on the list is $token—this is used to store the user credentials. A new instance of the oAuth class OAuthConsumer is created and stored in this variable. Thirdly, you'll see the variable $method—this is used to store the oAuth Signature Method (the way we sign our oAuth calls). Finally, the last two variables, $http_status and $last_api_call, are used to store the last HTTP Status Code and the URL of the last API call, respectively. These two variables are used solely for debugging purposes. Controller base class The Controller is the main area where we'll be working, so it is crucial that we design the best way to use it so that we don't have to repeat our code. Therefore, we're going to have our consumer key and consumer secret key in the Controller. Take a look at the Base of our class to get a better idea of what I mean. <?phpsession_start();class Twitter extends Controller{ var $data; function Twitter() { parent::Controller(); $this->data['consumer_key'] = ""; $this->data['consumer_secret'] = "";} The global variable $data will be used to store our consumer key and consumer secret. These must not be left empty and will be provided to you by Twitter when creating your application. We use these when instantiating the Library class, which is why we need it available throughout the Controller instead of just in one function. We also allow for sessions to be used in the Controller, as we want to temporarily store some of the data that we get from Twitter in a session. We could use the CodeIgniter Session Library, but it doesn't offer us as much flexibility as native PHP sessions; this is because with native sessions we don't need to rely on cookies and a database, so we'll stick with the native sessions for this Controller.
Read more
  • 0
  • 0
  • 2770

article-image-building-image-slideshow-using-scripty2
Packt
20 May 2010
10 min read
Save for later

Building an Image Slideshow using Scripty2

Packt
20 May 2010
10 min read
In our previous Scripty2 article, we saw the basics of the Scripty2 library, we saw the UI elements available, the fx transitions and some effects. We even build an small example of a image slide effect. This article is going to be a little more complex, just a little, so we are able to build a fully working image slideshow. If you haven't read our previous article, it would be interesting and useful if you do so before continuing with this one. You can find the article here: Scripty2 in Action Well, now we can continue. But first, why don't we take a look at what we are going to build in this article: As we can see in the image we have three main elements. The biggest one will be where the main images are placed, there is also one element where we will make the slide animation to take place. There's also a caption and some descriptive text for the image and, to the right, we have the miniatures slider, clicking on them will make the main image to also slide out and the new one to appear. Seems difficult to achieve? Don't worry, we will make it step by step, so it's very easy to follow. Our main steps are going to be these: First we we will create the html markup and css necessary, so our page looks like the design. Next step will be to create the slide effect for the available images to the right. And our final step will be to make the thumbnail slider to work. Good, enough talking, let's start with the action. Creating the necessary html markup and css We will start by creating an index.html file, with some basic html in it, just like this: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xml_lang="es-ES" lang="es-ES" ><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>Scripty2</title><link rel="stylesheet" href="css/reset.css" type="text/css" /><link rel="stylesheet" href="css/styles.css" type="text/css" /> </head><body id="article"> <div id="gallery"> </div> <script type="text/javascript" src="js/prototype.s2.min.js"></script> </body></html> Let's take a look at what we have here, first we are including a reset.css file, this time, for a change, we are going to use the Yahoo one, which we can find in this link: http://developer.yahoo.com/yui/3/cssreset/ We will create a folder called css, and a reset.css file inside it, where we will place the yahoo code. Note that we could also link the reset directly from the yahoo site: <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.1.1/build/cssreset/reset-min.css"> Just below the link to the reset.css file, we find a styles.css file. This file will be the place where we are going to place our own styles. Next we find a div: <div id="gallery"> </div> This will be our placeholder for the entire slideshow gallery. Then one last thing, the link to the Scripty2 library: <script type="text/javascript" src="js/prototype.s2.min.js"></script> Next step will be to add some styles in our styles.css file: html, body{ background-color: #D7D7D7; }#gallery{ font-family: arial; font-size: 12px; width: 470px; height: 265px; background-color: #2D2D2D; border: 1px solid #4F4F4F; margin: 50px auto; position: relative;} Mostly, we are defining a background colour for the page, and then some styles for our gallery div like its width, height, margin and also a background colour. With all this our page will look like the following screenshot: We will need to keep working on this, first in our index.html file, we need a bit more of code: <div id="gallery"> <div id="photos_container"> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> </div> <div id="text_container"> <p><strong>Lorem Ipsum</strong><br/>More lorem ipsum but smaller text</p> </div> <div id="thumbnail_container"> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> </div></div> We have placed three more divs inside our main gallery one. One of them would be the photos-photos_container, where we place our big photos. The other two will be one for the text- text_container, and the other for the thumbnail images, that will be thumbnail_container. After we have finished with our html, we need to work with our css. Remember we are going to do it in our styles.css: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; overflow: hidden;}#text_container{ width: 377px; height: 55px; background-color: #000000; color: #ffffff; position: absolute; z-index: 2; bottom: 9px; left: 9px;}#text_container p{ padding: 5px; }#thumbnail_container{ width: 75px; height: 247px; background-color: #000000; position: absolute; z-index: 3; top: 9px; right: 9px;}#thumbnail_container img{ margin: 13px 13px 0px 13px; }strong{ font-weight: bold; } Here we have added styles for each one of our divs, just quite basic styling for the necessary elements, so our page now looks a bit more like the design: Though this looks a bit better than before, it still does nothing and that's going to be our next step. Creating the slide effect First we need some modifications to our html code, this time, though we could use id tags in order to identify elements, we are going to use rel tags. So we can see a different way of doing things. Let's then modify the html: <div id="photos_container"> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="1"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="2"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="3"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="4"/> </div> <div id="text_container"> <p><strong>Lorem Ipsum</strong><br/>More lorem ipsum but smaller text</p> </div> <div id="thumbnail_container"> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="1"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="2"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="3"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="4"/> </div> Note the difference, we have added rel tags to each one of the images in every one of the divs. Now we are going to add a script after the next line: <script type="text/javascript" src="js/prototype.s2.min.js"></script> The script is going to look like this: <script type="text/javascript"> $$('#thumbnail_container img').each(function(image){ image.observe('click', function(){ $$('#photos_container img[rel="'+this. readAttribute('rel')+'"]').each(function(big_image){ alert(big_image.readAttribute('title')); }) }); });</script> First we select all the images inside the #thumbnail_container div: $$('#thumbnail_container img') Then we use the each function to loop through the results of this selection, and add the click event to them: image.observe('click', function(){ This event will fire a function, that will in turn select the bigger images, the one in which the rel attribute is equal to the rel attribute of the thumbnail: $$('#photos_container img[rel="'+this.readAttribute('rel')+'"]').each(function(big_image){ We know this will return only one value, but as the selected could, theoretically, return more than one value, we need to use the each function again. Note that we use the this.readAttribute('rel') function to read the value of the rel attribute of the thumbnail image. Then we use the alert function to show the title value of the big image: alert(big_image.readAttribute('title')); If we now click on any of the thumbnails, we will get an alert, just like this: We have done this just to check if our code is working and we are able to select the image we want. Now we are going to change this alert for something more interesting. But first, we need to do some modifications to our styles.css file, we will modify our photos container styles: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; overflow: hidden; position: relative;} Only to add the position relate in it, this way we will be able to absolute position the images inside it, adding these styles: #photos_container img{ position: absolute;} With these changes we are done with the styles for now, return to the index.html file, we are going to introduce some modifications here too: <script type="text/javascript" src="js/prototype.s2.min.js"></script> <script type="text/javascript"> var current_image = 1; $$('#photos_container img').each(function(image){ var pos_y = (image.readAttribute('rel') * 247) - 247; image.setStyle({top: pos_y+'px'}); })... I've placed the modifications in bold, so we can concentrate on them. What have we here? We are creating a new variable, current_image, so we can save which is the current active image. At page load this will be the first one, so we are placing 1 to its value. Next we loop through all of the big images, reading its rel attribute, to know which one of the images are we working with. We are multiplying this rel attribute with 247, which is the height of our div. We are also subtracting 247 so the first image is at 0 position. note Just after this, we are using prototype's setStyle function to give each image its proper top value. Now, I'm going to comment one of the css styles: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; //overflow: hidden; position: relative;} You don't need to do this, I' will do it for you, so we can see the result of our previous coding, and then I will turn back and leave it as it was before, prior to continuing. So our page would look like the next image: As we see in the image, all images are one on top of the others, this way we will be able to move them in the y axis. We are going to achieve that by modifying this code: $$('#thumbnail_container img').each(function(image){ image.observe('click', function(){ $$('#photos_container img[rel="'+this. readAttribute('rel')+'"]').each(function(big_image){ alert(big_image.readAttribute('title')); }) }); });
Read more
  • 0
  • 0
  • 8760
Banner background image

article-image-scripty2-action
Packt
30 Apr 2010
13 min read
Save for later

Scripty2 in Action

Packt
30 Apr 2010
13 min read
(For more resources on Scripty2, see here.) Introduction to Scripty2 Some years ago the web started to see, with great amazement, the born of many JavaScript libraries. Most of them really helped us developers in working with JavasScript code, making life easier, and coding more fun and efective. Some names that usually come to our minds are jQuery, MooTools, dojo, prototype, and surely many, many others. Among these, surely we can remember one called script.aculo.us. It's not only about the cool name, but the great features it brings along with it. Now Thomas Fuchs, the developer behind script.aculo.us, is announcing a newer version. This time called Scripty2, and most interesting of all, this is a full rewrite, every line of code is new, with a big emphasis on making things better, faster and yet easy to use. The three parts in which Scripty2 is divided is: Core Fx Ui We are going to take a quick glance to Fx and Ui, so you can see some of their impressive features. First steps, downloading and placing the necessary code. In order to download the library we need to go to http://scripty2.com/ here we will see an image just like the next one: Clicking on it will result in the file being downloaded, and when the download finishes, we will be able to unzip it. Inside there are three more folders, and the necessary license documents. These folders are: dist → we can find inside this folder the files we will need for the article. doc → the documentation for the library, equal to the online one, but we can check it while offline. However, it's advisable to check the online documentation when possible, as it will be more up to date. src → here we can find the source files for the library, each part of the library being on a separate file. For the Scripty2 library to work, we will also need to included the prototype library, which is also included in the package. But we have another option, that's to include a file called prototype.s2.min.js. This file includes both libraries in it. Summarizing it, if we want to use the Scripty2 libray we have 2 options, to include both libraries separately or simply include prototype.s2.min.js: <script type="text/javascript" src="js/prototype.js"></script> <script type="text/javascript" src="js/s2.js"></script> Note that we are including the prototype-one first, as Scripty2 needs it. The second option, and the one we are going to follow in this article is: <script type="text/javascript" src="js/prototype.s2.min.js"></script> Now, let's take a look at what will be our base structure, first we will have a index.html file, with this code in it: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xml_lang="es-ES" lang="es-ES" ><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>Scripty2</title><link rel="stylesheet" href="css/reset.css" type="text/css" /><link rel="stylesheet" href="css/styles.css" type="text/css" /> </head><body> <script type="text/javascript" src="js/prototype.s2.min.js"></script> </body></html> Note that we have our JavaScript file placed at the end of the code, this is usually better for performance. This JavaScript file is located in a folder called js. We have also included two css files, one styles.css, which is empty for now. And the other one is reset.css . I like to use Eric Meyer's css reset which you can find it here:http://meyerweb.com/eric/tools/css/reset/. And that's all we need for now. We are ready to go, we will start with the UI part. Scripty2 UI The Scripty2 includes some very interesting UI controls, like accordion, tabs, autocompleter and many others. I think we could start with the accordion one, as it will make a nice example. Accordion For this we will need to add some code to our index.html file, a good start would be something like this: <body> <div id="tabs_panel"> <ul> <li><a href="#tab1">Sample tab</a></li> <li><a href="#tab2">Another tab</a></li> <li><a href="#tab3">And another one</a></li> </ul> <div id="tab1">1.- This will be the content for the first tab.</div> <div id="tab2">2.- And here we can find the content for the second one.</div> <div id="tab3">3.- Of course we are adding some content to the third one.</div></div> What have we done here? Just three things: First we have created a tabs_panel div, inside which we will place the necessary code for tabs. It will be our container. Next we have placed three div elements, with a link element inside each one, targeting a div. Inside each link, we find the title for the tab. Finally we have placed the final divs, with the ids corresponding to these ones that where being targeted by the previous links. It will be in these divs that we will place the content for each tab. Once we have this code in place we need something more to do the work, as this alone won't do anything. We need to make the necessary Scripty2 function call: ... <div id="tab3">3.- Of course we are adding some content to the third one.</div> </div> <script type="text/javascript" src="./js/prototype.s2.min.js"></script><script type="text/javascript"> new S2.UI.Tabs('tabs_panel');</script> Easy, isn't it? We just need to add this call new S2.UI.Tabs('tabs_panel'); which targets our previously created div. Would this be enough? Let's take a look: It seems nothing has happened, but that's far from true; if we check our page using Firebug, we will see something like the next image: Want to learn more about Firebug? Check this Packt article: http://www.packtpub.com/article/installation-and-getting-started-with-firebug. As we can see in the image, a whole bunch of css classes have been added to our quite simple html code. These classes are responsible for the tabs to work, does that mean that we have to create all of them? Well, not really. Luckily for us, we can use jQuery UI themes for this. Yes, that's it, just go to this url: http://jqueryui.com/themeroller/ And download your favourite one, from the gallery panel: For example, I'm going to download the Hot sneaks one: Once downloaded, we will be able to find the styles we need, inside the packaged file. If we unzip the file we will see these folders: css development-bundle js index.html Opening the css folder we will see a folder called hot-sneaks, or the name of the theme you have downloaded. We will copy the entire folder into our own css folder. Thus we will have this structure: css hot-sneaks reset.css styles.css Inside the hot-sneaks folder there's a file called jquery-ui-1.8.custom.css , we need to link this file in our index.html one, we will add these modifications: … <title>Scripty2</title> <link rel="stylesheet" href="css/reset.css" type="text/css" /> <link rel="stylesheet" href="css/hot-sneaks/jquery-ui-1.8.custom.css" type="text/css" /> <link rel="stylesheet" href="css/styles.css" type="text/css" /> ... But before taking a look at the result of these changes, we still need to do some modifications, this time in our own styles.css file: body{ padding: 10px; }#tabs_panel{ width:350px; font-size: 12px;} And we are done! Our site will look mostly like this: In the image, we can see the three possible states of the tabs: Normal tab Active tab Hover tab It was easy to achieve, isn't it? Next example will be a text autocompleter, stay with us! Text Autocompleter In this example, we are going to use another of the Scripty2 nice feature, this time to build a text autocompleter. This can be used to enhance site search, and it's pretty easy to achieve, thanks to Scripty2. First we need to add the necessary markup in our index.html file: … <div id="tab3">3.- Of course we are adding some content to the third one.</div> </div> <br/><br/> <div id="text_autocompleter"> <input type="text" name="demo" /> </div>... Not much added here, just another container div, and an input, so we can write in it. We now need our JavasCript code to make this work: new S2.UI.Tabs('tabs_panel'); var favourite = [ 'PHP', 'Ruby', 'Python', '.NET', 'JavaScript', 'CSS', 'HTML', 'Java' ]; new S2.UI.Autocompleter('text_autocompleter', { choices: favourite }); </script> … First what we need to do is to create an array of possible values, and then we call the Autocompleter method, with two parameters, first the div we are targetting, and then the array of values. Also we are going to modify our styles.css file, just to add some styling to our text_autocompleter div: ...#tabs_panel, #text_autocompleter{ width:350px; ... If we check our page after these changes, it will be looking this: If we try to enter some text, like a p in the example, we will see how options appear in the box under the input. If we do click on the option, the input box will be filled: Just after we select our desired option the suggestions panel will disappear, as it will do if we click outside the input box. Note that if the theme we are using lacks the ui-helper-hidden class, the suggestions panel won't dissapear. But don't worry, solving this is as easy as adding this class to our styles.css file: .ui-helper-hidden{    visibility: hidden;    } And we are done, now lets see an example about the accordion control. Accordion This is quite similar to the tabs example, quite easy too, first, as always, we are going to add some html markup to our index.html file: <div id="accordion"> <h3><a href="#">Sample tab</a></h3> <div> 1.- This will be the content for the first tab. </div> <h3><a href="#">Another tab</a></h3> <div> 2.- And here we can find the content for the second one. </div> <h3><a href="#">And another one</a></h3> <div> 3.- Of course we are adding some content to the third one. </div> </div> Good, this will be enough for now. We have a container div, where we are placing the necessary elements, each h3 element, with links inside, will be the headings, and the divs will be the contents for each tab. Let's add some styles in our styles.css file: #tabs_panel, #text_autocompleter, #accordion{ width:350px; font-size: 12px;}#accordion h3 a{ padding-left: 30px; } I've placed the necessary changes in bold. Now to the JavaScript code, we will add this in our index.html file: … new S2.UI.Accordion('accordion'); </script> ... The first parameter will be the id of our container div, for now, we don't need anything more. How does all this look like? Just take a look: Good, clicking on each one of the headings will result in closing the current tab and opening the clicked one. But, what if we want to be able to open each clicked tab, but without closing the others? Well, thanks to Scripty2 we can also achieve that. We only need to make some small modifications to the JavaScript call: …new S2.UI.Accordion('accordion', { multiple: true }); </script> … As we see, the second parameter for our accordion function can receive some options, this time we are selecting multiple to true. This way our accordion tabs won't close: In the previous image we can see all our tabs open, but we have some more options, let's see them. The first one will help us define our prefered header selector. As our code is now we are using h3 elements: <h3><a href="#">Sample tab</a></h3> <div> 1.- This will be the content for the first tab.</div>   But what if we wanted to use h1 elements? Well, it won't be very hard, just a tiny add to our JavaScript code: new S2.UI.Accordion('accordion', { multiple: true, headerSelector: 'h1' }); The last option we are going to see is the icons one, by default, this option will use these values: icons: { header:'ui-icon-triangle-1-e',headerSelected: 'ui-icon-triangle-1-s' } Where do these icons come from? Well, these little icons are from the theme we downloaded, and we have plenty of them to use. If you open the theme package, the one we downloaded at the start of the article, and we click on the index.html file, we will be able to see a demo of all styles included in the package. More or less at the bottom we will see a group of tiny icons:   If we hover over these little icons, its name will appear, and that's what we can use to change our options. So in our index.html file, we could change our JavaScript code just like this: new S2.UI.Accordion('accordion', { multiple: true, headerSelector: 'h1', icons: { header: 'ui-icon-circle-plus', headerSelected: 'ui-icon-circle-minus' } }); We define one option for the headers, and other for the selected one, how will this look like:   And with this option we have seen all the three available. With them we can customize our accordion as we wish. Summarizing, we have found that the Scripty2 library includes some very useful UI controllers. We have seen some of them, but there are many others, such as: Buttons → Scripty2 helps us in creating good looking buttons. Not only normal buttons, but also buttons that behave as checkboxes, or even radio buttons. Dialog → There are also some functions in the Scripty2 library that will help us in creating modal dialog boxes, with the contents we want. Slider → If at anytime we are in need of creating a slider, be it for moving the contents of a div, for creating an image gallery or for creating an interesting price filter, it is pretty easy with Scripty2. Progress bar → This one is pretty interesting, as will help us in the task of developing an animated progress bar, very nice! Now we will be taking a look at another interesting part of the library, the FX one.
Read more
  • 0
  • 0
  • 1717

article-image-network-based-ubuntu-installations
Packt
08 Mar 2010
4 min read
Save for later

Network Based Ubuntu Installations

Packt
08 Mar 2010
4 min read
I will first outline the requirements and how to get started with a network installation. Next I will walk through a network installation including screenshots for every step. I will also include text descriptions of each step and screenshot. Requirements In order to install a machine over the network you'll need the network installer image. Unfortunately these images are not well publicized, and rarely listed alongside the other .ISO images. For this reason I have included direct download links to the 32bit and 64bit images. It is important that you download the network installer images from the same mirror that you will be installing from. These images are often bound to the kernel and library versions contained within the repository, and a mismatch will cause a failed installation. 32 bit http://archive.ubuntu.com/ubuntu/dists/karmic/main/installer-i386/current/images/netboot/mini.iso 64bit http://archive.ubuntu.com/ubuntu/dists/karmic/main/installer-amd64/current/images/netboot/mini.iso If you'd prefer to use a different repository, simply look for the "installer-$arch" folder within the main folder of the version you'd like to install. Once you've downloaded your preferred image you'll need to write the image to a CD. This can be done from an existing Linux installation (Ubuntu or otherwise), by following the steps below: Navigate to your download location (likely ~/Downloads/) Right-click on the mini.iso file Select Write to Disk... This will present you with an ISO image burning utility. Simply verify that it recognizes a disk in your CD writer, and that it has selected the mini.iso for writing. An image of this size (~12M) should only take a minute to write. If possible, you may want to burn this image to a business card CD. Due to the size of the installation image (~12M), you'll have plenty of room on even the smallest media. Installation Congratulations. You're now the proud owner of an Ubuntu network installation CD. You can use this small CD to install an Ubuntu machine anywhere you have access to an Ubuntu repository. This can be a public repository or a local repository. If you'd like to create a local repository you may want to read the article on Creating a Local Ubuntu Repository using Apt-Mirror and Apt-Cacher, for additional information on creating a mirror or caching server. To kick off your installation simply reboot your machine and instruct it to boot off a CD. This is often done by pressing a function key during the initial boot process. On many Dell machines this is the F12 button. Some machines are already configured to boot from a CD if present during the boot process. If this is not the case for you, please consult your BIOS settings for more information. When the CD boots you'll be presented with a very basic prompt. Simply press ENTER to continue. This will then load the Ubuntu specific boot menu. For this article I selected Install from the main menu. The other options are beyond the scope of this tutorial. This will load some modules and then start the installation program. The network installer is purely text based. This may seem like a step backward for those used to the LiveCD graphical installers, but the text based nature allows for greater flexibility and advanced features. During the following screens I will outline what the prompts are asking for, and what additional options (if any) are available at each stage. The first selection menu that you will be prompted with is the language menu. This should default to "English". Of course you can select your preferred language as needed. Second, to verify the language variant, you'll need to select your country. Based on your first selection your menu may not appear with the same options as in this screenshot. Third you'll be asked to select or verify your keyboard layout. The installer will ask you if you'd like to automatically detect the proper keyboard layout. If you select Yes you will be prompted to press specific keys from a displayed list until it has verified your layout. If you select No you'll be prompted to select your layout from a list.
Read more
  • 0
  • 0
  • 3573

article-image-forms-grok-10
Packt
12 Feb 2010
13 min read
Save for later

Forms in Grok 1.0

Packt
12 Feb 2010
13 min read
A quick demonstration of automatic forms Let's start by showing how this works, before getting into the details. To do that, we'll add a project model to our application. A project can have any number of lists associated with it, so that related to-do lists can be grouped together. For now, let's consider the project model by itself. Add the following lines to the app.py file, just after the Todo application class definition. We'll worry later about how this fits into the application as a whole. class IProject(interface.Interface): name = schema.TextLine(title=u'Name',required=True) kind = schema.Choice(title=u'Kind of project', values=['personal','business']) description = schema.Text(title=u'Description')class AddProject(grok.Form): grok.context(Todo) form_fields = grok.AutoFields(IProject) We'll also need to add a couple of imports at the top of the file: from zope import interfacefrom zope import schema Save the file, restart the server, and go to the URL http://localhost:8080/todo/addproject. The result should be similar to the following screenshot: OK, where did the HTML for the form come from? We know that AddProject is some sort of a view, because we used the grok.context class annotation to set its context and name. Also, the name of the class, but in lowercase, was used in the URL, like in previous view examples. The important new thing is how the form fields were created and used. First, a class named IProject was defined. The interface defines the fields on the form, and the grok.AutoFields method assigns them to the Form view class. That's how the view knows which HTML form controls to generate when the form is rendered. We have three fields: name, description, and kind. Later in the code, the grok.AutoFields line takes this IProject class and turns these fields into form fields. That's it. There's no need for a template or a render method. The grok.Form view takes care of generating the HTML required to present the form, taking the information from the value of the form_fields attribute that the grok.AutoFields call generated. Interfaces The I in the class name stands for Interface. We imported the zope.interface package at the top of the file, and the Interface class that we have used as a base class for IProject comes from this package. Example of an interface An interface is an object that is used to specify and describe the external behavior of objects. In a sense, the interface is like a contract. A class is said to implement an interface when it includes all of the methods and attributes defined in an interface class. Let's see a simple example: from zope import interfaceclass ICaveman(interface.Interface): weapon = interface.Attribute('weapon') def hunt(animal): """Hunt an animal to get food""" def eat(animal): """Eat hunted animal""" def sleep() """Rest before getting up to hunt again""" Here, we are describing how cavemen behave. A caveman will have a weapon, and he can hunt, eat, and sleep. Notice that the weapon is an attribute—something that belongs to the object, whereas hunt, eat, and sleep are methods. Once the interface is defined, we can create classes that implement it. These classes are committed to include all of the attributes and methods of their interface class. Thus, if we say: class Caveman(object): interface.implements(ICaveman) Then we are promising that the Caveman class will implement the methods and attributes described in the ICaveman interface: weapon = 'ax'def hunt(animal): find(animal) hit(animal,self.weapon)def eat(animal): cut(animal) bite()def sleep(): snore() rest() Note that though our example class implements all of the interface methods, there is no enforcement of any kind made by the Python interpreter. We could define a class that does not include any of the methods or attributes defined, and it would still work. Interfaces in Grok In Grok, a model can implement an interface by using the grok.implements method. For example, if we decided to add a project model, it could implement the IProject interface as follows: class Project(grok.Container): grok.implements(IProject) Due to their descriptive nature, interfaces can be used for documentation. They can also be used for enabling component architectures, but we'll see about that later on. What is of more interest to us right now is that they can be used for generating forms automatically. Schemas The way to define the form fields is to use the zope.schema package. This package includes many kinds of field definitions that can be used to populate a form. Basically, a schema permits detailed descriptions of class attributes that are using fields. In terms of a form—which is what is of interest to us here—a schema represents the data that will be passed to the server when the user submits the form. Each field in the form corresponds to a field in the schema. Let's take a closer look at the schema we defined in the last section: class IProject(interface.Interface): name = schema.TextLine(title=u'Name',required=True) kind = schema.Choice(title=u'Kind of project', required=False, values=['personal','business']) description = schema.Text(title=u'Description', required=False) The schema that we are defining for IProject has three fields. There are several kinds of fields, which are listed in the following table. In our example, we have defined a name field, which will be a required field, and will have the label Name beside it. We also have a kind field, which is a list of options from which the user must pick one. Note that the default value for required is True, but it's usually best to specify it explicitly, to avoid confusion. You can see how the list of possible values is passed statically by using the values parameter. Finally, description is a text field, which means it will have multiple lines of text. Available schema attributes and field types In addition to title, values, and required, each schema field can have a number of properties, as detailed in the following table: Attribute Description title A short summary or label. description A description of the field. required Indicates whether a field requires a value to exist. readonly If True, the field's value cannot be changed. default The field's default value may be None, or a valid field value. missing_value If input for this field is missing, and that's OK, then this is the value to use. order The order attribute can be used to determine the order in which fields in a schema are defined. If one field is created after another (in the same thread), its order will be greater. In addition to the field attributes described in the preceding table, some field types provide additional attributes. In the previous example, we saw that there are various field types, such as Text, TextLine, and Choice. There are several other field types available, as shown in the following table. We can create very sophisticated forms just by defining a schema in this way, and letting Grok generate them. Field type Description Parameters Bool Boolean field.   Bytes Field containing a byte string (such as the python str). The value might be constrained to be within length limits.   ASCII Field containing a 7-bit ASCII string. No characters > DEL (chr(127)) are allowed. The value might be constrained to be within length limits.   BytesLine Field containing a byte string without new lines.   ASCIILine Field containing a 7-bit ASCII string without new lines.   Text Field containing a Unicode string.   SourceText Field for the source text of an object.   TextLine Field containing a Unicode string without new lines.   Password Field containing a Unicode string without new lines, which is set as the password.   Int Field containing an Integer value.   Float Field containing a Float.   Decimal Field containing a Decimal.   DateTime Field containing a DateTime.   Date Field containing a date.   Timedelta Field containing a timedelta.   Time Field containing time.   URI A field containing an absolute URI.   Id A field containing a unique identifier. A unique identifier is either an absolute URI or a dotted name. If it's a dotted name, it should have a module or package name as a prefix.   Choice Field whose value is contained in a predefined set. values: A list of text choices for the field. vocabulary: A Vocabulary object that will dynamically produce the choices. source: A different, newer way to produce dynamic choices. Note: only one of the three should be provided. More information about sources and vocabularies is provided later in this book. Tuple Field containing a value that implements the API of a conventional Python tuple. value_type: Field value items must conform to the given type, expressed via a field. Unique. Specifies whether the members of the collection must be unique. List Field containing a value that implements the API of a conventional Python list. value_type: Field value items must conform to the given type, expressed via a field. Unique. Specifies whether the members of the collection must be unique. Set Field containing a value that implements the API of a conventional Python standard library sets.Set or a Python 2.4+ set. value_type: Field value items must conform to the given type, expressed via a field. FrozenSet Field containing a value that implements the API of a conventional Python2.4+ frozenset. value_type: Field value items must conform to the given type, expressed via a field. Object Field containing an object value. Schema: The interface that defines the fields comprising the object. Dict Field containing a conventional dictionary. The key_type and value_type fields allow specification of restrictions for keys and values contained in the dictionary. key_type: Field keys must conform to the given type, expressed via a field. value_type: Field value items must conform to the given type, expressed via a field. Form fields and widgets Schema fields are perfect for defining data structures, but when dealing with forms sometimes they are not enough. In fact, once you generate a form using a schema as a base, Grok turns the schema fields into form fields. A form field is like a schema field but has an extended set of methods and attributes. It also has a default associated widget that is responsible for the appearance of the field inside the form. Rendering forms requires more than the fields and their types. A form field needs to have a user interface, and that is what a widget provides. A Choice field, for example, could be rendered as a <select> box on the form, but it could also use a collection of checkboxes, or perhaps radio buttons. Sometimes, a field may not need to be displayed on a form, or a writable field may need to be displayed as text instead of allowing users to set the field's value. Form components Grok offers four different components that automatically generate forms. We have already worked with the first one of these, grok.Form. The other three are specializations of this one: grok.AddForm is used to add new model instances. grok.EditForm is used for editing an already existing instance. grok.DisplayForm simply displays the values of the fields. A Grok form is itself a specialization of a grok.View, which means that it gets the same methods as those that are available to a view. It also means that a model does not actually need a view assignment if it already has a form. In fact, simple applications can get away by using a form as a view for their objects. Of course, there are times when a more complex view template is needed, or even when fields from multiple forms need to be shown in the same view. Grok can handle these cases as well, which we will see later on. Adding a project container at the root of the site To get to know Grok's form components, let's properly integrate our project model into our to-do list application. We'll have to restructure the code a little bit, as currently the to-do list container is the root object of the application. We need to have a project container as the root object, and then add a to-do list container to it. To begin, let's modify the top of app.py, immediately before the TodoList class definition, to look like this: import grokfrom zope import interface, schemaclass Todo(grok.Application, grok.Container): def __init__(self): super(Todo, self).__init__() self.title = 'To-Do list manager' self.next_id = 0 def deleteProject(self,project): del self[project] First, we import zope.interface and zope.schema. Notice how we keep the Todo class as the root application class, but now it can contain projects instead of lists. We also omitted the addProject method, because the grok.AddForm instance is going to take care of that. Other than that, the Todo class is almost the same. class IProject(interface.Interface): title = schema.TextLine(title=u'Title',required=True) kind = schema.Choice(title=u'Kind of project',values=['personal', 'business']) description = schema.Text(title=u'Description',required=False) next_id = schema.Int(title=u'Next id',default=0) We then have the interface definition for IProject, where we add the title, kind, description, and next_id fields. These were the fields that we previously added during the call to the __init__ method at the time of product initialization. class Project(grok.Container): grok.implements(IProject) def addList(self,title,description): id = str(self.next_id) self.next_id = self.next_id+1 self[id] = TodoList(title,description) def deleteList(self,list): del self[list] The key thing to notice in the Project class definition is that we use the grok.implements class declaration to see that this class will implement the schema that we have just defined. class AddProjectForm(grok.AddForm): grok.context(Todo) grok.name('index') form_fields = grok.AutoFields(Project) label = "To begin, add a new project" @grok.action('Add project') def add(self,**data): project = Project() self.applyData(project,**data) id = str(self.context.next_id) self.context.next_id = self.context.next_id+1 self.context[id] = project return self.redirect(self.url(self.context[id])) The actual form view is defined after that, by using grok.AddForm as a base class. We assign this view to the main Todo container by using the grok.context annotation. The name index is used for now, so that the default page for the application will be the 'add form' itself. Next, we create the form fields by calling the grok.AutoFields method. Notice that this time the argument to this method call is the Project class directly, rather than the interface. This is possible because the Project class was associated with the correct interface when we previously used grok.implements. After we have assigned the fields, we set the label attribute of the form to the text: To begin, add a new project. This is the title that will be shown on the form. In addition to this new code, all occurrences of grok.context(Todo) in the rest of the file need to be changed to grok.context(Project), as the to-do lists and their views will now belong to a project and not to the main Todo application. For details, take a look at the source code of this article for Grok 1.0 Web Development>>Chapter 5.
Read more
  • 0
  • 0
  • 1133
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €14.99/month. Cancel anytime
article-image-testing-and-debugging-grok-10-part-1
Packt
11 Feb 2010
12 min read
Save for later

Testing and Debugging in Grok 1.0: Part 1

Packt
11 Feb 2010
12 min read
Grok offers some tools for testing, and in fact, a project created by grokproject (as the one we have been extending) includes a functional test suite. In this article, we are going to discuss testing a bit and then write some tests for the functionality that our application has so far. Testing helps us avoid bugs, but it does not eliminate them completely, of course. There are times when we will have to dive into the code to find out what's going wrong. A good set of debugging aids becomes very valuable in this situation. We'll see that there are several ways of debugging a Grok application and also try out a couple of them. Testing It's important to understand that testing should not be treated as an afterthought. As mentioned earlier, agile methodologies place a lot of emphasis on testing. In fact, there's even a methodology called Test Driven Development (TDD), which not only encourages writing tests for our code, but also writing tests before any other line of code. There are various kinds of testing, but here we'll briefly describe only two: Unit testing Integration or functional tests Unit testing The idea of unit testing is to break a program into its constituent parts and test each one of them in isolation. Every method or function call can be tested separately to make sure that it returns the expected results and handles all of the possible inputs correctly. An application which has unit tests that cover the majority of its lines of code, allows its developers to constantly run the tests after a change, and makes sure that modifications to the code do not break the existing functionality. Functional tests Functional tests are concerned with how the application behaves as a whole. In a web application, this means how it responds to a browser request and whether it returns the expected HTML for a given call. Ideally, the customer himself has a hand in defining these tests, usually through explicit functionality requirements or acceptance criteria. The more formal the requirements from the customer are, the easier it is to define appropriate functional tests. Testing in Grok Grok highly encourages the use of both kinds of tests, and in fact, includes a powerful testing tool that is automatically configured with every project. In the Zope world—from where Grok originated—a lot of value is placed in a kind of tests known as "doctests", so Grok comes with a sample test suite of this kind. Doctests A doctest is a test that's written as a text file, with lines of code mixed with explanations of what the code is doing. The code is written in a way that simulates a Python interpreter session. As tests exercise large portions of the code (ideally 100%), they usually offer a good way of finding out of what an application does and how. So, if an application has no written documentation, its tests would be the next obvious way of finding out what it does. Doctests take this idea further by allowing the developer to explain in the text file exactly what each test is doing. Doctests are especially useful for functional testing, because it makes more sense to document the high-level operations of a program. Unit tests, on the other hand, are expected to evaluate the program bit by bit and it can be cumbersome to write a text explanation for every little piece of code. A possible drawback of doctests is that they can make the developer think that he needs no other documentation for his project. In almost all of the cases, this is not true. Documenting an application or package makes it immediately more accessible and useful, so it is strongly recommended that doctests should not be used as a replacement for good documentation. We'll show an example of using doctests in the Looking at the test code section of this article. Default test setup for Grok projects As mentioned above, Grok projects that are started with the grokproject tool already include a simple functional test suite by default. Let's examine it in detail. Test configuration The default test configuration looks for packages or modules that have the word 'tests' in their name and tries to run the tests inside. For functional tests, any files ending with .txt or .rst are considered. For functional tests that need to simulate a browser, a special configuration is needed to tell Grok which packages to initialize in addition to the Grok infrastructure (usually the ones that are being worked on). The ftesting.zcml file in the package directory has this configuration. This also includes a couple of user definitions that are used by certain tests to examine functionality specific to a certain role, such as manager. Test files Besides the already mentioned ftesting.zcml file, in the same directory, there is a tests.py file added by grokproject, which basically loads the ZCML declarations and registers all of the tests in the package. The actual tests that are included with the default project files are contained in the app.txt file. These are doctests that do a functional test run by loading the entire Grok environment and imitating a browser. We'll take a look at the contents of the file soon, but first let's run the tests. Running the tests As part of the project's build process, a script named test is included in the bin directory when you create a new project. This is the test runner and calling it without arguments, finds and executes all of the tests in the packages that are included in the configuration. We haven't added a single test so far, so if we type bin/test in our project directory, we'll see more or less the same thing that doing that on a new project would show: $ bin/testRunning tests at level 1 Running todo.FunctionalLayer tests: Set up in 12.319 seconds. Running: ...2009-09-30 15:00:47,490 INFO sqlalchemy.engine.base.Engine.0x...782c PRAGMA table_info("users") 2009-09-30 15:00:47,490 INFO sqlalchemy.engine.base.Engine.0x...782c () Ran 3 tests with 0 failures and 0 errors in 0.465 seconds. Tearing down left over layers: Tear down todo.FunctionalLayer ... not supported The only difference between our output to that of a newly created Grok package is in the sqlalchemy lines. Of course, the most important part of the output is the "penultimate" line, which shows the number of tests that were run and whether there were any failures or errors. A failure means that some test didn't pass, which means that the code is not doing what it's supposed to do and needs to be checked. An error signifies that the code crashed unexpectedly at some point, and the test couldn't even be executed, so it's necessary to find the error and correct it before worrying about the tests. The test runner The test runner program looks for modules that contain tests. The test can be of three different types: Python tests, simple doctests, and full functionality doctests. To let the test runner know, which test file includes which kind of tests, a comment similar to the following is placed at the top of the file: Do a Python test on the app. :unittest: In this case, the Python unit test layer will be used to run the tests. The other value that we are going to use is "doctest" when we learn how to write doctests. The test runner then finds all of the test modules and runs them in the corresponding layer. Although unit tests are considered very important in regular development, we may find functional tests more necessary for a Grok web application, as we will usually be testing views and forms, which require the full Zope/Grok stack to be loaded to work. That's the reason why we find only functional doctests in the default setup. Test layers A test layer is a specific test setup which is used to differentiate the tests that are executed. By default, there is a test layer for each of the three types of tests handled by the test runner. It's possible to run a test layer without running the others and also to name new test layers to be able to cluster together tests that require a specific setup. Invoking the test runner As shown above, running bin/test will start the test runner with the default options. It's also possible to specify a number of options, and the most important ones are summarized below. In the following table, command-line options are shown to the left. Most options can be expressed with a short form (one dash) or a long form (two dashes). Arguments for the option in question are shown in uppercase. -s PACKAGE, --package=PACKAGE, --dir=PACKAGE Search the given package's directories for tests. This can be specified more than once, to run tests in multiple parts of the source tree. For example, when refactoring interfaces, you don't want to see the way you have broken setups for tests in other packages. You just want to run the interface tests. Packages are supplied as dotted names. For compatibility with the old test runner, forward and backward slashes in package names are converted to dots. (In the special case of packages, which are spread over multiple directories, only directories within the test search path are searched.) -m MODULE, --module=MODULE Specify a test-module filter as a regular expression. This is a case sensitive regular expression, which is used in search (not match) mode, to limit which test modules are searched for tests. The regular expressions are checked against dotted module names. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The option can specy multiple test-module filters. Test modules matching any of the test filters are searched. If no test-module filter is specified, then all of the test modules are used. -t TEST, --test=TEST Specify a test filter as a regular expression. This is a case sensitive regular expression, which is used in search (not match) mode, to limit which tests are run. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The option can specify multiple test filters. Tests matching any of the test filters are included. If no test filter is specified, then all of the tests are executed. --layer=LAYER Specify a test layer to run. The option can be given multiple times to specify more than one layer. If not specified, all of the layers are executed. It is common for the running script to provide default values for this option. Layers are specified regular expressions that are used in search mode, for dotted names of objects that define a layer. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The layer named 'unit' is reserved for unit tests, however, take note of the -unit and non-unit options. -u, --unit Executes only unit tests, ignoring any layer options. -f, --non-unit Executes tests other than unit tests. -v, --verbose Makes output more verbose. Increment the verbosity level. -q, --quiet Makes the output minimal by overriding any verbosity options. Looking at the test code Let's take a look at the three default test files of a Grok project, to see what each one does. ftesting.zcml As we explained earlier, ftesting.zcml is a configuration file for the test runner. Its main objective is to help us set up the test instance with users, so that we can test different roles according to our needs. <configure i18n_domain="todo" package="todo" > <include package="todo" /> <include package="todo_plus" /> <!-- Typical functional testing security setup --> <securityPolicy component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" /> <unauthenticatedPrincipal id="zope.anybody" title="Unauthenticated User" /> <grant permission="zope.View" principal="zope.anybody" /> <principal id="zope.mgr" title="Manager" login="mgr" password="mgrpw" /> <role id="zope.Manager" title="Site Manager" /> <grantAll role="zope.Manager" /> <grant role="zope.Manager" principal="zope.mgr" /> As shown in the preceding code, the configuration simply includes a security policy, complete with users and roles and the packages that should be loaded by the instance, in addition to the regular Grok infrastructure. If we run any tests that require an authenticated user to work, we'll use these special users. The includes at the top of the file just make sure that all of the Zope Component Architecture setup needed by our application is performed prior to running the tests. tests.py The default test module is very simple. It defines the functional layer and registers the tests for our package: import os.path import z3c.testsetup import todo from zope.app.testing.functional import ZCMLLayer ftesting_zcml = os.path.join( os.path.dirname(todo.__file__), 'ftesting.zcml') FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer', allow_teardown=True) test_suite = z3c.testsetup.register_all_tests('todo') After the imports, the first line gets the path for the ftesting.zcml file, which then is passed to the layer definition method ZCMLLayer. The final line in the module tells the test runner to find and register all of the tests in the package. This will be enough for our testing needs in this article, but if we needed to create another non-Grok package for our application, we would need to add a line like the last one to it, so that all of its tests are found by the test runner. This is pretty much boilerplate code, as only the package name has to be changed.
Read more
  • 0
  • 0
  • 1450

article-image-testing-and-debugging-grok-10-part-2
Packt
11 Feb 2010
8 min read
Save for later

Testing and Debugging in Grok 1.0: Part 2

Packt
11 Feb 2010
8 min read
Adding unit tests Apart from functional tests, we can also create pure Python test cases which the test runner can find. While functional tests cover application behavior, unit tests focus on program correctness. Ideally, every single Python method in the application should be tested. The unit test layer does not load the Grok infrastructure, so tests should not take anything that comes with it for granted; just the basic Python behavior. To add our unit tests, we'll create a module named unit_tests.py. Remember, in order for the test runner to find our test modules, their names have to end with 'tests'. Here's what we will put in this file: """ Do a Python test on the app. :unittest: """ import unittest from todo.app import Todo class InitializationTest(unittest.TestCase): todoapp = None def setUp(self): self.todoapp = Todo() def test_title_set(self): self.assertEqual(self.todoapp.title,u'To-do list manager') def test_next_id_set(self): self.assertEqual(self.todoapp.next_id,0) The :unittest: comment at the top, is very important. Without it, the test runner will not know in which layer your tests should be executed, and will simply ignore them. Unit tests are composed of test cases, and in theory, each should contain several related tests based on a specific area of the application's functionality. The test cases use the TestCase class from the Python unittest module. In these tests, we define a single test case that contains two very simple tests. We are not getting into the details here. Just notice that the test case can include a setUp and a tearDown method that can be used to perform any common initialization and destruction tasks which are needed to get the tests working and finishing cleanly. Every test inside a test case needs to have the prefix 'test' in its name, so we have exactly two tests that fulfill this condition. Both of the tests need an instance of the Todo class to be executed, so we assign it as a class variable to the test case, and create it inside the setUp method. The tests are very simple and they just verify that the default property values are set on instance creation. Both of the tests use the assertEqual method to tell the test runner that if the two values passed are different, the test should fail. To see them in action, we just run the bin/test command once more: $ bin/testRunning tests at level 1 Running todo.FunctionalLayer tests: Set up in 2.691 seconds. Running: .......2009-09-30 22:00:50,703 INFO sqlalchemy.engine.base.Engine.0x...684c PRAGMA table_info("users") 2009-09-30 22:00:50,703 INFO sqlalchemy.engine.base.Engine.0x...684c () Ran 7 tests with 0 failures and 0 errors in 0.420 seconds. Running zope.testing.testrunner.layer.UnitTests tests: Tear down todo.FunctionalLayer ... not supported Running in a subprocess. Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Ran 2 tests with 0 failures and 0 errors in 0.000 seconds. Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Total: 9 tests, 0 failures, 0 errors in 5.795 seconds Now, both the functional and unit test layers contain some tests and both are run one after the other. We can see the subtotal for each layer at the end of its tests as well as the grand total of the nine passed tests when the test runner finishes its work. Extending the test suite Of course, we just scratched the surface of which tests should be added to our application. If we continue to add tests, hundreds of tests may be there by the time we finish. However, this article is not the place to do so. As mentioned earlier, its way easier to have tests for each part of our application, if we add them as we code. There's no hiding from the fact that testing is a lot of work, but there is great value in having a complete test suite for our applications. More so, when third parties might use our work product independently. Debugging We will now take a quick look at the debugging facilities offered by Grok. Even if we have a very thorough test suite, chances are there that we will find a fair number of bugs in our application. When that happens, we need a quick and effective way to inspect the code as it runs and find the problem spots easily. Often, developers will use print statements (placed at key lines) throughout the code, in the hopes of finding the problem spot. While this is usually a good way to begin locating sore spots in the code, we often need some way to follow the code line by line to really find out what's wrong. In the next section, we'll see how to use the Python debugger to step through the code and find the problem spots. We'll also take a quick look at how to do post-mortem debugging in Grok, which means jumping into the debugger to analyze program state immediately after an exception has occurred. Debugging in Grok For regular debugging, where we need to step through the code to see what's going on inside, the Python debugger is an excellent tool. To use it, you just have to add the next line at the point where you wish to start debugging: import pdb; pdb.set_trace() Let's try it out. Open the app.py module and change the add method of the AddProjectForm class (line 108) to look like this: @grok.action('Add project') def add(self,**data): import pdb; pdb.set_trace() project = Project() project.creator = self.request.principal.title project.creation_date = datetime.datetime.now() project.modification_date = datetime.datetime.now() self.applyData(project,**data) id = str(self.context.next_id) self.context.next_id = self.context.next_id+1 self.context[id] = project return self.redirect(self.url(self.context[id])) Notice that we invoke the debugger at the beginning of the method. Now, start the instance, go to the 'add project' form, fill it up, and submit it. Instead of seeing the new project view, the browser will stay at the 'add form' page, and display the waiting for... message. This is because control has been transferred to the console for the debugger to act. Your console will look like this: > /home/cguardia/work/virtual/grok1/todo/src/todo/app.py(109)add() -> project = Project() (Pdb) | The debugger is now active and waiting for input. Notice that the line number where debugging started, appears right beside the path of the module where we are located. After the line number, comes the name of the method, add(). Below that, the next line of code to be executed is shown. The debugger commands are simple. To execute the current line, type n: (Pdb) n > /home/cguardia/work/virtual/grok1/todo/src/todo/app.py(110)add() -> project.creator = self.request.principal.title (Pdb) You can see the available commands if you type h: (Pdb) h Documented commands (type help <topic>): ======================================== EOF break condition disable help list q step w a bt cont down ignore n quit tbreak whatis alias c continue enable j next r u where args cl d exit jump p return unalias b clear debug h l pp s up Miscellaneous help topics: ========================== exec pdb Undocumented commands: ====================== retval rv (Pdb) The list command id is used for getting a bird's eye view of where in the code are we: (Pdb) list 105 106 @grok.action('Add project') 107 def add(self,**data): 108 import pdb; pdb.set_trace() 109 project = Project() 110 -> project.creator = self.request.principal.title 111 project.creation_date = datetime.datetime.now() 112 project.modification_date = datetime.datetime.now() 113 self.applyData(project,**data) 114 id = str(self.context.next_id) 115 self.context.next_id = self.context.next_id+1 (Pdb) As you can see, the current line is shown with an arrow. It's possible to type in the names of objects within the current execution context and find out their values: (Pdb) project <todo.app.Project object at 0xa0ef72c> (Pdb) data {'kind': 'personal', 'description': u'Nothing', 'title': u'Project about nothing'} (Pdb) We can of course, continue stepping line by line through all of the code in the application, including Grok's own code, checking values as we proceed. When we are through reviewing, we can click on c to return control to the browser. At this point, we will see the project view. The Python debugger is very easy to use and it can be invaluable for finding obscure bugs in your code.
Read more
  • 0
  • 0
  • 2088

article-image-selecting-dom-elements-using-mootools-12-part-1
Packt
07 Jan 2010
7 min read
Save for later

Selecting DOM Elements using MooTools 1.2: Part 1

Packt
07 Jan 2010
7 min read
In order to successfully and effortlessly write unobtrusive JavaScript, we must have a way to point to the Document Object Model (DOM) elements that we want to manipulate. The DOM is a representation of objects in our HTML and a way to access and manipulate them. In traditional JavaScript, this involves a lot (like, seriously a lot) of code authoring, and in many instances, a lot of head-banging-against-wall-and-pulling-out-hair as you discover a browser quirk that you must solve. Let me save you some bumps, bruises, and hair by showing you how to select DOM elements the MooTools way. This article will cover how you can utilize MooTools to select/match simple (like, "All div elements") up to the most complex and specific elements (like, "All links that are children of a span that has a class of awesomeLink and points to http://superAwesomeSite.com MooTools and CSS selectors MooTools selects an element (or a set of elements) in the DOM using CSS selectors syntax. Just a quick refresher on CSS terminology, a CSS style rule consists of: selector { property: property value; } selector: indicates what elements will be affected by the style rule. property: the CSS property (also referred to as attribute). For example, color is a CSS property, so is font-style. You can have multiple property declarations in one style rule property value: the value you want assigned to the property. For example, bold is a possible CSS property value of the font-weight CSS property. For example, if you wanted to select a paragraph element with an ID of awesomeParagraph to give it a red color (in hexadecimal, this is #ff0), in CSS syntax you'd write: #awesomeParagraph { color: #ff0; } Also, if I wanted to increase its specificity and make sure that only paragraph elements that have an ID of awesomeParagraph is selected: p#awesomeParagraph { color: #ff0;} You'll be happy to know that this same syntax ports over to MooTools. What's more is that you'll be able to take advantage of all of CSS3's more complex selection syntax because even though CSS3 isn't supported by all browsers yet, MooTools supports them already. So you don't have to learn another syntax for writing selectors, you can use your existing knowledge of CSS - awesome, isn't it? Working with the $() and $$() functions The $() and $$() functions are the bread and butter of MooTools. When you're working with unobtrusive JavaScript, you need to specify which elements you want to operate on. The dollar and dollars functions help you do just that - they will allow you to specify what elements you want to work on. Notice, the dollar sign $ is shaped like an S, which we can interpret to mean 'select'. The $() dollar function The dollar function is used for getting an element by it's ID, which returns a single element that is extended with MooTools Element methods or null if nothing matches. Let's go back to awesomeParagraph in the earlier example. If I wanted to select awesomeParagraph, this is what I would write: $('awesomeParagraph’) By doing so, we can now operate on it by passing methods to the selection. For example, if you wanted to change its style to have a color of red. You can use the .setStyle() method which allows you to specify a CSS property and its matching property value, like so $('awesomeParagraph').setStyle('color', '#ff0'); The $$() dollars function The $$() function is the $() big brother (that's why it gets an extra dollar sign). The $$() function can do more robust and complex selections, can select a group, or groups of element’s and always returns an array object, with or without selected elements in it. Likewise, it can be interchanged with the dollar function. If we wanted to select awesomeParagraph using the dollars function, we would write: $$('#awesomeParagraph') Note that you have to use the pound sign (#) in this case as if you were using CSS selectors. When to use which If you need to select just one element that has an ID, you should use the $() function because it performs better in terms of speed than the $$() function. Use the $$() function to select multiple elements. In fact, when in doubt, use the$$() function because it can do what the $() function can do (and more). A note on single quotes (') versus double quotes ("")The example above would work even if we used double quotes such as $("awesomeParagraph") or $$("#awesomeParagraph") ") - but many MooTools developers prefer single quotes so they don’t have to escape characters as much (since the double quote is often used in HTML, you'll have to do "in order not to prematurely end your strings). It's highly recommended that you use single quotes - but hey, it's your life! Now, let's see these functions in action. Let's start with the HTML markup first. Put the following block of code in an HTML document: <body> <ul id="superList"> <li>List item</li> <li><a href="#">List item link</a></li> <li id="listItem">List item with an ID.</li> <li class="lastItem">Last list item.</li> </ul></body> What we have here is an unordered list. We'll use it to explore the dollar and dollars function. If you view this in your web browser, you should see something like this: Time for action – selecting an element with the dollar function Let's select the list item with an ID of listItem and then give it a red color using the .setStyle() MooTools method. Inside your window.addEvent('domready') method, use the following code: $('listItem').setStyle('color', 'red'); Save the HTML document and view it on your web browser. You should see the 3rd list item will be red. Now let's select the entire unordered list (it has an ID of superList), then give it a black border (in hexadecimal, this is #000000). Place the following code, right below the code the line we wrote in step 1: $('superList').setStyle('border', '1px solid #000000'); If you didn't close your HTML document, hit your browser's refresh. You should now see something like this: Time for action – selecting elements with the dollars function We'll be using the same HTML document, but this time, let's explore the dollars function. We're going to select the last list item (it has a class of lastItem). Using the .getFirst(), we select the first element from the array $$() returned. Then, we're going to use the .get() method to get its text. To show us what it is, we'll pass it to the alert() function. The code to write to accomplish this is: alert( $$('.lastItem').getFirst().get('text') ); Save the HTML document and view it in your web browser (or just hit your browser's refresh button if you still have the HTML document from the preview Time for action open). You should now see the following: Time for action – selecting multiple sets of elements with the dollars function What if we wanted to select multiple sets of elements and run the same method (or methods) on them? Let's do that now. Let's select the list item that has an <a> element inside it and the last list item (class="lastItem") and then animate them to the right by transitioning their margin-left CSS property using the .tween() method. Right below the line we wrote previously, place the following line: $$('li a, .lastItem').tween('margin-left', '50px'); View your work in your web browser. You should see the second and last list item move to the right by 50 pixels. What just happened? We just explored the dollar and dollars function to see how to select different elements and apply methods on them. You just learned to select: An element with an ID (#listItem and #superList) using the dollar $() function An element with a class (.lastItem) using the dollars $$() function Multiple elements by separating them with commas (li and .lastItem) You also saw how you can execute methods on your selected elements. In the example, we used the .setStyle(), .getFirst(), get(), and .tween() MooTools methods. Because DOM selection is imperative to writing MooTools code, before we go any further, let's talk about some important points to note about what we just did.
Read more
  • 0
  • 0
  • 1519

article-image-working-events-mootools-part-1
Packt
07 Jan 2010
9 min read
Save for later

Working with Events in MooTools: Part 1

Packt
07 Jan 2010
9 min read
We have a lot of things to cover in this article, so hold on to your seats and enjoy the ride! What are Events, Exactly? Events are simply things that happen in our web pages. MooTools supports all HTML 4.01 event attributes like onclick and onmouseout, but the framework refers to them without the "on"  prefix (click instead of onclick, mouseout instead of onmouseout). What's neat about MooTools is that it not only extends HTML 4.01 event attributes with a few of its own, but also ensures that methods and functions that deal with web page events work across all web browsers by providing us with a solid, built-in object called Events. Event is part of the Native component of MooTools, and is also referred to as the Event hash. You can read the official W3C specifications on events, in the HTML 4.01 Specification, section 18.2.3, under Intrinsic Events:http://www.w3.org/TR/html401/interact/scripts.html#h-18.2.3 We'll go over all of the available event attributes in MooTools so you can learn what stuff we can listen to. There are several events that we can detect or "listen to". We can, for the sake of discussion, divide them into five groups: window events, form events, keyboard events, mouse events, and MooTools custom events. Window Events Window events refer to activities that occur in the background. There are only two window events. HTML Event attribute / MooTools event name What is it? onload / load This event occurs when the window and images on the page has fully loaded and/or when all of the iFrames in the page have loaded. It can be used for monitoring when the web page has fully loaded (such as when you want to know if all images have been downloaded). onunload / unload This even happens when a window or an iFrame is removed from the web page. It has limited use. Form events There are events that occur within Form elements (such as <input> elements), and we'll refer to these as form events. For example, the onfocus  event is triggered when the user clicks on an input field (you'll see this in action in this article), effectively focusing on that particular input field. Some of these events apply event to non-form elements. HTML Event attribute / MooTools event name What is it? onblur / blur This event occurs when an element loses focus, either because the user has clicked out of it, or because the user used the Tab key to move away from it. This is helpful for monitoring the instant the user loses focus on a particular element. onchange / change This event happens when the element loses focus or when its original value has changed. This is helpful for knowing when the user starts typing in a input text field or textarea, or when a user selects a different option in a select drop-down element. onfocus / focus This event is the opposite, of the blur event: it is triggered when the user focuses on an element. This is useful for watching when the user highlights a form field or when they have navigated to it using the Tab key. onreset / reset This event only applies to form elements. This event is triggered when the form has been reset to its default values. onselect / select This event happens when the user highlights (selects) text in a text field. onsubmit / submit This event is only for form elements. This event occurs when the user submits a web form. Keyboard events There are events that happen when a user presses on a keyboard input device; let's call these keyboard events. For example, the onkeypress event is triggered when you press any key on your keyboard. HTML Event attribute / MooTools event name What is it? onkeydown / keydown This event occurs when the user holds down a keyboard key. onkeypress / keypress This event is triggered whenever the user presses a keyboard key. onkeyup /keyup This event happens when the user releases a key. Mouse events There are several HTML event properties that allow you to deal with activities related to the mouse. Clicking, moving, double-clicking, and hovering are all mouse events. HTML Event attribute / MooTools event name What is it? onclick / click This event occurs whenever the user uses the mouse button to click on an element. ondblclick / dblclick This even occurs whenever the user double-clicks on an element. onmousedown / mousedown This event occurs when the mouse button is held down. onmouseup / mouseup This even occurs when the mouse button is released. onmousemove / mousemove This event occurs when the mouse is moved. onmouseout / mouseout This event occurs when the mouse pointer is removed from the target element. onmouseover / mouseover This event occurs when the mouse pointer enters the target element. MooTools Custom Mouse Events MooTools supplies us with three custom events that extend the standard mouse events. MooTools event name What is it? mouseenter This event is triggered when the user's mouse pointer enters an element, but does not fire again when the mouse goes over a children element (unlike mouseover). This is useful for detecting the mouseover event once in nested element structures, such as <li><a>item</a></li>. If we were to use the mouseover event, it would be triggered twice, once for <li> and once again for <a>. mouseleave This event works similarly to mouseenter in that it is triggered only once when the mouse pointer exits the target element. Unlike the mouseout event, which will be triggered more than once for nested element structures. mousewheel This even is triggered when the scroller on a mouse is used (available in most modern mice input devices, usually situated in between the left and right mouse buttons). Adding Event Listeners We can attach event listeners to elements on a web page using the addEvent and addEvents method. By doing so, we're able to find out whenever that event happens, as well as execute a function to react to them. Adding event listeners is the basis for interactivity and is where JavaScript (and subsequently) MooTools has gained its popularity. Imagine being able to perform an operation whenever a user hovers over an image, or clicks on a link, or whenever the user submits a form -- the possibilities are endless. Adding a single event listener The addEvent method allows you to add one event listener to an element method and follows the format: $(yourelement).addEvent(event, function(){}) For example, in the following code block, we attach a click event listener for all <a> elements. When the user clicks on any hyperlink on our web page, it runs a function that opens up an alert dialog box that says You clicked on a hyperlink. $$('a').addEvent('click', function(){ alert('You clicked on a hyperlink');}); In a moment, we'll create a simple web form the highlights the input field that the user is focused on. Time for action – Highlighting focused fields of web forms Let's start with our web form's HTML. We'll use <input> and <textarea> tags that will hold our user's information as well as provide them a means to submit the web form (input type="button").We use the <label>  tag to indicate to the user what information to put inside each form field. <form action="" method="get"> <p><label for="Name">Name: </label> <input name="Name" type="text"></p> <p><label for="Email">Email: </label> <input name="Email" type="text"></p> <p><label for="Comment">Comment: </label> <textarea name="Comment" cols="" rows=""></textarea></p> <p><input name="Submit" type="button" value="Submit"></p></form> With the above markup, this is how our form looks like: Our web form is a bit dull, so how about we spruce it up a bit with some CSS? Read the comments to gain insight on some of the more important CSS properties to take a note off. /* Center the fields using text-align:center */form { width:300px; border:1px solid #b1b8c2; background-color:#e3e9f2; text-align:center; padding:25px 0;}label { display:block; font:12px normal Verdana, Geneva, sans-serif;}/* Give the input and textarea fields a 1px border */input, textarea { width:250px; border:1px solid #5c616a;}textarea { height:100px;}p { text-align:left; display:block; width:250px; overflow:auto; padding:0; margin:5px 0;}/* We will give fields that are currently focused on the .focus class which will give them a distinct thicker border and background color compared to the other input fields */.focused { border:3px solid #b1b8c2; background-color: #e8e3e3;} With just a few styles, our simple web form has transformed to a more attractive form field. Let us move onto the JavaScript. We use the addEvent method to add an event listener for the form event, onfocus. When the user focuses on a particular field, we run a function that adds the .focus CSS class on that field we declared as a style rule in step 2. We'll also remove .focus class on other fields on the web page. window.addEvent('domready', function(){ var els = $$('input, textarea') els.addEvent('focus', function(){ els.removeClass('focused'); this.addClass('focused'); })}); Now, when you focus on a form field, it will be highlighted with a thick blue border and with a lighter blue background. Users who use the Tab key to navigate in between form fields will appreciate this feature since they'll clearly see which field is active. What just happened? In the previous example, we created a simple and interactive web form that highlights the current field the user has active. We did this by using the addEvent method, adding an event listener for the focus form event. When the user focuses on a particular input field, we ran a function that adds the .focusCSS class which highlights the focused field <input> or <textarea>with a thick blue border with a light blue background. By highlighting active fields in a web form, we have just improved our form's usability by providing visual feedback about which field the user is currently on.
Read more
  • 0
  • 0
  • 1496
article-image-working-events-mootools-part-2
Packt
07 Jan 2010
10 min read
Save for later

Working with Events in MooTools: Part 2

Packt
07 Jan 2010
10 min read
Removing, Cloning, and Firing off Events Besides adding event listeners, other operations you may want to do are removing events from an element, cloning events from other elements, and firing off events for elements manually. We'll go through each one of these operations. Removing events from elements There are instances when you want to remove an event listener that you've added to an element. One reason would be that you only want to an element to be triggered once, and after that event has been triggered, you no longer want to trigger it again. To ensure it only fires once, you should remove the event once certain conditions have been met. Removing a single event from elements There are two methods available to you for removing events from elements. The first is removeEvent() which removes a single specified event. Time for action – removing an event Let's say you have some hyperlinks on a page, that when clicked, will alert the user that they have clicked a hyperlink, but you only wanted to do it once. To ensure that the warning message appears only once, we'll have to remove the event after it has been fired. This type of thing may be utilized for instructional tips: when the user sees an unfamiliar interface element, you can display a help tip for them, but only once - because you don't want the tip to keep showing up every single time they perform an action. First, let's put some links on a web page. <a href="#">Hyperlink 1</a> <a href="#">Hyperlink 2</a> Next, let's create a function object that we will call whenever a click event happens on any of the links on our page. When the function fires, it will open up an alert box with a message, and then it will remove the click event  from all <a> elements on the web page. // Create an function objectvar warning = function() { alert('You have clicked a link. This is your only warning'); // After warning has executed, remove it $$('a').removeEvent('click', warning);}; Now we add a click event listener that will fire off the warning function object. // Add a click event listener which when triggered, executes the //warning function$$('a').addEvent('click', warning); Our script should look like the following window.addEvent('domready', function(){ // Create an function object that will be executed when a //click happens var warning = function() { alert('You have clicked a link. This is your only warning'); // After warning has executed, remove it from all <a> //elements on the web page $$('a').removeEvent('click', warning); }; // Add a click event listener which when triggered, executes the //warning function $$('a').addEvent('click', warning);}); Test in your web browser by clicking on any of the hyperlinks on the page. The first time you click, you'll see an alert dialog box with our message. The second (or third, forth, fifth… you get the picture) time you click on any hyperlink, the alert dialog box will no longer show up. Removing a type of event, or all events, from elements If you want to remove a type of event on an element (or set of elements), or if you want to remove all events regardless of its type from an element, you have to use the removeEvents method. To remove a type of event from an element, you pass the type of event you want to remove as a parameter of the removeEvents method. For example, if you wanted to remove all click events that were added using MooTools addEvent method from an element called myElement, you would do the following: $('myElement').removeEvents('click'); If instead, you wanted to remove all events that myElement has regardless of the type of event it has, then you would simply run removeEvents as follows: $('myElement').removeEvents(); Cloning events from another element What if you wanted to copy all event listeners from another element. This could be useful in situations where you clone an element using the clone MooTools element method. Cloning an element doesn't copy the event listeners attached to it, so you also have to run the cloneEvents method on the element being cloned if you wanted to also port the event listeners to the copy. To clone the events of an element, follow the format: // clone the elementvar original = $(‘originalElement’);var myClone = original.clone();// clone the events from the originalmyClone.cloneEvents(original); Firing off Events Sometimes you want to fire off events manually. This is helpful in many situations, such as manually firing off an event listener functions that is triggered by another event. For example, to fire off a click event on myElement without having the user actually clicking on myElement, you would do the following: $('myElement').fireEvent('click'); Time for action – firing off a click event Imagine that you have a hyperlink with a click event listener attached to it, that when triggered, alerts the user with a message. But you also want to fire off this alert message when the user presses the Ctrl key. Here's how you'd do this: First, let us place a hyperlink in an HTML document. We'll put it inside a <p> element and tell the users that clicking on the hyperlink or pressing the Ctrl key will open up an alert dialog box. <body> <p>Show a warning by clicking on this link: <a href="#">Click me</a>. Alternatively, you can show the warning by pressing the <strong>Ctrl</strong> key on your keyboard.</p></body> Next, let's add an event to <a> elements. We'll use the addEvent method to do this. // Add a click event$$('a').addEvent('click', function(){ alert('You either clicked a link or pressed the Ctrl key.');}); Now we have to add another event listener onto our HTML document that watches out for a keydown event. The function that the event listener executes will check if the key pressed is the Ctrl key by using the control Event method which returns a Boolean value of true if the Ctrl key is pressed. If the key that was pressed is the Ctrl key, we ask it to fire the click event function that we set in all our a elements by using the fireEvent method with click as its parameter. // Add a keydown event on our web pagewindow.addEvent('keydown', function(e){// If the keypress is the Ctrl key // manually fire off the click event if(e.control) { $$('a').fireEvent('click'); }}); All together, our MooTools script should look like this: window.addEvent('domready', function(){ // Add a click event $$('a').addEvent('click', function(){ alert('You either clicked a link or pressed the Ctrl key.'); }); // Add a keydown event on our web page window.addEvent('keydown', function(e){ // If the keypress is the Ctrl key // manually fire off the click event if(e.control) { $$('a').fireEvent('click'); } });}); Test your HTML document in the web browser. Click on the “Click me” link. It should show you the alert message we created. Press the Ctrl key as well. It should also open up the same alert message we created. The MooTools Event Object The MooTools Event object, which is part of the Native component, is what allows us to create and work with events. It's therefore worth it to take a bit of time to explore the Events object. Using Event Object Methods There are three Event methods: preventDefault, stopPropagation, stop. Preventing the default behavior Events usually has a default behavior; that is, it has a predefined reaction in the instance that the event is triggered. For example, clicking on a hyperlink will direct you to the URL that href property is assigned to. Clicking on a submit input field will submit the form to the value that the action property of the form element is assigned to. Perhaps you want to open the page in a new window, but instead of using the non-standard target property on an <a> element, you can use JavaScript to open the page in a new window. Or maybe you need to validate a form before submitting it. You will want to prevent the default behaviors of an event doing either one of these things. You can use the preventDefault method to do so. Time for action – preventing the default behavior of a hyperlink Imagine that you have a list of hyperlinks that go to popular sites. The thing is, you don't want your website visitors to ever get to see them (at least coming from your site). You can prevent the default behavior of your hyperlinks using the preventDefault method. Here is the HTML markup for a list of <a> elements that go to popular websites. Place it inside an HTML document. <h1>A list of links you can't go to.</h1><ul> <li><a href="http://www.google.com/">Google</a></li> <li><a href="http://www.yahoo.com/">Yahoo!</a></li> <li><a href="http://digg.com/">Digg</a></li> </ul> We will warn the user with an alert dialog box that tells them they can't access the links, even when they click on it. We'll fire this alert dialog box when a user clicks on it. Notice the e argument in the function? That is the event object that is passed into the function, allowing us to access events' methods and properties. $$('a').addEvent('click', function(e){alert('Sorry you can't go there. At least not from this page.'); }); Open your HTML document in a web browser and verify that the links still open their destination, since we haven't prevented the default yet. You will, however, see the alert dialog box we set up in step 2, showing you that, indeed, the click event listener function fires off. Now we will prevent the links from opening by using the preventDefault method. We'll just add the following line above the alert(); line: e.preventDefault(); Test the document again in your web browser. Clicking on any hyperlink opens the alert dialog box, but doesn't open the hyperlink. Preventing event bubbling Event bubbling occurs when you have an element inside another element. When an event is triggered from the child element, the same event is triggered for the parent element, with the child element taking precedence by being triggered first. You can prevent event bubbling using the stopPropagation method. Let's explore the concept of event bubbling and how to prevent it from occurring (if you want to), using the stopPropagation event method.
Read more
  • 0
  • 0
  • 1195

article-image-selecting-dom-elements-using-mootools-12-part-2
Packt
07 Jan 2010
7 min read
Save for later

Selecting DOM Elements using MooTools 1.2: Part 2

Packt
07 Jan 2010
7 min read
Time for action – using pseudo-classes to zebra stripe a table Let's set up the markup for our HTML table - it'll have three columns and six rows listing my favorite movies in order. Pseudo-class example HTML table markup: <body><table width="100%" cellpadding="1" cellspacing="0"> <!-- column headings --> <tr> <th>Rank</th> <th>Movie</th> <th>Genre</th> </tr> <tr> <td>1</td> <td>The Matrix</td> <td>Action</td> </tr> <tr> <td>2</td> <td>Die Hard</td> <td>Action</td> </tr> <tr> <td>3</td> <td>The Dark Knight</td> <td>Action</td> </tr> <tr> <td>4</td> <td>Friday</td> <td>Comedy</td> </tr> <tr> <td>5</td> <td>Love Actually</td> <td>Drama</td> </tr></table></body> Our HTML table should look like this: To color even rows with a light gray color, write this line of code (again, we use the .setStyle() method): $$('table tr:even').setStyle( 'background-color', '#ebebeb' ); Save your work. View your document in a web browser. You should see something like this: Now we're going to style the odd rows. This time, instead of .setStyle(), we're going to use the .setStyles() method so that we can supply more than one CSS property/CSS property value pair to be implemented. Here's the code to accomplish what we set out to do (which you can place right below the code in step 1): $$('table tr:odd').setStyles( { 'background-color' : '#252525', 'color' : '#ffffff'} ); Save your work and view your work in a web browser. Your HTML table that contains my favorite movies of all time should now looks like this: What just happened? We just learned one of the many ways where pseudo-class selectors are helpful. In this case, we took a regular HTML table and zebra striped it so that we have different styles at alternating rows. To zebra stripe our HTML table, we used the :even and :odd pseudo-class selectors to change the background color of even row with a light gray color (#ebebeb in hexadecimal) and all odd rows of our tables with a dark gray background (#252525) with a white foreground color (#ffffff). A couple of notes on the :odd and :even pseudo-class selectorsThe :odd and :even pseudo-classes aren't available in W3C specifications; although the concept of using them is the same, they are custom MooTools pseudo-class selectors.Secondly, the index of each one starts at 0. Because of this, using :even would select the first element  (index 0) and third child elements because their index is actually 0 and 2, respectively. So they're kind of switched around in the conventional sense of odd and even. Other Pseudo-class selectors There are nine MooTools pseudo-class selectors as of version 1.2: Pseudo-class Selector Description :contains Matches elements that contain a particular text string. For example, matching all <div>'s with the text "I love MooTools" is $$('div:contains(I love MooTools)') :empty Matches elements that don't contain anything. For example, $$(div:empty) would match this: <div></div> :enabled Matches elements that are enabled. Usually used in <input> tags. :even Matches all child elements that have an even index. For example, if there are four paragraphs, using $$('p:even') would select the first and third paragraphs (remember that the index starts at 0). :first-child Matches the first child element (i.e. the child with an index of 0). For example, if there are four paragraphs in a <div> element, using $$('div p:first-child') would select the first paragraph inside the <div> element. :last-child Matches the last child element (i.e. the child with the highest index). For example, if there are four paragraphs in a <div> element, using $$('div p:last-child') will select the fourth paragraph inside the <div> element. :not Matches elements that do not match a particular selector. For example, matching all paragraphs that do not have the class .intro would be $$('p:not(.intro)'). :nth-child Matches the nth expression child element. You can use mathematical expressions. For example, $$('div:nth-child(3n+1)') would select the first div (3(0)+1 = index 0 position), 4th div (3(1)+1 = index 4 position)... 3(n)+1 index position. You can also use, as an argument: even, odd, first, and last as in div:nth-child(even) which is exactly like the :even pseudo-class selector. :odd Matches all child elements with an odd index. For example, If there are four paragraphs, using $$('p:odd') would select the second paragraph and fourth paragraph (index 1 position and index 3 position). :only-child Matches all elements that are the only children of  the only child element. For example, $$(p:only-child) would match the paragraph <div><p>only child></p></div> but will not match these paragraphs <div>><p>not an only child></p>><p>not only child></p></div> because it has a sibling paragraph. Working with attribute selectors If you thought MooTools can't get any cooler with element selection - well, it gets much better. MooTools also implements CSS3's Attribute Selectors. An Attribute Selector allows you to select elements based on their CSS attributes, also commonly referred to as properties in MooTools. For example, an <input> tag's type is considered one of its attributes (or properties), so is its class <input type=”text” name=”query” value=”” /> In MooTools (as well as CSS3), the syntax for an attribute selector is as follows: element[attribute=attribute value] For example, if we wanted to select all <input> elements with a type of text, we would write: $$('input[type=text]'); Attribute selector operators Attribute selectors can match attribute values various ways using Attribute selector operators. The following table depicts a list and description of each attribute selector operator. Operator Description = Matches attribute value exactly and literally. For example, $$('a[class=myLinkClass]') will match all <a> elements with the class of myLinkClass. != Matches all elements with the attribute value that is not the value given. For example, $$('a[class!=myLinkClass]') will select all <a> elements that doesn't have the class of myLinkClass. ^= Matches all elements with attribute value that starts with the value given. For example, $$('img[src^=big]') will match all images with the src attribute value the begins with the word big, such as big-picture.png or biggiesmalls.jpg. $= Matches all elements with the attribute value that ends with the value given. For example, $$('img[src$=.jpg]') will select all images that end with .jpg - useful in selecting particular file extensions. Attribute Selector example: styling different types of links Often, you want to indicate to a user what a particular type of link is. For example, you may want to indicate to the user that a particular link goes to another website or that a link is a mailto: link that will open up their default email client. Perhaps, you want to highlight all links that point to a particular domain name like sixrevisions.com.
Read more
  • 0
  • 0
  • 1017

article-image-user-interface-design-icefaces-18-part-2
Packt
30 Nov 2009
11 min read
Save for later

User Interface Design in ICEfaces 1.8: Part 2

Packt
30 Nov 2009
11 min read
Facelets templating To implement the layout design, we use the Facelets templating that is officially a part of the JSF specification since release 2.0. This article will only have a look at certain parts of the Facelets technology. So, we will not discuss how to configure a web project to use Facelets. You can study the source code examples of this article, or have a look at the developer documentation (https://facelets.dev.java.net/nonav/docs/dev/docbook.html) and the articles section of the Facelets wiki (http://wiki.java.net/bin/view/Projects/FaceletsArticles)for further details. The page template First of all, we define a page template that follows our mockup design. For this, we reuse the HelloWorld(Facelets) application. You can import the WAR file now if you did not create a Facelets project. For importing a WAR file, use the menu File | Import | Web | WAR file. In the dialog box, click on the Browse button and select the corresponding WAR file. Click on the Finish button to start the import. The run configuration is done. However, you do not have to configure the Jetty server again. Instead, it can be simply selected as your target. We start coding with a new XHTML file in the WebContent folder. Use the menu File | New | Other | Web | HTML Page and click on the Next button. Use page-template.xhtml for File name in the next dialog. Click on the Next button again and choose New ICEfaces Facelets.xhtml File (.xhtml). Click on the Finish button to create the file. The ICEfaces plugin creates this code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <title> <ui:insert name="title"> Default title </ui:insert> </title> </head> <body> <div id="header"> <ui:include src="/header.xhtml"> <ui:param name="param_name" value="param_value"/> </ui:include> </div> <div id="content"> <ice:form> </ice:form> </div> </body> </html> The structure of the page is almost pure HTML. This is an advantage when using Facelets. The handling of pages is easier and can even be done with a standard HTML editor. The generated code is not what we need. If you try to run this, you will get an error because the header.xhtml file is missing in the project. So, we delete the code between the <body> tags and add the basic structure for the templating. The changed code looks like this: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <title> <ui:insert name="title"> Default title </ui:insert> </title> </head> <body> <table align="center" cellpadding="0" cellspacing="0"> <tr><td><!-- header --></td></tr> <tr><td><!-- main navigation --></td></tr> <tr><td><!-- content --></td></tr> <tr><td><!-- footer --></td></tr> </table> </body> </html> We change the <body> part to a table structure. You may wonder why we use a <table> for the layout, and even the align attribute, when there is a <div> tag and CSS. The answer is pragmatism. We do not follow the doctrine because we want to get a clean code and keep things simple. If you have a look at the insufficient CSS support of the Internet Explorer family and the necessary waste of time to get things running, it makes no sense to do so. The CSS support in Internet Explorer is a good example of the violation of user expectations. We define four rows in the table to follow our layout design. You may have recognized that the <title> tag still has its <ui:insert> definition. This is the Facelets tag we use to tell the templating where we want to insert our page-specific code. To separate the different insert areas from each other, the <ui:insert> has a name attribute. We substitute the comments with the <ui:insert> definitions, so that the templating can do the replacements: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <title> <ui:insert name="title"> Default title </ui:insert> </title> </head> <body> <table align="center" cellpadding="0" cellspacing="0"> <tr><td><ui:insert name="header"/></td></tr> <tr><td><ui:insert name="mainNavigation"/></td></tr> <tr><td><ui:insert name="content"/></td></tr> <tr><td><ui:insert name="footer"/></td></tr> </table> </body> </html> The <ui:insert> tag allows us to set defaults that are used if we do not define something for replacement. Everything defined between <ui:insert> and </ui:insert> will then be shown instead. We will use this to define a standard behavior of a page that can be overwritten, if necessary. Additionally, this allows us to give hints in the rendering output if something that should be defined in a page is missing. Here is the code showing both aspects: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <ice:outputStyle href="/xmlhttp/css/royale/royale.css" /> <title> <ui:insert name="title"> Please, define a title. </ui:insert> </title> </head> <body> <table align="center" cellpadding="0" cellspacing="0"> <tr><td> <ui:insert name="header"> <ice:graphicImage url="/logo.png" /> </ui:insert> </td></tr> <tr><td> <ui:insert name="mainNavigation"> <ice:form> <ice:menuBar noIcons="true"> <ice:menuItem value="Menu 1"/> <ice:menuItem value="Menu 2"/> <ice:menuItem value="Menu 3"/> </ice:menuBar> </ice:form> </ui:insert> </td></tr> <tr><td> <ui:insert name="content"> Please, define some content. </ui:insert> </td></tr> <tr><td> <ui:insert name="footer"> <ice:outputText value="&#169; 2009 by The ICEcubes." /> </ui:insert> </td></tr> </table> </body> </html> The header, the main navigation, and the footer now have defaults. For the page title and the page content, there are messages that ask for an explicit definition. The header has a reference to an image. Add any image you like to the WebContent and adapt the url attribute of the <ice:graphicImage> tag, if necessary. The example project for this article will show the ICEcube logo. It is the logo that is shown in the mockup above. The <ice:menuBar> tag has to be surrounded by a <ice:form> tag, so that the JSF actions of the menu entries can be processed. Additionally, we need a reference to one of the ICEfaces default skins in the <head> tag to get a correct menu presentation. We take the Royale skin here. If you do not know what the Royale skin looks like, you can have a look at the ICEfaces Component Showcase (http://component-showcase.icefaces.org) and select it in the combo box on the top left. After your selection, all components present themselves in this skin definition. Using the template A productive page template has a lot more to define and is also different in its structure. References to your own CSS, JavaScript, or FavIcon files are missing here. The page template would be unmaintainable soon if we were to manage the pull-down menu this way. However, we will primarily look at the basics here. So, we keep the page template for now. Next, we adapt the existing ICEfacesPage1.xhtml to use the page template for its rendering. Here is the original code: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head> <title> <ui:insert name="title"> Default title </ui:insert> </title> </head> <body> <div id="header"> <!-- <ui:include src="/header.xhtml" > <ui:param name="param_name" value="param_value" /> </ui:include> --> </div> <div id="content"> <ice:form> <ice:outputText value="Hello World!"/> <!-- drop ICEfaces components here --> </ice:form> </div> </body> </html> We keep the Hello World! output and use the new page template to give some decoration to it. First of all, we need a reference to the page template so that the templating knows that it has to manage the page. As the page template defines the page structure, we no longer need a <head> tag definition. You may recognize <ui:insert> in the <title> tag. This is indeed the code we normally use in a page template. Facelets has rendered the content in between because it did not find a replacement tag. Theoretically, you are free to define such statements in any location of your code. However, this is not recommended. Facelets has a look at the complete code base and matches pairs of corresponding name attribute definitions between <ui:insert name="..."> and <ui:define name="..."> tags. Here is the adapted code: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <body> <ui:composition template="/page-template.xhtml"> <div id="content"> <ice:form> <ice:outputText value="Hello World!"/> </ice:form> </div> </ui:composition> </body> </html> This code creates the following output: We can see our friendly reminders for the missing title and the missing content. The header, the main navigation, and the footer are rendered as expected. The structure of the template seems to be valid, although we recognize that a CSS fle is necessary to define some space between the rows of our layout table. However, something is wrong. Any idea what it is? If you have a look at the hello-world.xhtml again, you can find our Hello World! output; but this cannot be found in the rendering result. As we use the page template, we have to tell the templating where something has to be rendered in the page. However, we did not do this for our Hello World! output. The following code defines the missing <ui:define> tag and skips the <div> and <ice:form> tags that are not really necessary here: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <body> <ui:composition template="/page-template.xhtml"> <ui:define name="title"> Hello World on Facelets </ui:define> <ui:define name="content"> <ice:outputText value="Hello World!"/> </ui:define> </ui:composition> </body> </html>
Read more
  • 0
  • 0
  • 1685
article-image-user-interface-design-icefaces-18-part-1
Packt
30 Nov 2009
9 min read
Save for later

User Interface Design in ICEfaces 1.8: Part 1

Packt
30 Nov 2009
9 min read
Before we take a more detailed look at the ICEfaces components, we will discuss the desktop character of modern web applications in this article. Desktop technology  is about 40 years old now and there are best practices that can help us in our web application design. An important part of the user interface design is the page layout. We will have a look at the corresponding design process using a mockup tool. The Facelets example will be extended to show how to implement such a mockup design using Facelets templating. Finally, we will have a look at the production-ready templating of ICEfusion. Revival of the desktop The number of desktop-like web applications is growing faster and faster. The demand for this is not a big surprise. Using full-featured desktops meant that users had to suffer from the limited-user model of the first generation Web. This usage gap is now filled by web applications that mimic desktop behavior. However, there is a difference between the desktop and the Web. Although equipped with desktop-like presentations, web applications have to fulfill different user expectations. So, we have a revival of the desktop metaphor in the Web context but it is mixed with user habits based on the first decade of the Web. Nevertheless, the demand for a purer desktop presentation is already foreseeable. If you primarily followed the traditional web programming model in the past, namely the request-response pattern, you may first have to shift your mind to components and events. If you already have some desktop-programming experience you will discover a lot of similarities. However, you will also recognize how limited the Web 2.0 programming world is in comparison to modern desktops. The difference is understandable because desktop design has a long tradition. The first system was built at the end of the 1960s. There is a lot of experience in this domain. Best of all, we have established rules we can follow. Web design is still a challenge compared to desktop design. Although this article cannot discuss all of the important details of today's desktop design, we will have a quick look at the basics that are applicable to nearly all user interface designs. We can subsume all this with the following question: What makes a software system user-friendly? Software ergonomics Have you ever heard of the ISO standard 9241, Ergonomics of Human System Interaction (http://en.wikipedia.org/wiki/ISO_9241)? This standard describes how a system has to be designed to be human-engineered. There are a lot of aspects in it, from the hardware design for a machine that has to be used by a human to the user interface design of software applications. A poor hardware or interface design can result in not only injury, but also mental distress that leads to wastage of working time. The primary target is to prevent humans from damage. The most important part of ISO 9241 for software developers is part 110, dialog principles. It considers the design of dialogs between humans and information systems with a focus on: Suitability for the task Suitability for learning Suitability for individualization Conformity with user expectations Self-descriptiveness Controllability Error tolerance We will take a deeper look at these later. ISO 9241-110 has its roots in a German industry standard based on research work from the early 1980s. I frst had a look at all this during a study almost 20 years ago. Most interesting with part 110 is the stability of the theoretical model behind it. Independent of the technical advances of the IT industry in the last two decades, we can still apply these standards to modern web application design. Challenges The principles of ISO 9241-110 can help you to get better results, but they only serve as a rule. Even if you follow such principles slavishly, the result will not be automatically valuable. Creating a useful interface is still a challenging business. You have to accept a process of trial and error, ask for customer feedback, and accept a lot of iterations in development before usability becomes your friend. The technical limitations that derive from your framework decisions can be additionally frustrating. The problems that we have with today's AJAX technology are a good example of it, especially if you are already experienced with desktop development and its design rules. Apply Occam's razor Everything should be made as simple as possible, but not simpler. Albert Einstein's quote mentions two important aspects in creative processes that are also true for user interface design: Reduction Oversimplification Reduction Have you ever realized how difficult it is to recognize what is important or necessary, and what is superfluous when you enter a new domain? Often, things seem to be clear and pretty simple at the first sight. However, such a perception is based on experiences that were made outside of the domain. There is a lack of essential experiences in a majority of the cases. You may have to invest several years to get the whole picture and develop an accurate understanding before you come to an adequate decision. If your new domain is user interface design, these findings can help you to understand your customers better. If you keep questioning the eye-catching solutions that come to your mind and try to slip into the customer's role, you  will get better results faster. Oversimplification Oversimplification makes user interfaces more complex to use. This phenomenon arises if the target group for a user interface is defined as less experienced than it is in reality. For advanced users, a beginner's design is more time-consuming to use. In many cases, it is assumed that a bigger part of the users consists of beginners. However, reality shows us that advanced users make up the bigger part, whereas beginners and super users may have a portion of up to 10% each. Designing a user interface for beginners that can be used by all users may be an intuitive idea at first sight, but it is not. You have to consider the advanced users if you want to be successful with your design. This is indeed an essential experience to come to an adequate decision. User interface design principles Besides the aforementioned recommendations, the following are the most influential principles for an adequate interface design: Suitability for the task Self-descriptiveness Controllability Conformity with user expectations Error tolerance Suitability for individualization Suitability for learning Suitability for the task Although it seems to be a trivial requirement, the functionality of a web application seldom delivers what the user requires to fulfill his needs. Additionally, the presentation, navigation, or lingo often does not work for the user or is not well-suited for the function it represents. A good user interface design is based on the customer's lingo. You can write a glossary that describes the meaning of terms you use. A requirements management that results in a detailed use case model can help in implementing the adequate functionality. The iterative development of interactive user interface prototypes to get customer feedback allows finding a suitable presentation and navigation. Self-Descriptiveness Ergonomic applications have an interface design that allows answering the following questions at any time: What is the context I am working in at the moment? What is the next possible step? The answers to these questions become immediately important when a user is, for example, disrupted by a telephone call and continues his work after attending to it. The shorter the time to recognize the last working step, the better the design is. A rule of thumb is to have a caption for every web page that describes its context. Navigational elements, such as buttons, show descriptive text that allows recognizing the function behind it. If possible, separate a page into subsections that also have their captions for a better orientation. Controllability Applications have to offer their functionality in a way that the user can decide for himself when and how the application is fulfilling his requirements. For this, it is important that the application offers different ways to start a function. Beginners may prefer using the mouse to select an entry in a pull-down menu. Advanced users normally work with the keyboard because hotkeys let them use the application faster. It is also important that the user must be able to stop his/her work at any time; for example, for a lunch break or telephone call, without any disadvantages. It is not acceptable that the user has to start the last function again. With web application, this cannot be fulfilled in any case because of security reasons or limited server resources. Conformity with User Expectations User expectations are, maybe, the most important principle, but also the most sophisticated one. The expectations are closely connected to the cultural background of the target group. So, the interface designer has to have a similar socialization. We need to have a look at the use of words of the target language. Although target groups share the same language, certain terms can have different meanings; for example, the correct use of colors or pictures in icon bars is pretty important because we use these in contexts without extra explanation. However, there are cases when a color or an image can mean the opposite of what it was designed for. The behavior of an application can also be a problem when it differs from the standards of real-world processes. The advantage of standardization is an immediate understanding of processing steps, or the correct use of tools without education. If an application does not consider this and varies, the standard users have to rethink every step before they can fulfill their duties. This needs extra energy, is annoying, and is pretty bad for the acceptance of the application in the long run. If we look at the design itself, consistency in presentation, navigation, or form use is another important part. The user expects immutable behavior of the application in similar contexts. Contexts should be learned only once, and the learned ones are reusable in all other occurrences. Following this concept also helps to reuse the visual components during development. So, you have a single implementation for each context that is reused in different web pages.
Read more
  • 0
  • 0
  • 1352

article-image-load-validate-and-submit-forms-using-ext-js-30-part-3
Packt
19 Nov 2009
4 min read
Save for later

Load, Validate, and Submit Forms using Ext JS 3.0: Part 3

Packt
19 Nov 2009
4 min read
Loading form data from the server An important part of working with forms is loading the data that a form will display. Here's how to create a sample contact form and populate it with data sent from the server. How to do it... Declare the name and company panel: var nameAndCompany = { columnWidth: .5, layout: 'form', items: [ { xtype: 'textfield', fieldLabel: 'First Name', name: 'firstName', anchor: '95%' }, { xtype: 'textfield', fieldLabel: 'Last Name', name: 'lastName', anchor: '95%' }, { xtype: 'textfield', fieldLabel: 'Company', name: 'company', anchor: '95%' }, { xtype: 'textfield', fieldLabel: 'Title', name: 'title', anchor: '95%' } ]} Declare the picture box panel: var picBox = { columnWidth: .5, bodyStyle: 'padding:0px 0px 0px 40px', items: [ { xtype: 'box', autoEl: { tag: 'div', style: 'padding-bottom:20px', html: '<img id="pic" src="' + Ext.BLANK_IMAGE_URL + '" class="img-contact" />' } }, { xtype: 'button', text: 'Change Picture' } ]} Define the Internet panel: var internet = { columnWidth: .5, layout: 'form', items: [ { xtype: 'fieldset', title: 'Internet', autoHeight: true, defaultType: 'textfield', items: [{ fieldLabel: 'Email', name: 'email', vtype: 'email', anchor: '95%' }, { fieldLabel: 'Web page', name: 'webPage', vtype: 'url', anchor: '95%' }, { fieldLabel: 'IM', name: 'imAddress', anchor: '95%' }] }]} Declare the phone panel: var phones = { columnWidth: .5, layout: 'form', items: [{ xtype: 'fieldset', title: 'Phone Numbers', autoHeight: true, defaultType: 'textfield', items: [{ fieldLabel: 'Home', name: 'homePhone', anchor: '95%' }, { fieldLabel: 'Business', name: 'busPhone', anchor: '95%' }, { fieldLabel: 'Mobile', name: 'mobPhone', anchor: '95%' }, { fieldLabel: 'Fax', name: 'fax', anchor: '95%' }] }]} Define the business address panel: var busAddress = { columnWidth: .5, layout: 'form', labelAlign: 'top', defaultType: 'textarea', items: [{ fieldLabel: 'Business', labelSeparator:'', name: 'bAddress', anchor: '95%' }, { xtype: 'radio', boxLabel: 'Mailing Address', hideLabel: true, name: 'mailingAddress', value:'bAddress', id:'mailToBAddress' }]} Define the home address panel: var homeAddress = { columnWidth: .5, layout: 'form', labelAlign: 'top', defaultType: 'textarea', items: [{ fieldLabel: 'Home', labelSeparator:'', name: 'hAddress', anchor: '95%' }, { xtype: 'radio', boxLabel: 'Mailing Address', hideLabel: true, name: 'mailingAddress', value:'hAddress', id:'mailToHAddress' }]} Create the contact form: var contactForm = new Ext.FormPanel({ frame: true, title: 'TODO: Load title dynamically', bodyStyle: 'padding:5px', width: 650, items: [{ bodyStyle: { margin: '0px 0px 15px 0px' }, items: [{ layout: 'column', items: [nameAndCompany, picBox] }] }, { items: [{ layout: 'column', items: [phones, internet] }] }, { xtype: 'fieldset', title: 'Addresses', autoHeight: true, hideBorders: true, layout: 'column', items: [busAddress, homeAddress] }], buttons: [{ text: 'Save' }, { text: 'Cancel' }]}); Handle the form's actioncomplete event: contactForm.on({ actioncomplete: function(form, action){ if(action.type == 'load'){ var contact = action.result.data; Ext.getCmp(contact.mailingAddress).setValue(true); contactForm.setTitle(contact.firstName + ' ' + contact.lastName); Ext.getDom('pic').src = contact.pic; } }}); Render the form: contactForm.render(document.body); Finally, load the form: contactForm.getForm().load({ url: 'contact.php', params:{id:'contact1'}, waitMsg: 'Loading'}); How it works... The contact form's building sequence consists of defining each of the contained panels, and then defining a form panel that will serve as a host. The following screenshot shows the resulting form, with the placement of each of the panels pinpointed: Moving on to how the form is populated, the JSON-encoded response to a request to provide form data has a structure similar to this: {success:true,data:{id:'1',firstName:'Jorge',lastName:'Ramon',company:'MiamiCoder',title:'Mr',pic:'img/jorger.jpg',email:'[email protected]',webPage:'http://www.miamicoder.com',imAddress:'',homePhone:'',busPhone:'555 555-5555',mobPhone:'',fax:'',bAddress:'123 Acme Rd #001nMiami, FL 33133',hAddress:'',mailingAddress:'mailToBAddress'}} The success property indicates whether the request has succeeded or not. If the request succeeds, success is accompanied by a data property, which contains the contact's information. Although some fields are automatically populated after a call to load(), the form's title, the contact's picture, and the mailing address radio button require further processing. This can be done in the handler for the actioncomplete event: contactForm.on({ actioncomplete: function(form, action){ if(action.type == 'load'){} }}); As already mentioned, the contact's information arrives in the data property of the action's result: var contact = action.result.data; The default mailing address comes in the contact's mailingAddress property. Hence, the radio button for the default mailing address is set as shown in the following line of code: Ext.getCmp(contact.mailingAddress).setValue(true); The source for the contact's photo is the value of contact.pic: Ext.getDom('pic').src = contact.pic; And finally, the title of the form: contactForm.setTitle(contact.firstName + ' ' + contact.lastName); There's more... Although this recipe's focus is on loading form data, you should also pay attention to the layout techniques used—multiple rows, multiple columns, fieldsets—that allow you to achieve rich and flexible user interfaces for your forms. See Also... The next recipe, Serving the XML data to a form, explains how to use a form to load the XML data sent from the server.
Read more
  • 0
  • 0
  • 3594