<commit_before>import React, { PropTypes } from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import classnames from 'classnames';
//
import * as Basic from '../../basic';
import { LocalizationService } from '../../../services';
import { ConfigurationManager } from '../../../redux/data';
import { SecurityManager } from '../../../redux';
import { getNavigationItems, resolveNavigationParameters, collapseNavigation, i18nChange } from '../../../redux/config/actions';
import NavigationItem from './NavigationItem';
import NavigationSeparator from './NavigationSeparator';

/**
 * Top navigation
 *
 * @author Radek Tomiška
 */
export class Navigation extends Basic.AbstractContent {

  constructor(props, context) {
    super(props, context);
  }

  componentDidMount() {
    this.initSideMenu();
  }

  componentDidUpdate() {
    // this is needed - menu is updated after login
    this.initSideMenu();
  }

  initSideMenu() {
    if (typeof $ === undefined) {
      return;
    }
    const sideMenu = $('#side-menu');
    if (!sideMenu || sideMenu === undefined) {
      return;
    }

    sideMenu.metisMenu({
      toggle: true
    });

    $(window).bind('load resize', function sidebarResize() {
      let topOffset = 50;
      const width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
      if (width < 768) {
        $('div.navbar-collapse').addClass('collapse');
        topOffset = 100; // 2-row-menu
      } else {
        $('div.navbar-collapse').removeClass('collapse');
      }

      let height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1;
      height = height - topOffset;
      if (height < 1) height = 1;
      if (height > topOffset) {
        $('#content-wrapper').css('min-height', (height) + 'px');
      }
    });
    /*
    TODO: default menu collapse by url? Now is setted by react
    var url = window.location;
    var element = $('ul.nav a').filter(function() {
        return this.href === url || url.href.indexOf(this.href) === 0;
    }).addClass('active').parent().parent().addClass('in').parent();
    if (element.is('li')) {
        element.addClass('active');
    }*/
  }

  renderNavigationItems(section = 'main') {
    const { navigation, userContext, selectedNavigationItems } = this.props;
    const items = getNavigationItems(navigation, null, section, userContext);
    return this._renderNavigationItems(items, userContext, selectedNavigationItems);
  }

  _renderNavigationItems(items, userContext, selectedNavigationItems) {
    if (!items) {
      return null;
    }
    const renderedItems = [];
    for (const item of items) {
      const renderedItem = this.renderNavigationItem(item, userContext, selectedNavigationItems[0]);
      if (renderedItem) { // can be null
        renderedItems.push(renderedItem);
      }
    }
    return renderedItems;
  }

  _resolveNavigationItemText(item, userContext) {
    const labelParams = resolveNavigationParameters(userContext);
    labelParams.defaultValue = item.label;

    if (item.labelKey) {
      return (
          {this.i18n(item.labelKey, labelParams)}
      );
    }
    if (item.label) {
      return (
          {item.label}
      );
    }
    return (
       { this.i18n(item.titleKey, { defaultValue: item.title }) }
    );
  }

  renderNavigationItem(item, userContext, activeItem, titlePlacement = 'bottom', navigationCollapsed = false) {
    switch (item.type) {
      case 'DYNAMIC': {
        return (
          <NavigationItem
            id={`nav-item-${item.id}`}
            key={`nav-item-${item.id}`}
            to={item.to}
            title={this.i18n(item.titleKey, { defaultValue: item.title })}
            titlePlacement={titlePlacement}
            icon={item.icon}
            iconColor={item.iconColor}
            active={activeItem === item.id}
            text={this._resolveNavigationItemText(item, userContext)}
            collapsed={navigationCollapsed}/>
        );
      }
      case 'TAB': {
        // tab is not visible in menu
        return null;
      }
      case 'SEPARATOR': {
        return (
          <NavigationSeparator
            id={`nav-item-${item.id}`}
            key={`nav-item-${item.id}`}
            text={this._resolveNavigationItemText(item, userContext)} />
        );
      }
      default: {
        this.getLogger().warn('[Advanced.Navigation] ' + item.type + ' type not implemeted for item id [' + item.id + ']');
        return null;
      }
    }
  }

  toogleNavigationCollapse(navigationCollapsed, event) {
    if (event) {
      event.preventDefault();
    }
    this.context.store.dispatch(collapseNavigation(!navigationCollapsed));
  }

  // TODO: refator all sibedars (react component, drop original sibebar = detailTabs)
  renderSidebarItems(parentId = null, level = 0) {
    const { navigation, navigationCollapsed, userContext, selectedNavigationItems } = this.props;
    level = level + 1;
    const levelItems = getNavigationItems(navigation, parentId, 'main', userContext);
    if (!levelItems || levelItems.length === 0) {
      return null;
    }

    const items = [];
    for (const levelItem of levelItems) {
      if (levelItem.type !== 'DYNAMIC' && levelItem.type !== 'SEPARATOR') {
        continue;
      }
      const children = this.renderSidebarItems(levelItem.id, level);
      const isActive = selectedNavigationItems.length >= level && selectedNavigationItems[level - 1] === levelItem.id;
      if (children && !navigationCollapsed) {
        items.push(
          <li key={`nav-item-${levelItem.id}`} className={isActive ? 'has-children active' : 'has-children'}>
            <Basic.Tooltip id={`${levelItem.id}-tooltip`} placement="right" value={ this.i18n(levelItem.titleKey, { defaultValue: levelItem.title }) }>

                <Basic.Icon icon={levelItem.icon} color={levelItem.iconColor}/>
                {
                  navigationCollapsed
                  ?
                  null
                  :

                    { this._resolveNavigationItemText(levelItem, userContext) }

                }

            </Basic.Tooltip>
            { children }

        );
      } else {
        const item = this.renderNavigationItem(levelItem, userContext, selectedNavigationItems.length >= level ? selectedNavigationItems[level - 1] : null, 'right', navigationCollapsed);
        if (item) {
          items.push(item);
        }
      }
    }

    if (items.length === 0) {
      return null;
    }

    if (level === 100) { // collapse menu prepare
      items.push(

            <Basic.Icon value={`arrow-${navigationCollapsed ? 'right' : 'left'}`}/>
              {
                navigationCollapsed
                ?
                null
                :

                  Zmenšit menu

              }

      );
    }

    const classNames = classnames(
      'nav',
      { 'metismenu': level === 1 },
      { 'nav-second-level': level === 2 },
      { 'nav-third-level': level === 3 },
      { 'hidden': (level > 3 || (navigationCollapsed && level > 1)) }, // only three levels are supported
      { 'in': (selectedNavigationItems.length > level - 1 && selectedNavigationItems[level - 2]) === parentId },
      { 'collapse': parentId && !this._isSelected(selectedNavigationItems, parentId) && (selectedNavigationItems.length > level - 1 && selectedNavigationItems[level - 2]) !== parentId }
    );
    return (

        {items}

    );
  }

  _isSelected(selectedNavigationItems, parentId) {
    if (!parentId || !selectedNavigationItems) {
      return false;
    }
    for (const selectedNavigationItem of selectedNavigationItems) {
      if (parentId === selectedNavigationItem) {
        return true;
      }
    }
    return false;
  }

  render() {
    const { environment, userContext, navigationCollapsed, rendered, i18nReady } = this.props;
    //
    if (!rendered) {
      return false;
    }

    let environmentLabel = null;
    if (environment) {
      const environmentClassName = classnames(
        'label',
        {'label-success': environment === 'development'},
        {'label-warning': environment !== 'development'},
        {'hidden': environment === 'production'}
      );
      environmentLabel = (

            {this.i18n('environment.' + environment + '.label', { defaultValue: environment })}
            {this.i18n('environment.' + environment + '.short', { defaultValue: environment })}

      );
    }

    const supportedLanguages = LocalizationService.getSupportedLanguages();
    let flags = null;
    if (supportedLanguages && supportedLanguages.length > 1) {
      flags = (

              {
                supportedLanguages.map((lng, i) => {
                  const lgnClassName = classnames(
                    'flag',
                    lng,
                    { 'active': i18nReady === lng },
                    { 'last': i === supportedLanguages.length - 1 }
                  );
                  return (
                    <span
                      key={`locale-${lng}`}
                      className={lgnClassName}
                      onClick={() => { this.context.store.dispatch(i18nChange(lng, () => { window.location.reload(); } )); }}>

                  );
                })
              }

      );
    }

    const mainItems = this.renderNavigationItems('main');
    const systemItems = this.renderNavigationItems('system');
    const sidebarItems = this.renderSidebarItems();

    const sidebarClassName = classnames(
      'navbar-default',
      'sidebar',
      { collapsed: navigationCollapsed }
    );

    return (

              <button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
                {this.i18n('navigation.toogle')}

              </button>
              <Link to="/" title="Úvodní stránka" className="home">
                {' '}
              </Link>

              {
                !userContext.isExpired && !SecurityManager.isAuthenticated(userContext)
                ?

                  {mainItems}

                :
                null
              }

                { environmentLabel }
                { flags }

                  {
                    userContext.isExpired
                    ||
                    systemItems
                  }

            {
              !userContext.isExpired && SecurityManager.isAuthenticated(userContext)
              ?

                  { sidebarItems }

              :
              null
            }

    );
  }
}

Navigation.propTypes = {
  rendered: PropTypes.bool,
  navigation: PropTypes.object,
  navigationCollapsed: PropTypes.bool,
  selectedNavigationItems: PropTypes.array,
  environment: PropTypes.string,
  userContext: PropTypes.object,
  i18nReady: PropTypes.string
};

