Ext

Archive for the ‘Google’ Category

Building a Rating Widget with Ext Core 3.0 Final and Google CDN

Wednesday, June 10th, 2009

We are very proud to announce the final release of Ext Core under the MIT license. Your feedback was invaluable. Thank you for all the bugs reported and test cases created. For those of you who are new to Ext Core, we suggest you read the previous blog post about the all the features and examples that we released as part of the beta. You can find a list of changes and fixes we made for the final here.

For this post we will leverage the power of Ext by creating and dissecting a useful star rating example. We hope to share some of the general best practices behind creating unobtrusive, reusable code with Ext Core to liven up your pages.

Making a Splash

Including Ext Core on your site is easier than ever. We are honored to share with the community that Ext Core is now available via the Google AJAX Library API. Many thanks to Ben Lisbakken at Google for working with us to make this a reality.
//any of these will work ;)  <script type="text/javascript" src="....
http://ajax.googleapis.com/ajax/libs/ext-core/3.0/ext-core.js
http://ajax.googleapis.com/ajax/libs/ext-core/3/ext-core.js
http://ajax.googleapis.com/ajax/libs/ext-core/3.0/ext-core-debug.js
http://ajax.googleapis.com/ajax/libs/ext-core/3/ext-core-debug.js
Alternatively, you can use Google AJAX API Loader's google.load() method:
google.load('ext-core', '3');
google.load('ext-core', '3', {uncompressed : true});

Getting Started

Ext Core is a perfect fit for adding behavior to existing HTML. When designing a widget, having a markup structure that provides graceful degradation is an added plus. For this example, we will be using radio buttons. We can "group" the elements to specify which radio buttons are part of the control. It could look something like the following:
<div id="rating1">
    <input type="radio" name="rating1" value="1" title="Very poor">
    <input type="radio" name="rating1" value="2" title="Not that bad">
    <input type="radio" name="rating1" value="3" title="Average">
    <input type="radio" name="rating1" value="4" title="Good">
    <input type="radio" name="rating1" value="5" title="Perfect">
</div>
This markup allows user to have the ability to rate an item even without the fancy stars and additional functionality that we have in mind. Take notice that this simple markup contains powerful information like the name, value and title for each item which we can reuse with our rating widget.

The API

One of the most important aspects of building reusable code is providing your developers a powerful API. Our aim here is to allow developers to progressively enhance and convert the markup into a star rating with a simple API. In this case we will need the element that wraps around the radio controls, and some optional configuration to customize the behavior of the widget. Following the Ext tradition we will provide these configuration options in the form of an object literal. A possible API for our widget could look like this:
//Keep it simple
new Ext.ux.Rating('rating1', {
    showTitles: true
});

Ext.util.Observable

So now that we know how we want to use our component, lets go ahead and actually look at some details on how to write it! In our previous post we mentioned that Ext Core allows you to write neatly structured object-oriented code. Whenever you want to create a piece of functionality, you should try to bundle it into a separate class. In most cases you will need to be able to listen for events on instances of your class. Ext provides a power class, the Ext.util.Observable class, to springboard your development. This is the same class that almost all classes in Ext JS extend from! Our basic shell for our rating plugin could look something like this:
Ext.ns('Ext.ux');
Ext.ux.Rating = Ext.extend(Ext.util.Observable, {
    // Configuration default options
    showTitles: true,
 
    // Our class constructor
    constructor : function(element, config) {
        Ext.apply(this, config);      
        Ext.ux.Rating.superclass.constructor.call(this);     
 
        this.addEvents( 'change');  
 
        this.el = Ext.get(element);
        this.init()
    }
});
For those of you familiar with Ext JS will recognize this pattern. In this piece of code we have created a namespace to put our class into using the Ext.ns() function. Then we create our class using the Ext.extend method with Ext.util.Observable as the base class. We define some configuration options with default values and then set up our constructor method which will be called when we create a new instance of our class. We also define some custom events and wrap the element passed to the constructor with an Ext.Element instance. We use the Ext.get() flexible nature to have support of passing an id string, DOM Element or Ext.Element to our constructor.

Reaching the stars

It is time to think about the things we need to get our widget working. First we want to replace the radio buttons with our stars, we will need to store the values and titles for each star, we want to create a hidden input to put the current value in and finally we need to set up event listeners to listen for mouse hovers and clicks.
init : function() {
    var me = this; 
 
    // Some arrays we are going to store data in
    this.values = [];
    this.titles = [];
    this.stars = [];
 
    // We create a container to put all our stars into
    this.container = this.el.createChild({
        cls: 'ux-rating-container ux-rating-clearfix'
    });
 
    // We use DomQuery to select the radio buttons
    // Then we can loop over the CompositeElement using each
    this.radioBoxes = this.el.select('input[type=radio]');
    this.radioBoxes.each(this.initStar, this);
 
    // We use DomHelper to create our hidden input
    this.input = this.el.createChild({
        tag: 'input',
        type: 'hidden',
        name: this.name,
        value: this.values[this.defaultSelected]
    });
 
    // Lets remove all the radio buttons from the DOM
    this.radioBoxes.remove();
 
    if(this.disabled) {
        this.disable();
    } else {
        // Enable will set up our event listeners
        this.enable();
    }
}

Creating Stars - using DomHelper and accessing the DOM from Ext Element

 
initStar : function(item, all, i) {
    // We use the name and disabled attributes of the first radio button 
    if(i == 0) {
        this.name = item.dom.name;
        this.disabled = item.dom.disabled;		
    }
 
    // Saving the value and title for this star     
    this.values[i] = item.dom.value;
    this.titles[i] = item.dom.title;
 
    // Now actually create the star!
    var star = this.container.createChild({
        cls: 'ux-rating-star'
    });
 
    // Save the reference to this star so we can easily access it later
    this.stars.push(star.dom);
},

Enable and Select Stars - listening for events, using the target of an event and firing custom events

 
enable : function() {
    // ... some code missing here ...
 
    // We will be using the technique of event delegation by listening
    // for bubbled up events on the container       
    this.container.on({
        click: this.onStarClick, 
        mouseover: this.onStarOver,
        mouseout: this.onStarOut,
        scope: this,
        delegate: 'div.ux-rating-star'
    });        
},
 
onStarClick : function(ev, t) {
    if(!this.disabled) {
        this.select(this.stars.indexOf(t));
    }
},
 
select : function(index) {
    // ... some code missing here ...
    else if(index !== this.selected) {
        // Update some properties           
        this.selected = index;
        this.value = this.values[index];
        this.title = this.titles[index];
 
        // Set the value of our hidden input so the rating can be submitted			
        this.input.dom.value = this.value;
 
        // the fillTo() method will fill the stars up until the selected one
        this.fillTo(index, false);
 
        // Lets also not forget to fire our custom event!         
        this.fireEvent('change', this, this.values[index], this.stars[index]);  
}

Filler Up - dom manipulation (adding classes)

 
fillTo : function(index) {
    var cls = 'ux-rating-star-on';
 
    // We add a css class to each star up until the selected one   
    Ext.each(this.stars.slice(0, index+1), function() {
        Ext.fly(this).addClass(cls);
    });
 
    // And then remove the same class from all the stars after this one
    Ext.each(this.stars.slice(index), function() {
        Ext.fly(this).removeClass(cls);
    });      
}

We won't discuss all the details since most of it is pretty straightforward, but the final product should give you a general idea of how to use the basic functionality available in Ext Core to tie together all the missing pieces.

Wrapping it up

In this example we used the following cross-browser compatible functionality available in Ext core:
  • Classical Inheritance Class System
  • Observable Class
  • DomQuery
  • DOM manipulation and traversal
  • Event handling
  • Markup generation

Ext Core makes it fun to write code, and helps you create clean, well-structured classes using a set of cross-browser abstractions on the existing browser API's. For those of you who want to use it or are just interested in seeing the completed work, we have included a version of the widget in the Ext Core Final build. You can see the working widget embedded in the post below:

The example page illustrating this widget can be found here.

Final words

We hope that this library will find its way into many of your dynamic web pages and make your lives as web developers easier and more enjoyable. We are looking forward to seeing the great things you will create using it. We are always looking for ways to make this library better and we think the best way to do that is by listening to your suggestions. So, don't be shy and tell us what you think.

Ext CDN - Custom Builds, Compression, and Fast Performance

Tuesday, November 18th, 2008

We are pleased to announce that Ext has partnered with CacheFly, a global content network, to provide free CDN hosting for the Ext JS framework. Cachefly’s globally distributed network and aggressive caching accelerate the delivery of web content like JavaScript and CSS, making for an even faster Ext experience.

The Ext CDN also provides the ability to create your own custom builds using Ext’s Build It! tool, and host them on the CDN. The custom builder implements features to intelligently cache your component selections, adapter, and Ext version to create a unique custom build. These custom builds are cached across sessions and used by anyone who makes the same selections as you have - allowing for caching of custom builds across applications to fully realize the benefits of the CDN.

Creating a Custom Build

We’ve made the process of creating the custom build on the CDN as simple as a selecting the option.

Using the Custom build

To use your custom build on your own site, insert the output into the HEAD section of your site. If you needed to use a build with no grid or tree support you would just paste the following:

 <script type="text/javascript" src="http://extjs.cachefly.net/builds/ext-cdn-7.js"> </script>
 <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2/resources/css/ext-all.css" />

For those of you that need the complete library and use ext-all.js and ext-all.css we have those available as well.

 <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2/ext-all.js"> </script>
 <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2/resources/css/ext-all.css" />

Summary

There are many ways to judge an application’s performance, however none are as noticeable as the time it takes for an application to load. There are many techniques such as compression using gzip , minification using JSMin, and tools like YSlow to help developers make noticeable improvements. We hope the Ext CDN is another optimization our community will add to their toolbox.

Ext Charting and Mapping with Google Visualizations

Monday, October 13th, 2008

Daily Forum Ratio GaugesCreating cross-browser consistent visualizations of data without Adobe’s Flash plugin has always been a difficult issue to address. Google introduced a Visualization API earlier this year which enables you to present tabular data in the form of charts, maps, and other graphical representations without the need for Flash. (Some visualizations actually do use flash, but most are implemented with SVG and/or VML.)

Working with different API’s can present hurdles as we attempt to massage the same data in two different data structures - one for a grid and another for a pie chart. To address this specific challenge, I developed a short user extension Ext.ux.GVisualizationPanel enabling users to integrate visualizations into Ext JS applications without concern for these issues. The GVisualizationPanel adapts any Ext data Store into the google’s format and enables you to embed any type of visualization into a panel.

Adapting google’s DataTable to an Ext Store

All Google Visualization’s are backed by a google.visualization.DataTable. According to Google, “A DataTable is a two dimensional table, with rows and columns and cells. Each column has a defined data type.” Google’s DataTable and Ext’s data Store are analogous and serve similar purposes. Their primary purpose is to enable developers to manipulate data in a single place and drive your GUI from that data. In order to continue changing our data in a single place and avoid having to manually synchronize 2 data structures, we will need to create an adapter to convert any Ext Store to a Google Table.

Differences between Ext.data.Store and google.visualization.DataTable

A key difference between Ext’s Store and Google’s DataTable is that the Ext data Store only handles data & schema information. On the contrary, Google’s DataTable requires presentation information like Label’s. The Ext.ux.GDataTableAdapter eliminates any inconsistencies between the 2 API’s allowing you to apply the same store to a visualization as you would apply to an Ext GridPanel. Ext.data.Store provides the developer with more formats by choosing a JsonReader, XmlReader or ArrayReader. Google’s DataTable is limited to programmatically adding data via methods or loading data from a Google Spreadsheet. This makes the Ext.data.Store a more favorable data structure in most cases. A final difference between Ext.data.Store and Google DataTable is that they each use different data types.

Using the Adapter

By eliminating the differences between Store and Table with the adapter, a single Ext.data.Store can be bound to Ext components and Google Visualizations at the same time. The Organizational Chart sample demonstrates how to synchronize a Google OrganizationChart and an Ext grid by binding them to the same Ext.data.Store. The sample also demonstrates how to consume the ’select’ event exposed by the GVisualizationPanel.

Google Orgchart Screenshot with Binding

Adapting your existing Ext Store’s can be done with Ext.ux.GDataTableAdapter’s static adapt method.

var dataTable = Ext.ux.GDataTableAdapter.adapt({
	store: myDs,
	columns: [{
		dataIndex: 'yr',
		label: 'Year'
	},{
		dataIndex: 'sales',
		label: 'Sales'
	},{
		dataIndex: 'expenses',
		label: 'Expenses'
	}]
});


Using the GVisualizationPanel

GVisualizationPanel works like any typical Ext.Panel and can partake in the container model and layout management. This means you can integrate it into your existing border layout or as a custom portlet. The class has been registered with the xtype of ‘gvisualization’. To use a visualization you will need to determine the visualizationPkg you’d like to use from Google. Then setup an appropriate store and pass in the visualizationPkg, store and columns configuration to create a new visualization.

For example, to create the Intensity Map used in the demo we can use the following code:

var countryStore = new Ext.data.SimpleStore({
    fields: [{
        name: 'Country',
        type: 'string'
    },{
 
        name: 'pop',
        type: 'int'
    },{
        name: 'area',
        type: 'int'
    }],
    data: [
        ['CN', 1324, 9640821],        
        ['IN', 1134, 3287263],
        ['US', 304, 9629091],
        ['ID', 232, 1904569],
        ['BR', 187, 8514877]        
    ]
});
var intensityMap = new Ext.ux.GVisualizationPanel({
    id: 'intensityMap',
    visualizationPkg: 'intensitymap',
    title: 'Intensity Map Sample',
    store: countryStore,
    columns: ['Country',{
        dataIndex: 'pop',
        label: 'Population (mil)'
    },{
        dataIndex: 'area',
        label: 'Area (km2)'
    }]
});



In Conclusion

Using the GDataTableAdapter to adapt or convert an Ext.data.Store to a google.visualization.DataTable is a good way to allow Ext Developers to use Google Visualizations without worrying about any underlying differences. Some of Google’s Visualizations have additional configuration options which can be used through a visualizationCfg configuration. GVisualizationPanel is a powerful implementation which supports any of the visualizations provided by Google in their gallery by simply setting a visualizationPkg config. Take a look at the many different types of visualizations available in Google’s Visualization Gallery.

Google Contacts: Creating a Google Chrome App with Ext and the Google Data API

Tuesday, September 9th, 2008

When Google Chrome was released last week, I was interested in seeing how the Application mode feature worked. I revived an old project to interface with the Google Contacts Data API and built a small application to manage your google contacts which you can ‘install’. The example extends the Ext.data.DataProxy to allow you to populate a store with your contact information to bind to any store driven components such as Grid, EditorGrid, ComboBox and DataView. Google Contact Manager

Google Contact Manager

Google Contact Manager will show and allow you to edit the title, primary email and primary phone of all your contacts. At this time there is nothing special that you need to keep in mind when developing a Google Chrome Application. To ‘install’ an application, select the Page icon to the right of the URL box and choose “Create Application shortcuts…” You can then choose to create shortcuts on your Desktop, Start Menu or Quick Launch bar. I chose to create the shortcut on my Desktop. Hopefully Google releases an additional API or a 3rd party plugin which allows you to integrate your web app with more desktop like features. How to Install Google Contact Manager

Working with the Google Data API

This example interfaces directly with Google’s Data API with no need for a server-side backend. Google has released a JavaScript developer guide which is very useful when interfacing with their API. The example authenticates using Google’s AuthSub proxy to obtain the contact information. The authentication token is stored as a cookie with a two-year expiration. One additional caveat when using the Google JavaScript API is that you must have an image hosted at the same domain as your page or it cannot authenticate. Google has recently released many different Data API’s which you can interact with directly through JavaScript including a Language Translation API, a Visualization API and a Notebook API.

Google Chrome’s Future

Google Chrome seems like it will be a game-changing step made by Google for the browser environment. If they kept this project secret for nearly 2 years, I wonder what else they have up their sleeves. I am eagerly awaiting the stable release of Google Chrome as well as the Linux and OS X versions. Google Chrome is currently in Beta and therefore it is not yet an officially supported browser. We have full intentions of bringing Google Chrome into our supported platforms and have created an issue tracking thread on the forums.


© 2006-2009 Ext, LLC