skozlov / netzke
- Source
- Commits
- Network (1)
- Issues (0)
- Downloads (0)
- Wiki (8)
- Graphs
-
Branch:
master
| name | age | message | |
|---|---|---|---|
| |
README.rdoc | Thu Feb 12 10:27:18 -0800 2009 |
Netzke
Netzke is a framework facilitating creation of reusable and extendable Ext JS + Rails components (widgets), plus a set of ready-to-use components to start with. It’s primarily meant for creating desktop-like web-applications (for example, back-ends), but can also be used to create widgets to be embedded into normal Rails HTML views.
Currently the Netzke framework consists of 2 ruby gems (as well acting as Rails plugins): netzke-core (github.com/skozlov/netzke-core/tree/master) and netzke-basepack (github.com/skozlov/netzke-basepack/tree/master). In the nearest future a gem called ‘netzke’ will be released that will serve as a meta gem having the 2 previously mentioned ones as dependencies.
Introduction
I have seen several attempts to implement some kind of Rails / Ext JS integration, which either appeared to be too generic and rather helpless (something like Ruby wrappers for JavaScript), or too limited in functionality (like a Rails plugin providing an Ext grid). Those projects are trying to save a developer from writing JavaScript one way or another. After several months of working professionally with Rails and Ext JS, I came to the conclusion, that this simply is not realistic: in order to have access to all the power of Ext JS library, one sooner or later comes to the necessity of writing JavaScript - that’s where those approaches show their severe limitations.
Finally, after some 2 years of rethinking and reworking my applications, I came to a a different approach that proved to be satisfactory. I thought that if I need to write JavaScript, at least I want to do it as little as possible. I wanted a way to write the code which will be: reusable, extendible and efficient. Further down I elaborate on each of these key moments, which defined the shape of the framework that I’m calling "Netzke".
Reusability
Writing the client- and server-side code (JavaScript and Ruby, correspondingly) for an Ext grid maybe a lot of work - depending on how much functionality you want to throw in. I wanted my grids not only to allow me to do all the basic CRUD (create-read-update-delete) operations, I also wanted them to be configurable on the fly (say, you want to change the width of a column or the order of the columns), supporting filters, sorting, pagination, etc - a lot of different functionality that I wanted in all my grids. But, from the other side, I wanted my grids to be able to display data from different Rails models, or enforce different permissions, look or behave differently for different users that log into the system, etc. I didn’t want, however, write the JavaScript code for that, I wanted a component which is configurable on the level or Ruby.
Besides grids, of course, I needed other "primitives" - such as forms, trees, layouts of different sorts, as well as I needed reusable compound widgets, an example of which could be a combination of a grid and a form in the same panel, with a form displaying details of the record selected in the grid (doesn’t it sound like something pretty generic?) Or 2 grids, where the one displays the associations of the record selected in the other. Or a tree and a grid… or… well, examples can be many.
With Netzke you are able to embed a fully functional grid into your views by declaring it in the controller like this (a slightly extended example from my netzke-demo project):
netzke :bosses,
:widget_class_name => "GridPanel",
:data_class_name => 'Boss',
:ext_config => {
:rows_per_page => 20,
:title => "Bosses",
:width => 400
},
:prohibit => [:delete, :update],
:columns => [:id, # id should always be included and is by default hidden
:last_name,
{:name => :salary, :read_only => true, :label => "$", :renderer => 'usMoney'},
{:name => :email, :width => 180}]
Most of the configuration options are optional. But have a closer look at them: in :ext_config you may specify any configuration options that is understandable by Ext JS (and some extra, like :rows_per_page). With :prohibit you assign the permissions. With :columns you assign which columns you want the grid to show (and how). Isn’t it pretty?
Once the widget is declared in the controller, you automatically get a couple of helpers that make it easy to embed the widget anywhere in your view.
The same goes for any widget that is created with Netzke, be it a ready-to-use widget from netzke-basepack, or a widget that you created yourself (which, of course, can be made as configurable as you like).
Nesting widgets
Another aspect of reusability is nesting widgets one within another, such creating compound widgets. Any widget that displays one or more Ext.Panel-s with a layout ‘fit’ can easily embed any other widget (even an instance of itself) inside those panels. A typical example of it would be a Netzke::BorderLayoutPanel widget that allows specify nested widgets inside its regions at the configuration time (an example from the netzke-demo project, netzke-demo.local/basic_app/demo):
:clerks => {
:widget_class_name => "BorderLayoutPanel",
:regions => {
:center => {
:widget_class_name => "GridPanel",
:data_class_name => "Clerk",
:ext_config => {
:title => 'Clerks',
:rows_per_page => 20,
:config_tool => true
}
},
:north => {
:widget_class_name => "Panel",
:region_config => {
:height => 100,
:split => true
},
:ext_config => {
:title => false,
:html => '... some explanatory text...'
}
}
}
}
As the result, the widget ‘clerks’ will consist of a BorderLayoutPanel containing a GridPanel in its ‘center’ region and a simple Panel with an explanatory text in its ‘north’ region. You might ask how BorderLayoutPanel shows itself off in this example? Well, resize the region - and its size will get saved on the server.
Another example of a (very simple) compound widget is the last grid on the GridPanel live demo (netzke-demo.writelesscode.com/grid_panel/demo) - see how it gets reloaded by its container, the Wrapper widget, after you change the column configuration (to do that, click the configuration ‘tool’ on the right-up corner).
Dynamical loading of widgets
Talking about nested widgets we have come quite close to the issue of dynamically loaded widgets. Actually, the result of it is similar to nesting widgets at the configuration time, except that the nested widget can get loaded from the server at the run time. That’s what a typical "application" widget would do: when a user triggers a menu item, a corresponding widget gets loaded into the ‘fit’ Panel defined by the application.
Extensibility
Of course, the freedom introduced even by extensive configuration options is not always enough. Maybe you want you grid to implement a specific search, of provide a button for some manipulation on the selected records, etc. Netke allows you to extend widget as any other Ruby class, by means of inheritance.
Say, we want to add a button next to "standard" Netzke::GridPanel buttons, which will generate some default data into the table (a simplified example from Netzke::FieldsConfigurator from the netzke-basepack gem):
module Netzke
class FieldsConfigurator < GridPanel
interface :load_defaults
def actions
super + [{
:text => 'Restore defaults', :handler => 'loadDefaults'
}]
end
def self.js_extend_properties
super.merge({
:load_defaults => <<-JS.l,
function(){
Ext.Ajax.request({
url:this.initialConfig.interface.loadDefaults,
callback:function(){
this.store.reload();
},
scope:this
})
}, this);
}
JS
})
end
def load_defaults(params)
# restore the default data for the model
{}
end
end
end
From the top down:
- with a "interface" declaration we setup a connection between the client and server sides of the widget
- we add an action (which the GridPanel will display as a button in the bottom toolbar) which will call loadDefaults function
- we implement this function on the JavaScript level (yes, this is where we write the JavaScript code)
- we implement the server side functionality in the function with the same name that was specified after "interface"
That’s it. We’ve just created a new Netzke-widget called FieldsConfigurator which inherits all the functionality of the GridPanel, and introduces something more to it.
However, this approach is not the most efficient in the sense of consumed bandwidth in case you’re going to use both GridPanel and FieldsConfigurator widgets in your web-application. It’s because the JavaScript code generated for them is almost identical. This can be avoided by using inheritance on the JavaScript level (additionally to the inheritance in Ruby), in which case the JavaScript code for the FieldsConfigurator class will be as simple as extending GridPanel with the loadDefaults function. This is a somewhat advanced topic, which is not crucial for understanding the framework, so I’ll cover it later.
Efficiency
If you put 2 or more GridPanels in the same view (using provided helpers), Netzke will send the code definition for the GridPanel JavaScript class to the browser only once. Then the grids get instantiated with different configuration parameters. You can see a live demo of this here: netzke-demo.writelesscode.com/grid_panel/demo
When one widget dynamically loads other widgets (a general example would be an application loading a widget on a menu item selection), the classes for the widgets only get loaded into the browser once, which is provided by the built-in caching of widget classes. It makes it much faster to reload the widgets (in the example with an application it would mean activating consequent menu items), because not only the bandwidth is spared, but also the time needed by the browser to interpret the widget’s class code. Live demo of this can be found here: netzke-demo.writelesscode.com/basic_app/demo
FAQ
Will I need to write JavaScript while using Netzke?
In most of the cases - yes. However, the idea is that you do it only once per creating a widget (either from scratch, using only netzke-core, or extending an existing widget - for example, from netzke-basepack). After the widget is created, you can embed it into your views or use it in your Netzke-based desktop-like application.
However, I’m writing netzke-basepack driven by practical needs of my own, which means that the widgets included there are feature-packed and (going to be) used in the real life applications. So, try them out, maybe you’ll hardly need to write any JavaScript code at all.
What’s a Netzke widget precisely?
A Netzke widget is a Ruby class that provides both the server and the client (by generating JavaScript code) side of an isolated piece of client-server functionality. Put simpler, the Ruby class will generate JavaScript code, which (being run by a browser of any other JavaScript-enabled platform, like Adobe Air) will communicate back to the corresponding instance of the same Ruby class to request server-side actions. Having client and server parts of the code combined in the same class, we achieve modularity and testability.
What if I want to use jQuery instead of Ext or Sinatra instead of Rails?
The design decisions I have taken for creating Netzke are neither Ext, nor Rails specific. It means that in some future there may be a version of jQuery+Rails, Ext+Sinatra, or any xxx+yyy version of the Netzke framework, provided that Ruby is used for the server side and JavaScript for the client side. Concerning the language choice, Netzke would not be started without an extreme dynamic nature of both Ruby and JavaScript, and a great level of satisfaction that accompanies dealing with them.
When will there be more widgets available?
I’m creating new widgets according to my own practical needs. As soon as I’ll be getting something generic, I’ll be adding that to netzke-basepack. However, the key idea of Netzke is that it facilitates creating new widgets that are extremely easy to share. Anyone can release another gem/plugin containing other widgets, and that’s what I hope to see happening after a greater deal of documentation is provided on how to create a Netzke widget.
Contact
You may follow Netzke development news and find more tutorials on my blog: blog.writelesscode.com
More frequent news about Netzke mixed with random thoughts and discoveries: twitter.com/skozlov
Email your feedback and suggestions to: sergei@writelesscode.com
Google groups for discussions: groups.google.com/group/netzke