Navigation.defaultProps = {
  rendered: true,
  navigation: null,
  navigationCollapsed: false,
  selectedNavigationItems: null,
  environment: null,
  userContext: null,
  i18nReady: null
};

Navigation.contextTypes = {
  ...Basic.AbstractContextComponent.contextTypes,
  router: PropTypes.object.isRequired
};

function select(state) {
  return {
    navigation: state.config.get('navigation'),
    navigationCollapsed: state.config.get('navigationCollapsed'),
    selectedNavigationItems: state.config.get('selectedNavigationItems'),
    environment: ConfigurationManager.getEnvironmentStage(state),
    userContext: state.security.userContext,
    i18nReady: state.config.get('i18nReady')
  };
}

export default connect(select)(Navigation);
<commit_msg>FE: if menu contains only one subitem, which leeds to the same path - sub menu is truncated<commit_after>import React, { PropTypes } from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import classnames from 'classnames';
//
import * as Basic from '../../basic';
import { LocalizationService } from '../../../services';
import { ConfigurationManager } from '../../../redux/data';
import { SecurityManager } from '../../../redux';
import { getNavigationItems, resolveNavigationParameters, collapseNavigation, i18nChange } from '../../../redux/config/actions';
import NavigationItem from './NavigationItem';
import NavigationSeparator from './NavigationSeparator';

/**
 * Top navigation
 *
 * @author Radek Tomiška
 */
export class Navigation extends Basic.AbstractContent {

  constructor(props, context) {
    super(props, context);
  }

  componentDidMount() {
    this.initSideMenu();
  }

  componentDidUpdate() {
    // this is needed - menu is updated after login
    this.initSideMenu();
  }

  initSideMenu() {
    if (typeof $ === undefined) {
      return;
    }
    const sideMenu = $('#side-menu');
    if (!sideMenu || sideMenu === undefined) {
      return;
    }

    sideMenu.metisMenu({
      toggle: true
    });

    $(window).bind('load resize', function sidebarResize() {
      let topOffset = 50;
      const width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
      if (width < 768) {
        $('div.navbar-collapse').addClass('collapse');
        topOffset = 100; // 2-row-menu
      } else {
        $('div.navbar-collapse').removeClass('collapse');
      }

      let height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1;
      height = height - topOffset;
      if (height < 1) height = 1;
      if (height > topOffset) {
        $('#content-wrapper').css('min-height', (height) + 'px');
      }
    });
    /*
    TODO: default menu collapse by url? Now is setted by react
    var url = window.location;
    var element = $('ul.nav a').filter(function() {
        return this.href === url || url.href.indexOf(this.href) === 0;
    }).addClass('active').parent().parent().addClass('in').parent();
    if (element.is('li')) {
        element.addClass('active');
    }*/
  }

  renderNavigationItems(section = 'main') {
    const { navigation, userContext, selectedNavigationItems } = this.props;
    const items = getNavigationItems(navigation, null, section, userContext);
    return this._renderNavigationItems(items, userContext, selectedNavigationItems);
  }

  _renderNavigationItems(items, userContext, selectedNavigationItems) {
    if (!items) {
      return null;
    }
    const renderedItems = [];
    for (const item of items) {
      const renderedItem = this.renderNavigationItem(item, userContext, selectedNavigationItems[0]);
      if (renderedItem) { // can be null
        renderedItems.push(renderedItem);
      }
    }
    return renderedItems;
  }

  _resolveNavigationItemText(item, userContext) {
    const labelParams = resolveNavigationParameters(userContext);
    labelParams.defaultValue = item.label;

    if (item.labelKey) {
      return (
          {this.i18n(item.labelKey, labelParams)}
      );
    }
    if (item.label) {
      return (
          {item.label}
      );
    }
    return (
       { this.i18n(item.titleKey, { defaultValue: item.title }) }
    );
  }

  renderNavigationItem(item, userContext, activeItem, titlePlacement = 'bottom', navigationCollapsed = false) {
    switch (item.type) {
      case 'DYNAMIC': {
        return (
          <NavigationItem
            id={`nav-item-${item.id}`}
            key={`nav-item-${item.id}`}
            to={item.to}
            title={this.i18n(item.titleKey, { defaultValue: item.title })}
            titlePlacement={titlePlacement}
            icon={item.icon}
            iconColor={item.iconColor}
            active={activeItem === item.id}
            text={this._resolveNavigationItemText(item, userContext)}
            collapsed={navigationCollapsed}/>
        );
      }
      case 'TAB': {
        // tab is not visible in menu
        return null;
      }
      case 'SEPARATOR': {
        return (
          <NavigationSeparator
            id={`nav-item-${item.id}`}
            key={`nav-item-${item.id}`}
            text={this._resolveNavigationItemText(item, userContext)} />
        );
      }
      default: {
        this.getLogger().warn('[Advanced.Navigation] ' + item.type + ' type not implemeted for item id [' + item.id + ']');
        return null;
      }
    }
  }

  toogleNavigationCollapse(navigationCollapsed, event) {
    if (event) {
      event.preventDefault();
    }
    this.context.store.dispatch(collapseNavigation(!navigationCollapsed));
  }

  // TODO: refator all sibedars (react component, drop original sibebar = detailTabs)
  renderSidebarItems(parentId = null, level = 0) {
    const { navigation, navigationCollapsed, userContext, selectedNavigationItems } = this.props;
    level = level + 1;
    const levelItems = getNavigationItems(navigation, parentId, 'main', userContext);
    if (!levelItems || levelItems.length === 0) {
      return null;
    }

    const items = [];
    for (const levelItem of levelItems) {
      if (levelItem.type !== 'DYNAMIC' && levelItem.type !== 'SEPARATOR') {
        continue;
      }
      const childrenItems = getNavigationItems(navigation, levelItem.id, 'main', userContext);
      const children = this.renderSidebarItems(levelItem.id, level);
      const isActive = selectedNavigationItems.length >= level && selectedNavigationItems[level - 1] === levelItem.id;
      if (childrenItems.length === 1 && childrenItems[0].path === levelItem.path) {
        // if menu contains only one subitem, which leeds to the same path - sub menu is truncated
        items.push(this.renderNavigationItem(childrenItems[0], userContext, selectedNavigationItems.length >= level ? selectedNavigationItems[level - 1] : null, 'right', navigationCollapsed));
      } else if (children && !navigationCollapsed) {
        items.push(
          <li key={`nav-item-${levelItem.id}`} className={isActive ? 'has-children active' : 'has-children'}>
            <Basic.Tooltip id={`${levelItem.id}-tooltip`} placement="right" value={ this.i18n(levelItem.titleKey, { defaultValue: levelItem.title }) }>

                <Basic.Icon icon={levelItem.icon} color={levelItem.iconColor}/>
                {
                  navigationCollapsed
                  ?
                  null
                  :

                    { this._resolveNavigationItemText(levelItem, userContext) }

                }

            </Basic.Tooltip>
            { children }

        );
      } else {
        const item = this.renderNavigationItem(levelItem, userContext, selectedNavigationItems.length >= level ? selectedNavigationItems[level - 1] : null, 'right', navigationCollapsed);
        if (item) {
          items.push(item);
        }
      }
    }

    if (items.length === 0) {
      return null;
    }

    if (level === 100) { // collapse menu prepare
      items.push(

            <Basic.Icon value={`arrow-${navigationCollapsed ? 'right' : 'left'}`}/>
              {
                navigationCollapsed
                ?
                null
                :

                  Zmenšit menu

              }

      );
    }

    const classNames = classnames(
      'nav',
      { 'metismenu': level === 1 },
      { 'nav-second-level': level === 2 },
      { 'nav-third-level': level === 3 },
      { 'hidden': (level > 3 || (navigationCollapsed && level > 1)) }, // only three levels are supported
      { 'in': (selectedNavigationItems.length > level - 1 && selectedNavigationItems[level - 2]) === parentId },
      { 'collapse': parentId && !this._isSelected(selectedNavigationItems, parentId) && (selectedNavigationItems.length > level - 1 && selectedNavigationItems[level - 2]) !== parentId }
    );
    return (

        {items}

    );
  }

  _isSelected(selectedNavigationItems, parentId) {
    if (!parentId || !selectedNavigationItems) {
      return false;
    }
    for (const selectedNavigationItem of selectedNavigationItems) {
      if (parentId === selectedNavigationItem) {
        return true;
      }
    }
    return false;
  }

