NestedSortable Rails Plugin

November 19, 2007

If you are a Ruby on Rails developer (if not you should become one) I have good news for you: a Rails plugin that makes it really easy to implement a NestedSortable Widget data source is almost ready for primetime. That will make implementing the NestedSortable Widget as easy as 1-2-3. It is already working, as a matter of fact, its only missing some automated tests, helpers I want to create (for including the NestedSortable widget in your views) and documentation. It works for Rails 1.2.3, I haven’t tested it with Rails edge yet.

I will give a brief overview of how it works. All you need is a model with a column that should hold a foreign key to the parent and a column to hold an index number for the position of the element inside its hierarchy. The defaults (convention over configuration!) are “parent_id” and “position”. Suppose our model (the one we want to nest and sort) is named “Item”. You will only need one line of code to implement a data source for it in your controller:

class ItemsController < ApplicationController
	nested_sortable_data_source_for :item

By default the data source will be created under an action named “order”, inside your controller. Don’t worry, all the defaults can be overridden (wait for the docs or take a peak at the code).

In your view, it will be pretty easy to add the NestedSortable Widget, as always:

	jQuery( function($) {
 			loadUrl: "/items/order/1.json"
<div id="items_sort"></div>

Don’t forget that you will need to include the scripts (jQuery, Interface, etc) and the CSS file for the widget, by putting something like this in the HEAD of your HTML file, in your layout file probably:

<%= stylesheet_link_tag 'ns/nestedsortablewidget' %>
<%= javascript_include_tag "jquery-1.1.4.js" %>
<%= javascript_include_tag "interface-1.2.js" %>
<%= javascript_include_tag "inestedsortable-1.0.1.pack.js" %>
<%= javascript_include_tag "jquery.nestedsortablewidget-1.0.pack.js" %>

Ok, you say. That is neat, but how do I customize what data will be displayed in the columns by my NestedSortable Widget? The default is to display all the columns/attributes your model has (excluding the ID and foreign keys). You can use the :columns option of the nested_sortable_data_source_for to make your data source display pretty much anything you want, in any order you want. Just an example:

		[:title, 'Title of the Item'],
		[:description, 'Description of the Item'],
		[ lambda {|i| i.created_at.to_date.to_formatted_s(:long)}, 'Creation Date'],
		[ lambda {|i| i.attachments.count}, 'Attachments']

If you are smart enough you already got it: it will display a table with 4 columns, the title of the item, description, creation date and the number of attachments it has. Note the use of lambdas (functions that are passed as variables). It gives you the power to display whatever you want in the columns of your NestedSortable Widget.

Ok again, you say. The way things are until now will only allow me to have one set of items per database table. In your application, you will usually have a lot of users, and will not want to create one table per user. You want everything in the same table, and your “item” model probably have a “user_id” foreign key. That has been thought of as well. You have the :conditions option, which will give you the flexibility you need. An example:

	:conditions=> lambda {|controller| {:user_id => controller.params[:id]} }

Note the funky lambdas again. Instead of a lambda, you may pass in a symbol, like :conditions_generator with the name of a method in your controller (make it protected, please) that will generate the conditions for you. The conditions are exactly like the ones you may use in your finders in Rails: they may be strings with SQL, they may be arrays like [“a = ?”, “b”], and anything else that is allowed in Rails conditions.

In your view, in the part you set up the widget, you would probably use something like:

loadUrl: "/items/order/<%=current_user.id%>.json"

This is insecure: users could easily change the order of the items that belong to other users, with little effort. To implement security, you need to make our condition generator a little bit smarter. It is up to you, though…

Briefly, that is what this plugin for Rails does: it makes it ridiculously easy to implement a NestedSortable Widget in your Rails apps (I bet you could do it in 5 minutes!). Don’t show it to your boss, he will probably fire you and begin doing it himself. Note that the data source you create fully supports pagination: you may use any option the NestedSortable Widget provides and it should work like a charm.

To try the plugin, install it using Rails install command, in your Rails application path:

script/plugin install https://nestedsortables.googlecode.com/svn/trunk/rails/nested_sortable


New minor version of NestedSortable

October 17, 2007

The plain Nested Sortable plugin just had its first official version shift, with a minor improvement: you can now prevent a few elements from receiving children, by applying a class to them, and make sure they will always be nodes in the tree. You can configure this using the “noNestingClass” option. Thanks for Peter for giving the idea and figuring out a simple way to do it (it took 3 lines of code).

Get it here: http://nestedsortables.googlecode.com/

jQuery 1.2 was released and it is incompatible with Interface. Some things work, some don’t, and it turns out there is a bug with jQuery 1.2 and the Sortable, in IE only (thanks n3dst4 for reporting). So I am updating my tests to use jQuery 1.1.4, and recommend you guys avoiding  jQuery 1.2 until Interface gets updated (probably never) or the new jQuery user interface plugin, jQuery UI,  is usable enough  to replace it entirely (it is still a little far from it). I wonder whether releasing jQuery 1.2, without making sure it was compatible with Interface,  or waiting until jQuery UI was fully baked, was a good move. It might hurt jQuery popularity, since its current version doesn’t have a decent set of UI plugins (Interface being incompatible and jQuery UI pre-alpha), the first thing people look for when using a JS library.

So, in the not so distant future, I might need to update NestedSortable plugins to use jQuery UI, instead of Interface. It will be a good excuse for a 2.0 version…


The final bits of GSoC

September 16, 2007

I am now considering finalized my work on the GSoC project (from now on call it voluntary work… ;)). After a lot of bug fixing and some documentation, I am releasing the 1.0 version of both NestedSortables jQuery plugins. Please, visit the plugins’ homepage to check out and comment on the documentation. I have compiled the scripts into compressed format and they are now about 75% smaller, and will download pretty fast.

After a lot of helpful comments from folks at the WP-Hackers list, I improved a few details in the WordPress page ordering. I also managed to fix all the remaining problems I mentioned in my last post (more about them later on), so I believe it is now ready to be rolled out in the development version. To try it out, you can check my sandbox (user: test / pass: test), download the development version of WordPress with it (up-to-date as of 19-Sep 2007 16-Sep-2007 WP from trunk), or apply it to your own working copy of WordPress from SVN trunk using this patch (you will probably also need this image, which I think can’t be included in the patch). I will submit the patch to the WordPress TRAC. I hope it gets reviewed and accepted.

Read the rest of this entry »


First showcase of page sorting in WordPress

September 3, 2007

I have finished the integration of the nested sortable widget into WordPress. I have set up a Sandbox WordPress installation, which can be accessed here (use test/test for login, go to “Manage->Pages”, and click “Edit Page Order” in the end of the page list). I have also put up a diff file (untested), which can be applied to your WordPress SVN checkout if you want to try it out on your own instalation (Automattic folks, don’t apply this yet to the WordPress SVN, there are a few details left to be solved, such as compressing the JS code and others, as I explain bellow).

Read the rest of this entry »


The widget is feature complete now

August 25, 2007

UPDATE: The plugin has now reached its 1.0 version, and is available in a compressed version and with documentation. Please check the project homepage at: http://nestedsortables.googlecode.com/

The widget is feature complete now and working well with the major browsers I have tested it (that is, FF2, IE7, IE6 and Safari 3). It took a little bit of hacking to remove the bugs in IE, but in Safari it worked like a charm the first time I tried it (and Safari is also the browser where it looks and feels faster – they probably have the best JavaScript interpreter out there). I changed a few things in the underlying Nested Sortable plugin, so it should be a lot faster now, in all browsers. The test demo can be seen here as usual and is now up-to-date with my latest SVN updates.

Serialization will, by default, send the data using POST and encoding the data using the “query string standard” , which most server side languages should automatically convert to their equivalent data structures for arrays and hashes. You can also configure the widget to return the data in JSON format (for that you need to include the JSON jQuery pluing) and process it in your server using one of the countless JSON libraries available. Following the REST principles under the HTTP protocol, if the HTTP response has a success code the widget will think data was saved correctly. You can even use the same server path (ie. the same script) to retrieve and save the data, since it will use GET to retrieve and POST to save.

I am aware that the “incremental” feature (showcased in the last example) does have a few problems when you change the item from one “page” to the next (even though you see things in a continuum , what you see is actually the different pages, each inside its own UL with a NestedSortable, being rendered in sequence). I am also aware there is a minor cosmetic issue with the spacing of columns in IE6. I am not much of a CSS browser quircks’ wizard and “incremental” shouldn’t be used in WordPress, I presume, so I am going to leave those issues to be solved after the Widget is integrated in WordPress.

If you find any other bugs or have more suggestions, please post a comment.


New Improvements in the Widget

August 21, 2007

Following Mike’s suggestions, I am now using jQuery’s slideIn() and slideOut() as the default effect for page transitions. They are being applied in parallel (the old page slides out while the next slides in). To make this change I had to do some changes to the way different parts of the widget are displayed, I believe things are “jumping up” a lot less when you change from one page to the other. I also added the possibility for the user to use his own custom functions for the transition, which can be applied in parallel or in series.

I have also added the “incremental” option, which will make the new pages that are loaded be incremented to the existing ones in the user display. This is usable by itself. My intention was to allow the user to display the list inside a scrollable div to go along with this option, but after a few tests, I am seeing the dimensions stored in the Sortables would need to be recalculated every time you scroll the div, and I am afraid making this work seamlessly could take some time and possible changes to Interface’s Sortables itself. It would probably be unbearably slow as well.

I changed the demo to showcase these and also a lot of other options that are available. The demo will now load 5 different instances of the widget.

It can be seen here.


Nested Sortable Widget

August 19, 2007

UPDATE:  The plugin has now reached its 1.0 version, and is available in a compressed version and with documentation. Please check the project homepage at: http://nestedsortables.googlecode.com/

I am posting a demo of what I am calling the Nested Sortable Widget here.

In this example I am only showing a small subset of the possible configuration options it has. The component/widget is basically finished, but there is still a tiny bug in IE when you drag items with more than one hierarchy, which I am going to investigate soon. The “save” function also need a few extra hours of work to be finished, but that doesn’t affect the demo. Reports for any other bugs are welcome.

The main features of the component are:

  • Loads data from a JSON data source, with a predefined format (I will explain it once I create the final doc. for the widget, but it is very simple and can be inferred from the demo) . This format is very compact and very easy to generate and manipulate in any server side language, since it only uses standard data structures, like arrays and hashes, unlike XML.
  • Support for pagination, both in the server (it will only load smaller chunks of data each time) and in the client (it will display smaller chunks of data at a time).
  • Funky way to move items from one page to another, following Mike’s suggestion.
  • Can display data with multiple columns, all you have to do is change your data source.
  • Allows you to change the nesting direction to right to left, and it will change the order of the columns automatically.
  • Lots and lots of easy options to to customize the visual appearance of the widget and most of it other aspects. Don’t worry, I will document them all (or you may dig in the code and figure it out now :)).

Read the rest of this entry »