Bringing (Re)Order with AJAX
One very important aspect to the usability of SASS::CMS is giving the user the ability to easily set the order of certain items (such as menu items or articles in a newsletter) appear on the site. I felt the best way to accomplish this was to use AJAX to make a drag and drop sortable list. I started with an example by Jordan Boesch at Boe Design. The example was exactly what I wanted, but I needed to translate it to Catalyst.
I wasted a bit of time by not really understanding what I was trying to do. One way SASS::CMS uses this feature is allowing a user to set the order that articles appear in the finalized version. This is a little complicated because the articles should be able to exist in in multiple newsletters, but if an article is reused it might need to be in a different spot in the ordering. So I have three tables in the database articles and newsletters which have a many-to-many relationship with newsletter_articles. The newsletter_articles table has three columns: article_id, newsletter_id and ordering.
This is using an older version of the prototype.js - version 1.5.0_rc2. I hope one day soon, I'll figure out how to make it work with the latest version.
In my <head> tag I have:
[% Catalyst.uri_for('/static/js/prototype.js') %]
[% Catalyst.uri_for('/static/js/scriptaculous.js') %]
[% Catalyst.uri_for('/static/css/reorder.css') %]
<script type="text/javascript">
function updateOrder()
{
var params = {
method : 'post',
parameters : Sortable.serialize('itemlist'),
onLoading: function(){$('msg').show()},
onLoaded: function(){$('msg').hide()}
};
[%# Since SASS::CMS uses this method for different parts of the site. We take a value #%]
[%# that is stashed in the controller to set appropriate function #%]
[% IF newsletter_order == '1' %]
new Ajax.Request('/admin/newsletters/reorder/[% newsletter.id %]', params);
[% ELSIF reorder == '1' %]
new Ajax.Request('/admin/menus/reorder', params);
[% END %]
}
</script>
You can see the CSS at http://sass-cms.net/static/css/reorder.css
Then I put this in the template for the page:
<div>
Click and drag articles to reorder them:
</div>
<div id="msg" style="display:none">
Updating...
</div>
<div id="itemlist" class="list" style="width: 250px;">
[% FOREACH article IN articles -%]
<div class="item" id="item_[% article.id %]">
<div class="remove">
<a href="/admin/newsletters/remove_article/[% article.id %]/[% newsletter.id %]" title="Remove Article">
<img src="/images/icons/delete.png" border="0" alt="Remove Article" />
</a>
</div>
[% article.title %]
</div>
[% END -%]
</div>
<script type="text/javascript">
Sortable.create('itemlist', { onUpdate: updateOrder, treeTag: 'div', tag: 'div' });
</script>
This sends the following to the reorder function:
parameters => { _ => "", "itemlist[]" => [1, 2, 4, 3] },
The array of parameters represents the article's id values that are called by the id="item_[% article.id %]"
So what we have to do in our reorder function is search for an entry in our newsletter_articles join table for the newsletter id that we are working on and for each article id in the order from the "itemlist[]" parameters. Once we have that in our result set, we iterate through the results' value for ordering and update them to reflect the new ordering.
package MyApp::Controller::Admin::Newsletter;
sub reorder : Local {
my ($self, $c, $newsletter_id ) = @_;
my $sort = 0;
my $articles = $c->request->body_params->{"itemlist[]"};
foreach my $article ( ref $articles ? @$articles : $articles ) {
my $ordering = $c->model('MyAppDB::ArticleNewsletter')->find(
{
article_id => $article,
newsletter_id => $newsletter_id
}
);
++$sort;
$ordering->update({ordering => $sort});
}
$c->response->body('Matched YAY');
}
Posted by jay On: Monday April, 2008 11:08