  render() {
    const { environment, userContext, navigationCollapsed, rendered, i18nReady } = this.props;
    //
    if (!rendered) {
      return false;
    }

    let environmentLabel = null;
    if (environment) {
      const environmentClassName = classnames(
        'label',
        {'label-success': environment === 'development'},
        {'label-warning': environment !== 'development'},
        {'hidden': environment === 'production'}
      );
      environmentLabel = (

            {this.i18n('environment.' + environment + '.label', { defaultValue: environment })}
            {this.i18n('environment.' + environment + '.short', { defaultValue: environment })}

      );
    }

    const supportedLanguages = LocalizationService.getSupportedLanguages();
    let flags = null;
    if (supportedLanguages && supportedLanguages.length > 1) {
      flags = (

              {
                supportedLanguages.map((lng, i) => {
                  const lgnClassName = classnames(
                    'flag',
                    lng,
                    { 'active': i18nReady === lng },
                    { 'last': i === supportedLanguages.length - 1 }
                  );
                  return (
                    <span
                      key={`locale-${lng}`}
                      className={lgnClassName}
                      onClick={() => { this.context.store.dispatch(i18nChange(lng, () => { window.location.reload(); } )); }}>

                  );
                })
              }

      );
    }

    const mainItems = this.renderNavigationItems('main');
    const systemItems = this.renderNavigationItems('system');
    const sidebarItems = this.renderSidebarItems();

    const sidebarClassName = classnames(
      'navbar-default',
      'sidebar',
      { collapsed: navigationCollapsed }
    );

    return (

              <button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
                {this.i18n('navigation.toogle')}

              </button>
              <Link to="/" title="Úvodní stránka" className="home">
                {' '}
              </Link>

              {
                !userContext.isExpired && !SecurityManager.isAuthenticated(userContext)
                ?

                  {mainItems}

                :
                null
              }

                { environmentLabel }
                { flags }

                  {
                    userContext.isExpired
                    ||
                    systemItems
                  }

            {
              !userContext.isExpired && SecurityManager.isAuthenticated(userContext)
              ?

                  { sidebarItems }

              :
              null
            }

    );
  }
}

Navigation.propTypes = {
  rendered: PropTypes.bool,
  navigation: PropTypes.object,
  navigationCollapsed: PropTypes.bool,
  selectedNavigationItems: PropTypes.array,
  environment: PropTypes.string,
  userContext: PropTypes.object,
  i18nReady: PropTypes.string
};

Navigation.defaultProps = {
  rendered: true,
  navigation: null,
  navigationCollapsed: false,
  selectedNavigationItems: null,
  environment: null,
  userContext: null,
  i18nReady: null
};

Navigation.contextTypes = {
  ...Basic.AbstractContextComponent.contextTypes,
  router: PropTypes.object.isRequired
};

function select(state) {
  return {
    navigation: state.config.get('navigation'),
    navigationCollapsed: state.config.get('navigationCollapsed'),
    selectedNavigationItems: state.config.get('selectedNavigationItems'),
    environment: ConfigurationManager.getEnvironmentStage(state),
    userContext: state.security.userContext,
    i18nReady: state.config.get('i18nReady')
  };
}

export default connect(select)(Navigation);
<|endoftext|>


<commit_before>function Thermostat() {
  this.temperature = 20;
  this.powerSaving = true;
  this.maximumTemperature = 25
  this.minimumTemperature = 10;
  this.currentEnergyUsage = "yellow"

};

Thermostat.prototype.increaseTemperature = function() {
  if(this.temperature === this.maximumTemperature) {
    throw new Error("Cannot increase above 25 degrees!")
  }
  this.temperature += 1;
  this._energyUsage();
};

Thermostat.prototype.decreaseTemperature = function () {
  if(this.temperature === 10) {
    throw new Error("Cannot decrease below 10 degrees!");
  }
    this.temperature -= 1;
    this._energyUsage();
};

Thermostat.prototype.switchPowerSaving = function() {
  if(this.powerSaving === true) {
  this.powerSaving = false;
  this.maximumTemperature = 32;
} else {
  this.powerSaving = true;
  this.maximumTemperature = 25;
  };
};

Thermostat.prototype.reset = function () {
  this.temperature = 20;
};

Thermostat.prototype._energyUsage = function() {
  if (this.temperature < 18) {
    this.currentEnergyUsage = 'green';
  } else if(this.temperature > 25){
    this.currentEnergyUsage = 'red';
  } else {
    this.currentEnergyUsage = 'yellow';
  };
};
<commit_msg>Removed some magic numbers<commit_after>function Thermostat() {
  this.DEFAULT_TEMP = 20;
  this.MEDIUM_USAGE_LIMIT = 25;
  this.LOW_USAGE_LIMIT = 18;
  this.temperature = this.DEFAULT_TEMP;
  this.powerSaving = true;
  this.maximumTemperature = 25
  this.minimumTemperature = 10;
  this.currentEnergyUsage = "yellow"

};

Thermostat.prototype.increaseTemperature = function() {
  if(this.temperature === this.maximumTemperature) {
    throw new Error("Cannot increase above 25 degrees!")
  }
  this.temperature += 1;
  this._energyUsage();
};

Thermostat.prototype.decreaseTemperature = function () {
  if(this.temperature === 10) {
    throw new Error("Cannot decrease below 10 degrees!");
  }
    this.temperature -= 1;
    this._energyUsage();
};

Thermostat.prototype.switchPowerSaving = function() {
  if(this.powerSaving === true) {
  this.powerSaving = false;
  this.maximumTemperature = 32;
} else {
  this.powerSaving = true;
  this.maximumTemperature = 25;
  };
};

Thermostat.prototype.reset = function () {
  this.temperature = this.DEFAULT_TEMP;
};

Thermostat.prototype._energyUsage = function() {
  if (this.temperature < this.LOW_USAGE_LIMIT) {
    this.currentEnergyUsage = 'green';
  } else if(this.temperature > this.MEDIUM_USAGE_LIMIT){
    this.currentEnergyUsage = 'red';
  } else {
    this.currentEnergyUsage = 'yellow';
  };
};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/**
 * Implements `document.register`
 * @module CustomElements
*/

/**
 * Polyfilled extensions to the `document` object.
 * @class Document
*/

