Built motion from commit 76eb00b9e.|1.0.24
[motion.git] / public / bower_components / Sortable / react-sortable-mixin.js
1 /**
2  * @author RubaXa <trash@rubaxa.org>
3  * @licence MIT
4  */
5
6 (function (factory) {
7         'use strict';
8
9         if (typeof module != 'undefined' && typeof module.exports != 'undefined') {
10                 module.exports = factory(require('./Sortable'));
11         }
12         else if (typeof define === 'function' && define.amd) {
13                 define(['./Sortable'], factory);
14         }
15         else {
16                 /* jshint sub:true */
17                 window['SortableMixin'] = factory(Sortable);
18         }
19 })(function (/** Sortable */Sortable) {
20         'use strict';
21
22         var _nextSibling;
23
24         var _activeComponent;
25
26         var _defaultOptions = {
27                 ref: 'list',
28                 model: 'items',
29
30                 animation: 100,
31                 onStart: 'handleStart',
32                 onEnd: 'handleEnd',
33                 onAdd: 'handleAdd',
34                 onUpdate: 'handleUpdate',
35                 onRemove: 'handleRemove',
36                 onSort: 'handleSort',
37                 onFilter: 'handleFilter',
38                 onMove: 'handleMove'
39         };
40
41
42         function _getModelName(component) {
43                 return component.sortableOptions && component.sortableOptions.model || _defaultOptions.model;
44         }
45
46
47         function _getModelItems(component) {
48                 var name = _getModelName(component),
49                         items = component.state && component.state[name] || component.props[name];
50
51                 return items.slice();
52         }
53
54
55         function _extend(dst, src) {
56                 for (var key in src) {
57                         if (src.hasOwnProperty(key)) {
58                                 dst[key] = src[key];
59                         }
60                 }
61
62                 return dst;
63         }
64
65
66         /**
67          * Simple and easy mixin-wrapper for rubaxa/Sortable library, in order to
68          * make reorderable drag-and-drop lists on modern browsers and touch devices.
69          *
70          * @mixin
71          */
72         var SortableMixin = {
73                 sortableMixinVersion: '0.1.1',
74
75
76                 /**
77                  * @type {Sortable}
78                  * @private
79                  */
80                 _sortableInstance: null,
81
82
83                 componentDidMount: function () {
84                         var DOMNode, options = _extend(_extend({}, _defaultOptions), this.sortableOptions || {}),
85                                 copyOptions = _extend({}, options),
86
87                                 emitEvent = function (/** string */type, /** Event */evt) {
88                                         var method = this[options[type]];
89                                         method && method.call(this, evt, this._sortableInstance);
90                                 }.bind(this);
91
92
93                         // Bind callbacks so that "this" refers to the component
94                         'onStart onEnd onAdd onSort onUpdate onRemove onFilter onMove'.split(' ').forEach(function (/** string */name) {
95                                 copyOptions[name] = function (evt) {
96                                         if (name === 'onStart') {
97                                                 _nextSibling = evt.item.nextElementSibling;
98                                                 _activeComponent = this;
99                                         }
100                                         else if (name === 'onAdd' || name === 'onUpdate') {
101                                                 evt.from.insertBefore(evt.item, _nextSibling);
102
103                                                 var newState = {},
104                                                         remoteState = {},
105                                                         oldIndex = evt.oldIndex,
106                                                         newIndex = evt.newIndex,
107                                                         items = _getModelItems(this),
108                                                         remoteItems,
109                                                         item;
110
111                                                 if (name === 'onAdd') {
112                                                         remoteItems = _getModelItems(_activeComponent);
113                                                         item = remoteItems.splice(oldIndex, 1)[0];
114                                                         items.splice(newIndex, 0, item);
115
116                                                         remoteState[_getModelName(_activeComponent)] = remoteItems;
117                                                 }
118                                                 else {
119                                                         items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]);
120                                                 }
121
122                                                 newState[_getModelName(this)] = items;
123                                                 
124                                                 if (copyOptions.stateHandler) {
125                                                         this[copyOptions.stateHandler](newState);
126                                                 } else {
127                                                         this.setState(newState);
128                                                 }
129                                                 
130                                                 (this !== _activeComponent) && _activeComponent.setState(remoteState);
131                                         }
132
133                                         setTimeout(function () {
134                                                 emitEvent(name, evt);
135                                         }, 0);
136                                 }.bind(this);
137                         }, this);
138
139                         DOMNode = this.getDOMNode() ? (this.refs[options.ref] || this).getDOMNode() : this.refs[options.ref] || this;
140
141                         /** @namespace this.refs — http://facebook.github.io/react/docs/more-about-refs.html */
142                         this._sortableInstance = Sortable.create(DOMNode, copyOptions);
143                 },
144
145                 componentWillReceiveProps: function (nextProps) {
146                         var newState = {},
147                                 modelName = _getModelName(this),
148                                 items = nextProps[modelName];
149
150                         if (items) {
151                                 newState[modelName] = items;
152                                 this.setState(newState);
153                         }
154                 },
155
156                 componentWillUnmount: function () {
157                         this._sortableInstance.destroy();
158                         this._sortableInstance = null;
159                 }
160         };
161
162
163         // Export
164         return SortableMixin;
165 });