📜 ⬆️ ⬇️

Sortable v1.0: New Features

Hi habr! On the eve of the new year, I want to share my joy - the release of Sortable v1.0 . Exactly a year ago, I presented to your court my little tool for sorting a list using drag'n'drop. All this time I scrupulously collected feedback, added new features and rules, minor bugs. Under the cut, I will talk about new features, integration with AngularJS , Meteor and other nuances.


Introduction


Sortable is a minimalistic tool for organizing sorting within a list and between lists. The library does not depend on jQuery or other solutions, uses the Native Drag'n'Drop API, works on both desktop and touch devices. It has a simple API, easily integrates into a project, and is a great replacement for jQueryUI / Sortable ;]

And so, what new brought this release:


')

Advanced Groups


From the very beginning the library had the opportunity to move between groups, it was enough to give them the same name and it was ready:
// foo  bar —   HTMLElement Sortable.create(foo, { group: 'shared', }); Sortable.create(bar, { group: 'shared' }); 
http://jsbin.com/yexine/1/edit
Work Example (gif)
image

Over time, it became obvious that this was not enough. For example, it was impossible to make so that one list only gave, and another only accepted elements. In addition, the key drawback was the inability to somehow organize the interaction of several groups. It was necessary to develop a solution that would allow to realize the arisen tasks and leave the possibility of expansion for the future, while not losing the current interface.

Now you can set the `group` option as an object with the following properties:

How it works is easier to explain with an example:

To show all possibilities at once, I will solve this problem in two ways.
General groupSeveral groups
http://jsbin.com/yexine/2/edithttp://jsbin.com/yexine/8/edit
 Sortable.create(listA, { group: { name: 'shared', pull: 'clone', put: false } }); Sortable.create(listB, { group: { name: 'shared', put: false } }); Sortable.create(listC, { group: 'shared' }); 
 Sortable.create(listA, { group: { name: 'A', pull: 'clone' } }); Sortable.create(listB, { group: 'B' }); Sortable.create(listC, { group: { put: ['A', 'B'] } }); 

Animation


There is nothing special to paint here, the animation is made very simply, with the help of CSS3 transition, you can enable it by setting the `animation` option to` ms`. Alas, it has shortcomings that have not yet been resolved, but I hope in the future there will be a way to fix them “cheaply”.
http://jsbin.com/yexine/4/edit
Work Example (gif)


Smart scrolling window and list


More recently, the problem arose: to scroll the window when you reach one of the edges. In theory, this should have worked by default, since Native Drag'n'Drop API is used, but in reality the browser is extremely unwilling to scroll the window. There was also a problem if the list is in overflow. Therefore, on reflection, it turned out to make smart scrolling, which scrolled the list first, if it is in an overflow and / or a window if we have reached the edge of the browser. For more fine-tuning three additional options are introduced:
Examples:

Disable sorting


Yes, exactly, it may seem strange, but with the help of this parameter you can disable what this tool was created for;] For example, this can be used to simulate draggable and droppable: http://jsbin.com/xizeh/3/edit ? html, js, output


Methods for getting and changing sorting


Since this library appeared as a result of research into the capabilities of the Drag'n'Drop API, banal methods to get the order or change it simply did not work. Looking into the jQueryUI API, I found that they can only get the order of the elements, but it cannot be changed, this is not the order;] To solve all these problems, the property `store` was added, which accepts an object of two parameters` get` and ` set` for getting and saving sorting, as well as two methods `toArray` and` sort`.

For example, maintaining order through `localStorage` will look like this:
 Sortable.create(users, { store: { //   (  ) get: function (sortable) { var order = localStorage.getItem(sortable.options.group); return order ? order.split('|') : []; }, //   (     ) set: function (sortable) { var order = sortable.toArray(); localStorage.setItem(sortable.options.group, order.join('|')); } } }); 

http://jsbin.com/yexine/7/edit (reorder and refresh the page)


Filtering capability


Suppose you need to make a sortable list with the ability to edit and delete an item. Previously, you would need to independently hang up the necessary handlers. Now, this problem can be solved using the library itself, without additional tools: http://jsbin.com/yexine/6/edit?html,js,output


AngularJS support


Angular is increasingly conquering the market and in order to make it easier for people to use Sortable, it was decided to make a directive for quick integration into the project. Looking at the analogs, I saw an oddity, one and all doing so:
 <ul ui-sortable="sortableOptions" ng-model="items"> <li ng-repeat="item in items">{{ item }}</li> </ul> 

What for? After all, this is simply a copy-paste, and if to be completely honest, a crutch. In my opinion, the following entry would be logical and correct, without `ng-model`:
 <ul ng-sortable="sortableOptions"> <li ng-repeat="item in items">{{ item }}</li> </ul> 

The data we are interested in already contains `ng-repeat`, to get it we need the function` $ parse` and a little trick. The trick is that the data from `ng-repeat` can be obtained only by finding the spec. comment left by the angulyar:
 <ul ng-sortable="{ animation: 150 }"> <!-- ngRepeat: item in items --> <!-- end ngRepeat: item in items --> </ul> 

Now we can create a method for working with data related to `ng-repeat`:
 /** *        ng-repeat * @param {HTMLElement} el * @returns {object} */ function getNgRepeat(el) { //   `scope`    var scope = angular.element(el).scope(); //     var ngRepeat = [].filter.call(el.childNodes, function (node) { return ( (node.nodeType === 8) && (node.nodeValue.indexOf('ngRepeat:') !== -1) ); })[0]; //       ngRepeat = ngRepeat.nodeValue.match(/ngRepeat:\s*([^\s]+)\s+in\s+([^\s|]+)/); //     `expression`      `scope` var itemExpr = $parse(ngRepeat[1]); var itemsExpr = $parse(ngRepeat[2]); return { //     item: function (el) { return itemExpr(angular.element(el).scope()); }, //     `ng-repeat` items: function () { return itemsExpr(scope); } }; } 

Work Example: http://jsbin.com/fumote/1/edit
Full directive code: https://github.com/RubaXa/Sortable/blob/master/ng-sortable.js


Integration with Meteor


This is a completely new feature, which appeared thanks to Dan Dascalescu , so if you use meteor, the library is added to the atmosphere , and Dan added a detailed manual on usage and an example . If anything, put a task labeled meteor on him, he will be happy to help;]


In conclusion, I want to say thanks to all those who took part in the testing and development of the library, even though it is a bit overweight, but it’s still the same easy and flexible tool. Thanks for attention.

Future plans




Examples | Code and documentation | My github | @ibnRubaXa


Source: https://habr.com/ru/post/246373/


All Articles