(function(scope) {

// imports

if (!scope) {
  scope = window.CustomElements = {flags:{}};
}
var flags = scope.flags;

// native document.register?

var hasNative = Boolean(document.register);
var useNative = !flags.register && hasNative;

if (useNative) {

  // stub
  var nop = function() {};

  // exports
  scope.registry = {};
  scope.upgradeElement = nop;

  scope.watchShadow = nop;
  scope.upgrade = nop;
  scope.upgradeAll = nop;
  scope.upgradeSubtree = nop;
  scope.observeDocument = nop;
  scope.upgradeDocument = nop;
  scope.takeRecords = nop;

} else {

  /**
   * Registers a custom tag name with the document.
   *
   * When a registered element is created, a `readyCallback` method is called
   * in the scope of the element. The `readyCallback` method can be specified on
   * either `options.prototype` or `options.lifecycle` with the latter taking
   * precedence.
   *
   * @method register
   * @param {String} name The tag name to register. Must include a dash ('-'),
   *    for example 'x-component'.
   * @param {Object} options
   *    @param {String} [options.extends]
   *      (_off spec_) Tag name of an element to extend (or blank for a new
   *      element). This parameter is not part of the specification, but instead
   *      is a hint for the polyfill because the extendee is difficult to infer.
   *      Remember that the input prototype must chain to the extended element's
   *      prototype (or HTMLElement.prototype) regardless of the value of
   *      `extends`.
   *    @param {Object} options.prototype The prototype to use for the new
   *      element. The prototype must inherit from HTMLElement.
   *    @param {Object} [options.lifecycle]
   *      Callbacks that fire at important phases in the life of the custom
   *      element.
   *
   * @example
   *      FancyButton = document.register("fancy-button", {
   *        extends: 'button',
   *        prototype: Object.create(HTMLButtonElement.prototype, {
   *          readyCallback: {
   *            value: function() {
   *              console.log("a fancy-button was created",
   *            }
   *          }
   *        })
   *      });
   * @return {Function} Constructor for the newly registered type.
   */
  function register(name, options) {
    //console.warn('document.register("' + name + '", ', options, ')');
    // construct a defintion out of options
    // TODO(sjmiles): probably should clone options instead of mutating it
    var definition = options || {};
    if (!name) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('document.register: first argument `name` must not be empty');
    }
    if (name.indexOf('-') < 0) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('document.register: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
    }
    // elements may only be registered once
    if (getRegisteredDefinition(name)) {
      throw new Error('DuplicateDefinitionError: a type with name \'' + String(name) + '\' is already registered');
    }
    // must have a prototype, default to an extension of HTMLElement
    // TODO(sjmiles): probably should throw if no prototype, check spec
    if (!definition.prototype) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('Options missing required prototype property');
    }
    // record name
    definition.elementName = name.toLowerCase();
    // ensure a lifecycle object so we don't have to null test it
    definition.lifecycle = definition.lifecycle || {};
    // build a list of ancestral custom elements (for native base detection)
    // TODO(sjmiles): we used to need to store this, but current code only
    // uses it in 'resolveTagName': it should probably be inlined
    definition.ancestry = ancestry(definition.extends);
    // extensions of native specializations of HTMLElement require localName
    // to remain native, and use secondary 'is' specifier for extension type
    resolveTagName(definition);
    // some platforms require modifications to the user-supplied prototype
    // chain
    resolvePrototypeChain(definition);
    // overrides to implement attributeChanged callback
    overrideAttributeApi(definition.prototype);
    // 7.1.5: Register the DEFINITION with DOCUMENT
    registerDefinition(definition.elementName, definition);
    // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
    // 7.1.8. Return the output of the previous step.
    definition.ctor = generateConstructor(definition);
    definition.ctor.prototype = definition.prototype;
    // force our .constructor to be our actual constructor
    definition.prototype.constructor = definition.ctor;
    // if initial parsing is complete
    if (scope.ready) {
      // upgrade any pre-existing nodes of this type
      scope.upgradeAll(document);
    }
    return definition.ctor;
  }

  function ancestry(extnds) {
    var extendee = getRegisteredDefinition(extnds);
    if (extendee) {
      return ancestry(extendee.extends).concat([extendee]);
    }
    return [];
  }

  function resolveTagName(definition) {
    // if we are explicitly extending something, that thing is our
    // baseTag, unless it represents a custom component
    var baseTag = definition.extends;
    // if our ancestry includes custom components, we only have a
    // baseTag if one of them does
    for (var i=0, a; (a=definition.ancestry[i]); i++) {
      baseTag = a.is && a.tag;
    }
    // our tag is our baseTag, if it exists, and otherwise just our name
    definition.tag = baseTag || definition.elementName;
    if (baseTag) {
      // if there is a base tag, use secondary 'is' specifier
      definition.is = definition.elementName;
    }
  }

  function resolvePrototypeChain(definition) {
    // if we don't support __proto__ we need to locate the native level
    // prototype for precise mixing in
    if (!Object.__proto__) {
      // default prototype
      var nativePrototype = HTMLElement.prototype;
      // work out prototype when using type-extension
      if (definition.is) {
        var inst = document.createElement(definition.tag);
        nativePrototype = Object.getPrototypeOf(inst);
      }
      // ensure __proto__ reference is installed at each point on the prototype
      // chain.
      // NOTE: On platforms without __proto__, a mixin strategy is used instead
      // of prototype swizzling. In this case, this generated __proto__ provides
      // limited support for prototype traversal.
      var proto = definition.prototype, ancestor;
      while (proto && (proto !== nativePrototype)) {
        var ancestor = Object.getPrototypeOf(proto);
        proto.__proto__ = ancestor;
        proto = ancestor;
      }
    }
    // cache this in case of mixin
    definition.native = nativePrototype;
  }

  // SECTION 4

  function instantiate(definition) {
    // 4.a.1. Create a new object that implements PROTOTYPE
    // 4.a.2. Let ELEMENT by this new object
    //
    // the custom element instantiation algorithm must also ensure that the
    // output is a valid DOM element with the proper wrapper in place.
    //
    return upgrade(domCreateElement(definition.tag), definition);
  }

  function upgrade(element, definition) {
    // some definitions specify an 'is' attribute
    if (definition.is) {
      element.setAttribute('is', definition.is);
    }
    // remove 'unresolved' attr, which is a standin for :unresolved.
    element.removeAttribute('unresolved');
    // make 'element' implement definition.prototype
    implement(element, definition);
    // flag as upgraded
    element.__upgraded__ = true;
    // there should never be a shadow root on element at this point
    // we require child nodes be upgraded before `created`
    scope.upgradeSubtree(element);
    // lifecycle management
    created(element);
    // OUTPUT
    return element;
  }

  function implement(element, definition) {
    // prototype swizzling is best
    if (Object.__proto__) {
      element.__proto__ = definition.prototype;
    } else {
      // where above we can re-acquire inPrototype via
      // getPrototypeOf(Element), we cannot do so when
      // we use mixin, so we install a magic reference
      customMixin(element, definition.prototype, definition.native);
      element.__proto__ = definition.prototype;
    }
  }

  function customMixin(inTarget, inSrc, inNative) {
    // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
    // any property. This set should be precalculated. We also need to
    // consider this for supporting 'super'.
    var used = {};
    // start with inSrc
    var p = inSrc;
    // sometimes the default is HTMLUnknownElement.prototype instead of
    // HTMLElement.prototype, so we add a test
    // the idea is to avoid mixing in native prototypes, so adding
    // the second test is WLOG
    while (p !== inNative && p !== HTMLUnknownElement.prototype) {
      var keys = Object.getOwnPropertyNames(p);
      for (var i=0, k; k=keys[i]; i++) {
        if (!used[k]) {
          Object.defineProperty(inTarget, k,
              Object.getOwnPropertyDescriptor(p, k));
          used[k] = 1;
        }
      }
      p = Object.getPrototypeOf(p);
    }
  }

  function created(element) {
    // invoke createdCallback
    if (element.createdCallback) {
      element.createdCallback();
    }
  }

  // attribute watching

  function overrideAttributeApi(prototype) {
    // overrides to implement callbacks
    // TODO(sjmiles): should support access via .attributes NamedNodeMap
    // TODO(sjmiles): preserves user defined overrides, if any
    if (prototype.setAttribute._polyfilled) {
      return;
    }
    var setAttribute = prototype.setAttribute;
    prototype.setAttribute = function(name, value) {
      changeAttribute.call(this, name, value, setAttribute);
    }
    var removeAttribute = prototype.removeAttribute;
    prototype.removeAttribute = function(name) {
      changeAttribute.call(this, name, null, removeAttribute);
    }
    prototype.setAttribute._polyfilled = true;
  }

  // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
  // index.html#dfn-attribute-changed-callback
  function changeAttribute(name, value, operation) {
    var oldValue = this.getAttribute(name);
    operation.apply(this, arguments);
    var newValue = this.getAttribute(name);
    if (this.attributeChangedCallback
        && (newValue !== oldValue)) {
      this.attributeChangedCallback(name, oldValue, newValue);
    }
  }

  // element registry (maps tag names to definitions)

  var registry = {};

  function getRegisteredDefinition(name) {
    if (name) {
      return registry[name.toLowerCase()];
    }
  }

  function registerDefinition(name, definition) {
    registry[name] = definition;
  }

  function generateConstructor(definition) {
    return function() {
      return instantiate(definition);
    };
  }

  function createElement(tag, typeExtension) {
    // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
    // error check it, or perhaps there should only ever be one argument
    var definition = getRegisteredDefinition(typeExtension || tag);
    if (definition) {
      return new definition.ctor();
    }
    return domCreateElement(tag);
  }

  function upgradeElement(element) {
    if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
      var type = element.getAttribute('is') || element.localName;
      var definition = getRegisteredDefinition(type);
      return definition && upgrade(element, definition);
    }
  }

  function cloneNode(deep) {
    // call original clone
    var n = domCloneNode.call(this, deep);
    // upgrade the element and subtree
    scope.upgradeAll(n);
    // return the clone
    return n;
  }
  // capture native createElement before we override it

  var domCreateElement = document.createElement.bind(document);

  // capture native cloneNode before we override it

  var domCloneNode = Node.prototype.cloneNode;

  // exports

  document.register = register;
  document.createElement = createElement; // override
  Node.prototype.cloneNode = cloneNode; // override

  scope.registry = registry;

  /**
   * Upgrade an element to a custom element. Upgrading an element
   * causes the custom prototype to be applied, an `is` attribute
   * to be attached (as needed), and invocation of the `readyCallback`.
   * `upgrade` does nothing if the element is already upgraded, or
   * if it matches no registered custom tag name.
   *
   * @method ugprade
   * @param {Element} element The element to upgrade.
   * @return {Element} The upgraded element.
   */
  scope.upgrade = upgradeElement;
}

scope.hasNative = hasNative;
scope.useNative = useNative;

})(window.CustomElements);
<commit_msg>use two underscores, less likely to have conflict<commit_after>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/**
 * Implements `document.register`
 * @module CustomElements
*/

/**
 * Polyfilled extensions to the `document` object.
 * @class Document
*/

(function(scope) {

// imports

if (!scope) {
  scope = window.CustomElements = {flags:{}};
}
var flags = scope.flags;

// native document.register?

var hasNative = Boolean(document.register);
var useNative = !flags.register && hasNative;

if (useNative) {

  // stub
  var nop = function() {};

  // exports
  scope.registry = {};
  scope.upgradeElement = nop;

  scope.watchShadow = nop;
  scope.upgrade = nop;
  scope.upgradeAll = nop;
  scope.upgradeSubtree = nop;
  scope.observeDocument = nop;
  scope.upgradeDocument = nop;
  scope.takeRecords = nop;

} else {

  /**
   * Registers a custom tag name with the document.
   *
   * When a registered element is created, a `readyCallback` method is called
   * in the scope of the element. The `readyCallback` method can be specified on
   * either `options.prototype` or `options.lifecycle` with the latter taking
   * precedence.
   *
   * @method register
   * @param {String} name The tag name to register. Must include a dash ('-'),
   *    for example 'x-component'.
   * @param {Object} options
   *    @param {String} [options.extends]
   *      (_off spec_) Tag name of an element to extend (or blank for a new
   *      element). This parameter is not part of the specification, but instead
   *      is a hint for the polyfill because the extendee is difficult to infer.
   *      Remember that the input prototype must chain to the extended element's
   *      prototype (or HTMLElement.prototype) regardless of the value of
   *      `extends`.
   *    @param {Object} options.prototype The prototype to use for the new
   *      element. The prototype must inherit from HTMLElement.
   *    @param {Object} [options.lifecycle]
   *      Callbacks that fire at important phases in the life of the custom
   *      element.
   *
   * @example
   *      FancyButton = document.register("fancy-button", {
   *        extends: 'button',
   *        prototype: Object.create(HTMLButtonElement.prototype, {
   *          readyCallback: {
   *            value: function() {
   *              console.log("a fancy-button was created",
   *            }
   *          }
   *        })
   *      });
   * @return {Function} Constructor for the newly registered type.
   */
  function register(name, options) {
    //console.warn('document.register("' + name + '", ', options, ')');
    // construct a defintion out of options
    // TODO(sjmiles): probably should clone options instead of mutating it
    var definition = options || {};
    if (!name) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('document.register: first argument `name` must not be empty');
    }
    if (name.indexOf('-') < 0) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('document.register: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
    }
    // elements may only be registered once
    if (getRegisteredDefinition(name)) {
      throw new Error('DuplicateDefinitionError: a type with name \'' + String(name) + '\' is already registered');
    }
    // must have a prototype, default to an extension of HTMLElement
    // TODO(sjmiles): probably should throw if no prototype, check spec
    if (!definition.prototype) {
      // TODO(sjmiles): replace with more appropriate error (EricB can probably
      // offer guidance)
      throw new Error('Options missing required prototype property');
    }
    // record name
    definition.__name = name.toLowerCase();
    // ensure a lifecycle object so we don't have to null test it
    definition.lifecycle = definition.lifecycle || {};
    // build a list of ancestral custom elements (for native base detection)
    // TODO(sjmiles): we used to need to store this, but current code only
    // uses it in 'resolveTagName': it should probably be inlined
    definition.ancestry = ancestry(definition.extends);
    // extensions of native specializations of HTMLElement require localName
    // to remain native, and use secondary 'is' specifier for extension type
    resolveTagName(definition);
    // some platforms require modifications to the user-supplied prototype
    // chain
    resolvePrototypeChain(definition);
    // overrides to implement attributeChanged callback
    overrideAttributeApi(definition.prototype);
    // 7.1.5: Register the DEFINITION with DOCUMENT
    registerDefinition(definition.__name, definition);
    // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
    // 7.1.8. Return the output of the previous step.
    definition.ctor = generateConstructor(definition);
    definition.ctor.prototype = definition.prototype;
    // force our .constructor to be our actual constructor
    definition.prototype.constructor = definition.ctor;
    // if initial parsing is complete
    if (scope.ready) {
      // upgrade any pre-existing nodes of this type
      scope.upgradeAll(document);
    }
    return definition.ctor;
  }

  function ancestry(extnds) {
    var extendee = getRegisteredDefinition(extnds);
    if (extendee) {
      return ancestry(extendee.extends).concat([extendee]);
    }
    return [];
  }

  function resolveTagName(definition) {
    // if we are explicitly extending something, that thing is our
    // baseTag, unless it represents a custom component
    var baseTag = definition.extends;
    // if our ancestry includes custom components, we only have a
    // baseTag if one of them does
    for (var i=0, a; (a=definition.ancestry[i]); i++) {
      baseTag = a.is && a.tag;
    }
    // our tag is our baseTag, if it exists, and otherwise just our name
    definition.tag = baseTag || definition.__name;
    if (baseTag) {
      // if there is a base tag, use secondary 'is' specifier
      definition.is = definition.__name;
    }
  }

  function resolvePrototypeChain(definition) {
    // if we don't support __proto__ we need to locate the native level
    // prototype for precise mixing in
    if (!Object.__proto__) {
      // default prototype
      var nativePrototype = HTMLElement.prototype;
      // work out prototype when using type-extension
      if (definition.is) {
        var inst = document.createElement(definition.tag);
        nativePrototype = Object.getPrototypeOf(inst);
      }
      // ensure __proto__ reference is installed at each point on the prototype
      // chain.
      // NOTE: On platforms without __proto__, a mixin strategy is used instead
      // of prototype swizzling. In this case, this generated __proto__ provides
      // limited support for prototype traversal.
      var proto = definition.prototype, ancestor;
      while (proto && (proto !== nativePrototype)) {
        var ancestor = Object.getPrototypeOf(proto);
        proto.__proto__ = ancestor;
        proto = ancestor;
      }
    }
    // cache this in case of mixin
    definition.native = nativePrototype;
  }

  // SECTION 4

  function instantiate(definition) {
    // 4.a.1. Create a new object that implements PROTOTYPE
    // 4.a.2. Let ELEMENT by this new object
    //
    // the custom element instantiation algorithm must also ensure that the
    // output is a valid DOM element with the proper wrapper in place.
    //
    return upgrade(domCreateElement(definition.tag), definition);
  }

  function upgrade(element, definition) {
    // some definitions specify an 'is' attribute
    if (definition.is) {
      element.setAttribute('is', definition.is);
    }
    // remove 'unresolved' attr, which is a standin for :unresolved.
    element.removeAttribute('unresolved');
    // make 'element' implement definition.prototype
    implement(element, definition);
    // flag as upgraded
    element.__upgraded__ = true;
    // there should never be a shadow root on element at this point
    // we require child nodes be upgraded before `created`
    scope.upgradeSubtree(element);
    // lifecycle management
    created(element);
    // OUTPUT
    return element;
  }

  function implement(element, definition) {
    // prototype swizzling is best
    if (Object.__proto__) {
      element.__proto__ = definition.prototype;
    } else {
      // where above we can re-acquire inPrototype via
      // getPrototypeOf(Element), we cannot do so when
      // we use mixin, so we install a magic reference
      customMixin(element, definition.prototype, definition.native);
      element.__proto__ = definition.prototype;
    }
  }

  function customMixin(inTarget, inSrc, inNative) {
    // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of
    // any property. This set should be precalculated. We also need to
    // consider this for supporting 'super'.
    var used = {};
    // start with inSrc
    var p = inSrc;
    // sometimes the default is HTMLUnknownElement.prototype instead of
    // HTMLElement.prototype, so we add a test
    // the idea is to avoid mixing in native prototypes, so adding
    // the second test is WLOG
    while (p !== inNative && p !== HTMLUnknownElement.prototype) {
      var keys = Object.getOwnPropertyNames(p);
      for (var i=0, k; k=keys[i]; i++) {
        if (!used[k]) {
          Object.defineProperty(inTarget, k,
              Object.getOwnPropertyDescriptor(p, k));
          used[k] = 1;
        }
      }
      p = Object.getPrototypeOf(p);
    }
  }

  function created(element) {
    // invoke createdCallback
    if (element.createdCallback) {
      element.createdCallback();
    }
  }

  // attribute watching

  function overrideAttributeApi(prototype) {
    // overrides to implement callbacks
    // TODO(sjmiles): should support access via .attributes NamedNodeMap
    // TODO(sjmiles): preserves user defined overrides, if any
    if (prototype.setAttribute._polyfilled) {
      return;
    }
    var setAttribute = prototype.setAttribute;
    prototype.setAttribute = function(name, value) {
      changeAttribute.call(this, name, value, setAttribute);
    }
    var removeAttribute = prototype.removeAttribute;
    prototype.removeAttribute = function(name) {
      changeAttribute.call(this, name, null, removeAttribute);
    }
    prototype.setAttribute._polyfilled = true;
  }

  // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
  // index.html#dfn-attribute-changed-callback
  function changeAttribute(name, value, operation) {
    var oldValue = this.getAttribute(name);
    operation.apply(this, arguments);
    var newValue = this.getAttribute(name);
    if (this.attributeChangedCallback
        && (newValue !== oldValue)) {
      this.attributeChangedCallback(name, oldValue, newValue);
    }
  }

  // element registry (maps tag names to definitions)

  var registry = {};

  function getRegisteredDefinition(name) {
    if (name) {
      return registry[name.toLowerCase()];
    }
  }

  function registerDefinition(name, definition) {
    registry[name] = definition;
  }

  function generateConstructor(definition) {
    return function() {
      return instantiate(definition);
    };
  }

  function createElement(tag, typeExtension) {
    // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
    // error check it, or perhaps there should only ever be one argument
    var definition = getRegisteredDefinition(typeExtension || tag);
    if (definition) {
      return new definition.ctor();
    }
    return domCreateElement(tag);
  }

  function upgradeElement(element) {
    if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
      var type = element.getAttribute('is') || element.localName;
      var definition = getRegisteredDefinition(type);
      return definition && upgrade(element, definition);
    }
  }

  function cloneNode(deep) {
    // call original clone
    var n = domCloneNode.call(this, deep);
    // upgrade the element and subtree
    scope.upgradeAll(n);
    // return the clone
    return n;
  }
  // capture native createElement before we override it

  var domCreateElement = document.createElement.bind(document);

  // capture native cloneNode before we override it

  var domCloneNode = Node.prototype.cloneNode;

  // exports

  document.register = register;
  document.createElement = createElement; // override
  Node.prototype.cloneNode = cloneNode; // override

  scope.registry = registry;

  /**
   * Upgrade an element to a custom element. Upgrading an element
   * causes the custom prototype to be applied, an `is` attribute
   * to be attached (as needed), and invocation of the `readyCallback`.
   * `upgrade` does nothing if the element is already upgraded, or
   * if it matches no registered custom tag name.
   *
   * @method ugprade
   * @param {Element} element The element to upgrade.
   * @return {Element} The upgraded element.
   */
  scope.upgrade = upgradeElement;
}

scope.hasNative = hasNative;
scope.useNative = useNative;

})(window.CustomElements);
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

class TimeSelect extends React.Component {
  render = () => {
    // FIXME: Do a Simple Select here:
    // https://material-ui.com/components/selects/#simple-select
    return
Imagine a dropdown here

  }
}

TimeSelect.propTypes = {
  onSelect: PropTypes.func.isRequired
}

export default TimeSelect
<commit_msg>Add a proper dropdown<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import NativeSelect from '@material-ui/core/NativeSelect'

class TimeSelect extends React.Component {
  render = () => {
    // Inspired by: https://material-ui.com/components/selects/#native-select
    return (
      <NativeSelect value={'now'}>
        <option value={'now'}>Now</option>
        <option value={'tomorrow'}>Tomorrow</option>
      </NativeSelect>
    )
  }
}

TimeSelect.propTypes = {
  onSelect: PropTypes.func.isRequired
}

export default TimeSelect
<|endoftext|>


<commit_before>/**
 * Joint abstract class.
 * A Joint represents a node in the hierarchy.
 */
