Code coverage report for components/tags.js

Statements: 100% (24 / 24)      Branches: 93.75% (15 / 16)      Functions: 100% (6 / 6)      Lines: 100% (24 / 24)      Ignored: none     

All files » components/ » tags.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 1091 1 1                           1                       1             35               2   2 1 1 1                         38 38   38 38   38 3         35 3                         38               2 8 8                     1
var React = window.React || require('react/addons');
var _ = require('lodash');
var Styles = require('../styles/tags');
 
/*
 * Tags element displays either a textual list of tags ("one, two, three")
 * or a count ("3 tags") button that, when clicked, reveals a menu popup of those tags.
 *
 * Individual tags are clickable and, if passed a navigation utility, will set filters
 * and route to tag-filtered view (however defined). Alternatively, you may pass in a callback
 * that is called on tag click to produce some other behavior.
 *
 * Note: The Tags element merely displays tags; for tag editing functionality, use in
 * conjunction with the TagEdit element.
 */
 
var Tags = React.createClass({
 
  propTypes: {
    tags: React.PropTypes.arrayOf(React.PropTypes.string),
    condensed: React.PropTypes.bool,
    navigatorUtility: React.PropTypes.object,
    altOnTagClick: React.PropTypes.func
  },
 
  mixins: [Styles],
 
  getDefaultProps: function() {
    return {
      tags: '',
      condensed: false
    };
  },
 
  getInitialState: function() {
    return {};
  },
 
  onTagClick: function(ev) {
    /*
     * If navigatorUtility prop passed in, will trigger navigation event to tag-filtered
     * view. Alternatively, pass in a different callback to trigger some other event.
     */
    var tag = ev.target.textContent;
 
    if (this.props.navigatorUtility) {
      this.props.navigatorUtility.setTagFilterAndRoute(tag);
    } else Eif (this.props.altOnTagClick) {
      this.props.altOnTagClick(tag);
    }
  },
 
  render: function() {
    /*
     * If the item has no tags, the TagEdit sibling element takes over,
     * adding the 'Add a tag.' button.
     * If we only have a single tag, print the tag.
     * If we have more than one tag and if condensed,
     * prints the number of tags: ie, "4 tags"; or, if expanded,
     * shows a full textual representation of tags: "tag1, tag2, tag3"
     */
    var wrapped = null;
    var tagListItems = [];
 
    var len = this.props.tags.length;
    var liStyle = this.props.condensed ? Styles.listItem : Styles.expanded;
 
    if (len === 1) {
      wrapped = (
        <button style={Styles.tag} onClick={this.onTagClick}>
          {this.props.tags}
        </button>
      );
    } else if (len > 1) {
      wrapped = this.props.condensed ?
        (
          <button style={Styles.tag}>
            {len.toString() + ' tags'}
          </button>
        ) :
        (
          <ul style={Styles.list}>
            {this.buildTagList()}
          </ul>
        );
    }
 
    return (
      <div style={Styles.wrapper}>
        {wrapped}
      </div>
    );
  },
 
  buildTagList: function() {
    return _.map(this.props.tags, function(tag, i, arr) {
      var maybeComma = i === (arr.length - 1) ? null : ',';
      return (
        <li key={'tag' + ':' + i} style={Styles.expanded}>
          <button style={Styles.tag} onClick={this.onTagClick}>
            {tag}
          </button>{maybeComma}
        </li>
      );
    }, this);
  }
});
 
module.exports = Tags;