Skip to content

Instantly share code, notes, and snippets.

@dustingetz
Created June 10, 2014 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dustingetz/d3d6490a3af2c2b10d58 to your computer and use it in GitHub Desktop.
Save dustingetz/d3d6490a3af2c2b10d58 to your computer and use it in GitHub Desktop.
KendoPanelBar
define([
'underscore', 'react', 'jquery', 'kendo', 'underscore.string'
], function (_, React, $, kendo, str) {
'use strict';
var KendoPanelBar = React.createClass({
getDefaultProps: function () {
return {
panels: undefined,
value: undefined, // selected panel index
onChange: undefined, // select a panel index
expandMode: 'single',
animation: undefined
};
},
render: function () {
// We are extremely careful here with how we reconcile the DOM from underneath kendo.
// The LIs are stable - they will never change across renders.
// The content must unmount if it isn't visible as part of the React contract. Kendo
// gets references to the content element, so we wrap the content in a div. We're allowed
// to reconcile underneath that div.
//
// Additionally, when changing the selected row, we have to collapse the prev panel before
// the prev content unmounts, and expand the next panel after the next content mounts. So
// we hook willUpdate and didUpdate appropriately. To keep this simple, we turn off kendo
// collapse/expand animations.
var index = 0;
var lis = _.map(this.props.panels, function (content, title) {
var id = str.sprintf('%s-%s', this.stableUniqueId, index);
var selected = index === this.props.value;
var wrappedContent = div({}, selected ? content : null);
return (li({ id: id, 'data-index': index++ }, title, wrappedContent));
}.bind(this));
return (
ul({}, lis)
);
},
componentWillMount: function () {
this.stableUniqueId = _.uniqueId('KendoPanelBar-');
},
componentDidMount: function () {
var $el = $(this.getDOMNode());
$el.kendoPanelBar({
expandMode: this.props.expandMode,
animation: this.props.animation
// no expand handler yet
});
var kendoWidget = $(this.getDOMNode()).data('kendoPanelBar');
var nextId = str.sprintf('%s-%s', this.stableUniqueId, this.props.value);
// no expand handler yet, let this one through
kendoWidget.expand('#'+nextId, false);
kendoWidget.bind('expand', this.onKendoExpand);
},
componentWillUpdate: function (nextProps) {
var kendoWidget = $(this.getDOMNode()).data('kendoPanelBar');
// before the react reconcile, collapse the shown content
var id = str.sprintf('%s-%s', this.stableUniqueId, this.props.value);
kendoWidget.unbind('expand', this.onKendoExpand);
kendoWidget.collapse('#'+id, false);
kendoWidget.bind('expand', this.onKendoExpand);
},
componentDidUpdate: function (prevProps) {
var kendoWidget = $(this.getDOMNode()).data('kendoPanelBar');
// after the react reconcile, expand the new content
var nextId = str.sprintf('%s-%s', this.stableUniqueId, this.props.value);
kendoWidget.unbind('expand', this.onKendoExpand);
kendoWidget.expand('#'+nextId, false);
kendoWidget.bind('expand', this.onKendoExpand);
},
onKendoExpand: function (e) {
// Prevent the expand, and then allow it during componentDidUpdate.
e.preventDefault();
var nextSelectedIndex = $(e.item).data('index');
this.props.onChange(nextSelectedIndex);
}
});
var ul = React.DOM.ul;
var li = React.DOM.li;
var div = React.DOM.div;
return KendoPanelBar;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment