-```
-
-```js
-var el = document.getElementById('items');
-var sortable = Sortable.create(el);
-```
-
-You can use any element for the list and its elements, not just `ul`/`li`. Here is an [example with `div`s](http://jsbin.com/luxero/2/edit?html,js,output).
-
-
----
-
-
-### Options
-```js
-var sortable = new Sortable(el, {
- group: "name", // or { name: "...", pull: [true, false, clone], put: [true, false, array] }
- sort: true, // sorting inside list
- delay: 0, // time in milliseconds to define when the sorting should start
- disabled: false, // Disables the sortable if set to true.
- store: null, // @see Store
- animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
- handle: ".my-handle", // Drag handle selector within list items
- filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function)
- draggable: ".item", // Specifies which items inside the element should be sortable
- ghostClass: "sortable-ghost", // Class name for the drop placeholder
- dataIdAttr: 'data-id',
-
- scroll: true, // or HTMLElement
- scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling.
- scrollSpeed: 10, // px
-
- setData: function (dataTransfer, dragEl) {
- dataTransfer.setData('Text', dragEl.textContent);
- },
-
- // dragging started
- onStart: function (/**Event*/evt) {
- evt.oldIndex; // element index within parent
- },
-
- // dragging ended
- onEnd: function (/**Event*/evt) {
- evt.oldIndex; // element's old index within parent
- evt.newIndex; // element's new index within parent
- },
-
- // Element is dropped into the list from another list
- onAdd: function (/**Event*/evt) {
- var itemEl = evt.item; // dragged HTMLElement
- evt.from; // previous list
- // + indexes from onEnd
- },
-
- // Changed sorting within list
- onUpdate: function (/**Event*/evt) {
- var itemEl = evt.item; // dragged HTMLElement
- // + indexes from onEnd
- },
-
- // Called by any change to the list (add / update / remove)
- onSort: function (/**Event*/evt) {
- // same properties as onUpdate
- },
-
- // Element is removed from the list into another list
- onRemove: function (/**Event*/evt) {
- // same properties as onUpdate
- },
-
- // Attempt to drag a filtered element
- onFilter: function (/**Event*/evt) {
- var itemEl = evt.item; // HTMLElement receiving the `mousedown|tapstart` event.
- },
-
- // Event when you move an item in the list or between lists
- onMove: function (/**Event*/evt) {
- // Example: http://jsbin.com/tuyafe/1/edit?js,output
- evt.dragged; // dragged HTMLElement
- evt.draggedRect; // TextRectangle {left, top, right и bottom}
- evt.related; // HTMLElement on which have guided
- evt.relatedRect; // TextRectangle
- // retrun false; — for cancel
- }
-});
-```
-
-
----
-
-
-#### `group` option
-To drag elements from one list into another, both lists must have the same `group` value.
-You can also define whether lists can give away, give and keep a copy (`clone`), and receive elements.
-
- * name: `String` — group name
- * pull: `true|false|'clone'` — ability to move from the list. `clone` — copy the item, rather than move.
- * put: `true|false|["foo", "bar"]` — whether elements can be added from other lists, or an array of group names from which elements can be taken. Demo: http://jsbin.com/naduvo/2/edit?html,js,output
-
-
----
-
-
-#### `sort` option
-Sorting inside list.
-
-Demo: http://jsbin.com/xizeh/2/edit?html,js,output
-
-
----
-
-
-#### `delay` option
-Time in milliseconds to define when the sorting should start.
-
-Demo: http://jsbin.com/xizeh/4/edit?html,js,output
-
-
----
-
-
-#### `disabled` options
-Disables the sortable if set to `true`.
-
-Demo: http://jsbin.com/xiloqu/1/edit?html,js,output
-
-```js
-var sortable = Sortable.create(list);
-
-document.getElementById("switcher").onclick = function () {
- var state = sortable.option("disabled"); // get
-
- sortable.option("disabled", !state); // set
-};
-```
-
-
----
-
-
-#### `handle` option
-To make list items draggable, Sortable disables text selection by the user.
-That's not always desirable. To allow text selection, define a drag handler,
-which is an area of every list element that allows it to be dragged around.
-
-Demo: http://jsbin.com/newize/1/edit?html,js,output
-
-```js
-Sortable.create(el, {
- handle: ".my-handle"
-});
-```
-
-```html
-
-
:: list item text one
-
:: list item text two
-
-```
-
-```css
-.my-handle {
- cursor: move;
- cursor: -webkit-grabbing;
-}
-```
-
-
----
-
-
-#### `filter` option
-
-
-```js
-Sortable.create(list, {
- filter: ".js-remove, .js-edit",
- onFilter: function (evt) {
- var item = evt.item,
- ctrl = evt.target;
-
- if (Sortable.utils.is(ctrl, ".js-remove")) { // Click on remove button
- item.parentNode.removeChild(item); // remove sortable item
- }
- else if (Sortable.utils.is(ctrl, ".js-edit")) { // Click on edit link
- // ...
- }
- }
-})
-```
-
-
----
-
-
-#### `ghostClass` option
-Class name for the drop placeholder.
-
-Demo: http://jsbin.com/hunifu/1/edit?css,js,output
-
-```css
-.ghost {
- opacity: 0.4;
-}
-```
-
-```js
-Sortable.create(list, {
- ghostClass: "ghost"
-});
-```
-
-
----
-
-
-#### `scroll` option
-If set to `true`, the page (or sortable-area) scrolls when coming to an edge.
-
-Demo:
- - `window`: http://jsbin.com/boqugumiqi/1/edit?html,js,output
- - `overflow: hidden`: http://jsbin.com/kohamakiwi/1/edit?html,js,output
-
-
----
-
-
-#### `scrollSensitivity` option
-Defines how near the mouse must be to an edge to start scrolling.
-
-
----
-
-
-#### `scrollSpeed` option
-The speed at which the window should scroll once the mouse pointer gets within the `scrollSensitivity` distance.
-
-
----
-
-
-
-### Support AngularJS
-Include [ng-sortable.js](ng-sortable.js)
-
-Demo: http://jsbin.com/naduvo/1/edit?html,js,output
-
-```html
-
-```
-
-Using this bindingHandler sorts the observableArray when the user sorts the HTMLElements.
-
-The sortable/draggable bindingHandlers supports the same syntax as Knockouts built in [template](http://knockoutjs.com/documentation/template-binding.html) binding except for the `data` option, meaning that you could supply the name of a template or specify a separate templateEngine. The difference between the sortable and draggable handlers is that the draggable has the sortable `group` option set to `{pull:'clone',put: false}` and the `sort` option set to false by default (overridable).
-
-Other attributes are:
-* options: an object that contains settings for the underlaying sortable, ie `group`,`handle`, events etc.
-* collection: if your `foreach` array is a computed then you would supply the underlaying observableArray that you would like to sort here.
-
-
----
-
-
-### Method
-
-
-##### option(name:`String`[, value:`*`]):`*`
-Get or set the option.
-
-
-
-##### closest(el:`String`[, selector:`HTMLElement`]):`HTMLElement|null`
-For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
-
-
-##### toArray():`String[]`
-Serializes the sortable's item `data-id`'s (`dataIdAttr` option) into an array of string.
-
-
-##### sort(order:`String[]`)
-Sorts the elements according to the array.
-
-```js
-var order = sortable.toArray();
-sortable.sort(order.reverse()); // apply
-```
-
-
-##### save()
-Save the current sorting (see [store](#store))
-
-
-##### destroy()
-Removes the sortable functionality completely.
-
-
----
-
-
-
-### Store
-Saving and restoring of the sort.
-
-```html
-
-
order
-
save
-
restore
-
-```
-
-```js
-Sortable.create(el, {
- group: "localStorage-example",
- store: {
- /**
- * Get the order of elements. Called once during initialization.
- * @param {Sortable} sortable
- * @returns {Array}
- */
- get: function (sortable) {
- var order = localStorage.getItem(sortable.options.group);
- return order ? order.split('|') : [];
- },
-
- /**
- * Save the order of elements. Called onEnd (when the item is dropped).
- * @param {Sortable} sortable
- */
- set: function (sortable) {
- var order = sortable.toArray();
- localStorage.setItem(sortable.options.group, order.join('|'));
- }
- }
-})
-```
-
-
----
-
-
-
-### Bootstrap
-Demo: http://jsbin.com/luxero/2/edit?html,js,output
-
-```html
-
-
-
-
-
-
-
-
-
-
Try sorting the list on the left. It is not possible because it has it's sort option set to false. However, you can still drag from the list on the left to the list on the right.
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
Item 5
+
Item 6
+
-
-
-
Оля✖
-
Владимир✖
-
Алина✖
-
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
Item 5
+
Item 6
+
+
+
new Sortable(example4Left, {
+ group: {
+ name: 'shared',
+ pull: 'clone',
+ put: false // Do not allow items to be put into this list
+ },
+ animation: 150,
+ sort: false // To disable sorting: set sort to false
+});
-
+new Sortable(example4Right, {
+ group: 'shared',
+ animation: 150
+});
+
+
+
+
+
+
Handle
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
Item 5
+
Item 6
+
+
+
new Sortable(example5, {
+ handle: '.handle', // handle's class
+ animation: 150
+});
+
+
+
+
+
+
Filter
+
Try dragging the item with a red background. It cannot be done, because that item is filtered out using the filter option.
+
+
Item 1
+
Item 2
+
Item 3
+
Filtered
+
Item 4
+
Item 5
+
+
+
new Sortable(example6, {
+ filter: '.filtered', // 'filtered' class is not draggable
+ animation: 150
+});
+
+
+
+
+
+
Thresholds
+
Try modifying the inputs below to affect the swap thresholds. You can see the swap zones of the squares colored in dark blue, while the "dead zones" (that do not cause a swap) are colored in light blue.
NOTE: When using nested Sortables with animation, it is recommended that the fallbackOnBody option is set to true. It is also always recommended that either the invertSwap option is set to true, or the swapThreshold option is lower than the default value of 1 (eg 0.65).
+
+
Item 1.1
+
+
Item 2.1
+
Item 2.2
+
+
Item 3.1
+
Item 3.2
+
Item 3.3
+
Item 3.4
+
+
+
Item 2.3
+
Item 2.4
+
+
+
Item 1.2
+
Item 1.3
+
Item 1.4
+
+
Item 2.1
+
Item 2.2
+
Item 2.3
+
Item 2.4
+
+
+
Item 1.5
-
-
-
only put
-
-
Money
-
Force
-
Agility
-
+
+
// Loop through each nested sortable element
+for (var i = 0; i < nestedSortables.length; i++) {
+ new Sortable(nestedSortables[i], {
+ group: 'nested',
+ animation: 150,
+ fallbackOnBody: true,
+ swapThreshold: 0.65
+ });
+}
+
-
+
+
Plugins
-
+
+
+
+
MultiDrag
+
The MultiDrag plugin allows for multiple items to be dragged at a time. You can click to "select" multiple items, and then drag them as one item.
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
Item 5
+
Item 6
+
+
+
new Sortable(multiDragDemo, {
+ multiDrag: true, // Enable multi-drag
+ selectedClass: 'selected', // The class applied to the selected items
+ fallbackTolerance: 3, // So that we can select items on mobile
+ animation: 150
+});
+
+
+
+
+
+
Swap
+
The Swap plugin changes the behaviour of Sortable to allow for items to be swapped with eachother rather than sorted.
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
Item 5
+
Item 6
+
+
+
new Sortable(swapDemo, {
+ swap: true, // Enable swap plugin
+ swapClass: 'highlight', // The class applied to the hovered swap item
+ animation: 150
+});
+
+
+
-
-
-
-
-
Drag handle and selectable text
-
-
-
☰Select text freely
-
☰Drag my handle
-
☰Best of both worlds
-
-
+
-
+
+
Comparisons
-
+
-
-
-
-
-
AngularJS / ng-sortable
-
-
-
- {{remaining()}} of {{todos.length}} remaining
- [ archive ]
-
-
-
- {{todo.text}}
-
-
-
-
-
-
-
-
-
- {{remaining()}} of {{todos.length}} remaining
-
-
-
- {{todo.text}}
-
-
-
-
+
+
jQuery-UI
+
-
+
Dragula
+
-
+
-
-
-
-
-
Code example
-
// Simple list
-var list = document.getElementById("my-ui-list");
-Sortable.create(list); // That's all.
+
-// Or
-var container = document.getElementById("multi");
-var sort = Sortable.create(container, {
- animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
- handle: ".tile__title", // Restricts sort start click/touch to the specified element
- draggable: ".tile", // Specifies which items inside the element should be sortable
- onUpdate: function (evt/**Event*/){
- var item = evt.item; // the current dragged HTMLElement
- }
-});
+
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
diff --git a/jquery.binding.js b/jquery.binding.js
deleted file mode 100644
index 16d7729b4..000000000
--- a/jquery.binding.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * jQuery plugin for Sortable
- * @author RubaXa
- * @license MIT
- */
-(function (factory) {
- "use strict";
-
- if (typeof define === "function" && define.amd) {
- define(["jquery"], factory);
- }
- else {
- /* jshint sub:true */
- factory(jQuery);
- }
-})(function ($) {
- "use strict";
-
-
- /* CODE */
-
-
- /**
- * jQuery plugin for Sortable
- * @param {Object|String} options
- * @param {..*} [args]
- * @returns {jQuery|*}
- */
- $.fn.sortable = function (options) {
- var retVal;
-
- this.each(function () {
- var $el = $(this),
- sortable = $el.data('sortable');
-
- if (!sortable && (options instanceof Object || !options)) {
- sortable = new Sortable(this, options);
- $el.data('sortable', sortable);
- }
-
- if (sortable) {
- if (options === 'widget') {
- return sortable;
- }
- else if (options === 'destroy') {
- sortable.destroy();
- $el.removeData('sortable');
- }
- else if (options in sortable) {
- retVal = sortable[sortable].apply(sortable, [].slice.call(arguments, 1));
- }
- }
- });
-
- return (retVal === void 0) ? this : retVal;
- };
-});
diff --git a/knockout-sortable.js b/knockout-sortable.js
deleted file mode 100644
index 6a7f70137..000000000
--- a/knockout-sortable.js
+++ /dev/null
@@ -1,161 +0,0 @@
-(function () {
- "use strict";
-
- var init = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {
-
- var options = buildOptions(valueAccessor, sortableOptions);
-
- //It's seems that we cannot update the eventhandlers after we've created the sortable, so define them in init instead of update
- ['onStart', 'onEnd', 'onRemove', 'onAdd', 'onUpdate', 'onSort', 'onFilter'].forEach(function (e) {
- if (options[e] || eventHandlers[e])
- options[e] = function (eventType, parentVM, parentBindings, handler, e) {
- var itemVM = ko.dataFor(e.item),
- //All of the bindings on the parent element
- bindings = ko.utils.peekObservable(parentBindings()),
- //The binding options for the draggable/sortable binding of the parent element
- bindingHandlerBinding = bindings.sortable || bindings.draggable,
- //The collection that we should modify
- collection = bindingHandlerBinding.collection || bindingHandlerBinding.foreach;
- if (handler)
- handler(e, itemVM, parentVM, collection, bindings);
- if (eventHandlers[eventType])
- eventHandlers[eventType](e, itemVM, parentVM, collection, bindings);
- }.bind(undefined, e, viewModel, allBindings, options[e]);
- });
-
- viewModel._sortable = Sortable.create(element, options);
-
- //Destroy the sortable if knockout disposes the element it's connected to
- ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
- viewModel._sortable.destroy();
- });
- return ko.bindingHandlers.template.init(element, valueAccessor);
- },
- update = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {
-
- //There seems to be some problems with updating the options of a sortable
- //Tested to change eventhandlers and the group options without any luck
-
- return ko.bindingHandlers.template.update(element, valueAccessor, allBindings, viewModel, bindingContext);
- },
- eventHandlers = (function (handlers) {
-
- var moveOperations = [],
- tryMoveOperation = function (e, itemVM, parentVM, collection, parentBindings) {
- //A move operation is the combination of a add and remove event, this is to make sure that we have both the target and origin collections
- var currentOperation = { event: e, itemVM: itemVM, parentVM: parentVM, collection: collection, parentBindings: parentBindings },
- existingOperation = moveOperations.filter(function (op) {
- return op.itemVM === currentOperation.itemVM;
- })[0];
-
- if (!existingOperation) {
- moveOperations.push(currentOperation);
- }
- else {
- //We're finishing the operation and already have a handle on the operation item meaning that it's safe to remove it
- moveOperations.splice(moveOperations.indexOf(existingOperation), 1);
-
- var removeOperation = currentOperation.event.type === 'remove' ? currentOperation : existingOperation,
- addOperation = currentOperation.event.type === 'add' ? currentOperation : existingOperation;
-
- moveItem(itemVM, removeOperation.collection, addOperation.collection, addOperation.event.clone, addOperation.event);
- }
- },
- //Moves an item from the to (collection to from (collection), these can be references to the same collection which means it's a sort,
- //clone indicates if we should move or copy the item into the new collection
- moveItem = function (itemVM, from, to, clone, e) {
- //Unwrapping this allows us to manipulate the actual array
- var fromArray = from(),
- //It's not certain that the items actual index is the same as the index reported by sortable due to filtering etc.
- originalIndex = fromArray.indexOf(itemVM);
-
- //Remove sortables "unbound" element
- e.item.parentNode.removeChild(e.item);
-
- //This splice is necessary for both clone and move/sort
- //In sort/move since it shouldn't be at this index/in this array anymore
- //In clone since we have to work around knockouts valuHasMutated when manipulating arrays and avoid a "unbound" item added by sortable
- fromArray.splice(originalIndex, 1);
- //Update the array, this will also remove sortables "unbound" clone
- from.valueHasMutated();
- if (clone && from !== to) {
- //Readd the item
- fromArray.splice(originalIndex, 0, itemVM);
- //Force knockout to update
- from.valueHasMutated();
- }
- //Insert the item on its new position
- to().splice(e.newIndex, 0, itemVM);
- //Make sure to tell knockout that we've modified the actual array.
- to.valueHasMutated();
- };
-
- handlers.onRemove = tryMoveOperation;
- handlers.onAdd = tryMoveOperation;
- handlers.onUpdate = function (e, itemVM, parentVM, collection, parentBindings) {
- //This will be performed as a sort since the to/from collections reference the same collection and clone is set to false
- moveItem(itemVM, collection, collection, false, e);
- };
-
- return handlers;
- })({}),
- //bindingOptions are the options set in the "data-bind" attribute in the ui.
- //options are custom options, for instance draggable/sortable specific options
- buildOptions = function (bindingOptions, options) {
- //deep clone/copy of properties from the "from" argument onto the "into" argument and returns the modified "into"
- var merge = function (into, from) {
- for (var prop in from) {
- if (Object.prototype.toString.call(from[prop]) === '[object Object]') {
- if (Object.prototype.toString.call(into[prop]) !== '[object Object]') {
- into[prop] = {};
- }
- into[prop] = merge(into[prop], from[prop]);
- }
- else
- into[prop] = from[prop];
- }
-
- return into;
- },
- //unwrap the supplied options
- unwrappedOptions = ko.utils.peekObservable(bindingOptions()).options || {};
-
- //Make sure that we don't modify the provided settings object
- options = merge({}, options);
-
- //group is handled differently since we should both allow to change a draggable to a sortable (and vice versa),
- //but still be able to set a name on a draggable without it becoming a drop target.
- if (unwrappedOptions.group && Object.prototype.toString.call(unwrappedOptions.group) !== '[object Object]') {
- //group property is a name string declaration, convert to object.
- unwrappedOptions.group = { name: unwrappedOptions.group };
- }
-
- return merge(options, unwrappedOptions);
- };
-
- ko.bindingHandlers.draggable = {
- sortableOptions: {
- group: { pull: 'clone', put: false },
- sort: false
- },
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
- return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.draggable.sortableOptions);
- },
- update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
- return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.draggable.sortableOptions);
- }
- };
-
- ko.bindingHandlers.sortable = {
- sortableOptions: {
- group: { pull: true, put: true }
- },
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
- return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.sortable.sortableOptions);
- },
- update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
- return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.sortable.sortableOptions);
- }
- };
-
-})();
\ No newline at end of file
diff --git a/meteor/README.md b/meteor/README.md
deleted file mode 100644
index c3403582e..000000000
--- a/meteor/README.md
+++ /dev/null
@@ -1,119 +0,0 @@
-Reactive reorderable lists with [Sortable](http://rubaxa.github.io/Sortable/),
-backed by [Meteor.js](http://meteor.com) collections:
-
-* new elements arriving in the collection will update the list as you expect
-* elements removed from the collection will be removed from the list
-* drag and drop between lists updates collections accordingly
-
-Demo: http://rubaxa-sortable.meteor.com
-
-# Meteor
-
-If you're new to Meteor, here's what the excitement is all about -
-[watch the first two minutes](https://www.youtube.com/watch?v=fsi0aJ9yr2o); you'll be hooked by 1:28.
-That screencast is from 2012. In the meantime, Meteor has become a mature JavaScript-everywhere web
-development framework. Read more at [Why Meteor](http://www.meteorpedia.com/read/Why_Meteor).
-
-
-# Usage
-
-Simplest invocation - order will be lost when the page is refreshed:
-
-```handlebars
-{{#sortable }}
-```
-
-Persist the sort order in the 'order' field of each document in the collection:
-
-*Client:*
-
-```handlebars
-{{#sortable items= sortField="order"}}
-```
-
-*Server:*
-
-```js
-Sortable.collections = ; // the name, not the variable
-```
-
-Along with `items`, `sortField` is the only Meteor-specific option. If it's missing, the package will
-assume there is a field called "order" in the collection, holding unique `Number`s such that every
-`order` differs from that before and after it by at least 1. Basically, keep to 0, 1, 2, ... .
-Try not to depend on a particular format for this field; it *is* though guaranteed that a `sort` will
-produce lexicographical order, and that the order will be maintained after an arbitrary number of
-reorderings, unlike with [naive solutions](http://programmers.stackexchange.com/questions/266451/maintain-ordered-collection-by-updating-as-few-order-fields-as-possible).
-
-Remember to declare on the server which collections you want to be reorderable from the client.
-Otherwise, the library will error because the client would be able to modify numerical fields in
-any collection, which represents a security risk.
-
-
-## Passing options to the Sortable library
-
- {{#sortable items= option1=value1 option2=value2...}}
- {{#sortable items= options=myOptions}}
-
-For available options, please refer to [the main README](../README.md#options). You can pass them directly
-or under the `options` object. Direct options (`key=value`) override those in `options`. It is best
-to pass presentation-related options directly, and functionality-related settings in an `options`
-object, as this will enable designers to work without needing to inspect the JavaScript code:
-
-
- ...
- {{#sortable items=Players handle=".sortable-handle" ghostClass="sortable-ghost" options=playerOptions}}
-
-
-Define the options in a helper for the template that calls Sortable:
-
-```js
-Template.myTemplate.helpers({
- playerOptions: function () {
- return {
- group: {
- name: "league",
- pull: true,
- put: false
- },
- sort: false
- };
- }
-});
-```
-
-
-## Events
-
-All the original Sortable events are supported. In addition, they will receive
-the data context in `event.data`. You can access `event.data.order` this way:
-
-```handlebars
-{{#sortable items=players options=playersOptions}}
-```
-
-```js
-Template.myTemplate.helpers({
- playersOptions: function () {
- return {
- onSort: function(/**Event*/event) {
- console.log('Moved player #%d from %d to %d',
- event.data.order, event.oldIndex, event.newIndex
- );
- }
- };
- }
-});
-```
-
-
-# Issues
-
-If you encounter an issue while using this package, please CC @dandv when you file it in this repo.
-
-
-# TODO
-
-* Array support
-* Tests
-* Misc. - see reactivize.js
-* [GitHub issues](https://github.com/RubaXa/Sortable/labels/%E2%98%84%20meteor)
diff --git a/meteor/example/.meteor/.finished-upgraders b/meteor/example/.meteor/.finished-upgraders
deleted file mode 100644
index 8a761038c..000000000
--- a/meteor/example/.meteor/.finished-upgraders
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file contains information which helps Meteor properly upgrade your
-# app when you run 'meteor update'. You should check it into version control
-# with your project.
-
-notices-for-0.9.0
-notices-for-0.9.1
-0.9.4-platform-file
-notices-for-facebook-graph-api-2
diff --git a/meteor/example/.meteor/.gitignore b/meteor/example/.meteor/.gitignore
deleted file mode 100644
index 408303742..000000000
--- a/meteor/example/.meteor/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-local
diff --git a/meteor/example/.meteor/.id b/meteor/example/.meteor/.id
deleted file mode 100644
index b39baa1d8..000000000
--- a/meteor/example/.meteor/.id
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file contains a token that is unique to your project.
-# Check it into your repository along with the rest of this directory.
-# It can be used for purposes such as:
-# - ensuring you don't accidentally deploy one app on top of another
-# - providing package authors with aggregated statistics
-
-ir0jg2douy3yo5mehw
diff --git a/meteor/example/.meteor/packages b/meteor/example/.meteor/packages
deleted file mode 100644
index a33b0edfd..000000000
--- a/meteor/example/.meteor/packages
+++ /dev/null
@@ -1,12 +0,0 @@
-# Meteor packages used by this project, one per line.
-#
-# 'meteor add' and 'meteor remove' will edit this file for you,
-# but you can also edit it by hand.
-
-meteor-platform
-autopublish
-insecure
-rubaxa:sortable
-dburles:mongo-collection-instances
-fezvrasta:bootstrap-material-design
-# twbs:bootstrap
diff --git a/meteor/example/.meteor/platforms b/meteor/example/.meteor/platforms
deleted file mode 100644
index 8a3a35f9f..000000000
--- a/meteor/example/.meteor/platforms
+++ /dev/null
@@ -1,2 +0,0 @@
-browser
-server
diff --git a/meteor/example/.meteor/release b/meteor/example/.meteor/release
deleted file mode 100644
index dab6b552c..000000000
--- a/meteor/example/.meteor/release
+++ /dev/null
@@ -1 +0,0 @@
-METEOR@1.1.0.2
diff --git a/meteor/example/.meteor/versions b/meteor/example/.meteor/versions
deleted file mode 100644
index abcbcf0a3..000000000
--- a/meteor/example/.meteor/versions
+++ /dev/null
@@ -1,53 +0,0 @@
-autopublish@1.0.3
-autoupdate@1.2.1
-base64@1.0.3
-binary-heap@1.0.3
-blaze@2.1.2
-blaze-tools@1.0.3
-boilerplate-generator@1.0.3
-callback-hook@1.0.3
-check@1.0.5
-dburles:mongo-collection-instances@0.3.3
-ddp@1.1.0
-deps@1.0.7
-ejson@1.0.6
-fastclick@1.0.3
-fezvrasta:bootstrap-material-design@0.3.0
-geojson-utils@1.0.3
-html-tools@1.0.4
-htmljs@1.0.4
-http@1.1.0
-id-map@1.0.3
-insecure@1.0.3
-jquery@1.11.3_2
-json@1.0.3
-lai:collection-extensions@0.1.3
-launch-screen@1.0.2
-livedata@1.0.13
-logging@1.0.7
-meteor@1.1.6
-meteor-platform@1.2.2
-minifiers@1.1.5
-minimongo@1.0.8
-mobile-status-bar@1.0.3
-mongo@1.1.0
-observe-sequence@1.0.6
-ordered-dict@1.0.3
-random@1.0.3
-reactive-dict@1.1.0
-reactive-var@1.0.5
-reload@1.1.3
-retry@1.0.3
-routepolicy@1.0.5
-rubaxa:sortable@1.2.0
-session@1.1.0
-spacebars@1.0.6
-spacebars-compiler@1.0.6
-templating@1.1.1
-tracker@1.0.7
-twbs:bootstrap@3.3.4
-ui@1.0.6
-underscore@1.0.3
-url@1.0.4
-webapp@1.2.0
-webapp-hashing@1.0.3
diff --git a/meteor/example/README.md b/meteor/example/README.md
deleted file mode 100644
index 51d154718..000000000
--- a/meteor/example/README.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# RubaXa:Sortable Meteor demo
-
-This demo showcases the two-way integration between the reorderable list
-widget [Sortable](https://github.com/RubaXa/Sortable/) and Meteor.js. Meteor
-Mongo collections are updated when items are added, removed or reordered, and
-the order is persisted.
-
-It also shows list grouping and control over what lists can give or receive
-elements. You can only drag elements from the list to the left onto the list
-to the right.
-
-## Usage
-
-The example uses the local package from the checkout, so it needs to wire
-up some files (`package.js` and `package.json`). This is done by the handy
-run script:
-
-### Windows
-
- git clone https://github.com/RubaXa/Sortable.git
- cd Sortable
- git checkout dev
- cd meteor\example
- run.bat
-
-### Elsewhere
-
- git clone https://github.com/RubaXa/Sortable.git
- cd Sortable
- git checkout dev
- meteor/example./run.sh
-
-## Prior art
-
-### Differential
-
-Differential wrote [a blog post on reorderable lists with
-Meteor](http://differential.com/blog/sortable-lists-in-meteor-using-jquery-ui) and
-[jQuery UI Sortable](http://jqueryui.com/sortable/). It served as inspiration
-for integrating [rubaxa:sortable](rubaxa.github.io/Sortable/),
-which uses the HTML5 native drag&drop API (not without [its
-limitations](https://github.com/RubaXa/Sortable/issues/106)).
-The reordering method used by the Differential example can lead to data loss
-though, because it calculates the new order of a dropped element as the
-arithmetic mean of the elements before and after it. This [runs into limitations
-of floating point precision](http://programmers.stackexchange.com/questions/266451/maintain-ordered-collection-by-updating-as-few-order-fields-as-possible)
-in JavaScript after <50 reorderings.
-
-### Todos animated
-
-http://todos-dnd-animated.meteor.com/ ([source](https://github.com/nleush/meteor-todos-sortable-animation))
-is based on old Meteor Blaze (back then Spark) API, and won't work with current versions.
-It does showcase some neat features, such as animation when collection elements
-are reordered by another client. It uses jQuery UI Sortable as well, which lacks
-some features vs. rubaxa:Sortable, e.g. text selection within the item.
-
-## TODO
-
-* Animation
-* Indication that an item is being edited
diff --git a/meteor/example/client/define-object-type.css b/meteor/example/client/define-object-type.css
deleted file mode 100644
index d67b4b1d7..000000000
--- a/meteor/example/client/define-object-type.css
+++ /dev/null
@@ -1,57 +0,0 @@
-.glyphicon {
- vertical-align: baseline;
- font-size: 80%;
- margin-right: 0.5em;
-}
-
-[class^="mdi-"], [class*=" mdi-"] {
- vertical-align: baseline;
- font-size: 90%;
- margin-right: 0.4em;
-}
-
-.list-pair {
- display: flex; /* use the flexbox model */
- flex-direction: row;
-}
-.sortable {
-/* font-size: 2em;*/
-}
-
-.sortable.source {
- /*background: #9FA8DA;*/
- flex: 0 0 auto;
- margin-right: 1em;
- cursor: move;
- cursor: -webkit-grabbing;
-}
-
-.sortable.target {
- /*background: #3F51B5;*/
- flex: 1 1 auto;
- margin-left: 1em;
-}
-
-.target .well {
-
-}
-
-.sortable-handle {
- cursor: move;
- cursor: -webkit-grabbing;
-}
-.sortable-handle.pull-right {
- margin-top: 0.3em;
-}
-
-.sortable-ghost {
- opacity: 0.6;
-}
-
-/* show the remove button on hover */
-.removable .close {
- display: none;
-}
-.removable:hover .close {
- display: block;
-}
diff --git a/meteor/example/client/define-object-type.html b/meteor/example/client/define-object-type.html
deleted file mode 100644
index d852cbcb5..000000000
--- a/meteor/example/client/define-object-type.html
+++ /dev/null
@@ -1,94 +0,0 @@
-
- Reactive RubaXa:Sortable for Meteor
-
-
-
- {{> navbar}}
-
-
-
-
RubaXa:Sortable - reactive reorderable lists for Meteor
-
Drag attribute types from the left to define an object type on the right
-
\ No newline at end of file
diff --git a/meteor/example/client/define-object-type.js b/meteor/example/client/define-object-type.js
deleted file mode 100644
index ad2a19e2a..000000000
--- a/meteor/example/client/define-object-type.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// Define an object type by dragging together attributes
-
-Template.typeDefinition.helpers({
- types: function () {
- return Types.find({}, { sort: { order: 1 } });
- },
- typesOptions: {
- sortField: 'order', // defaults to 'order' anyway
- group: {
- name: 'typeDefinition',
- pull: 'clone',
- put: false
- },
- sort: false // don't allow reordering the types, just the attributes below
- },
-
- attributes: function () {
- return Attributes.find({}, {
- sort: { order: 1 },
- transform: function (doc) {
- doc.icon = Types.findOne({name: doc.type}).icon;
- return doc;
- }
- });
- },
- attributesOptions: {
- group: {
- name: 'typeDefinition',
- put: true
- },
- onAdd: function (event) {
- delete event.data._id; // Generate a new id when inserting in the Attributes collection. Otherwise, if we add the same type twice, we'll get an error that the ids are not unique.
- delete event.data.icon;
- event.data.type = event.data.name;
- event.data.name = 'Rename me (double click)'
- },
- // event handler for reordering attributes
- onSort: function (event) {
- console.log('Item %s went from #%d to #%d',
- event.data.name, event.oldIndex, event.newIndex
- );
- }
- }
-});
-
-Template.sortableItemTarget.events({
- 'dblclick .name': function (event, template) {
- // Make the name editable. We should use an existing component, but it's
- // in a sorry state - https://github.com/arillo/meteor-x-editable/issues/1
- var name = template.$('.name');
- var input = template.$('input');
- if (input.length) { // jQuery never returns null - http://stackoverflow.com/questions/920236/how-can-i-detect-if-a-selector-returns-null
- input.show();
- } else {
- input = $('');
- name.after(input);
- }
- name.hide();
- input.focus();
- },
- 'blur input[type=text]': function (event, template) {
- // commit the change to the name, if any
- var input = template.$('input');
- input.hide();
- template.$('.name').show();
- // TODO - what is the collection here? We'll hard-code for now.
- // https://github.com/meteor/meteor/issues/3303
- if (this.name !== input.val() && this.name !== '')
- Attributes.update(this._id, {$set: {name: input.val()}});
- },
- 'keydown input[type=text]': function (event, template) {
- if (event.which === 27) {
- // ESC - discard edits and keep existing value
- template.$('input').val(this.name);
- event.preventDefault();
- event.target.blur();
- } else if (event.which === 13) {
- // ENTER
- event.preventDefault();
- event.target.blur();
- }
- }
-});
-
-// you can add events to all Sortable template instances
-Template.sortable.events({
- 'click .close': function (event, template) {
- // `this` is the data context set by the enclosing block helper (#each, here)
- template.collection.remove(this._id);
- // custom code, working on a specific collection
- if (Attributes.find().count() === 0) {
- Meteor.setTimeout(function () {
- Attributes.insert({
- name: 'Not nice to delete the entire list! Add some attributes instead.',
- type: 'String',
- order: 0
- })
- }, 1000);
- }
- }
-});
diff --git a/meteor/example/model.js b/meteor/example/model.js
deleted file mode 100644
index 8ae88226a..000000000
--- a/meteor/example/model.js
+++ /dev/null
@@ -1,2 +0,0 @@
-Types = new Mongo.Collection('types');
-Attributes = new Mongo.Collection('attributes');
diff --git a/meteor/example/run.bat b/meteor/example/run.bat
deleted file mode 100755
index a6d845af5..000000000
--- a/meteor/example/run.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-mklink ..\..\package.js "meteor/package.js"
-mklink package.json "../../package.json"
-meteor run
-del ..\..\package.js package.json
diff --git a/meteor/example/run.sh b/meteor/example/run.sh
deleted file mode 100755
index aab44abf2..000000000
--- a/meteor/example/run.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-# sanity check: make sure we're in the root directory of the example
-cd "$( dirname "$0" )"
-
-# delete temp files even if Ctrl+C is pressed
-int_trap() {
- echo "Cleaning up..."
-}
-trap int_trap INT
-
-ln -s "meteor/package.js" ../../package.js 2>/dev/null
-ln -s "../../package.json" package.json 2>/dev/null
-
-meteor run "$@"
-
-rm ../../package.js package.json
diff --git a/meteor/example/server/fixtures.js b/meteor/example/server/fixtures.js
deleted file mode 100644
index 617acf948..000000000
--- a/meteor/example/server/fixtures.js
+++ /dev/null
@@ -1,75 +0,0 @@
-Meteor.startup(function () {
- if (Types.find().count() === 0) {
- [
- {
- name: 'String',
- icon: ''
- },
- {
- name: 'Text, multi-line',
- icon: ''
- },
- {
- name: 'Category',
- icon: ''
- },
- {
- name: 'Number',
- icon: ''
- },
- {
- name: 'Date',
- icon: ''
- },
- {
- name: 'Hyperlink',
- icon: ''
- },
- {
- name: 'Image',
- icon: ''
- },
- {
- name: 'Progress',
- icon: ''
- },
- {
- name: 'Duration',
- icon: ''
- },
- {
- name: 'Map address',
- icon: ''
- },
- {
- name: 'Relationship',
- icon: ''
- }
- ].forEach(function (type, i) {
- Types.insert({
- name: type.name,
- icon: type.icon,
- order: i
- });
- }
- );
- console.log('Initialized attribute types.');
- }
-
- if (Attributes.find().count() === 0) {
- [
- { name: 'Name', type: 'String' },
- { name: 'Created at', type: 'Date' },
- { name: 'Link', type: 'Hyperlink' },
- { name: 'Owner', type: 'Relationship' }
- ].forEach(function (attribute, i) {
- Attributes.insert({
- name: attribute.name,
- type: attribute.type,
- order: i
- });
- }
- );
- console.log('Created sample object type.');
- }
-});
diff --git a/meteor/example/server/sortable-collections.js b/meteor/example/server/sortable-collections.js
deleted file mode 100644
index 76069a592..000000000
--- a/meteor/example/server/sortable-collections.js
+++ /dev/null
@@ -1,3 +0,0 @@
-'use strict';
-
-Sortable.collections = ['attributes'];
diff --git a/meteor/methods-client.js b/meteor/methods-client.js
deleted file mode 100644
index 52f4ebec2..000000000
--- a/meteor/methods-client.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-Meteor.methods({
- /**
- * Update the sortField of documents with given ids in a collection, incrementing it by incDec
- * @param {String} collectionName - name of the collection to update
- * @param {String[]} ids - array of document ids
- * @param {String} orderField - the name of the order field, usually "order"
- * @param {Number} incDec - pass 1 or -1
- */
- 'rubaxa:sortable/collection-update': function (collectionName, ids, sortField, incDec) {
- var selector = {_id: {$in: ids}}, modifier = {$inc: {}};
- modifier.$inc[sortField] = incDec;
- Mongo.Collection.get(collectionName).update(selector, modifier, {multi: true});
- }
-});
diff --git a/meteor/methods-server.js b/meteor/methods-server.js
deleted file mode 100644
index 9598bfc99..000000000
--- a/meteor/methods-server.js
+++ /dev/null
@@ -1,31 +0,0 @@
-'use strict';
-
-Sortable = {};
-Sortable.collections = []; // array of collection names that the client is allowed to reorder
-
-Meteor.methods({
- /**
- * Update the sortField of documents with given ids in a collection, incrementing it by incDec
- * @param {String} collectionName - name of the collection to update
- * @param {String[]} ids - array of document ids
- * @param {String} orderField - the name of the order field, usually "order"
- * @param {Number} incDec - pass 1 or -1
- */
- 'rubaxa:sortable/collection-update': function (collectionName, ids, sortField, incDec) {
- check(collectionName, String);
- // don't allow the client to modify just any collection
- if (!Sortable || !Array.isArray(Sortable.collections)) {
- throw new Meteor.Error(500, 'Please define Sortable.collections');
- }
- if (Sortable.collections.indexOf(collectionName) === -1) {
- throw new Meteor.Error(403, 'Collection <' + collectionName + '> is not Sortable. Please add it to Sortable.collections in server code.');
- }
-
- check(ids, [String]);
- check(sortField, String);
- check(incDec, Number);
- var selector = {_id: {$in: ids}}, modifier = {$inc: {}};
- modifier.$inc[sortField] = incDec;
- Mongo.Collection.get(collectionName).update(selector, modifier, {multi: true});
- }
-});
diff --git a/meteor/package.js b/meteor/package.js
deleted file mode 100644
index 51bf04b14..000000000
--- a/meteor/package.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// package metadata file for Meteor.js
-'use strict';
-
-var packageName = 'rubaxa:sortable'; // http://atmospherejs.com/rubaxa/sortable
-
-var packageJson = JSON.parse(Npm.require("fs").readFileSync('package.json'));
-
-Package.describe({
- name: packageName,
- summary: 'Sortable: reactive minimalist reorderable drag-and-drop lists on modern browsers and touch devices',
- version: packageJson.version,
- git: 'https://github.com/RubaXa/Sortable.git',
- documentation: 'meteor/README.md'
-});
-
-Package.onUse(function (api) {
- api.versionsFrom(['METEOR@0.9.0', 'METEOR@1.0']);
- api.use('templating', 'client');
- api.use('dburles:mongo-collection-instances@0.3.3'); // to watch collections getting created
- api.export('Sortable'); // exported on the server too, as a global to hold the array of sortable collections (for security)
- api.addFiles([
- 'Sortable.js',
- 'meteor/template.html', // the HTML comes first, so reactivize.js can refer to the template in it
- 'meteor/reactivize.js'
- ], 'client');
- api.addFiles('meteor/methods-client.js', 'client');
- api.addFiles('meteor/methods-server.js', 'server');
-});
-
-Package.onTest(function (api) {
- api.use(packageName, 'client');
- api.use('tinytest', 'client');
-
- api.addFiles('meteor/test.js', 'client');
-});
diff --git a/meteor/publish.sh b/meteor/publish.sh
deleted file mode 100755
index 56cd665ef..000000000
--- a/meteor/publish.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-# Publish package to Meteor's repository, Atmospherejs.com
-
-# Make sure Meteor is installed, per https://www.meteor.com/install.
-# The curl'ed script is totally safe; takes 2 minutes to read its source and check.
-type meteor >/dev/null 2>&1 || { curl https://install.meteor.com/ | sh; }
-
-# sanity check: make sure we're in the root directory of the checkout
-cd "$( dirname "$0" )/.."
-
-ALL_EXIT_CODE=0
-
-# test any package*.js packages we may have, e.g. package.js, package-compat.js
-for PACKAGE_FILE in meteor/package*.js; do
-
- # Meteor expects package.js to be in the root directory of the checkout, so copy there our package file under that name, temporarily
- cp $PACKAGE_FILE ./package.js
-
- # publish package, creating it if it's the first time we're publishing
- PACKAGE_NAME=$(grep -i name package.js | head -1 | cut -d "'" -f 2)
-
- echo "Publishing $PACKAGE_NAME..."
-
- # Attempt to re-publish the package - the most common operation once the initial release has
- # been made. If the package name was changed (rare), you'll have to pass the --create flag.
- meteor publish "$@"; EXIT_CODE=$?
- ALL_EXIT_CODE=$(( $ALL_EXIT_CODE + $EXIT_CODE ))
- if (( $EXIT_CODE == 0 )); then
- echo "Thanks for releasing a new version. You can see it at"
- echo "https://atmospherejs.com/${PACKAGE_NAME/://}"
- else
- echo "We got an error. Please post it at https://github.com/raix/Meteor-community-discussions/issues/14"
- fi
-
- # rm the temporary build files and package.js
- rm -rf ".build.$PACKAGE_NAME" versions.json package.js
-
-done
-
-exit $ALL_EXIT_CODE
diff --git a/meteor/reactivize.js b/meteor/reactivize.js
deleted file mode 100644
index a068a5ebb..000000000
--- a/meteor/reactivize.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
-Make a Sortable reactive by binding it to a Mongo.Collection.
-Calls `rubaxa:sortable/collection-update` on the server to update the sortField of affected records.
-
-TODO:
- * supply consecutive values if the `order` field doesn't have any
- * .get(DOMElement) - return the Sortable object of a DOMElement
- * create a new _id automatically onAdd if the event.from list had pull: 'clone'
- * support arrays
- * sparse arrays
- * tests
- * drop onto existing empty lists
- * insert back into lists emptied by dropping
- * performance on dragging into long list at the beginning
- * handle failures on Collection operations, e.g. add callback to .insert
- * when adding elements, update ranks just for the half closer to the start/end of the list
- * revisit http://programmers.stackexchange.com/questions/266451/maintain-ordered-collection-by-updating-as-few-order-fields-as-possible
- * reproduce the insidious bug where the list isn't always sorted (fiddle with dragging #1 over #2, then back, then #N before #1)
-
- */
-
-'use strict';
-
-Template.sortable.created = function () {
- var templateInstance = this;
- // `this` is a template instance that can store properties of our choice - http://docs.meteor.com/#/full/template_inst
- if (templateInstance.setupDone) return; // paranoid: only run setup once
- // this.data is the data context - http://docs.meteor.com/#/full/template_data
- // normalize all options into templateInstance.options, and remove them from .data
- templateInstance.options = templateInstance.data.options || {};
- Object.keys(templateInstance.data).forEach(function (key) {
- if (key === 'options' || key === 'items') return;
- templateInstance.options[key] = templateInstance.data[key];
- delete templateInstance.data[key];
- });
- templateInstance.options.sortField = templateInstance.options.sortField || 'order';
- // We can get the collection via the .collection property of the cursor, but changes made that way
- // will NOT be sent to the server - https://github.com/meteor/meteor/issues/3271#issuecomment-66656257
- // Thus we need to use dburles:mongo-collection-instances to get a *real* collection
- if (templateInstance.data.items && templateInstance.data.items.collection) {
- // cursor passed via items=; its .collection works client-only and has a .name property
- templateInstance.collectionName = templateInstance.data.items.collection.name;
- templateInstance.collection = Mongo.Collection.get(templateInstance.collectionName);
- } else if (templateInstance.data.items) {
- // collection passed via items=; does NOT have a .name property, but _name
- templateInstance.collection = templateInstance.data.items;
- templateInstance.collectionName = templateInstance.collection._name;
- } else if (templateInstance.data.collection) {
- // cursor passed directly
- templateInstance.collectionName = templateInstance.data.collection.name;
- templateInstance.collection = Mongo.Collection.get(templateInstance.collectionName);
- } else {
- templateInstance.collection = templateInstance.data; // collection passed directly
- templateInstance.collectionName = templateInstance.collection._name;
- }
-
- // TODO if (Array.isArray(templateInstance.collection))
-
- // What if user filters some of the items in the cursor, instead of ordering the entire collection?
- // Use case: reorder by preference movies of a given genre, a filter within all movies.
- // A: Modify all intervening items **that are on the client**, to preserve the overall order
- // TODO: update *all* orders via a server method that takes not ids, but start & end elements - mild security risk
- delete templateInstance.data.options;
-
- /**
- * When an element was moved, adjust its orders and possibly the order of
- * other elements, so as to maintain a consistent and correct order.
- *
- * There are three approaches to this:
- * 1) Using arbitrary precision arithmetic and setting only the order of the moved
- * element to the average of the orders of the elements around it -
- * http://programmers.stackexchange.com/questions/266451/maintain-ordered-collection-by-updating-as-few-order-fields-as-possible
- * The downside is that the order field in the DB will increase by one byte every
- * time an element is reordered.
- * 2) Adjust the orders of the intervening items. This keeps the orders sane (integers)
- * but is slower because we have to modify multiple documents.
- * TODO: we may be able to update fewer records by only altering the
- * order of the records between the newIndex/oldIndex and the start/end of the list.
- * 3) Use regular precision arithmetic, but when the difference between the orders of the
- * moved item and the one before/after it falls below a certain threshold, adjust
- * the order of that other item, and cascade doing so up or down the list.
- * This will keep the `order` field constant in size, and will only occasionally
- * require updating the `order` of other records.
- *
- * For now, we use approach #2.
- *
- * @param {String} itemId - the _id of the item that was moved
- * @param {Number} orderPrevItem - the order of the item before it, or null
- * @param {Number} orderNextItem - the order of the item after it, or null
- */
- templateInstance.adjustOrders = function adjustOrders(itemId, orderPrevItem, orderNextItem) {
- var orderField = templateInstance.options.sortField;
- var selector = {}, modifier = {$set: {}};
- var ids = [];
- var startOrder = templateInstance.collection.findOne(itemId)[orderField];
- if (orderPrevItem !== null) {
- // Element has a previous sibling, therefore it was moved down in the list.
- // Decrease the order of intervening elements.
- selector[orderField] = {$lte: orderPrevItem, $gt: startOrder};
- ids = _.pluck(templateInstance.collection.find(selector, {fields: {_id: 1}}).fetch(), '_id');
- Meteor.call('rubaxa:sortable/collection-update', templateInstance.collectionName, ids, orderField, -1);
-
- // Set the order of the dropped element to the order of its predecessor, whose order was decreased
- modifier.$set[orderField] = orderPrevItem;
- } else {
- // element moved up the list, increase order of intervening elements
- selector[orderField] = {$gte: orderNextItem, $lt: startOrder};
- ids = _.pluck(templateInstance.collection.find(selector, {fields: {_id: 1}}).fetch(), '_id');
- Meteor.call('rubaxa:sortable/collection-update', templateInstance.collectionName, ids, orderField, 1);
-
- // Set the order of the dropped element to the order of its successor, whose order was increased
- modifier.$set[orderField] = orderNextItem;
- }
- templateInstance.collection.update(itemId, modifier);
- };
-
- templateInstance.setupDone = true;
-};
-
-
-Template.sortable.rendered = function () {
- var templateInstance = this;
- var orderField = templateInstance.options.sortField;
-
- // sorting was changed within the list
- var optionsOnUpdate = templateInstance.options.onUpdate;
- templateInstance.options.onUpdate = function sortableUpdate(/**Event*/event) {
- var itemEl = event.item; // dragged HTMLElement
- event.data = Blaze.getData(itemEl);
- if (event.newIndex < event.oldIndex) {
- // Element moved up in the list. The dropped element has a next sibling for sure.
- var orderNextItem = Blaze.getData(itemEl.nextElementSibling)[orderField];
- templateInstance.adjustOrders(event.data._id, null, orderNextItem);
- } else if (event.newIndex > event.oldIndex) {
- // Element moved down in the list. The dropped element has a previous sibling for sure.
- var orderPrevItem = Blaze.getData(itemEl.previousElementSibling)[orderField];
- templateInstance.adjustOrders(event.data._id, orderPrevItem, null);
- } else {
- // do nothing - drag and drop in the same location
- }
- if (optionsOnUpdate) optionsOnUpdate(event);
- };
-
- // element was added from another list
- var optionsOnAdd = templateInstance.options.onAdd;
- templateInstance.options.onAdd = function sortableAdd(/**Event*/event) {
- var itemEl = event.item; // dragged HTMLElement
- event.data = Blaze.getData(itemEl);
- // let the user decorate the object with additional properties before insertion
- if (optionsOnAdd) optionsOnAdd(event);
-
- // Insert the new element at the end of the list and move it where it was dropped.
- // We could insert it at the beginning, but that would lead to negative orders.
- var sortSpecifier = {}; sortSpecifier[orderField] = -1;
- event.data.order = templateInstance.collection.findOne({}, { sort: sortSpecifier, limit: 1 }).order + 1;
- // TODO: this can obviously be optimized by setting the order directly as the arithmetic average, with the caveats described above
- var newElementId = templateInstance.collection.insert(event.data);
- event.data._id = newElementId;
- if (itemEl.nextElementSibling) {
- var orderNextItem = Blaze.getData(itemEl.nextElementSibling)[orderField];
- templateInstance.adjustOrders(newElementId, null, orderNextItem);
- } else {
- // do nothing - inserted after the last element
- }
- // remove the dropped HTMLElement from the list because we have inserted it in the collection, which will update the template
- itemEl.parentElement.removeChild(itemEl);
- };
-
- // element was removed by dragging into another list
- var optionsOnRemove = templateInstance.options.onRemove;
- templateInstance.options.onRemove = function sortableRemove(/**Event*/event) {
- var itemEl = event.item; // dragged HTMLElement
- event.data = Blaze.getData(itemEl);
- // don't remove from the collection if group.pull is clone or false
- if (typeof templateInstance.options.group === 'undefined'
- || typeof templateInstance.options.group.pull === 'undefined'
- || templateInstance.options.group.pull === true
- ) templateInstance.collection.remove(event.data._id);
- if (optionsOnRemove) optionsOnRemove(event);
- };
-
- // just compute the `data` context
- ['onStart', 'onEnd', 'onSort', 'onFilter'].forEach(function (eventHandler) {
- if (templateInstance.options[eventHandler]) {
- var userEventHandler = templateInstance.options[eventHandler];
- templateInstance.options[eventHandler] = function (/**Event*/event) {
- var itemEl = event.item; // dragged HTMLElement
- event.data = Blaze.getData(itemEl);
- userEventHandler(event);
- };
- }
- });
-
- templateInstance.sortable = Sortable.create(templateInstance.firstNode.parentElement, templateInstance.options);
- // TODO make the object accessible, e.g. via Sortable.getSortableById() or some such
-};
-
-
-Template.sortable.destroyed = function () {
- this.sortable.destroy();
-};
diff --git a/meteor/runtests.sh b/meteor/runtests.sh
deleted file mode 100755
index 94aaecf05..000000000
--- a/meteor/runtests.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-# Test Meteor package before publishing to Atmospherejs.com
-
-# Make sure Meteor is installed, per https://www.meteor.com/install.
-# The curl'ed script is totally safe; takes 2 minutes to read its source and check.
-type meteor >/dev/null 2>&1 || { curl https://install.meteor.com/ | sh; }
-
-# sanity check: make sure we're in the root directory of the checkout
-cd "$( dirname "$0" )/.."
-
-
-# delete the temporary files even if Ctrl+C is pressed
-int_trap() {
- printf "\nTests interrupted. Cleaning up...\n\n"
-}
-trap int_trap INT
-
-
-ALL_EXIT_CODE=0
-
-# test any package*.js packages we may have, e.g. package.js, package-standalone.js
-for PACKAGE_FILE in meteor/package*.js; do
-
- # Meteor expects package.js in the root dir of the checkout, so copy there our package file under that name, temporarily
- cp $PACKAGE_FILE ./package.js
-
- PACKAGE_NAME=$(grep -i name package.js | head -1 | cut -d "'" -f 2)
-
- echo "### Testing $PACKAGE_NAME..."
-
- # provide an invalid MONGO_URL so Meteor doesn't bog us down with an empty Mongo database
- if [ $# -gt 0 ]; then
- # interpret any parameter to mean we want an interactive test
- MONGO_URL=mongodb:// meteor test-packages ./
- else
- # automated/CI test with phantomjs
- ./node_modules/.bin/spacejam --mongo-url mongodb:// test-packages ./
- ALL_EXIT_CODES=$(( $ALL_EXIT_CODES + $? ))
- fi
-
- # delete temporary build files and package.js
- rm -rf .build.* versions.json package.js
-
-done
-
-exit $ALL_EXIT_CODES
diff --git a/meteor/template.html b/meteor/template.html
deleted file mode 100644
index 3923d3d9c..000000000
--- a/meteor/template.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
- {{#each items}}
- {{> Template.contentBlock this}}
- {{/each}}
-
diff --git a/meteor/test.js b/meteor/test.js
deleted file mode 100644
index f7c00a9fb..000000000
--- a/meteor/test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-Tinytest.add('Sortable.is', function (test) {
- var items = document.createElement('ul');
- items.innerHTML = '