Move react.backbone.js to component mixins

Change-Id: I6dd9ade9a7b1aad7f84bac9ebfc1318031a20ef7
This commit is contained in:
Julia Aranovich 2016-05-31 10:05:33 +03:00
parent aeac27993c
commit d459fb33f7
5 changed files with 104 additions and 171 deletions

View File

@ -21,9 +21,8 @@ import React from 'react';
import ReactDOM from 'react-dom';
import dispatcher from 'dispatcher';
import {DiscardSettingsChangesDialog} from 'views/dialogs';
import 'react.backbone';
export var backboneMixin = React.BackboneMixin;
export {default as backboneMixin} from 'react_backbone_mixin';
export function dispatcherMixin(events, callback) {
return {

View File

@ -0,0 +1,101 @@
/*
* Copyright 2016 Mirantis, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 Turboprop Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**/
/*
* Taken from https://github.com/clayallsopp/react.backbone
* Modified to use ES2015 features and Lodash 4.x methods.
**/
import _ from 'underscore';
import Backbone from 'backbone';
var subscribe = (component, modelOrCollection, customChangeOptions) => {
if (!modelOrCollection) return;
var updateScheduler = modelOrCollection instanceof Backbone.Collection ?
(func) => _.debounce(func, 0, {leading: true, trailing: true}) : _.identity;
var triggerUpdate = updateScheduler(() => {
if (component.isMounted()) {
(component.onModelChange || component.forceUpdate).call(component);
}
});
var changeOptions = customChangeOptions ||
component.changeOptions ||
(modelOrCollection instanceof Backbone.Collection ? 'update reset sort' : 'change');
modelOrCollection.on(changeOptions, triggerUpdate, component);
};
var unsubscribe = (component, modelOrCollection) => {
if (!modelOrCollection) return;
modelOrCollection.off(null, null, component);
};
var backboneMixin = (options, customChangeOptions) => {
var modelOrCollection;
if (_.isPlainObject(options)) {
customChangeOptions = options.renderOn;
modelOrCollection = options.modelOrCollection;
} else {
modelOrCollection = (props) => props[options];
}
return {
componentDidMount() {
subscribe(this, modelOrCollection(this.props), customChangeOptions);
},
componentWillReceiveProps(nextProps) {
if (modelOrCollection(this.props) === modelOrCollection(nextProps)) return;
unsubscribe(this, modelOrCollection(this.props));
subscribe(this, modelOrCollection(nextProps), customChangeOptions);
if (_.isFunction(this.componentWillChangeModel)) this.componentWillChangeModel();
},
componentDidUpdate(prevProps) {
if (modelOrCollection(this.props) === modelOrCollection(prevProps)) return;
if (_.isFunction(this.componentDidChangeModel)) this.componentDidChangeModel();
},
componentWillUnmount() {
unsubscribe(this, modelOrCollection(this.props));
}
};
};
export default backboneMixin;

View File

@ -1,166 +0,0 @@
/*
* Taken from https://github.com/clayallsopp/react.backbone
* Modified for better debouncing of collection events
*
* The MIT License (MIT)
*
* Copyright (c) 2013 Turboprop Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**/
(function(root, factory) {
if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('backbone'), require('react'), require('underscore'));
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['backbone', 'react', 'underscore'], factory);
} else {
// Browser globals
root.amdWeb = factory(root.Backbone, root.React, root._);
}
}(this, function(Backbone, React, _) {
'use strict';
var collectionBehavior = {
changeOptions: 'update reset sort',
updateScheduler: function(func) { return _.debounce(func, 0, {leading: true, trailing: true}); }
};
var modelBehavior = {
changeOptions: 'change',
//note: if we debounce models too we can no longer use model attributes
//as properties to react controlled components due to https://github.com/facebook/react/issues/955
updateScheduler: _.identity
};
var subscribe = function(component, modelOrCollection, customChangeOptions) {
if (!modelOrCollection) {
return;
}
var behavior = modelOrCollection instanceof Backbone.Collection ? collectionBehavior : modelBehavior;
var triggerUpdate = behavior.updateScheduler(function() {
if (component.isMounted()) {
(component.onModelChange || component.forceUpdate).call(component);
}
});
var changeOptions = customChangeOptions || component.changeOptions || behavior.changeOptions;
modelOrCollection.on(changeOptions, triggerUpdate, component);
};
var unsubscribe = function(component, modelOrCollection) {
if (!modelOrCollection) {
return;
}
modelOrCollection.off(null, null, component);
};
React.BackboneMixin = function(optionsOrPropName, customChangeOptions) {
var propName, modelOrCollection;
if (typeof optionsOrPropName === "object") {
customChangeOptions = optionsOrPropName.renderOn;
propName = optionsOrPropName.propName;
modelOrCollection = optionsOrPropName.modelOrCollection;
} else {
propName = optionsOrPropName;
}
if (!modelOrCollection) {
modelOrCollection = function(props) {
return props[propName];
}
}
return {
componentDidMount: function() {
// Whenever there may be a change in the Backbone data, trigger a reconcile.
subscribe(this, modelOrCollection(this.props), customChangeOptions);
},
componentWillReceiveProps: function(nextProps) {
if (modelOrCollection(this.props) === modelOrCollection(nextProps)) {
return;
}
unsubscribe(this, modelOrCollection(this.props));
subscribe(this, modelOrCollection(nextProps), customChangeOptions);
if (typeof this.componentWillChangeModel === 'function') {
this.componentWillChangeModel();
}
},
componentDidUpdate: function(prevProps, prevState) {
if (modelOrCollection(this.props) === modelOrCollection(prevProps)) {
return;
}
if (typeof this.componentDidChangeModel === 'function') {
this.componentDidChangeModel();
}
},
componentWillUnmount: function() {
// Ensure that we clean up any dangling references when the component is destroyed.
unsubscribe(this, modelOrCollection(this.props));
}
};
};
React.BackboneViewMixin = {
getModel: function() {
return this.props.model;
},
model: function() {
return this.getModel();
},
getCollection: function() {
return this.props.collection;
},
collection: function() {
return this.getCollection();
},
el: function() {
return this.isMounted() && React.findDOMNode(this);
}
};
React.createBackboneClass = function(spec) {
var currentMixins = spec.mixins || [];
spec.mixins = currentMixins.concat([
React.BackboneMixin('model'),
React.BackboneMixin('collection'),
React.BackboneViewMixin
]);
return React.createClass(spec);
};
return React;
}));

View File

@ -56,7 +56,7 @@ var DashboardTab = React.createClass({
backboneMixin({
modelOrCollection: (props) => props.cluster.get('deployedNetworkConfiguration')
}),
backboneMixin('cluster', 'change'),
backboneMixin('cluster'),
pollingMixin(20, true)
],
statics: {

View File

@ -561,8 +561,7 @@ var NetworkTab = React.createClass({
backboneMixin({
modelOrCollection(props) {
return props.cluster.get('networkConfiguration').get('networking_parameters');
},
renderOn: 'change'
}
}),
backboneMixin({
modelOrCollection(props) {