## Datums

module.exports = class Datum extends React.Component

### Datum

This is base class of all display+input components that render presentation of an attribute from a Backbone.Model or Javascript object.

There is one required prop, 'attr' - the model attribute name.

There are two modes of presentation controlled by the `inputMode` prop. All Datums support `inputMode="readonly"` - the display presentation of the data; and most support `inputMode="edit"` - the input or form presentation of the attribute. The default presentation is `inputMode="readonly"`

The backbone model or javascript object to get and set attributes on is specified in the @props.model or @context.model. Note that @props.model always has precendence.

Display attributes from a Backbone model:

    1234567891011121314151617render: function(){   user = new UserModel()  user.fetch()   // you don't need to wait for the fetch to complete because we are using  // the **Model** contextual data component below which will rerender when  // the model triggers 'sync'   return (    <Model model={user}>      <Datum attr="firstName" label="First Name: "/>      <Datum attr="lastName" label="Last Name: "/>      <Datum attr="title"/>    </Model>  )}

Note that for clarity we have provided the Text datum which will also ellipsize the display value for you. You should probably use that instead of using Datum directly like the example above. e.g.

    1<Text attr="firstName" label="FirstName"/>

#### Validations

Datums support validations. All validation methods should return either true or an error message. All datums should support 'required' validation prop.

To make a datum required, simply add the required prop to the component. Ex:

    1<Text attr="name" required>

Validations are run at time of change and the datum element will get an invalid class for optional styling. An exclamation icon is rendered and has a popup that will show all errors for that input.

#### Metadata

Several of the Datum props can be given values via metadata. If the model associated with this datum has a getDatumMetadata() method, it will be called with the following arguments: `(prop, datumInstance)`

`prop` is the name of the datum prop for which metadata is being requested. `datumInstance` is a reference to the datum component instance. You can use the documented API methods on datumInstance, such as datumInstance.getModel() to get the model associated with datumInstance. Or as in the example below, to get the attribute name associated with the datum.

    12345678910111213141516171819202122232425262728293031323334353637var modelMetadata = {  firstName: {    label: "First Name",    tooltip: "This is the user's first given name"  }  lastName: {    label: "Last Name",    tooltip: "This is the user's legal last name or family name"    placeholder: "no last name (sorta like Madonna)"  }} var UserModel = Backbone.Model.extend({   getDatumMetadata: function(prop, datumInstance){    attrMetadata = modelMetadata[datumInstance.getAttr()]    if( attrMetadata == null ){       return null    }     return attrMetadata[prop]  }}) user = new UserModel()user.fetch() var userCard = React.createClass({  render: function(){    return (      <ReactDatum.Model model={user}>        <ReactDatum.Text attr="firstName"/>        <ReactDatum.Text attr="lastName" tooltip="Simply the last name (no Madonnas allowed)"/>        <ReactDatum.Text attr="title"/>      </ReactDatum.Model>    )  }})

The example above would have labels on firstName and lastName, since they are not given label props. The firstName datum would also be given the tooltip associated with it in the metadata. The lastName datum would recieve the tooltip associated with it via the JSX.

Metadata values are only used if a prop is not specified.

See also getMetadata callback prop in DatumProps

#### ReactBootstrap

If ReactBootstrap is available globally, Datum will use that for the ellipsize and validation error popovers. You can style the popover as you will.

#### Extending ReactDatum.Datum

Datum, and any of it's descendants, can be extended using either ES6 or Coffeescript inheritance. The API docs below call out the methods that you will most likely need to override or extend for customization.

    12345678910111213141516171819202122232425262728###  A lightweight extension of ReactDatum number for hightlighting certain numbers,  by default negative,  in red when thresholds are exceeded###class x.RedNumber extends ReactDatum.Number  @displayName: "widgets.react.RedNumber"   @propTypes: _.extend {}, ReactDatum.Number.propTypes,    upperThreshold: React.PropTypes.number    lowerThreshold: React.PropTypes.number    @defaultProps: _.extend {}, ReactDatum.Number.defaultProps,    lowerThreshold: 0    # no upper threshold by default makes all numbers less than zero red    renderValueForDisplay: ->    superRendering = super    value = @getValueForDisplay()    upperExceeded = @props.upperThreshold? && value > @props.upperThreshold    lowerExceeded = @props.lowerThreshold? && value < @props.lowerThreshold    style = if upperExceeded || lowerExceeded      {color: 'red'}    else      {}     <span style={style}>{superRendering}</span>

The example above simply extends ReactDatum.Number, adds a couple of additional props and extends the renderValueForDisplay method.

#### Datum propTypes:

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101# additional css classes (space seperated) to add to wrapper divclassName: React.PropTypes.string # can also accept model instance as context var. prop has precendencemodel: React.PropTypes.oneOfType([  React.PropTypes.instanceOf(Backbone.Model)  React.PropTypes.object]) # the backbone attribute on the model to get and setattr: React.PropTypes.string # optional label to render before value or input.  text values get wrapped in <label></label># Can also be specified via metadata.label: React.PropTypes.node # optional tooltip / help text to show on hover over datum label.  You can use this to display # a more wordy & helpful description of this attribute.  Get's applied as the title attribute# of our label element.  Can also be specified via metadata.  ## Ignored if props.label or metadata label does not exist or are both null.# # Uses ReactBootstrap if provided.  See [ReactDatum.Options](#Options) below.tooltip: React.PropTypes.string # optional value or component to display if model.get(attr) returns null or undefined# Can also be specified via metadataplaceholder: React.PropTypes.node # 'readonly' = render for display;# 'edit' = render for input;# 'inlineEdit' = datum will transition from readonly to edit on clickinputMode: React.PropTypes.oneOf(['readonly', 'edit', 'inlineEdit']) # getMetadata is an optional function that will be called to retrieve the props above where# metadata support is indicated.  The getMetadata method is passed the following # arguments:  #     (prop, datumInstance) # where `prop` is the datum prop for which metadata is being requested.  `datumInstance` is a reference # to the datum component instance.  You can use the documented API methods on datumInstance, such# as getModel() to get the model associated with datumInstance, add datumInstance.props.attr to # get the associated attr.## In addition to this prop, which has first precedence, ReactDatum will also look for a # getDatumMetadata method on the model instance and, if found, call it with the same arguments# to acquire the label, tooltip, placeholder and any other props supported by metadata. # See [discussion and example above on model driven metadata](#metadata).getMetadata: React.PropTypes.func   # set to true to not render a popover on ellipsized valuesnoPopover: React.PropTypes.bool # props for ReactBootstrap Overlay used for popovers if React Bootstrap is available.   # The rbOverlayProps prop has precedence over the 'rbOverlayProps' you can specify# via global optionsrbOverlayProps: React.PropTypes.object  # set to true to set the model value on change. this defaults to true if inputMode = inlineEditsetOnChange: React.PropTypes.bool # set to true to set model value when the input is blurredsetOnBlur: React.PropTypes.bool # set to true to save the model whenever it's attribute value is set by this DatumsaveOnSet: React.PropTypes.bool # set to the name of the method on model to use to save (typically 'save', but could be 'patch')# Note that the model save method is expected to accept (attributesToSet, options) in accordance# with the Backbone Model.save arguments.  See also modelSaveOptions which allows you to # specify additional options passed as the second argument.  ## Requires saveOnSet={true}modelSaveMethod: React.PropTypes.string # this prop is passed to modelSaveMethod (eg. `model.save({}, modelSaveOptions)`) ## Requires saveOnSet={true}modelSaveOptions: React.PropTypes.object # (ms) set the length of time 'saved' css class stays on outer datum element after savingsavedIndicatorTimeout: React.PropTypes.number # make this input readonly regardless of context or inputMode propreadonly: React.PropTypes.bool # make this input required and give it required class and invalid class when invalidrequired: React.PropTypes.bool # style to apply to outer datum divstyle: React.PropTypes.object # if true, renders a div as the component wrapperasDiv: React.PropTypes.bool # call back for when the datum changesonChange: React.PropTypes.func # value to use instead of model attribute.  You can use this instead of a model and attr to manually set # the initial value of the component.   Model value is ignored for display, but still updated if in an# editable statevalue: React.PropTypes.node

#### Datum defaultProps:

    1234567# no default for inputMode because we can also get from context, see @getInputMode()# inputMode: 'readonly'setOnBlur: truesetOnChange: falsesaveOnSet: falsemodelSaveMethod: 'save'savedIndicatorTimeout: 5000

#### Datum contextTypes:

    123456789101112# can also accept model instance as a prop.  prop has precendencemodel: React.PropTypes.oneOfType([  React.PropTypes.instanceOf(Backbone.Model)  React.PropTypes.object]) # note that the readonly prop takes precendenceinputMode: React.PropTypes.oneOf(['readonly', 'edit', 'inlineEdit']) # if there is a form context, we will register with it so that it can# interact with usform: React.PropTypes.object

#### Datum Instance Methods:

##### renderValueOrPlaceholder

Override this method only if you need to not render the placeholder.

##### renderValueForDisplay

In most cases, this is the method you want to override in a custom datum to alter the way the model attribute is displayed when inputMode='readonly'

This method is only called if the model value is not null.

##### renderEllipsizedValue(value, options={})

Note that this method is not called by Datum directly. It is provided here in the Datum base class so that any Datum extensions can ellipsize whatever part of their rendering neccessary and have a consistent prop and method for doing so.

##### renderInput

In most cases this is the method you want to override to alter the presentation of the datum when inputMode='edit'.

If you override this method, be sure to add @onBlur() and @onChange() to your input component

##### renderIcons

Override / extend this method to add or alter icons presented after datum.

Datum implementation renders the error icon if needed.

##### renderErrors

Override / extend this method to control what is rendered in the error icon popup

##### renderWithPopover(value, tooltip, popoverId, valueClass)

You can use this to render a value with the standard popover treatment or extend and override to effect the standard popover treatment

##### getRbOverlayProps(value, popoverId)

Override this method to provide things like custom positioning of error popovers

##### isDirty()

This method can be overriden to provide custom determination of dirty state. dirty meaning, has the input value changed. The base implementation assumes that the base behavior of setting state.value to null on model.set() happens.

##### isEditable

This method is called to determine if the inputMode (prop, context) is one of the editable types. ('edit' or 'inlineEdit')

Note that a return of true does NOT indicate that the Datum is in its edit display. If the component is an inputMode='inlineEdit', in may be showing it's display presentation. See also isEditing()

##### isEditing

This method is called to determine if the Datum is displaying its input presentation.

##### addValidations(validations)

When extending Datum, use @addValidations from constructor to add additional validations. 'required' validation is automatically added (only invalid if empty and has 'required' prop)

For example, see Number datum

You can add validations to an individual instance of any Datum extension.

`validations` argument should be one or an array of methods that accept the (value) to validate and return true if valid, false if not.

##### getValueForDisplay()

This method should return the value for display from the model. You can extend this method in a custom Datum to coerce or manipulate just the value used for display.

In most cases, you'll probably want to extend the Datum.renderValueForDisplay() instead

##### getValueForInput()

Extend this method to coerce or intepret the value from the model that is displayed when in input

##### getInputValue()

this method returns the value in the input as seen by user

##### getModel(newProps = props, newContext = context)

returns the Backbone Model currently associated with the datum.

##### getModelValue(newProps = props, newContext = context)

Returns the value set via value prop or the value currently set on the model

warning: Do not override this method to return a component element or jsx; bad things will happen.

##### getAttr(props = props)

When extending react datum, use this method to get the attribute name specified to the component as props.attr.

You can also override this method in an extension to dynamically select the attribute to get from the model. For say an international price datum that selects a price attribute based on the local currency (not a contrived example)

##### setModelValue(value, options={})

Extend this model to interpret the value prior to saving for example a Percent datum that the user enters a value that is 100x what gets saved to model

options pass through to model.set()

##### getFullClassName

Override / extend this method to add conditional css classes to the outer datum element

##### getInputComponent()

This method can be used to get at the inner input component if one exists, only while inputMode=='edit'

##### validate(value=getValueForInput())

This method is called to validate the value in the input.

Note that validations such as props.required also need to apply if the user hasn't changed the input, so the default value is the coalesce of state.value or model value. state.value (see getInputValue()) is null if the user has not made changes.

##### clearErrors

This method can be used to clear any validation or save errors manually

module.exports = class Email extends Datum

### Email

For rendering and input of email addresses. Can render mailto: links like `<a href="mailto:">` in display mode

Validates that email address is a semi valid email based on matching `/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/`

#### Email propTypes:

See Also: Datum propTypes

    12# If true, display as mailto address link when `inputMode='readonly'`displayAsLink: React.PropTypes.bool

#### Email defaultProps:

See Also: Datum defaultProps
module.exports = class Label extends Text

### Label

The ReactDatum.Label component is for the display of labels.

It is a simple extension of ReactDatum.Text that wraps the value in an HTML tag and provides tooltip support. If a tooltip is provided by metadata or prop, the tooltip will be used as either the `title` attribute of the element or, if ReactBootstrap is set via ReactDatum.Options.set(), wraps the label with a ReactBootstrap Overlay and Popover.

    1<ReactDatum.Label value="I'm a label" tooltip="Just an example of using static labels"/>

You can also provide the label content via children:

    123<ReactDatum.Label tooltip="my children are my life">  I am also a label.</ReactDatum.Label>

#### Adding an indicator to labels with tooltips

If you want your users to see an indication that a label has tooltip help, you can do something like the following in your CSS:

    1234567891011.datum-tooltip label::after {  display: inline-block;  font: normal normal normal 14px/1 FontAwesome;  text-rendering: auto;  -webkit-font-smoothing: antialiased;      content: "\f059";   color: #4767aa;  font-size: 11px;  margin-left: 3px;}

The example above renders a FontAwesome 4 question-mark-circle icon after any labels that have tooltips.

see ./label.md

#### Label propTypes:

See Also: Text propTypes

#### Label defaultProps:

See Also: Text defaultProps
module.exports = class LazyPhoto extends Datum

### LazyPhoto

This is a lazy loading image.

To prevent a page heavily loaded with images preventing other content from loading, a small blank image is downloaded and rendered first and then onLoad the real image src is used and rerender.

On error a notFoundUrl is set as the image src to prevent broken image display.

The model attribute specified in @props.attr should return a fully qualified url. The image is only rendered if it's visible and in view. Otherwise the placeholder image is rendered.

#### LazyPhoto propTypes:

See Also: Datum propTypes

#### LazyPhoto defaultProps:

See Also: Datum defaultProps
module.exports = class Link extends Datum

### Link

For rendering links like `<a href="...">`.

Example:

    123456var model = new Backbone.Model({  url: "http://www.zulily.com",   name: "Zulily"}) <ReactDatum.Link attr="url" nameAttr="name"/>

The 'attr' prop should return a url from the model and is the href of the link. The 'nameAttr' prop is optional and can used to specify a model attribute value to display between the tags. If 'nameAttr' prop is not specified, the children of the link are rendered:

    1<ReactDatum.Link attr="url">Go to <ReactDatum.Text attr="name"/> and discover somthing today!</Rd.Link>

In this example the link would enclose the rendered contents: "Go to Zulily and ..."

If no nameAttr prop and no children, ReactDatum.Link will render the value of the attr specified (what should be the url of the href):

    1<ReactDatum.Link attr="url"/>

The example above renders `<a href="http://www.zulily.com">http://www.zulily.com</a>`

see ./link.md

#### Link propTypes:

See Also: Datum propTypes

    12345678910111213141516171819# attribute on model to display as the <a> content. if null ReactDatum.Link will # render the children enclosed in an <a></a>nameAttr: React.PropTypes.string# passed to <a> as the targettarget: React.PropTypes.string # The link's content between the A tags can be ellisized.  Set ellipsizeAt to false # to display whole value. Only effects 'readonly' display, values displayed # in 'edit' mode are never truncated.ellipsizeAt: React.PropTypes.oneOfType([  React.PropTypes.number  React.PropTypes.bool]) # If we want the ellipsis to be like ...Long Name we need to make this truereverseEllipsis: React.PropTypes.bool #If you would like to show the url without the http/https, pass this prop as truehideProtocol: React.PropTypes.bool

#### Link defaultProps:

See Also: Datum defaultProps

    1234# ellipsizeAt is defaulted to prevent really long strings from breaking layoutsellipsizeAt: 35target: '_blank'hideProtocol: false

module.exports = class Number extends Datum

### Number

For real numbers.

Only allows `/^\-?[0-9]*\.?[0-9]*$/` on input

#### Number propTypes:

See Also: Datum propTypes

    1234567891011121314151617181920212223242526# format only effects display, not input.  Possible values:## 'abbreviate' - Add M and K to numbers greater than 1 million and 1 thousand respectively# 'money' - display dollar sign and two decimal places zero filled# 'comma' - add comma separators at thousands# 'percent' - multiply by 100 and postfix '%'## can be an array of formats or a single string formatformat: React.PropTypes.oneOfType [  React.PropTypes.array  React.PropTypes.string] # rounds value to n decimal placesdecimalPlaces: React.PropTypes.number # if decimalPlaces, zeroFill={true} will round out to n places zeroFill: React.PropTypes.bool # when input, validate value is at least this value on change. # Can also be specified via metadata.minValue: React.PropTypes.number # when input, validate value is at most this value on change# Can also be specified via metadata.maxValue: React.PropTypes.number

#### Number defaultProps:

See Also: Datum defaultProps

    123456789101112# Exceptional case: when format='money' is used without format='abbreviate',# this defaults to 2decimalPlaces: null # Exceptional case: when format='money' is used without format='abbreviate',# this defaults to 2, you can however change the money behavior by explicitly# setting zerofill to falsezeroFill: null # This might be controversial, but our standard here at the zoo is to always use# thousand ticksformat: ['comma']

#### Number Class Methods:

##### safelyFloat(value)

fail proof conversion from sting to float that will never return NaN

#### Number Instance Methods:

##### renderValueForDisplay

overrides super - adds formatting

##### roundToDecimalPlaces(value, options={})

returns a string with number value input rounded to user requested props.decimalPlaces and optionally zeroFilled if @props.zeroFill == true note that 'money', when not 'abbreviate'd should zero fill out to two decimal places unless props indicate otherwise

##### abbreviate(value, formats=getFormats())

returns a string with number value abbreviated and rounded to user requested props.decimalPlaces

##### monetize(value, formats=getFormats())

If props.formats includes 'money', this method prepends the value displayed with '$'

Override this method to do things like create an internationalized display of money value for another currency.

module.exports = class Percent extends Number

### Percent

This datum is an extension of ReactDatum.Number for display and input of percent values.

- Display value is affixed with '%'
- Display and input value are model value * 100 (model value is assumed to be fractional value)
- User input is assumed to be number percentage (* 100)
- props.decimalPlaces is respected for both display and input

Number datum has (maybe use to have) a format called 'percent' that will also do a little part of what Percent datum does. The Percent datum is meant to supercede 'percent' format to Number datum.

#### Percent propTypes:

See Also: Number propTypes

#### Percent defaultProps:

See Also: Number defaultProps

#### Percent Instance Methods:

##### getModelValue()

Model value returned is multiplied by 100. Internal value for Percent is always the whole number displayed percentage rounded to requested decimal places.

##### setModelValue(value=getInputValue(), options={})

What get's saved to the model is the user entered value divided by 100

##### getFormats()

Other formats like 'money' and 'abbreviate' are ignored. Override react-datum.Money

##### renderValueForDisplay

Renders value for display as nn.n%.

Base number has (maybe use to have) a format called 'percent' that will also do this little part of it. The Percent datum is meant to supercede 'percent' format to Number datum.

module.exports = class Text extends Datum

### Text

This react-datum component is for the presentation and input of text. See also ReactDatum.Datum. The Datum base class does much of the work by default of handling text.

Text Component provides the following additional features:

- Display values can be ellipsized via ellipsizeAt prop.
- Values are ellipsized by default to prevent unexpected long strings from breaking your layout
- Can display HTML via the displayAsHtml prop
- Will gracefully and textually handle various types of model values

A note about using displayAsHtml

It's not advised unless you are sure as to the sanity of the data value you are displaying. The danger is in cross site scripting attacks. Read more here.

Also note that using `displayAsHtml` and anything other than `ellipsizeAt={false}` is not advised as you may end up ellipsizing in the middle of an element and leave unclosed tags or, worse, break your entire layout.

For example, given this model:

    1model = new Backbone.model({name="Foo Bar", description="Lorem ipsum <b>dolor sit amet</b>, consectetur adipiscing elit. Duis rhoncus lacinia lectus a volutpat. this could go on forever"});

this will render the description truncated with ellipsis to not exceed 35 total characters:

    1<ReactDatum.Text attr="description">

this will render the description at it's full length:

    1<ReactDatum.Text attr="description" ellipsizeAt={false}>

this will render the description with "dolor sit amet" in bold:

    1<ReactDatum.Text attr="description" displayAsHtml ellipsizeAt={false}>

see ./text.md

#### Text propTypes:

See Also: Datum propTypes

    123456789101112# set to true if rendering known, safe, html.  # see https://facebook.github.io/react/tips/dangerously-set-inner-html.html. displayAsHtml: React.PropTypes.bool # set ellipsizeAt to false to display whole value. Only effects 'readonly' display# values displayed in 'edit' mode are never truncated.ellipsizeAt: React.PropTypes.oneOfType([  React.PropTypes.number  React.PropTypes.bool])# If we want the ellipsis to be like ...Long Name we need to make this truereverseEllipsis: React.PropTypes.bool

#### Text defaultProps:

See Also: Datum defaultProps

    123# ellipsizeAt is defaulted to prevent really long strings from breaking layoutsellipsizeAt: 35reverseEllipsis: false

#### Text Instance Methods:

##### renderWrappedDisplayValue(value)

Extends Datum#renderWrappedDisplayValue to provide support for displayAsHtml option.

module.exports = class WholeNumber extends Number

### WholeNumber

For whole numbers (no decimal input allowed).

#### WholeNumber propTypes:

See Also: Number propTypes

#### WholeNumber defaultProps:

See Also: Number defaultProps

## More Datums

module.exports = class CollectionPicker extends Datum

### CollectionPicker

This react-datum component provides a selector (picker) based on react-select.

The `props.attr` on `props.model` should return and id or other key that is used to find a model in a collection and display a value from the lookup model.

Say for example, you have a model like this:

    12345var kittenModel = new Backbone.Model({  name: "Fluffy",  title: "His Royal Cuteness",  updatedByUserId: 905793});

and a collection of users like this:

    123456var usersCollection = new Backbone.Collection([{  id: 905793  fullName: "Jane Doe"},{  ...}])

To display the user's full name instead of the id:

    12345<ReactDatum.CollectionPicker  attr="updatedByUserId"    model={kittenModel}  collection={usersCollection}  displayAttr="fullName"/>

In `inputMode ='readonly'`, the CollectionPicker above will display the fullName from a model in the usersCollection with id matching kittenModel.get('updatedByUserId') from usersCollection instance var.

In `inputMode='edit'`, the suggestions would also render the displayAttr because we didn't specify a suggestionAttr prop

#### onChange

The first parameter passed to the @props.onChange callback will be either one or an array of option objects of the currently selected options. The option objects have look like,

    123label: "30 Days until Christmas (Chatties Gifts)"model: Eventvalue: 206802

If the `multi` prop is used, an array of option objects is passed else a single object is passed.

#### Asynchronous suggestions

Use the asyncLoadCallback prop to load suggestions asynchronously from a server:

    12345678910111213141516loadData = function(userInput, doneCallback) {  usersCollection.fetch({    data: {search: userInput}    success: function(model. response) {      # doneCallback accepts error and collection, array of models,       # or array of {label: "displan name", value: "value"}       doneCallback(null, usersCollection)    }  )}<ReactDatum.CollectionPicker  attr="userId"  model="myOtherModel"  collection="usersCollection"  asyncLoadCallback={loadData} />

#### Custom display

By default the CollectionPicker will display the value of props.model.get(props.displayAttr), or model.toString() (if it exists and no displayAttr specified).

You can provide custom rendering via the the `optionComponent`, `valueComponent` and `displayComponent` props.

The optionComponent and valueComponent are passed throught to react-select. For optionComponent, you are required to handle and pass events back through the props given. Providing a custom option render, is a little longish, but value display is easy. The GravatarOption and GravatarValue components below were taken directly from the react-select CustomComponents example

To provide a custom option (suggestion) display:

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455const GravatarOption = React.createClass({    propTypes: {        className: React.PropTypes.string,        isDisabled: React.PropTypes.bool,        isFocused: React.PropTypes.bool,        isSelected: React.PropTypes.bool,        onSelect: React.PropTypes.func,        onFocus: React.PropTypes.func,        onUnfocus: React.PropTypes.func,        option: React.PropTypes.object.isRequired,    },    handleMouseDown (event) {        event.preventDefault();        event.stopPropagation();        this.props.onSelect(this.props.option, event);    },    handleMouseEnter (event) {        this.props.onFocus(this.props.option, event);    },    handleMouseMove (event) {        if (this.props.focused) return;        this.props.onFocus(this.props.option, event);    },    handleMouseLeave (event) {        this.props.onUnfocus(this.props.option, event);    },    render () {        let gravatarStyle = {            borderRadius: 3,            display: 'inline-block',            marginRight: 10,            position: 'relative',            top: -2,            verticalAlign: 'middle',        };        return (            <div className={this.props.className}                onMouseDown={this.handleMouseDown}                onMouseEnter={this.handleMouseEnter}                onMouseMove={this.handleMouseMove}                onMouseLeave={this.handleMouseLeave}                title={this.props.option.title}>                <Gravatar email={this.props.option.email} size={GRAVATAR_SIZE} style={gravatarStyle} />                {this.props.children}            </div>        );    }}); <CollectionPicker  model={myModel}  collection={usersCollection}  optionComponent={GravatarOption}  placeholder="Select user"/>

You can also provide a custom value display for the current value displayed when the input doesn't have focus:

    1234567891011121314151617181920212223242526272829303132const GravatarValue = React.createClass({    propTypes: {        placeholder: React.PropTypes.string,        value: React.PropTypes.object    },    render () {        var gravatarStyle = {            borderRadius: 3,            display: 'inline-block',            marginRight: 10,            position: 'relative',            top: -2,            verticalAlign: 'middle',        };        return (            <div className="Select-value" title={this.props.value.title}>                <span className="Select-value-label">                    <Gravatar email={this.props.value.email} size={GRAVATAR_SIZE} style={gravatarStyle} />                    {this.props.children}                </span>            </div>        );    }});  <CollectionPicker  model={myModel}  collection={usersCollection}  valueComponent={GravatarValue}  placeholder="Select user"/>

Custom display when CollectionPicker is in inputMode="readonly" is even easier:

TODO: finish me!

#### CollectionPicker propTypes:

See Also: Datum propTypes

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103#  TBD: Can also be the string name of a shared collection (see ../sharedCollection.cjsx)#  TBD: Can also accept an array of [{lable: "option 1", id: 1}, ...]#  #  Can also accept collection instance as context var via ReactDatum.Collection component. #    prop has precendencecollection: React.PropTypes.oneOfType([  React.PropTypes.instanceOf(Backbone.Collection)  React.PropTypes.string  React.PropTypes.array]) # The selected values from the collection when in in display mode, can be individually# ellipsized. Set ellipsizeAt to false to display whole value. Only effects 'readonly' # display; values displayed in 'edit' mode are never truncated.ellipsizeAt: React.PropTypes.oneOfType([  React.PropTypes.number  React.PropTypes.bool]) # If we want the ellipsis to be like ...Long Name we need to make this truereverseEllipsis: React.PropTypes.bool # Component for rendering the custom optionsoptionComponent: React.PropTypes.func # Component for rendering the value optionsvalueComponent: React.PropTypes.func # Attribute which indicates if we need to fetch the model if not found in collection.fetchUnknownModelsInCollection: React.PropTypes.bool #  Attribute value from model in lookup collection to render in inputMode='readonly'.#  if not specified, model.toString() will be displayeddisplayAttr: React.PropTypes.string #  attribute value from model in lookup collection to set as value on props.attr#  in props.modeloptionSaveAttr: React.PropTypes.string.isRequired # react component to render when in inputMode='readonly'. displayComponent: React.PropTypes.any # This is to be set if the loading need not happen asynchronously for every search.# External/collection fetch loading can happen for the first time.# If loading externally/using collection fetch, set loading prop to true until external load is complete.synchronousLoading: React.PropTypes.bool # This makes sense only in conjunction with synchronousLoading.# Set to true if loading externally until loading is complete.isLoading: React.PropTypes.bool #  Specify a callback to load suggestions asynchronously.  #  The callback method  should accept the following arguments: #    `(collection, userInput, ayncOptions, doneCallback)` #  where #    `collection` is the value of the collection prop#    `userInput` is the what the user has entered so far  #    `doneCallback` is a method to be called with `(error, data)` when data is ready.#        the first argument, `error` should be false or an error that will be thrown#        `data` argument should be an array of Backbone.Models or array of #              {label: "string", value: "string"} pairs#    `asyncOptions` is the options object passed via prop to CollectionPicker##  Note that internally, CollectionPicker always renders a Select.Async when inputMode='edit' #  and provides an internal loadOptions method to pull suggestions from the models in #  the lookup collection. #  #  *Where do they all come from?*  #  #  We will use the returned filtered set of models from the following chain (in order):#    **Collection.filterForPicker()**  - if we find a method on the collection called #      'filterForPicker' - it will be called with `(userInput, doneCallback, asyncOptions)`#      and should return an array of models to render suggestions from #    **props.asyncSuggestionCallback** - this prop#    **Internal filter** (this.filterOptions(userInput, doneCallback)) seaches through the #      props.optionDisplayAttr of models currently in the collection to find suggestions based on #      userInput and groups results#  TODO : tests!asyncSuggestionCallback: React.PropTypes.func #  Options above are proprietary to the CollectionPicker component.#  #  Remaining options are passed through to react-select, see # [react-select](https://github.com/JedWatson/react-select)#  #  You can use any of the options supported by react-select Select and Select.Async, #  *except for the loadOptions prop* of Select.Async.  ##  see # [react-select](https://github.com/JedWatson/react-select) for additional props    #   #  can accept and display multiple values.  If this prop is set, we assume that #  value of our @props.model.get(@props.attr) returns the IDs either as an#  array or comma separated value.  multi: React.PropTypes.bool # editPlaceholder will be useful in inlineEdit mode when you want to display a # placeholder text which is different from the placeholder which you display before the select editor is displayededitPlaceholder: React.PropTypes.string # if setAsString and multi, set the value of the model as a comma delimited string instead of array of valuessetAsString: React.PropTypes.bool # if true, displays the model value in when in display mode without collection lookup  displayModelValue: React.PropTypes.bool

#### CollectionPicker defaultProps:

See Also: Datum defaultProps

    123456# ellipsizeAt is defaulted to prevent really long strings from breaking layoutsellipsizeAt: 35fetchUnknownModelsInCollection: trueloading: false# This is required as this is used to set the value to model which is shown on the picker.attr: 'value'

#### CollectionPicker contextTypes:

See Also: Datum contextTypes

    12345# see @proptypes.collection above collection: React.PropTypes.oneOfType([  React.PropTypes.instanceOf(Backbone.Collection)  React.PropTypes.string])

#### CollectionPicker Instance Methods:

##### onChange(optionsSelected)

Extends Datum class - react-select returns array of options and not a synth event super expects a synth event but only uses value.

Also note that the value passed back to the usage through @props.onChange is the option object(s) for the currently selected option(s)

##### filterSuggestionModels(collection, userInput, callback)

weak string compare userInput to suggestion model's display value

##### getModel(newProps = props, newContext = context)

This is the model associated with the collectionPicker. This is required to exist because this is the model in which the value is saved. If this does not exist or re-created every time we will not be able to show the value option on the picker.

## Forms, Models and Collections

module.exports = class ClickToEditForm extends Form

### ClickToEditForm

This component is an extension of Form that initially presents an "Edit" button that the user can click to switch between display and input.

Datum children are initialized readonly, when the user clicks edit, the 'inputMode' context variable is set to 'edit' and all children are rerendered.

See react-datum Form component for more props. All Form properties are supported by ClickToEditForm

Note that the readonly prop is observed. If @props.readonly == true then the edit button will not render and the form acts like a static container. This is for programatic setting of the form to readonly

#### ClickToEditForm propTypes:

See Also: Form propTypes

#### ClickToEditForm defaultProps:

See Also: Form defaultProps
module.exports = class Collection extends ContextualData

### Collection

This react-datum component provides datums with a Backbone collection and rerenders descendants on collection changes.

- provides a collection context to all children
- rerenders children on collection changes
- adds SelectableCollection mixin to collection if it doesn't already have it
- will optionally fetch the collection
- can accept either a Collection class (which will be instantiated) or a collection instance variable to another collection or Collection component

Any descendant datum or react-datum based components like (ReactDatum.TileGrid)[TODO: add a link do doc page], or the (ReactDatum.SelectedModel)[TODO: add link to doc page] that accept a `collection` context or prop, can be wrapped in a ReactDatum.Collection component and will respond to changes in the collection.

Simple example:

    12345678910111213var Rd = ReactDatum; <Rd.Collection collection={myBackboneCollection}>  <Rd.SelectedModel placeholder="Wait for it...">    <Rd.Text label="You selected: " attr="name"/>  </Rd.SelectedModel></Rd> var index = 0;setInterval(function(){  myBackboneCollection.selectModelByIndex(index);  index += 1;}, 5000)

The (example above)[TODO: add link to github.io example] when run, will initially display a placeholder, "Wait for it..." and then every five seconds select a new model. See (SelectedModel)[TODO: add link to doc page] for more information about selections.

#### Adds selection tracking to collection

In order for the components such as ReactDatum.Tilegrid and ReactDatum.SelectedModel to have a common understanding of what is selected, a small mixin called SelectableCollection is added to the collection, unless the collection has an instance variable hasSelectableCollectionMixin=`true`.

Once used with the ReactDatum.Collection component, your Backbone collection instance will be given the following methods:

- `getSelectedModels()` returns array of currently selected models
- `selectModel(model, selected=true, options={})` selects the model. default options: {silent: false}
- `selectModelById(id, selected=true, options={})` see selectModel()
- `selectModelByIndex(index, selected=true, options={})` see selectModel()
- `selectAll(options={})` default options: {silent: false}
- `selectNone(options{})` default options: {silent: false}

A console warning will be issued if any of the methods above already exist on a collection without this.hasSelectableCollectionMixin==true.

If you use another mixin or service for this, it should be relatively easy to build a bridge. Just add the methods above to your collection and call the existing plugin, mixin or external methods.

#### Collection propTypes:

See Also: ContextualData propTypes

    12345# can only accept collection via prop.  Collection component should# not interfere with any parent Collection commponent or other that# would provide a collection context, but it will become the provider# of collection context for all of it's childrencollection: @collectionPropType.isRequired

#### Collection defaultProps:

See Also: ContextualData defaultProps
module.exports = class CollectionStats extends React.Component

### CollectionStats

- provides information about the items in your collection.

  Requires either a 'collection' context or prop. And displays counts of items found, selected and viewing.

#### CollectionStats propTypes:

    123456789# a Backbone.Collectioncollection: React.PropTypes.instanceOf(Backbone.Collection) # used as the display name for found items. ex.#```javascript#  <CollectionStats itemDisplayName="thing"/>#```# => "Found 1,230 things".itemDisplayName: React.PropTypes.string

#### CollectionStats defaultProps:

    1itemDisplayName: "item"

#### CollectionStats contextTypes:

    1collection: React.PropTypes.instanceOf(Backbone.Collection)

module.exports = class ContextualData extends React.Component

### ContextualData

This is an abstract base class for contextual data components like ReactDatum.Collection and ReactDatum.Model that provide a single contextual data element.

The ReactDatum.ContextualData base class also provides the listener to model or collection events and rendering of child components on changes.

You shouldn't need to use this class directly.

#### ContextualData propTypes:

    1234567891011121314151617# set this to true to issue the initial fetch of the collection on mountfetch: React.PropTypes.bool# passed through to collection|model fetchfetchOptions: React.PropTypes.object# something to render if our input model|collection is not availableplaceholder: React.PropTypes.node  # anything react can render# additional css classes to addclassName: React.PropTypes.string# set debouncedUpdate = false to not debounce, i.e. 1:1 collection or# model triggered events to renders. debouncedUpdate: React.PropTypes.bool# set debounceMs to a higher delay. debounceMs: React.PropTypes.number# set to true to show console messages about useful thingsdebug: React.PropTypes.bool# style override object for the rendered div.style: React.PropTypes.object

#### ContextualData defaultProps:

    12345678910111213141516# when true, we will automatically fetch the model or collection on mountfetch: false# additional fetch options (see Backbone Collection|Model fetch() options)fetchOptions: {}# We don't define placeholder, that's up to our subclass. with # `placeholder: undefined` by default, there is no placeholder,# the renderContent method will always render children.  # To render no placeholder but not render children, set this to nullplaceholder: undefined# We do not define any default style data.style: {}# effectively batch and defer multiple syncronous events into one defaults to  # 0s debounce which will effectively ignore all but the last triggered event# in a long sequencedebouncedUpdate: truedebounceMs: 0

#### ContextualData Instance Methods:

##### constructor(props)

This is the class of thing being placed in the context. ex. `Backbone.Model` or `Backbone.Collection` this is the key in @context children should use to access thing ex. "model"

##### fetchCollectionOrModel()

override this model to do a custom fetch method like fetchForUser or some such

##### initializeCollectionOrModel()

extend this method to provide additional initialization on the thing you provide. You should probably call super

##### getInputCollectionOrModel()

override this method to input from somewhere other than the context or props being passed in

##### getCollectionOrModelToProvide()

override or extend this method to provide something other than what we recieve

##### needsReinitializing()

extend this method to provide additional tests to determine if initialization is needed. You should probably extend this method like so:

    1return super() || this._someOtherTest()

module.exports = class Form extends React.Component

### Form

This contextual component provides a form context to all of the datums within.

Adding the ReactDatum.Form component, you can easily convert a group of datums into an editable form with save and cancel buttons. By default, when children of a Form component all datums will render in their input presentation `inputMode='edit'`.

    123456789101112131415161718192021var kittenCard = React.createClass({  displayName:"KittenCard",  render: function(){    return (      <div className='kitten-card'>        <ReactDatum.Model model={kittenModel}>          <h3>Adopt <ReactDatum.Text attr="name"/> Today!</h3>          <ReactDatum.Form>            <div><ReactDatum.LazyPhoto attr="imgUrl"/></div>            <div><ReactDatum.Text attr="name" label="Name" setOnChange/> (<ReactDatum.Text attr="title"/>)</div>            <label>Say something about <ReactDatum.Text attr="name" readonly/>: </label>            <div><ReactDatum.Text attr="description" className="wide-input"/></div>            <div><ReactDatum.Email attr="sponsorEmail" label="Adoption Sponsor" displayLink/></div>            <label>Leave a Comment!</label>            <div><ReactDatum.Text attr="comment" className="wide-input"/></div>          </ReactDatum.Form>        </ReactDatum.Model>      </div>    )  }})

The ReactDatum.Form component adds save and cancel buttons. When the user presses save, model.save() is called. All of the attributes were set() when the user entered new values If cancel is clicked, the model and subsequently, the form are reset back to the state of the last model.save().

By wrapping the datums in the ReactDatum.Form tag, they implicitedly recieve `inputMode='edit'` props that make them all render as inputs. Almost all. Some Datums, like ReactDatum.LazyPhoto, only have a display presentation, no update. If given an `inputMode='edit'` they will ignore, and continue showing their display (`inputMode='readonly'``) representation.

#### Form propTypes:

    12345678910111213141516171819202122232425262728# can also accept model instance as context var. prop has precendence model: @modelOrObject() # you can specify any method on the model to call when save is clicked# TODO : add ability to also pass in a func?  would need to accept model, attrs, optionsmodelSaveMethod: React.PropTypes.string #  no formMode like zform, but we have to support programatic readonly#  see also ClickToEditForm component.   readonly should always take precendencereadonly: React.PropTypes.bool # you can style a buttonPossiton: 'top' to float left or right in css.buttonPosition: React.PropTypes.oneOf(['top', 'bottom', 'none']) # specify className of form elementclassName: React.PropTypes.string # on save success this method, if specified, will be called with the standard# Backbone success callback arguments (model, response, options)# If you don't specify a saveSuccessCallback, a small success message will be rerendered# below the form button after successfully saving the formsaveSuccessCallback: React.PropTypes.func # on save error this method, if specified, will be called with the standard# Backbone error callback arguments (model, response, options)# If you don't specify a saveErrorCallback, an error message will be rerendered# below the form button after failing to save the form on user requestsaveErrorCallback: React.PropTypes.func

#### Form defaultProps:

    1234readonly: falsebuttonPosition: 'bottom'className: 'form'modelSaveMethod: 'save'

#### Form contextTypes:

    1234### can also accept model instance as a prop.  prop has precendence ###model: @modelOrObject() inputMode: Datum.contextTypes.inputMode

#### Form Instance Methods:

##### focus

Gives the first editable datum focus

##### save(options={})

Save the changes from datums on the form to the Backbone model.

Calls model.save after first attempting to validate() the model. Handles inconsistencies in model.validate() between versions 0.9.2 - 1.2.2 of Backbone.

The user clicking on the save button belonging to the Form will call this Method

The options argument is passed on to Backbone model.save()

##### validateDatums(options={})

Validate the datums on the form.

returns false if any are currently invalid

##### validateModel(options={})

Calls Backbone model.validate and handles inconsistencies in model.validate() between versions 0.9.2 - 1.2.2 of Backbone.

##### saveModel(options={})

calls Backbone model.save and calls success and error handlers.

You should probably call Form.save() above instead. It will also validate the model and datums.

##### addDatum(datumComponent)

This method is called by the datum children when they mount

##### removeDatum(datumComponent)

This method is called by the datum children when they unmount

module.exports = class Model extends ContextualData

### Model

This react-datum component provides datums with a Backbone model and rerenders descendants on model changes.

Any datum component like ReactDatum.Text, will accept the Backbone model provided by this class as a context variable. Outside of a ReactDatum.Model* component, datums will not respond to model changes.

#### Model propTypes:

See Also: ContextualData propTypes

    1model: @modelPropType.isRequired

#### Model defaultProps:

See Also: ContextualData defaultProps
module.exports = class Options

### Options

These are global options used to control various aspects of ReactDatum rendering and functionality.

Currently supported configurable options:

ReactBootstrap: Defaults to global 'ReactBootstrap' if it exists. If set this option will use ReactBootstrap for popovers such as when a Datum is ellipsized and for validation errors. If not set, ReactDatum will use the HTML5 title tooltips for popovers

RbOverlayProps: You can change the placement, trigger, etc used for popovers when using ReactBootstrap.

errorIconClass: default: null. Icon css class to use for indicating validation errors. If not set, a red unicode exclamation point is used.

#### Options Class Methods:

##### set(option, value)

These are defaulted onto whatever is provided via ReactDatum.Options.set().

Use to set a ReactDatum option. Arguments can be either `(key, value)` or `({key: value, key: value})`

Example:

    12345678910ReactDatum = require('react-datum') // use the version of react bootstrap I got somewhere ReactDatum.Options.set('ReactBootstrap', loadedBootstrapLib) // use the fontawesome 4.5 exclamation sign icon for errorsReactDatum.Options.set('errorIconClass', 'fa fa-exclamation-circle') // change the placement of the popover (if using ReactBootstrap)ReactDatum.Options.set({RbOverlayProps: {placement: 'bottom'}})

##### get(option=null)

Get a previously set option or it's default if not set. Returns full set of options if no option arg is provided.

module.exports = class SelectedModel extends ContextualData

### SelectedModel

This react-datum contextual component provides datums with a Backbone model that is selected model in the collection. It also rerenders descendants on collection selection changes.

Any descendant datum that accept a `model` context or prop, can be wrapped in a ReactDatum.SelectedModel component and will respond to changes in the model and on changes to the selected model in the collection.

Simple example:

    1234567891011var Rd = ReactDatum; <Rd.SelectedModel collection={myBackboneCollection} placeholder="Wait for it...">  <Rd.Text label="You selected: " attr="name"/></Rd.SelectedModel> var index = 0;setInterval(function(){  myBackboneCollection.selectModelByIndex(index);  index += 1;}, 5000)

The (example above)[TODO: add link to github.io example] when run, will initially display a placeholder, "Wait for it..." and then every five seconds select the next model in the collection.

The placeholder prop will render in place of any children when there is no selected model in the collection and can be any React renderable.

#### SelectableCollection mixin

Use of the SelectedModel component will automatically add the ReactDatum.SelectableCollection to the collection instance unless collection.hasSelectableCollectionMixin is true. setModelByIndex(index) in the example above is one of the methods added by that mixin. See (ReactDatum.SelectableCollection)[TODO: add doc link]

#### SelectedModel propTypes:

See Also: ContextualData propTypes

#### SelectedModel defaultProps:

See Also: ContextualData defaultProps

#### SelectedModel contextTypes:

See Also: ContextualData contextTypes

    1collection: React.PropTypes.instanceOf(Backbone.Collection)

#### SelectedModel Instance Methods:

##### getInputCollectionOrModel()

override - We are going to provide a 'model' context (contextKey), but we listen to a collection