define([
    'events-emitter/EventsEmitter',
    'services/broadcaster',
    '../util/extend',
    'mout/array/insert',
    'mout/array/remove',
    'has'
], function (EventsEmitter, broadcaster, extend, insert, remove, has) {

    'use strict';

    /**
     * Constructor.
     */
    function Joint() {
        this._downlinks = [];
        this._emitter = new EventsEmitter();
    }

    Joint.extend = extend;

    /**
     * Adds a listener for an upcast or broadcast event.
     * Duplicate listeners for the same event will be discarded.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context to be used to call the handler, defaults to the joint instance
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.on = function (event, fn, context) {
        this._emitter.on(event, fn, context);
        broadcaster.on(event, fn, context);

        return this;
    };

    /**
     * Adds a one time listener for an upcast or broadcast event.
     * Duplicate listeners for the same event will be discarded.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context to be used to call the handler, defaults to the joint instance
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.once = function (event, fn, context) {
        this._emitter.once(event, fn, context);
        broadcaster.once(event, fn, context);

        return this;
    };

    Joint.prototype.one = Joint.prototype.once;

    /**
     * Removes a previously added listener.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context passed to the on() method
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.off = function (event, fn, context) {
        this._emitter.off(event, fn, context);
        broadcaster.off(event, fn, context);

        return this;
    };

    /**
     * Checks if the instance is destroyed.
     *
     * @return {Boolean} True if it is, false otherwise
     */
    Joint.prototype.isDestroyed = function () {
        return !!this._destroyed;
    };

    /**
     * Destroys the instance, releasing all of its resources.
     * Note that all downlinks will also be destroyed.
     */
    Joint.prototype.destroy = function () {
        if (!this._destroyed) {
            this._destroyed = true;
            this._onDestroy();
        }
    };

    // --------------------------------------------

    /**
     * Creates a link between this joint and another one.
     *
     * @param {Joint} joint Another joint to link to this one
     *
     * @return {Joint} The joint passed in as the argument
     */
    Joint.prototype._link = function (joint) {
        if (has('debug') && joint._uplink && joint._uplink !== this) {
            throw new Error('"' + joint.$name + '" is already linked to other joint');
        }

        if (joint._uplink !== this) {
            joint._uplink = this;
            insert(this._downlinks, joint);
            joint._emitter.emit('link', this);
        }

        return joint;
    };

    /**
     * Removes a previously created link between this joint and another one.
     *
     * @param {Joint} joint Another joint to link to this one
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype._unlink = function (joint) {
        remove(this._downlinks, joint);

        if (joint._uplink === this) {
            joint._uplink = null;
            joint._emitter.emit('unlink', this);
        }

        return this;
    };

    /**
     * Fires an event.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._emit = function (event, args) {
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        return false;
    };

    /**
     * Fires an event upwards the chain.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._bubbleUp = function (event, args) {
        if (this._uplink) {
            return this._uplink._upcast(event, args);
        }

        if (has('debug')) {
            console.warn('[spoonjs] Unhandled upcast event "' + event + '".');
        }

        return false;
    };

    /**
     * Fires an event downwards the chain.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._bubbleDown = function (event, args) {
        var x,
            length,
            last,
            curr,
            currHandled,
            handled = false;

        // Cycle each downlink
        length = this._downlinks.length;
        for (x = 0; x < length; x += 1) {
            curr = this._downlinks[x];

            // Protect against triggered events that cause the destruction of links
            if (!curr || curr === last) {
                continue;
            }

            currHandled = curr._downcast.apply(curr, arguments);
            if (currHandled) {
                handled = true;
            }
        }

        return handled;
    };

    /**
     * Fires an event upwards the chain, starting in this Joint.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._upcast = function (event, args) {
        // Check if the event will be handled locally
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        // Otherwise we will keep upcasting upwards the chain
        if (this._uplink) {
            return this._uplink._upcast.apply(this._uplink, arguments);
        }

        if (has('debug')) {
            console.warn('[spoonjs] Unhandled upcast event "' + event + '".');
        }

        return false;
    };

    /**
     * Fires an event downwards the chain, starting in this Joint.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._downcast = function (event, args) {
        var x,
            length,
            last,
            curr,
            currHandled,
            handled = false;

        // Check if the event will be handled locally
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        // Cycle each downlink
        length = this._downlinks.length;
        for (x = 0; x < length; x += 1) {
            curr = this._downlinks[x];

            // Protect against triggered events that cause the destruction of links
            if (!curr || curr === last) {
                continue;
            }

            currHandled = curr._downcast.apply(curr, arguments);
            if (currHandled) {
                handled = true;
            }
        }

        return handled;
    };

    /**
     * Fires an event to all the joints.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._broadcast = function (event, args) {
        return broadcaster.broadcast.apply(broadcaster, arguments);
    };

    /**
     * Function called by destroy().
     * Subclasses should override this method to release additional resources.
     *
     * The default implementation will also destroy any linked joints.
     */
    Joint.prototype._onDestroy = function () {
        var x,
            curr;

        // Foreach downlink, automatically destroy
        for (x = this._downlinks.length - 1; x >= 0; x -= 1) {
            curr = this._downlinks[x];
            curr && curr.destroy();  // We need to check if it still exists
        }
        this._downlinks = null;

        // Foreach uplink, automatically unlink this instance
        if (this._uplink) {
            this._uplink._unlink(this);
            this._uplink = null;
        }

        // Remove the listeners from the broadcaster
        this._emitter.forEach(broadcaster.off, broadcaster);

        // Clear the listeners
        this._emitter.off();
    };

    return Joint;
});
<commit_msg>[fix] bubbleUp with arguments<commit_after>/**
 * Joint abstract class.
 * A Joint represents a node in the hierarchy.
 */
define([
    'events-emitter/EventsEmitter',
    'services/broadcaster',
    '../util/extend',
    'mout/array/insert',
    'mout/array/remove',
    'has'
], function (EventsEmitter, broadcaster, extend, insert, remove, has) {

    'use strict';

    /**
     * Constructor.
     */
    function Joint() {
        this._downlinks = [];
        this._emitter = new EventsEmitter();
    }

    Joint.extend = extend;

    /**
     * Adds a listener for an upcast or broadcast event.
     * Duplicate listeners for the same event will be discarded.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context to be used to call the handler, defaults to the joint instance
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.on = function (event, fn, context) {
        this._emitter.on(event, fn, context);
        broadcaster.on(event, fn, context);

        return this;
    };

    /**
     * Adds a one time listener for an upcast or broadcast event.
     * Duplicate listeners for the same event will be discarded.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context to be used to call the handler, defaults to the joint instance
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.once = function (event, fn, context) {
        this._emitter.once(event, fn, context);
        broadcaster.once(event, fn, context);

        return this;
    };

    Joint.prototype.one = Joint.prototype.once;

    /**
     * Removes a previously added listener.
     *
     * @param {String}   event     The event name
     * @param {Function} fn        The handler
     * @param {Object}   [context] The context passed to the on() method
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype.off = function (event, fn, context) {
        this._emitter.off(event, fn, context);
        broadcaster.off(event, fn, context);

        return this;
    };

    /**
     * Checks if the instance is destroyed.
     *
     * @return {Boolean} True if it is, false otherwise
     */
    Joint.prototype.isDestroyed = function () {
        return !!this._destroyed;
    };

    /**
     * Destroys the instance, releasing all of its resources.
     * Note that all downlinks will also be destroyed.
     */
    Joint.prototype.destroy = function () {
        if (!this._destroyed) {
            this._destroyed = true;
            this._onDestroy();
        }
    };

    // --------------------------------------------

    /**
     * Creates a link between this joint and another one.
     *
     * @param {Joint} joint Another joint to link to this one
     *
     * @return {Joint} The joint passed in as the argument
     */
    Joint.prototype._link = function (joint) {
        if (has('debug') && joint._uplink && joint._uplink !== this) {
            throw new Error('"' + joint.$name + '" is already linked to other joint');
        }

        if (joint._uplink !== this) {
            joint._uplink = this;
            insert(this._downlinks, joint);
            joint._emitter.emit('link', this);
        }

        return joint;
    };

    /**
     * Removes a previously created link between this joint and another one.
     *
     * @param {Joint} joint Another joint to link to this one
     *
     * @return {Joint} The instance itself to allow chaining
     */
    Joint.prototype._unlink = function (joint) {
        remove(this._downlinks, joint);

        if (joint._uplink === this) {
            joint._uplink = null;
            joint._emitter.emit('unlink', this);
        }

        return this;
    };

    /**
     * Fires an event.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._emit = function (event, args) {
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        return false;
    };

    /**
     * Fires an event upwards the chain.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._bubbleUp = function (event, args) {
        if (this._uplink) {
            return this._uplink._upcast.apply(this._uplink, arguments);
        }

        if (has('debug')) {
            console.warn('[spoonjs] Unhandled upcast event "' + event + '".');
        }

        return false;
    };

    /**
     * Fires an event downwards the chain.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._bubbleDown = function (event, args) {
        var x,
            length,
            last,
            curr,
            currHandled,
            handled = false;

        // Cycle each downlink
        length = this._downlinks.length;
        for (x = 0; x < length; x += 1) {
            curr = this._downlinks[x];

            // Protect against triggered events that cause the destruction of links
            if (!curr || curr === last) {
                continue;
            }

            currHandled = curr._downcast.apply(curr, arguments);
            if (currHandled) {
                handled = true;
            }
        }

        return handled;
    };

    /**
     * Fires an event upwards the chain, starting in this Joint.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._upcast = function (event, args) {
        // Check if the event will be handled locally
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        // Otherwise we will keep upcasting upwards the chain
        if (this._uplink) {
            return this._uplink._upcast.apply(this._uplink, arguments);
        }

        if (has('debug')) {
            console.warn('[spoonjs] Unhandled upcast event "' + event + '".');
        }

        return false;
    };

    /**
     * Fires an event downwards the chain, starting in this Joint.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._downcast = function (event, args) {
        var x,
            length,
            last,
            curr,
            currHandled,
            handled = false;

        // Check if the event will be handled locally
        if (this._emitter.has(event)) {
            this._emitter.emit.apply(this._emitter, arguments);
            return true;
        }

        // Cycle each downlink
        length = this._downlinks.length;
        for (x = 0; x < length; x += 1) {
            curr = this._downlinks[x];

            // Protect against triggered events that cause the destruction of links
            if (!curr || curr === last) {
                continue;
            }

            currHandled = curr._downcast.apply(curr, arguments);
            if (currHandled) {
                handled = true;
            }
        }

        return handled;
    };

    /**
     * Fires an event to all the joints.
     *
     * @param {String}   event  The event name
     * @param {...mixed} [args] The arguments to pass along with the event
     *
     * @return {Boolean} True if it was handled, false otherwise
     */
    Joint.prototype._broadcast = function (event, args) {
        return broadcaster.broadcast.apply(broadcaster, arguments);
    };

    /**
     * Function called by destroy().
     * Subclasses should override this method to release additional resources.
     *
     * The default implementation will also destroy any linked joints.
     */
    Joint.prototype._onDestroy = function () {
        var x,
            curr;

        // Foreach downlink, automatically destroy
        for (x = this._downlinks.length - 1; x >= 0; x -= 1) {
            curr = this._downlinks[x];
            curr && curr.destroy();  // We need to check if it still exists
        }
        this._downlinks = null;

        // Foreach uplink, automatically unlink this instance
        if (this._uplink) {
            this._uplink._unlink(this);
            this._uplink = null;
        }

        // Remove the listeners from the broadcaster
        this._emitter.forEach(broadcaster.off, broadcaster);

        // Clear the listeners
        this._emitter.off();
    };

    return Joint;
});
<|endoftext|>


<commit_before>import config from './Config';

const DISCORD_GATEWAY_ENDPOINT = 'wss://gateway.discord.gg/?v=6&encoding=json';

const OS = navigator.platform;
const BROWSER = 'Chrome';
const DEVICE = chrome.i18n.getMessage('appName');

export default class DiscordGateway {
  constructor(token, retryDelay = 500, closeDelay = 600000) {
    this._token = token;
    this._retryDelay = retryDelay;
    this._closeDelay = closeDelay;
  }
  sendStatusUpdate(newStatus) {
    clearTimeout(this._retryTimer);
    clearTimeout(this._closeTimer);
    if (!this._ws || this._ws.readyState === WebSocket.CLOSED) {
      /* Connect websocket */
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: initialize websocket...`);
      }
      this._ws = new WebSocket(DISCORD_GATEWAY_ENDPOINT);
      this._lastSeq = null;
      this._ws.onopen = (e) => {
        this._send(this._getOpIdentifyPayload(newStatus)); /* Identify and send initial status */
        this._identifyStatus = newStatus;
      };
      this._ws.onmessage = (e) => this._messageHandler(JSON.parse(e.data));
      this._ws.onerror = (e) => console.log(`Token ${this._token}: connection error`);
      this._ws.onclose = (e) => {
        clearInterval(this._heartbeatTimer);
        if (config.loggingEnabled) {
          console.log(`Token ${this._token}: connection closed\n - code: ${e.code}\n - reason: ${e.reason}\n - wasClean: ${e.wasClean}`);
        }
      };
    } else if (this._ws.readyState === WebSocket.OPEN) {
      this._send(this._getOpStatusUpdatePayload(newStatus)); /* Send status update */
    } else if (this._ws.readyState === WebSocket.CONNECTING || this._ws.readyState === WebSocket.CLOSING) {
      this._retryTimer = setTimeout(() => this.sendStatusUpdate(newStatus), this._retryDelay); /* Retry later */
    }
    if (this._closeDelay > 0) {
      this._closeTimer = setTimeout(this.close, this._closeDelay);
    }
  }
  close() {
    clearTimeout(this._retryTimer);
    clearTimeout(this._closeTimer);
    if (this._ws && (this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CONNECTING)) {
      this._ws.close();
    }
  }
  _send(payload) {
    this._ws.send(JSON.stringify(payload));
    if (config.loggingEnabled) {
      console.log(`Token ${this._token}: sent ${JSON.stringify(payload, null, 4)}`);
    }
  }
  /* Send heartbeat */
  _sendHeartbeat() {
    if (this._ws && this._ws.readyState === WebSocket.OPEN) {
      this._send(getOpHeartbeatPayload());
    }
  }
  _messageHandler(data) {
    this._lastSeq = data.s;
    switch (data.op) {
    case 1: /* heartbeat request */
      this._sendHeartbeat();
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: received heartbeat request message: ${JSON.stringify(data, null, 4)}`);
      }
      break;
    case 10: /* hello */
      clearInterval(this._heartbeatTimer);
      this._heartbeatTimer = setInterval(this._sendHeartbeat, data.d.heartbeat_interval)
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: received hello message: ${JSON.stringify(data, null, 4)}`);
      }
      if (!this._identifyStatus) {
        this._send(this._getOpStatusUpdatePayload(this._identifyStatus)); /* Send status update if status is null, because null initial status doesn't work */
      }
      break;
    default:
    }
  }
  /* Get heartbeat operation payload */
  _getOpHeartbeatPayload() {
    return {
      op: 1,
      d: this._lastSeq,
    };
  }
  /* Get status update partial payload */
  _getStatusUpdatePayload(status) {
    return {
      game: status === null ? null : {
        name: status,
        type: 2,
      },
      status: 'online',
      since: null,
      afk: false,
    };
  }
  /* Get identify operation payload */
  _getOpIdentifyPayload(status) {
    return {
      op: 2,
      d: {
        token: this._token,
        properties: {
          $os: OS,
          $browser: BROWSER,
          $device: DEVICE,
        },
        compress: false,
        large_threshold: 50,
        presence: this._getStatusUpdatePayload(status),
      }
    };
  }
  /* Get status update operation payload */
  _getOpStatusUpdatePayload(status) {
    return {
      op: 3,
      d: this._getStatusUpdatePayload(status),
    };
  }
}
<commit_msg>Corrige la déconnexion au bout de 2 minutes<commit_after>import config from './Config';

const DISCORD_GATEWAY_ENDPOINT = 'wss://gateway.discord.gg/?v=6&encoding=json';

const OS = navigator.platform;
const BROWSER = 'Chrome';
const DEVICE = chrome.i18n.getMessage('appName');

export default class DiscordGateway {
  constructor(token, retryDelay = 500, closeDelay = 600000) {
    this._token = token;
    this._retryDelay = retryDelay;
    this._closeDelay = closeDelay;
  }
  sendStatusUpdate(newStatus) {
    clearTimeout(this._retryTimer);
    clearTimeout(this._closeTimer);
    if (!this._ws || this._ws.readyState === WebSocket.CLOSED) {
      /* Connect websocket */
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: initialize websocket...`);
      }
      this._ws = new WebSocket(DISCORD_GATEWAY_ENDPOINT);
      this._lastSeq = null;
      this._ws.onopen = (e) => {
        this._send(this._getOpIdentifyPayload(newStatus)); /* Identify and send initial status */
        this._identifyStatus = newStatus;
      };
      this._ws.onmessage = (e) => this._messageHandler(JSON.parse(e.data));
      this._ws.onerror = (e) => console.log(`Token ${this._token}: connection error`);
      this._ws.onclose = (e) => {
        clearInterval(this._heartbeatTimer);
        if (config.loggingEnabled) {
          console.log(`Token ${this._token}: connection closed\n - code: ${e.code}\n - reason: ${e.reason}\n - wasClean: ${e.wasClean}`);
        }
      };
    } else if (this._ws.readyState === WebSocket.OPEN) {
      this._send(this._getOpStatusUpdatePayload(newStatus)); /* Send status update */
    } else if (this._ws.readyState === WebSocket.CONNECTING || this._ws.readyState === WebSocket.CLOSING) {
      this._retryTimer = setTimeout(() => this.sendStatusUpdate(newStatus), this._retryDelay); /* Retry later */
    }
    if (this._closeDelay > 0) {
      this._closeTimer = setTimeout(this.close, this._closeDelay);
    }
  }
  close() {
    clearTimeout(this._retryTimer);
    clearTimeout(this._closeTimer);
    if (this._ws && (this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CONNECTING)) {
      this._ws.close();
    }
  }
  _send(payload) {
    this._ws.send(JSON.stringify(payload));
    if (config.loggingEnabled) {
      console.log(`Token ${this._token}: sent ${JSON.stringify(payload, null, 4)}`);
    }
  }
  /* Send heartbeat */
  _sendHeartbeat() {
    if (this._ws && this._ws.readyState === WebSocket.OPEN) {
      this._send(this._getOpHeartbeatPayload());
    }
  }
  _messageHandler(data) {
    this._lastSeq = data.s;
    switch (data.op) {
    case 1: /* heartbeat request */
      this._sendHeartbeat();
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: received heartbeat request message: ${JSON.stringify(data, null, 4)}`);
      }
      break;
    case 10: /* hello */
      clearInterval(this._heartbeatTimer);
      this._heartbeatTimer = setInterval(this._sendHeartbeat.bind(this), data.d.heartbeat_interval)
      if (config.loggingEnabled) {
        console.log(`Token ${this._token}: received hello message: ${JSON.stringify(data, null, 4)}`);
      }
      if (!this._identifyStatus) {
        this._send(this._getOpStatusUpdatePayload(this._identifyStatus)); /* Send status update if status is null, because null initial status doesn't work */
      }
      break;
    default:
    }
  }
  /* Get heartbeat operation payload */
  _getOpHeartbeatPayload() {
    return {
      op: 1,
      d: this._lastSeq,
    };
  }
  /* Get status update partial payload */
  _getStatusUpdatePayload(status) {
    return {
      game: status === null ? null : {
        name: status,
        type: 2,
      },
      status: 'online',
      since: null,
      afk: false,
    };
  }
  /* Get identify operation payload */
  _getOpIdentifyPayload(status) {
    return {
      op: 2,
      d: {
        token: this._token,
        properties: {
          $os: OS,
          $browser: BROWSER,
          $device: DEVICE,
        },
        compress: false,
        large_threshold: 50,
        presence: this._getStatusUpdatePayload(status),
      }
    };
  }
  /* Get status update operation payload */
  _getOpStatusUpdatePayload(status) {
    return {
      op: 3,
      d: this._getStatusUpdatePayload(status),
    };
  }
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';

import Meadow from './Meadow';

export default React.createClass({
  displayName: 'Meadow.TypeChoice',

  getDefaultProps() {
    return {
      types: [],
      onReplaceInfoAtKeyPath: null,
      tabIndex: 0
    };
  },

  shouldComponentUpdate(nextProps, nextState) {
    const currentProps = this.props;

    return (
      nextProps.types !== currentProps.types ||
      nextProps.value != currentProps.value ||
      nextProps.typeSpecs !== currentProps.typeSpecs ||
      nextProps.fieldSpecs !== currentProps.fieldSpecs ||
      nextProps.fieldComponent !== currentProps.fieldComponent ||
      nextProps.onReplaceInfoAtKeyPath !== currentProps.onReplaceInfoAtKeyPath
    );
  },

  getDefaultSelectedType() {
    // Choose first item by default.
    const { types } = this.props;
    if (types.length > 0) {
      return types[0].id;
    }
  },

  getSelectedType() {
    const { value } = this.props;
    let selectedType = value ? value.type : null;
    if (!selectedType) {
      selectedType = this.getDefaultSelectedType();
    }
    return selectedType;
  },

  onChangeType(newSelectedType) {
    const info = {
      type: newSelectedType
    };

    const { onReplaceInfoAtKeyPath } = this.props;
    if (onReplaceInfoAtKeyPath) {
      onReplaceInfoAtKeyPath(info, []);
    }
  },

  onChildFieldReplaceInfoAtKeyPath(info, keyPath) {
    let selectedType = this.getSelectedType();

    keyPath = [selectedType].concat(keyPath);

    var onReplaceInfoAtKeyPath = this.props.onReplaceInfoAtKeyPath;
    if (onReplaceInfoAtKeyPath) {
      onReplaceInfoAtKeyPath(info, keyPath);
    }
  },

  render() {
    const {
      types,
      value,
      typeSpecs,
      fieldSpecs,
      fieldComponent: Field,
      onReplaceInfoAtKeyPath,
      ...rest,
    } = this.props;

    const selectedType = this.getSelectedType();
    let selectedTypeSpec = null;

    types.some(typeID => {
      if (typeID === selectedType) {
        selectedTypeSpec = typeSpecs[typeID];
        return false;
      }

      return true;
    });

    const typeChoices = types.map(typeID => ({
      id: typeID,
      title: typeSpecs[typeID].title,
    }));

    let element = (
      <Field key='typeChoice'
        type='choice'
        value={ selectedType }
        choices={ typeChoices }
        { ...rest }
        onChangeValue={ this.onChangeType }
      />
    );

    let children = [ element ];

    // Show fields for the selected choice.
    if (!!selectedTypeSpec && selectedTypeSpec.fields) {
      children = children.concat(
        <Meadow key='fields'
          fields={ selectedTypeSpec.fields }
          values={ value }
          typeSpecs={ typeSpecs }
          fieldSpecs={ fieldSpecs }
          onReplaceInfoAtKeyPath={ this.onChildFieldReplaceInfoAtKeyPath }
          fieldComponent={ Field }
        />
      );
    }

    return (

{ children }

    );
  }
});
<commit_msg>Refactor TypeChoice<commit_after>import React, { PropTypes } from 'react';

import Meadow from './Meadow';

export default React.createClass({
  displayName: 'Meadow.TypeChoice',

  getDefaultProps() {
    return {
      types: [],
      onReplaceInfoAtKeyPath: null,
      tabIndex: 0
    };
  },

  shouldComponentUpdate(nextProps, nextState) {
    const currentProps = this.props;

    return (
      nextProps.types !== currentProps.types ||
      nextProps.value != currentProps.value ||
      nextProps.typeSpecs !== currentProps.typeSpecs ||
      nextProps.fieldSpecs !== currentProps.fieldSpecs ||
      nextProps.fieldComponent !== currentProps.fieldComponent ||
      nextProps.onReplaceInfoAtKeyPath !== currentProps.onReplaceInfoAtKeyPath
    );
  },

  getDefaultSelectedType() {
    // Choose first item by default.
    const { types } = this.props;
    if (types.length > 0) {
      return types[0];
    }
  },

  getSelectedType() {
    const { value } = this.props;
    let selectedType = value ? value.type : null;
    if (!selectedType) {
      selectedType = this.getDefaultSelectedType();
    }
    return selectedType;
  },

  onChangeType(newSelectedType) {
    if (!!value && (value.type === newSelectedType)) {
      return;
    }

    const info = {
      type: newSelectedType
    };

    this.props.onReplaceInfoAtKeyPath(info, []);
  },

  render() {
    const {
      types,
      value,
      typeSpecs,
      fieldSpecs,
      fieldComponent: Field,
      onReplaceInfoAtKeyPath,
      ...rest,
    } = this.props;

    const selectedType = this.getSelectedType();
    let selectedTypeSpec = null;

    types.some(typeID => {
      if (typeID === selectedType) {
        selectedTypeSpec = typeSpecs[typeID];;
      }

      return false;
    });

    const typeChoices = types.map(typeID => ({
      id: typeID,
      title: typeSpecs[typeID].title,
    }));

    let element = (
      <Field key='typeChoice'
        type='choice'
        value={ selectedType }
        choices={ typeChoices }
        { ...rest }
        onChangeValue={ this.onChangeType }
      />
    );

    let children = [ element ];

    // Show fields for the selected choice.
    if (!!selectedTypeSpec && !!selectedTypeSpec.fields) {
      children.push(
        <Meadow key='fields'
          fields={ selectedTypeSpec.fields }
          values={ value }
          typeSpecs={ typeSpecs }
          fieldSpecs={ fieldSpecs }
          fieldComponent={ Field }
          onReplaceInfoAtKeyPath={ onReplaceInfoAtKeyPath }
        />
      );
    }

    return (

{ children }

    );
  },
});
<|endoftext|>


<commit_before>
import _ from 'lodash';

import Tyr      from '../tyr';
import NamePath from './namePath';

export default class Field {

  constructor(def) {
    this.def = def;
  }

  get label() {
    return _.result(this.def, 'label') || Tyr.labelize(this.name);
  }

  get namePath() {
    let np = this._np;
    if (!np) {
      np = this._np = new NamePath(this.collection, this.path);
    }
    return np;
  }

  get spath() {
    let sp = this._spath;
    if (!sp) {
      sp = this._spath = this.path.replace('._', '');
    }

    return sp;
  }

  get db() {
    return this.def.db !== false;
  }

  /** @private @isopmorphic */
  _calcPathLabel() {
    const p = this.parent,
          l = this.def.pathLabel || this.label;

    if (p) {
      const pl = p.pathLabel;

      if (pl) {
        return pl + ' ' + l;
      }
    }

    return l;
  }

  get pathLabel() {
    return this._calcPathLabel();
  }
}

Tyr.Field = Field;
<commit_msg>fixes #56, need to replaceAll to create spath<commit_after>
import _ from 'lodash';

import Tyr      from '../tyr';
import NamePath from './namePath';

const PATH_REGEX = /\._/g;

export default class Field {

  constructor(def) {
    this.def = def;
  }

  get label() {
    return _.result(this.def, 'label') || Tyr.labelize(this.name);
  }

  get namePath() {
    let np = this._np;
    if (!np) {
      np = this._np = new NamePath(this.collection, this.path);
    }
    return np;
  }

  get spath() {
    let sp = this._spath;
    if (!sp) {
      sp = this._spath = this.path.replace(PATH_REGEX, '');
    }
    return sp;
  }

  get db() {
    return this.def.db !== false;
  }

  /** @private @isopmorphic */
  _calcPathLabel() {
    const p = this.parent,
          l = this.def.pathLabel || this.label;

    if (p) {
      const pl = p.pathLabel;

      if (pl) {
        return pl + ' ' + l;
      }
    }

    return l;
  }

  get pathLabel() {
    return this._calcPathLabel();
  }
}

Tyr.Field = Field;
<|endoftext|>