Drag-n-Drop Sorting of Documents [ROUGH CUT]
Imagine the following situation - say you've got a set of documents which are all children of one container document. From within this parent container document you want to be able to quickly change the order in which the child documents appear. Sound familiar? It's a scenario I've come across a couple of times before and only now have I found a solution I'm happy with enough to share.
A Real-World Scenario
Let's use the example of a newsletter document. In this case the parent form is called something like newsletter and simply contains the title and date of the newsletter. Once saved we can add the child news item document to it. It's these news items that it would be nice to be able to sort as the author pleases.
In most cases news would be sorted by date/time. However with newsletter this is not always the case and so being able to adjust the order is a must in most cases. Whether or not you need to compile newsletters there's bound to be a scenario where the following technique would come in handy.
How to Sort Documents
The idea for the technique came to me both out of a necessity to develop it and from the inspiration I took from a demo of the Yahoo! UI Library, where they have a cross-browser sortable list.
Support
- Full
- Win / IE 6+ (IE 5.5 too?)
- Win & Mac / Mozilla (Firefox 1.5, Camino 1.0 etc)
- Mac / Safari 2.0 (should work in 1.2+ ?)
- Partial
- Win & Mac / Opera 8.5 (No Ajax, but sorting and form submission work)
- None
- Win / Opera 9.0 (sorting broken)
- Mac / IE 5.2 (no Ajax OR sorting. dead browser anyhow)
ass
Coding
Flesh-out the following items:
- An embedded view is treated as HTML and renders a set of LI elements on the parent document.
- When the page loads the script.aculo.us code makes this list sortable.
- Whenever a news item is moved (i.e the list items) the list of UNIDs for each child (in the new order) is posted to the server as an Ajax request.
- The Ajax request is sent to the UpdateOrder form where the UNIDs are stored in a multivalue field called NewOrder.
- The WQS agent for the UpdateOrder form iterates through each UNID and updates the news item's order (but only if it needs to)
- The agent returns (content-type:text/plain) a list of what it did.
- The browser-side script displays this list of changes to the user and uses the Yellow Fade Technique to highlight the message.
Notes:
- When Ajax isn't supported the "Update" button can be used. Note, however, that Ajax is only likely not to work on older browser or those with no script support. On these browsers it's unlikely that the drag-n-drop sorting will work and, so, there's not much point in the button. I left the button on because there could be a case when sorting does work but Ajax doesn't. Safari 1.0 or some Opera versions for example.
- Each LI has a hidden field called NewOrder. This is passed via POST to the server when Ajax is not used and the button is pressed instead.
Turned off conflicts in child form.
Mention inclusion of hidden text field in each LI element for use when no Ajax (although not in Safari, where order of fields is not reflected after re-sort)
Demo
Available here
Downloads
Most up to date database is Version 0.5
Version 0.5 fixes a problem in all previous versions described in this blog entry and also up
grades to Prototype 1.5 and Scriptaculous 1.7.
Version 0.1 uses the Yahoo! UI Library instead of Script.aculo.us and does NO T use Ajax. Horses for courses.
Taking It Further
Rep conflicts are a problem. How about having the Ajax call check the last-mod dates. Or with XML
Summary
Put summary here
Is using Ajax a good idea?
Wither SortOrder fields
I'm working on something EXACTLY like this right now, only my problem is I want to be able to drag/drop table rows.
I've only seen IE only solutions. No good here, so I was going to write my own. Wonder if it's not just easier to build a list like this... and create a new table/row for each list item and just drag/drop that way. Hmmm...
I use a bunch of functionality that uses a hidden iframe as a controller to send URL's back to the server when something is done (like clicking on a delete document link). I'd probably just call an agent with a bunch of parameters identifying the changes to the sort order, so no need for ajax.
Reply
Re: Wither SortOrder fields
Hi Bob,
Just had a quick thought for your problem with the Table row.
Instead of replacing the row itself, why not just swap the contents of the rows around!
Later
Patrick
Reply
Re: Wither SortOrder fields
Bob. Look here http://ajaxscaffold.height1percent.com/ Download the code and look at script.js file. In it the comment states:
// The following is a cross browser way to move around <tr> elements in a <table> or <tbody>
Not tested/tried but it sounds promising.
Jake
Reply
Re: Wither SortOrder fields
Bob/Jake,
Any luck with sorting table rows as I m struggling to implement such a scenario as fields are constructed on the fly using AJAX and DHHTML ?
Jas
Reply
That's the ticket!
That is some cool stuff!!
Reply
Wow!
That's cool! :)
Reply
Problems in IE
A couple of notes. I'm going to look deeper, but I figured I'd pass along what I found. Re-ordering in IE leaves the innerHTML tag set to the red message. If you then perform another drang and drop, it appears to trigger the onComplete as the yellow fade happens, though the entire message is not calculated (the documents are not listed after the message). The script also appears to crash Firefox 1.5. 1.5.0.1 works but does not print out the proper message.
Reply
Re: Problems in IE
It turned out to be something screwy here. I downloaded the app again and re-signed the agent and it works fine. Now I can start picking it apart and learning more from the maestro.
Reply
lotusnotes
very nice
Reply
Do you have a later version
I noticed that you upgraded the code at one time. Is this still the method you use for drag and drop sorting of documents?
Have you or anyone implemented this with a categorized view?
Reply
Re: Do you have a later version
Hi Tanny,
Yes, this is still what I use and recommend.
Adding it to a categorised view might not be easy.
It would depend if you want to drag items from one category to another?
Jake
Reply
Hide the rest of this thread
Re: Do you have a later version
Yes, I would like to drag items from one category to another, but maybe a rethinking the design will negate that requirement. If I restrict to category then make the user go into the document to change the category might be the ticket. I'll have to look at how that works with the UI. What I have is a database that users can create a corporate look and feel website. The top menu is made up of up to six sections which is the category. In the administration view I can limit the documents to just one category. It's a thought.
Reply
Re: Do you have a later version
It's possible to do it using the same D'N'D feature. You'd have to have the view treated as HTML and have each category live inside a new UL. You'd then have to specify that each UL is "droppable". Whether the AJAX call can alert the server which category it was dropped in to or not I'm not sure. I'd imagine it could. If I had a bit more spare time I'd do it for you. It can be done though. Jake
Reply
Re: Do you have a later version
I already create a multi-level unordered list for the left navigation, there's no reason I couldn't do that for a view. I use aqtree3clickable.js to make each section collapsible.
http://www.kryogenix.org/code/browser/aqlists/
Reply
Re: Do you have a later version
I got it done, though I had to change setStyle in the prototype.js file because of a "feature" of IE 7. When you add a CSS filter to an element in IE 7 it turns off clear type.
http://tanny.ica.com/ICA/TKO/tkoblog.nsf/dx/has-ie7-broken-css-filters
Now that might not be a problem for some, but it is a problem for me. The D'N'D code sets opacity when dragging then sets opacity to 1 when it finishes dragging. In IE a filter is used to set opacity. Because it leaves a filter the dropped item's text appears pixilated. The solution is to remove the filter if the filter is blank. I added the following statements after the three places that it sets adds the filter in setStyle for opacity.
if(element.style.filter.length === 0) element.style.removeAttribute('filter');
Not the best solution, the text is still pixilated when dragging but at least clear type gets turned back on when the item is dropped.
Reply
Window scrolling when dragging
Currently the code does not allow the user to drag a news item below the bottom of the browser window if the body is scrolled. To fix that change the code at the bottom of the page from:
Sortable.create('NewOrder', {onUpdate:updateOrder})
To:
Sortable.create('NewOrder', {scroll:window,onUpdate:updateOrder})
This will allow the window to scroll while the user drags a news item to the non-visible area of the page.
Reply
Can this sort technique be used for a view that has been imbedded in a subform?
Reply
The technique should apply anywhere - no matter whether it's on a subform or not.
Reply
Show the rest of this thread