h1

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 :)).

More details about pagination

In the demo I am showing it being used with pagination, with 5 items per page, on a dataset of about 30 items. I set up a simple PHP page as a demo data source that will spit clusters of a bigger JSON with the whole data, according to the page requested (actually, you request the first item and the total number of items you want, as I will explain). Optionally, you may simplify the data source and always reply with the whole dataset, pagination will still happen in the client side. Or your data source may be “greedy” and reply with a bigger chunk than the one requested. The component will be smart enough not to request any data it already has. Using Firebug in Firefox allows you to see very easily when and what data is being requested/returned.

In most cases I think sending the whole chunk of data could be the simpler and also the faster way to handle pagination, specially in the WordPress page list use case. It would be very unlikely, to have a user with more than, say, 100 pages to order, which are still very fast to load at once (I am guessing it would take less than 5kB for 100 items). If you do that, the client will still see the data paginated, but the server doesn’t need to worry about it at all. The component obviously has support for no pagination as well, you only have to turn a flag off, and in this case the client will see all the data at once.

You will notice that in my demo a page won’t always have 5 items, sometimes it will have more: this is by design, as if I was to enforce only 5 items per page we would have to break hierarchies in half, what would be weird for the user and terrible to program, as well, as I have discussed in earlier posts. The way I figured to solve the inconsistencies and avoid duplicate items among pages is described in the following paragraphs:

First, what does the component displays in each page then? Initially, when it is loaded, it requests the first item of the page being loaded. If loading the third page with 5 elements per page, that would be the element with the zero-based index order of 15. But it will actually display the first element after the one with index 15 that doesn’t have any parents – we will call it a ‘root’ element from now on. And it will display at least 5 items, since it will always show complete hierarchies.

When the component needs some data to display a page, it will make a request with 2 parameters:

  • firstIndex (what is the zero-based ordered position of the next item I want to fetch and display. Note the component actually wants to display, as the first item in the page being shown to the user, the first root element after it, but it doesn’t know in advance what it is )
  • count (how many items, at minimum, should be returned)

The server should reply with the data, in JSON format, that, besides the data itself, has the following parameters:

  • requestFirstIndex (what firstIndex was requested)
  • count (how many items were actually returned, which should be greater or equal to what was requested)
  • firstIndex (what was the index of the first element actually returned; ideally, it should be the first root item after requestFirstIndex , but it could be also be any root element before it, it could even be ’0′, if the server decided to return the whole dataset )
  • totalCount (how many items does the dataset has in total)

Note that the server should always return the whole data that the component wanted to display. Eg: if we request firstIndex = 10, count=5, the server could return firstIndex = 5, count=20, but not firstIndex = 5, count=8.

To be brief: The server should always return what the component wants to display right now, but it could also return more, to the left, or to the right. I know it may sound a little confusing, but it is actually not that big deal.

About these ads

4 comments

  1. Nice work.

    The interface feels a little odd, though, when moving from page to page.

    Instead of the yellow glow, what do you think about sliding the old content up out of view and sliding the new content up into view. That’d be a nice visual cue that you were actually moving to the next page.

    Or instead of sliding, you could have it display all the pages it’s been sent so far in a div of (almost) fixed height with a scroll bar, and the “hover over this” elements could just do the scrolling for you. You’d get sliding for free then, and maybe being able to scroll through stuff is the most natural experience for people.

    If you think the scroll idea is a good one, you could even do something fancy like infinite scrolling (see http://userscripts.org/scripts/show/8430).

    Not sure which of those ideas would result in a cleaner feeling interface. What do you think?


  2. Mike: I think both suggestions sound great. I wonder if the infinite scrolling solution would not confuse the user a little bit, since it is very different from how things are paginated in the web.

    Do you think that, in the infinite scrolling solution, we should keep the ‘load next/previous page’ links? I think it would be very weird for the user to have things loading when he scrolled to the end of the page, without any apparent action from him. Considering the delays involved, things could get nasty. Maybe adding an option to just show the whole list at once, but inside a scrollable div, would be a good compromise. I already added auto-scrolling to the NestedSortable plugin, so it should be very easy to do.

    The sliding solution seems more “web intuitive” to me, and, as long as it doesn’t get too slow, I think it could be a good choice. Maybe providing the user a choice on what transition effect could be the best compromise.

    Actually, I think pagination in this context of sorting things is a bit awkward, any way you handle it. In the WordPress Page list use case, where it will be very hard for a user to have hundreds of pages, I think it shouldn’t be used, at least not as a default option.


  3. You’re right, some kind of user action is a good idea in the infinite scrolling case. If you don’t think it would feel right, there’s no need to work on it. Just something to keep in mind.

    jQuery slides have never seemed slow to me (slow as is processor intensive); they seem to work just fine. And yeah, for the jQuery plugin, you could offer something like effectIn and effectOut options for what effect to use for the removing the page you were just looking at and adding the page you’re about to be looked at (you know best).

    Pagination is awkward, that’s why it was a GSoC project :) It needed someone’s attention. The problem is that most people have at most a dozen or so pages, but that a few people have multiple hundreds. For those few people, organizing is a nightmare both because the current interface is really annoying and because the Manage -> Pages screen can take a long time to load.

    I’d guess we’d paginate at 50 or 100 for WP.


  4. I already implemented the slide option and most of the ‘infinite pagination’, it is a little late now, I will update the demo tomorrow. With slide it really feels fast and looks better.



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: