Browse Source

Allow a custom setState handler on the using component

Only components having a state are currently working correctly with the sortable mixing. The proposed fix is to allow custom state handling method to be passed in as config.
pull/595/head
Slavic Dragovtev 9 years ago
parent
commit
44e1ab8f00
  1. 303
      react-sortable-mixin.js

303
react-sortable-mixin.js vendored

@ -4,155 +4,160 @@
*/ */
(function (factory) { (function (factory) {
'use strict'; 'use strict';
if (typeof module != 'undefined' && typeof module.exports != 'undefined') { if (typeof module != 'undefined' && typeof module.exports != 'undefined') {
module.exports = factory(require('./Sortable')); module.exports = factory(require('./Sortable'));
} }
else if (typeof define === 'function' && define.amd) { else if (typeof define === 'function' && define.amd) {
define(['./Sortable'], factory); define(['./Sortable'], factory);
} }
else { else {
/* jshint sub:true */ /* jshint sub:true */
window['SortableMixin'] = factory(Sortable); window['SortableMixin'] = factory(Sortable);
} }
})(function (/** Sortable */Sortable) { })(function (/** Sortable */Sortable) {
'use strict'; 'use strict';
var _nextSibling; var _nextSibling;
var _activeComponent; var _activeComponent;
var _defaultOptions = { var _defaultOptions = {
ref: 'list', ref: 'list',
model: 'items', model: 'items',
animation: 100, animation: 100,
onStart: 'handleStart', onStart: 'handleStart',
onEnd: 'handleEnd', onEnd: 'handleEnd',
onAdd: 'handleAdd', onAdd: 'handleAdd',
onUpdate: 'handleUpdate', onUpdate: 'handleUpdate',
onRemove: 'handleRemove', onRemove: 'handleRemove',
onSort: 'handleSort', onSort: 'handleSort',
onFilter: 'handleFilter', onFilter: 'handleFilter',
onMove: 'handleMove' onMove: 'handleMove'
}; };
function _getModelName(component) { function _getModelName(component) {
return component.sortableOptions && component.sortableOptions.model || _defaultOptions.model; return component.sortableOptions && component.sortableOptions.model || _defaultOptions.model;
} }
function _getModelItems(component) { function _getModelItems(component) {
var name = _getModelName(component), var name = _getModelName(component),
items = component.state && component.state[name] || component.props[name]; items = component.state && component.state[name] || component.props[name];
return items.slice(); return items.slice();
} }
function _extend(dst, src) { function _extend(dst, src) {
for (var key in src) { for (var key in src) {
if (src.hasOwnProperty(key)) { if (src.hasOwnProperty(key)) {
dst[key] = src[key]; dst[key] = src[key];
} }
} }
return dst; return dst;
} }
/** /**
* Simple and easy mixin-wrapper for rubaxa/Sortable library, in order to * Simple and easy mixin-wrapper for rubaxa/Sortable library, in order to
* make reorderable drag-and-drop lists on modern browsers and touch devices. * make reorderable drag-and-drop lists on modern browsers and touch devices.
* *
* @mixin * @mixin
*/ */
var SortableMixin = { var SortableMixin = {
sortableMixinVersion: '0.1.0', sortableMixinVersion: '0.1.0',
/** /**
* @type {Sortable} * @type {Sortable}
* @private * @private
*/ */
_sortableInstance: null, _sortableInstance: null,
componentDidMount: function () { componentDidMount: function () {
var options = _extend(_extend({}, _defaultOptions), this.sortableOptions || {}), var DOMNode, options = _extend(_extend({}, _defaultOptions), this.sortableOptions || {}),
copyOptions = _extend({}, options), copyOptions = _extend({}, options),
emitEvent = function (/** string */type, /** Event */evt) { emitEvent = function (/** string */type, /** Event */evt) {
var method = this[options[type]]; var method = this[options[type]];
method && method.call(this, evt, this._sortableInstance); method && method.call(this, evt, this._sortableInstance);
}.bind(this); }.bind(this);
// Bind callbacks so that "this" refers to the component // Bind callbacks so that "this" refers to the component
'onStart onEnd onAdd onSort onUpdate onRemove onFilter onMove'.split(' ').forEach(function (/** string */name) { 'onStart onEnd onAdd onSort onUpdate onRemove onFilter onMove'.split(' ').forEach(function (/** string */name) {
copyOptions[name] = function (evt) { copyOptions[name] = function (evt) {
if (name === 'onStart') { if (name === 'onStart') {
_nextSibling = evt.item.nextElementSibling; _nextSibling = evt.item.nextElementSibling;
_activeComponent = this; _activeComponent = this;
} }
else if (name === 'onAdd' || name === 'onUpdate') { else if (name === 'onAdd' || name === 'onUpdate') {
evt.from.insertBefore(evt.item, _nextSibling); evt.from.insertBefore(evt.item, _nextSibling);
var newState = {}, var newState = {},
remoteState = {}, remoteState = {},
oldIndex = evt.oldIndex, oldIndex = evt.oldIndex,
newIndex = evt.newIndex, newIndex = evt.newIndex,
items = _getModelItems(this), items = _getModelItems(this),
remoteItems, remoteItems,
item; item;
if (name === 'onAdd') { if (name === 'onAdd') {
remoteItems = _getModelItems(_activeComponent); remoteItems = _getModelItems(_activeComponent);
item = remoteItems.splice(oldIndex, 1)[0]; item = remoteItems.splice(oldIndex, 1)[0];
items.splice(newIndex, 0, item); items.splice(newIndex, 0, item);
remoteState[_getModelName(_activeComponent)] = remoteItems; remoteState[_getModelName(_activeComponent)] = remoteItems;
} }
else { else {
items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]); items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]);
} }
newState[_getModelName(this)] = items; newState[_getModelName(this)] = items;
this.setState(newState); if (copyOptions["stateHandler"]) {
(this !== _activeComponent) && _activeComponent.setState(remoteState); this[copyOptions["stateHandler"]](newState);
} } else {
this.setState(newState);
setTimeout(function () { }
emitEvent(name, evt); (this !== _activeComponent) && _activeComponent.setState(remoteState);
}, 0); }
}.bind(this);
}, this); setTimeout(function () {
emitEvent(name, evt);
}, 0);
/** @namespace this.refs — http://facebook.github.io/react/docs/more-about-refs.html */ }.bind(this);
this._sortableInstance = Sortable.create((this.refs[options.ref] || this).getDOMNode(), copyOptions); }, this);
},
DOMNode = this.getDOMNode() ? (this.refs[options.ref] || this).getDOMNode() : this.refs[options.ref] || this;
componentWillReceiveProps: function (nextProps) {
var newState = {}, /** @namespace this.refs — http://facebook.github.io/react/docs/more-about-refs.html */
modelName = _getModelName(this), this._sortableInstance = Sortable.create(DOMNode, copyOptions);
items = nextProps[modelName]; },
if (items) { componentWillReceiveProps: function (nextProps) {
newState[modelName] = items; var newState = {},
this.setState(newState); modelName = _getModelName(this),
} items = nextProps[modelName];
},
if (items) {
componentWillUnmount: function () { newState[modelName] = items;
this._sortableInstance.destroy(); this.setState(newState);
this._sortableInstance = null; }
} },
};
componentWillUnmount: function () {
this._sortableInstance.destroy();
// Export this._sortableInstance = null;
return SortableMixin; }
};
// Export
return SortableMixin;
}); });

Loading…
Cancel
Save